diff options
author | Steve Klebanoff <steve.klebanoff@gmail.com> | 2018-12-22 06:57:16 +0800 |
---|---|---|
committer | Steve Klebanoff <steve.klebanoff@gmail.com> | 2018-12-22 06:57:16 +0800 |
commit | e144ebbb936c74b4af0e1c1776578208ea148de4 (patch) | |
tree | c5ab2823603b25d11d46493e9c8f79801bef0dcd | |
parent | aa9aa1f58a4e63b5e5c7863f3b7afb020d7712c5 (diff) | |
parent | 9b540fd8e52e7578d3749e6d9ef9cd97d602ffb3 (diff) | |
download | dexon-0x-contracts-e144ebbb936c74b4af0e1c1776578208ea148de4.tar.gz dexon-0x-contracts-e144ebbb936c74b4af0e1c1776578208ea148de4.tar.zst dexon-0x-contracts-e144ebbb936c74b4af0e1c1776578208ea148de4.zip |
Merge branch 'development' into feature/instant/tell-amount-available
411 files changed, 14395 insertions, 1165 deletions
diff --git a/.github/stale.yml b/.github/stale.yml index af12c62d5..09eb40a77 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -1,7 +1,7 @@ # Number of days of inactivity before an issue becomes stale daysUntilStale: 30 # Number of days of inactivity before a stale issue is closed -daysUntilClose: 7 +daysUntilClose: 30 # Issues with these labels will never be considered stale exemptLabels: - pinned diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1fea8f501..3e709b36f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -79,7 +79,20 @@ If using the Atom text editor, we recommend you install the following packages: * VSCode: [prettier-vscode](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) * Atom: [prettier-atom](https://atom.io/packages/prettier-atom) -## Fix `submit-coverage` CI failure +## Unenforced coding conventions + +A few of our coding conventions are not yet enforced by the linter/auto-formatter. Be careful to follow these conventions in your PR's. + +1. Unused anonymous function parameters should be named with an underscore + number (e.g \_1, \_2, etc...) +1. There should be a new-line between methods in a class and between test cases. +1. If a string literal has the same value in two or more places, it should be a single constant referenced in both places. +1. Do not import from a project's `index.ts` (e.g import { Token } from '../src';). Always import from the source file itself. +1. Generic error variables should be named `err` instead of `e` or `error`. +1. If you _must_ cast a variable to any - try to type it back as fast as possible. (e.g., `const cw = ((zeroEx as any)._contractWrappers as ContractWrappers);`). This ensures subsequent code is type-safe. +1. Our enum conventions coincide with the recommended Typescript conventions, using capitalized keys, and all-caps snake-case values. Eg `GetStats = 'GET_STATS'` +1. All public, exported methods/functions/classes must have associated Javadoc-style comments. + +### Fix `submit-coverage` CI failure If you simply fork the repo and then create a PR from it, your PR will fail the `submit-coverage` check on CI. This is because the 0x CircleCI configuration sets the `COVERALLS_REPO_TOKEN` environment variable to the token for `0xProject/0x-monorepo`, but when running the check against your fork the token needs to match your repo's name `your-username/0x-monorepo`. diff --git a/contracts/.solhint.json b/contracts/.solhint.json index 076afe9f3..3090d981a 100644 --- a/contracts/.solhint.json +++ b/contracts/.solhint.json @@ -5,6 +5,7 @@ "avoid-tx-origin": "warn", "bracket-align": false, "code-complexity": false, + "compiler-fixed": false, "const-name-snakecase": "error", "expression-indent": "error", "function-max-lines": false, diff --git a/contracts/examples/package.json b/contracts/examples/package.json index 77846241e..37b73f98c 100644 --- a/contracts/examples/package.json +++ b/contracts/examples/package.json @@ -13,7 +13,8 @@ "build": "yarn pre_build && tsc -b", "build:ci": "yarn build", "pre_build": "run-s compile generate_contract_wrappers", - "compile": "sol-compiler --contracts-dir contracts", + "compile": "sol-compiler", + "watch": "sol-compiler -w", "clean": "shx rm -rf lib generated-artifacts generated-wrappers", "generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers", "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", diff --git a/contracts/extensions/CHANGELOG.json b/contracts/extensions/CHANGELOG.json index 19ac770af..083ad33fb 100644 --- a/contracts/extensions/CHANGELOG.json +++ b/contracts/extensions/CHANGELOG.json @@ -1,5 +1,22 @@ [ { + "version": "1.1.0", + "changes": [ + { + "note": "Added Balance Threshold Filter", + "pr": 1383 + }, + { + "note": "Add OrderMatcher", + "pr": 1117 + }, + { + "note": "Add OrderValidator", + "pr": 1464 + } + ] + }, + { "timestamp": 1544741676, "version": "1.0.2", "changes": [ diff --git a/contracts/extensions/compiler.json b/contracts/extensions/compiler.json index 69d607b3e..2bb468724 100644 --- a/contracts/extensions/compiler.json +++ b/contracts/extensions/compiler.json @@ -18,5 +18,5 @@ } } }, - "contracts": ["DutchAuction", "Forwarder"] + "contracts": ["BalanceThresholdFilter", "DutchAuction", "Forwarder", "OrderMatcher", "OrderValidator"] } diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/BalanceThresholdFilter.sol b/contracts/extensions/contracts/BalanceThresholdFilter/BalanceThresholdFilter.sol new file mode 100644 index 000000000..16cacd461 --- /dev/null +++ b/contracts/extensions/contracts/BalanceThresholdFilter/BalanceThresholdFilter.sol @@ -0,0 +1,45 @@ +/* + + Copyright 2018 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity 0.4.24; + +import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol"; +import "./interfaces/IThresholdAsset.sol"; +import "./MixinBalanceThresholdFilterCore.sol"; + + +contract BalanceThresholdFilter is + MixinBalanceThresholdFilterCore +{ + + /// @dev Constructs BalanceThresholdFilter. + /// @param exchange Address of 0x exchange. + /// @param thresholdAsset The asset that must be held by makers/takers. + /// @param balanceThreshold The minimum balance of `thresholdAsset` that must be held by makers/takers. + constructor( + address exchange, + address thresholdAsset, + uint256 balanceThreshold + ) + public + { + EXCHANGE = IExchange(exchange); + THRESHOLD_ASSET = IThresholdAsset(thresholdAsset); + BALANCE_THRESHOLD = balanceThreshold; + } +} diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol b/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol new file mode 100644 index 000000000..da050bf72 --- /dev/null +++ b/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol @@ -0,0 +1,135 @@ +/* + + Copyright 2018 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.4.24; + +import "@0x/contracts-libs/contracts/libs/LibExchangeSelectors.sol"; +import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; +import "./mixins/MBalanceThresholdFilterCore.sol"; +import "./MixinExchangeCalldata.sol"; + + +contract MixinBalanceThresholdFilterCore is + MBalanceThresholdFilterCore, + MixinExchangeCalldata, + LibOrder, + LibExchangeSelectors +{ + + /// @dev Executes an Exchange transaction iff the maker and taker meet + /// the hold at least `BALANCE_THRESHOLD` of the asset `THRESHOLD_ASSET` OR + /// the exchange function is a cancellation. + /// Supported Exchange functions: + /// batchFillOrders + /// batchFillOrdersNoThrow + /// batchFillOrKillOrders + /// fillOrder + /// fillOrderNoThrow + /// fillOrKillOrder + /// marketBuyOrders + /// marketBuyOrdersNoThrow + /// marketSellOrders + /// marketSellOrdersNoThrow + /// matchOrders + /// cancelOrder + /// batchCancelOrders + /// cancelOrdersUpTo + /// Trying to call any other exchange function will throw. + /// @param salt Arbitrary number to ensure uniqueness of transaction hash. + /// @param signerAddress Address of transaction signer. + /// @param signedExchangeTransaction AbiV2 encoded calldata. + /// @param signature Proof of signer transaction by signer. + function executeTransaction( + uint256 salt, + address signerAddress, + bytes signedExchangeTransaction, + bytes signature + ) + external + { + // Get accounts whose balances must be validated + address[] memory addressesToValidate = getAddressesToValidate(signerAddress); + + // Validate account balances + uint256 balanceThreshold = BALANCE_THRESHOLD; + IThresholdAsset thresholdAsset = THRESHOLD_ASSET; + for (uint256 i = 0; i < addressesToValidate.length; ++i) { + uint256 addressBalance = thresholdAsset.balanceOf(addressesToValidate[i]); + require( + addressBalance >= balanceThreshold, + "AT_LEAST_ONE_ADDRESS_DOES_NOT_MEET_BALANCE_THRESHOLD" + ); + } + emit ValidatedAddresses(addressesToValidate); + + // All addresses are valid. Execute exchange function. + EXCHANGE.executeTransaction( + salt, + signerAddress, + signedExchangeTransaction, + signature + ); + } + + /// @dev Constructs an array of addresses to be validated. + /// Addresses depend on which Exchange function is to be called + /// (defined by `signedExchangeTransaction` above). + /// @param signerAddress Address of transaction signer. + /// @return addressesToValidate Array of addresses to validate. + function getAddressesToValidate(address signerAddress) + internal pure + returns (address[] memory addressesToValidate) + { + bytes4 exchangeFunctionSelector = bytes4(exchangeCalldataload(0)); + // solhint-disable expression-indent + if ( + exchangeFunctionSelector == BATCH_FILL_ORDERS_SELECTOR || + exchangeFunctionSelector == BATCH_FILL_ORDERS_NO_THROW_SELECTOR || + exchangeFunctionSelector == BATCH_FILL_OR_KILL_ORDERS_SELECTOR || + exchangeFunctionSelector == MARKET_BUY_ORDERS_SELECTOR || + exchangeFunctionSelector == MARKET_BUY_ORDERS_NO_THROW_SELECTOR || + exchangeFunctionSelector == MARKET_SELL_ORDERS_SELECTOR || + exchangeFunctionSelector == MARKET_SELL_ORDERS_NO_THROW_SELECTOR + ) { + addressesToValidate = loadMakerAddressesFromOrderArray(0); + addressesToValidate = addressesToValidate.append(signerAddress); + } else if ( + exchangeFunctionSelector == FILL_ORDER_SELECTOR || + exchangeFunctionSelector == FILL_ORDER_NO_THROW_SELECTOR || + exchangeFunctionSelector == FILL_OR_KILL_ORDER_SELECTOR + ) { + address makerAddress = loadMakerAddressFromOrder(0); + addressesToValidate = addressesToValidate.append(makerAddress); + addressesToValidate = addressesToValidate.append(signerAddress); + } else if (exchangeFunctionSelector == MATCH_ORDERS_SELECTOR) { + address leftMakerAddress = loadMakerAddressFromOrder(0); + addressesToValidate = addressesToValidate.append(leftMakerAddress); + address rightMakerAddress = loadMakerAddressFromOrder(1); + addressesToValidate = addressesToValidate.append(rightMakerAddress); + addressesToValidate = addressesToValidate.append(signerAddress); + } else if ( + exchangeFunctionSelector != CANCEL_ORDER_SELECTOR && + exchangeFunctionSelector != BATCH_CANCEL_ORDERS_SELECTOR && + exchangeFunctionSelector != CANCEL_ORDERS_UP_TO_SELECTOR + ) { + revert("INVALID_OR_BLOCKED_EXCHANGE_SELECTOR"); + } + // solhint-enable expression-indent + return addressesToValidate; + } +} diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/MixinExchangeCalldata.sol b/contracts/extensions/contracts/BalanceThresholdFilter/MixinExchangeCalldata.sol new file mode 100644 index 000000000..a15e95a9d --- /dev/null +++ b/contracts/extensions/contracts/BalanceThresholdFilter/MixinExchangeCalldata.sol @@ -0,0 +1,103 @@ + + /* + + Copyright 2018 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.4.24; + +import "./mixins/MExchangeCalldata.sol"; +import "@0x/contracts-libs/contracts/libs/LibAddressArray.sol"; + + +contract MixinExchangeCalldata is + MExchangeCalldata +{ + + using LibAddressArray for address[]; + + /// @dev Emulates the `calldataload` opcode on the embedded Exchange calldata, + /// which is accessed through `signedExchangeTransaction`. + /// @param offset Offset into the Exchange calldata. + /// @return value Corresponding 32 byte value stored at `offset`. + function exchangeCalldataload(uint256 offset) + internal pure + returns (bytes32 value) + { + assembly { + // Pointer to exchange transaction + // 0x04 for calldata selector + // 0x40 to access `signedExchangeTransaction`, which is the third parameter + let exchangeTxPtr := calldataload(0x44) + + // Offset into Exchange calldata + // We compute this by adding 0x24 to the `exchangeTxPtr` computed above. + // 0x04 for calldata selector + // 0x20 for length field of `signedExchangeTransaction` + let exchangeCalldataOffset := add(exchangeTxPtr, add(0x24, offset)) + value := calldataload(exchangeCalldataOffset) + } + return value; + } + + /// @dev Convenience function that skips the 4 byte selector when loading + /// from the embedded Exchange calldata. + /// @param offset Offset into the Exchange calldata (minus the 4 byte selector) + /// @return value Corresponding 32 byte value stored at `offset` + 4. + function loadExchangeData(uint256 offset) + internal pure + returns (bytes32 value) + { + value = exchangeCalldataload(offset + 4); + return value; + } + + /// @dev Extracts the maker address from an order stored in the Exchange calldata + /// (which is embedded in `signedExchangeTransaction`). + /// @param orderParamIndex Index of the order in the Exchange function's signature. + /// @return makerAddress The extracted maker address. + function loadMakerAddressFromOrder(uint256 orderParamIndex) + internal pure + returns (address makerAddress) + { + uint256 orderOffsetInBytes = orderParamIndex * 32; + uint256 orderPtr = uint256(loadExchangeData(orderOffsetInBytes)); + makerAddress = address(loadExchangeData(orderPtr)); + return makerAddress; + } + + /// @dev Extracts the maker addresses from an array of orders stored in the Exchange calldata + /// (which is embedded in `signedExchangeTransaction`). + /// @param orderArrayParamIndex Index of the order array in the Exchange function's signature + /// @return makerAddresses The extracted maker addresses. + function loadMakerAddressesFromOrderArray(uint256 orderArrayParamIndex) + internal pure + returns (address[] makerAddresses) + { + uint256 orderArrayOffsetInBytes = orderArrayParamIndex * 32; + uint256 orderArrayPtr = uint256(loadExchangeData(orderArrayOffsetInBytes)); + uint256 orderArrayLength = uint256(loadExchangeData(orderArrayPtr)); + uint256 orderArrayLengthInBytes = orderArrayLength * 32; + uint256 orderArrayElementPtr = orderArrayPtr + 32; + uint256 orderArrayElementEndPtr = orderArrayElementPtr + orderArrayLengthInBytes; + for (uint orderPtrOffset = orderArrayElementPtr; orderPtrOffset < orderArrayElementEndPtr; orderPtrOffset += 32) { + uint256 orderPtr = uint256(loadExchangeData(orderPtrOffset)); + address makerAddress = address(loadExchangeData(orderPtr + orderArrayElementPtr)); + makerAddresses = makerAddresses.append(makerAddress); + } + return makerAddresses; + } +} diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IBalanceThresholdFilterCore.sol b/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IBalanceThresholdFilterCore.sol new file mode 100644 index 000000000..4a1bf1fb2 --- /dev/null +++ b/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IBalanceThresholdFilterCore.sol @@ -0,0 +1,55 @@ + +/* + + Copyright 2018 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.4.24; + + +contract IBalanceThresholdFilterCore { + + /// @dev Executes an Exchange transaction iff the maker and taker meet + /// the hold at least `BALANCE_THRESHOLD` of the asset `THRESHOLD_ASSET` OR + /// the exchange function is a cancellation. + /// Supported Exchange functions: + /// - batchFillOrders + /// - batchFillOrdersNoThrow + /// - batchFillOrKillOrders + /// - fillOrder + /// - fillOrderNoThrow + /// - fillOrKillOrder + /// - marketBuyOrders + /// - marketBuyOrdersNoThrow + /// - marketSellOrders + /// - marketSellOrdersNoThrow + /// - matchOrders + /// - cancelOrder + /// - batchCancelOrders + /// - cancelOrdersUpTo + /// Trying to call any other exchange function will throw. + /// @param salt Arbitrary number to ensure uniqueness of transaction hash. + /// @param signerAddress Address of transaction signer. + /// @param signedExchangeTransaction AbiV2 encoded calldata. + /// @param signature Proof of signer transaction by signer. + function executeTransaction( + uint256 salt, + address signerAddress, + bytes signedExchangeTransaction, + bytes signature + ) + external; +} diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IThresholdAsset.sol b/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IThresholdAsset.sol new file mode 100644 index 000000000..f78f9c2de --- /dev/null +++ b/contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IThresholdAsset.sol @@ -0,0 +1,31 @@ +/* + + Copyright 2018 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.4.24; + + +contract IThresholdAsset { + + /// @param _owner The address from which the balance will be retrieved + /// @return Balance of owner + function balanceOf(address _owner) + external + view + returns (uint256); + +} diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol b/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol new file mode 100644 index 000000000..074686e8d --- /dev/null +++ b/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol @@ -0,0 +1,54 @@ +/* + + Copyright 2018 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.4.24; + +import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol"; +import "../interfaces/IThresholdAsset.sol"; +import "../interfaces/IBalanceThresholdFilterCore.sol"; + + +contract MBalanceThresholdFilterCore is + IBalanceThresholdFilterCore +{ + + // Points to 0x exchange contract + // solhint-disable var-name-mixedcase + IExchange internal EXCHANGE; + + // The asset that must be held by makers/takers + IThresholdAsset internal THRESHOLD_ASSET; + + // The minimum balance of `THRESHOLD_ASSET` that must be held by makers/takers + uint256 internal BALANCE_THRESHOLD; + // solhint-enable var-name-mixedcase + + // Addresses that hold at least `BALANCE_THRESHOLD` of `THRESHOLD_ASSET` + event ValidatedAddresses ( + address[] addresses + ); + + /// @dev Constructs an array of addresses to be validated. + /// Addresses depend on which Exchange function is to be called + /// (defined by `signedExchangeTransaction` above). + /// @param signerAddress Address of transaction signer. + /// @return addressesToValidate Array of addresses to validate. + function getAddressesToValidate(address signerAddress) + internal pure + returns (address[] memory addressesToValidate); +} diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MExchangeCalldata.sol b/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MExchangeCalldata.sol new file mode 100644 index 000000000..40536d820 --- /dev/null +++ b/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MExchangeCalldata.sol @@ -0,0 +1,56 @@ + + /* + + Copyright 2018 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.4.24; + + +contract MExchangeCalldata { + + /// @dev Emulates the `calldataload` opcode on the embedded Exchange calldata, + /// which is accessed through `signedExchangeTransaction`. + /// @param offset Offset into the Exchange calldata. + /// @return value Corresponding 32 byte value stored at `offset`. + function exchangeCalldataload(uint256 offset) + internal pure + returns (bytes32 value); + + /// @dev Convenience function that skips the 4 byte selector when loading + /// from the embedded Exchange calldata. + /// @param offset Offset into the Exchange calldata (minus the 4 byte selector) + /// @return value Corresponding 32 byte value stored at `offset` + 4. + function loadExchangeData(uint256 offset) + internal pure + returns (bytes32 value); + + /// @dev Extracts the maker address from an order stored in the Exchange calldata + /// (which is embedded in `signedExchangeTransaction`). + /// @param orderParamIndex Index of the order in the Exchange function's signature. + /// @return makerAddress The extracted maker address. + function loadMakerAddressFromOrder(uint256 orderParamIndex) + internal pure + returns (address makerAddress); + + /// @dev Extracts the maker addresses from an array of orders stored in the Exchange calldata + /// (which is embedded in `signedExchangeTransaction`). + /// @param orderArrayParamIndex Index of the order array in the Exchange function's signature + /// @return makerAddresses The extracted maker addresses. + function loadMakerAddressesFromOrderArray(uint256 orderArrayParamIndex) + internal pure + returns (address[] makerAddresses); +} diff --git a/contracts/extensions/contracts/Forwarder/MixinAssets.sol b/contracts/extensions/contracts/Forwarder/MixinAssets.sol index 3ebf75161..116cdf267 100644 --- a/contracts/extensions/contracts/Forwarder/MixinAssets.sol +++ b/contracts/extensions/contracts/Forwarder/MixinAssets.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol"; import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol"; diff --git a/contracts/extensions/contracts/Forwarder/MixinExchangeWrapper.sol b/contracts/extensions/contracts/Forwarder/MixinExchangeWrapper.sol index 210eb14c2..cab26741d 100644 --- a/contracts/extensions/contracts/Forwarder/MixinExchangeWrapper.sol +++ b/contracts/extensions/contracts/Forwarder/MixinExchangeWrapper.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; pragma experimental ABIEncoderV2; import "./libs/LibConstants.sol"; diff --git a/contracts/extensions/contracts/Forwarder/MixinForwarderCore.sol b/contracts/extensions/contracts/Forwarder/MixinForwarderCore.sol index bab78d79b..11c0147a5 100644 --- a/contracts/extensions/contracts/Forwarder/MixinForwarderCore.sol +++ b/contracts/extensions/contracts/Forwarder/MixinForwarderCore.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; pragma experimental ABIEncoderV2; import "./libs/LibConstants.sol"; diff --git a/contracts/extensions/contracts/Forwarder/MixinWeth.sol b/contracts/extensions/contracts/Forwarder/MixinWeth.sol index 2a281f3ae..25a35f47b 100644 --- a/contracts/extensions/contracts/Forwarder/MixinWeth.sol +++ b/contracts/extensions/contracts/Forwarder/MixinWeth.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; import "@0x/contracts-libs/contracts/libs/LibMath.sol"; import "./libs/LibConstants.sol"; diff --git a/contracts/extensions/contracts/Forwarder/interfaces/IAssets.sol b/contracts/extensions/contracts/Forwarder/interfaces/IAssets.sol index 1e034c003..cebfd3706 100644 --- a/contracts/extensions/contracts/Forwarder/interfaces/IAssets.sol +++ b/contracts/extensions/contracts/Forwarder/interfaces/IAssets.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; contract IAssets { diff --git a/contracts/extensions/contracts/Forwarder/interfaces/IForwarder.sol b/contracts/extensions/contracts/Forwarder/interfaces/IForwarder.sol index f5a26e2ba..6ce8a1d31 100644 --- a/contracts/extensions/contracts/Forwarder/interfaces/IForwarder.sol +++ b/contracts/extensions/contracts/Forwarder/interfaces/IForwarder.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; pragma experimental ABIEncoderV2; import "./IForwarderCore.sol"; diff --git a/contracts/extensions/contracts/Forwarder/interfaces/IForwarderCore.sol b/contracts/extensions/contracts/Forwarder/interfaces/IForwarderCore.sol index eede20bb8..7f62722e7 100644 --- a/contracts/extensions/contracts/Forwarder/interfaces/IForwarderCore.sol +++ b/contracts/extensions/contracts/Forwarder/interfaces/IForwarderCore.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; pragma experimental ABIEncoderV2; import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; diff --git a/contracts/extensions/contracts/Forwarder/libs/LibConstants.sol b/contracts/extensions/contracts/Forwarder/libs/LibConstants.sol index 4a81abf76..0d2f6e36d 100644 --- a/contracts/extensions/contracts/Forwarder/libs/LibConstants.sol +++ b/contracts/extensions/contracts/Forwarder/libs/LibConstants.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol"; import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol"; diff --git a/contracts/extensions/contracts/Forwarder/libs/LibForwarderErrors.sol b/contracts/extensions/contracts/Forwarder/libs/LibForwarderErrors.sol index fb3ade1db..7a95b78a0 100644 --- a/contracts/extensions/contracts/Forwarder/libs/LibForwarderErrors.sol +++ b/contracts/extensions/contracts/Forwarder/libs/LibForwarderErrors.sol @@ -17,7 +17,7 @@ */ // solhint-disable -pragma solidity 0.4.24; +pragma solidity ^0.4.24; /// This contract is intended to serve as a reference, but is not actually used for efficiency reasons. diff --git a/contracts/extensions/contracts/Forwarder/mixins/MAssets.sol b/contracts/extensions/contracts/Forwarder/mixins/MAssets.sol index 9e7f80d97..1757b37fb 100644 --- a/contracts/extensions/contracts/Forwarder/mixins/MAssets.sol +++ b/contracts/extensions/contracts/Forwarder/mixins/MAssets.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; import "../interfaces/IAssets.sol"; diff --git a/contracts/extensions/contracts/Forwarder/mixins/MExchangeWrapper.sol b/contracts/extensions/contracts/Forwarder/mixins/MExchangeWrapper.sol index d9e71786a..143f888b1 100644 --- a/contracts/extensions/contracts/Forwarder/mixins/MExchangeWrapper.sol +++ b/contracts/extensions/contracts/Forwarder/mixins/MExchangeWrapper.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; pragma experimental ABIEncoderV2; import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; diff --git a/contracts/extensions/contracts/Forwarder/mixins/MWeth.sol b/contracts/extensions/contracts/Forwarder/mixins/MWeth.sol index 88e77be4e..15d66942f 100644 --- a/contracts/extensions/contracts/Forwarder/mixins/MWeth.sol +++ b/contracts/extensions/contracts/Forwarder/mixins/MWeth.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; contract MWeth { diff --git a/contracts/extensions/contracts/OrderMatcher/MixinAssets.sol b/contracts/extensions/contracts/OrderMatcher/MixinAssets.sol new file mode 100644 index 000000000..f0f91cfc0 --- /dev/null +++ b/contracts/extensions/contracts/OrderMatcher/MixinAssets.sol @@ -0,0 +1,195 @@ +/* + + Copyright 2018 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.4.24; + +import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol"; +import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol"; +import "@0x/contracts-tokens/contracts/tokens/ERC20Token/IERC20Token.sol"; +import "@0x/contracts-tokens/contracts/tokens/ERC721Token/IERC721Token.sol"; +import "./mixins/MAssets.sol"; +import "./libs/LibConstants.sol"; + + +contract MixinAssets is + MAssets, + Ownable, + LibConstants +{ + using LibBytes for bytes; + + /// @dev Withdraws assets from this contract. The contract requires a ZRX balance in order to + /// function optimally, and this function allows the ZRX to be withdrawn by owner. It may also be + /// used to withdraw assets that were accidentally sent to this contract. + /// @param assetData Byte array encoded for the respective asset proxy. + /// @param amount Amount of asset to withdraw. + function withdrawAsset( + bytes assetData, + uint256 amount + ) + external + onlyOwner + { + transferAssetToSender(assetData, amount); + } + + /// @dev Approves or disapproves an AssetProxy to spend asset. + /// @param assetData Byte array encoded for the respective asset proxy. + /// @param amount Amount of asset to approve for respective proxy. + function approveAssetProxy( + bytes assetData, + uint256 amount + ) + external + onlyOwner + { + bytes4 proxyId = assetData.readBytes4(0); + + if (proxyId == ERC20_DATA_ID) { + approveERC20Token(assetData, amount); + } else if (proxyId == ERC721_DATA_ID) { + approveERC721Token(assetData, amount); + } else { + revert("UNSUPPORTED_ASSET_PROXY"); + } + } + + /// @dev Transfers given amount of asset to sender. + /// @param assetData Byte array encoded for the respective asset proxy. + /// @param amount Amount of asset to transfer to sender. + function transferAssetToSender( + bytes memory assetData, + uint256 amount + ) + internal + { + bytes4 proxyId = assetData.readBytes4(0); + + if (proxyId == ERC20_DATA_ID) { + transferERC20Token(assetData, amount); + } else if (proxyId == ERC721_DATA_ID) { + transferERC721Token(assetData, amount); + } else { + revert("UNSUPPORTED_ASSET_PROXY"); + } + } + + /// @dev Decodes ERC20 assetData and transfers given amount to sender. + /// @param assetData Byte array encoded for the respective asset proxy. + /// @param amount Amount of asset to transfer to sender. + function transferERC20Token( + bytes memory assetData, + uint256 amount + ) + internal + { + // 4 byte id + 12 0 bytes before ABI encoded token address. + address token = assetData.readAddress(16); + + // Transfer tokens. + // We do a raw call so we can check the success separate + // from the return data. + bool success = token.call(abi.encodeWithSelector( + ERC20_TRANSFER_SELECTOR, + msg.sender, + amount + )); + require( + success, + "TRANSFER_FAILED" + ); + + // Check return data. + // If there is no return data, we assume the token incorrectly + // does not return a bool. In this case we expect it to revert + // on failure, which was handled above. + // If the token does return data, we require that it is a single + // value that evaluates to true. + assembly { + if returndatasize { + success := 0 + if eq(returndatasize, 32) { + // First 64 bytes of memory are reserved scratch space + returndatacopy(0, 0, 32) + success := mload(0) + } + } + } + require( + success, + "TRANSFER_FAILED" + ); + } + + /// @dev Decodes ERC721 assetData and transfers given amount to sender. + /// @param assetData Byte array encoded for the respective asset proxy. + /// @param amount Amount of asset to transfer to sender. + function transferERC721Token( + bytes memory assetData, + uint256 amount + ) + internal + { + require( + amount == 1, + "INVALID_AMOUNT" + ); + // Decode asset data. + // 4 byte id + 12 0 bytes before ABI encoded token address. + address token = assetData.readAddress(16); + // 4 byte id + 32 byte ABI encoded token address before token id. + uint256 tokenId = assetData.readUint256(36); + + // Perform transfer. + IERC721Token(token).transferFrom( + address(this), + msg.sender, + tokenId + ); + } + + /// @dev Sets approval for ERC20 AssetProxy. + /// @param assetData Byte array encoded for the respective asset proxy. + /// @param amount Amount of asset to approve for respective proxy. + function approveERC20Token( + bytes memory assetData, + uint256 amount + ) + internal + { + address token = assetData.readAddress(16); + require( + IERC20Token(token).approve(ERC20_PROXY_ADDRESS, amount), + "APPROVAL_FAILED" + ); + } + + /// @dev Sets approval for ERC721 AssetProxy. + /// @param assetData Byte array encoded for the respective asset proxy. + /// @param amount Amount of asset to approve for respective proxy. + function approveERC721Token( + bytes memory assetData, + uint256 amount + ) + internal + { + address token = assetData.readAddress(16); + bool approval = amount >= 1; + IERC721Token(token).setApprovalForAll(ERC721_PROXY_ADDRESS, approval); + } +} diff --git a/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol b/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol new file mode 100644 index 000000000..1787deb59 --- /dev/null +++ b/contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol @@ -0,0 +1,86 @@ +/* + + Copyright 2018 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.4.24; +pragma experimental ABIEncoderV2; + +import "./libs/LibConstants.sol"; +import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; +import "@0x/contracts-libs/contracts/libs/LibFillResults.sol"; +import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol"; + + +contract MixinMatchOrders is + Ownable, + LibConstants +{ + /// @dev Match two complementary orders that have a profitable spread. + /// Each order is filled at their respective price point. However, the calculations are + /// carried out as though the orders are both being filled at the right order's price point. + /// The profit made by the left order is then used to fill the right order as much as possible. + /// This results in a spread being taken in terms of both assets. The spread is held within this contract. + /// @param leftOrder First order to match. + /// @param rightOrder Second order to match. + /// @param leftSignature Proof that order was created by the left maker. + /// @param rightSignature Proof that order was created by the right maker. + function matchOrders( + LibOrder.Order memory leftOrder, + LibOrder.Order memory rightOrder, + bytes memory leftSignature, + bytes memory rightSignature + ) + public + onlyOwner + { + // Match orders, maximally filling `leftOrder` + LibFillResults.MatchedFillResults memory matchedFillResults = EXCHANGE.matchOrders( + leftOrder, + rightOrder, + leftSignature, + rightSignature + ); + + uint256 leftMakerAssetSpreadAmount = matchedFillResults.leftMakerAssetSpreadAmount; + uint256 rightOrderTakerAssetAmount = rightOrder.takerAssetAmount; + + // Do not attempt to call `fillOrder` if no spread was taken or `rightOrder` has been completely filled + if (leftMakerAssetSpreadAmount == 0 || matchedFillResults.right.takerAssetFilledAmount == rightOrderTakerAssetAmount) { + return; + } + + // The `assetData` fields of the `rightOrder` could have been null for the `matchOrders` call. We reassign them before calling `fillOrder`. + rightOrder.makerAssetData = leftOrder.takerAssetData; + rightOrder.takerAssetData = leftOrder.makerAssetData; + + // Query `rightOrder` info to check if it has been completely filled + // We need to make this check in case the `rightOrder` was partially filled before the `matchOrders` call + LibOrder.OrderInfo memory orderInfo = EXCHANGE.getOrderInfo(rightOrder); + + // Do not attempt to call `fillOrder` if order has been completely filled + if (orderInfo.orderTakerAssetFilledAmount == rightOrderTakerAssetAmount) { + return; + } + + // We do not need to pass in a signature since it was already validated in the `matchOrders` call + EXCHANGE.fillOrder( + rightOrder, + leftMakerAssetSpreadAmount, + "" + ); + } +} diff --git a/contracts/extensions/contracts/OrderMatcher/OrderMatcher.sol b/contracts/extensions/contracts/OrderMatcher/OrderMatcher.sol new file mode 100644 index 000000000..4879b7bca --- /dev/null +++ b/contracts/extensions/contracts/OrderMatcher/OrderMatcher.sol @@ -0,0 +1,38 @@ +/* + + Copyright 2018 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity 0.4.24; +pragma experimental ABIEncoderV2; + +import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol"; +import "./libs/LibConstants.sol"; +import "./MixinMatchOrders.sol"; +import "./MixinAssets.sol"; + + +// solhint-disable no-empty-blocks +contract OrderMatcher is + MixinMatchOrders, + MixinAssets +{ + constructor (address _exchange) + public + LibConstants(_exchange) + Ownable() + {} +} diff --git a/contracts/extensions/contracts/OrderMatcher/interfaces/IAssets.sol b/contracts/extensions/contracts/OrderMatcher/interfaces/IAssets.sol new file mode 100644 index 000000000..9fcc0023a --- /dev/null +++ b/contracts/extensions/contracts/OrderMatcher/interfaces/IAssets.sol @@ -0,0 +1,43 @@ +/* + + Copyright 2018 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.4.24; + + +contract IAssets { + + /// @dev Withdraws assets from this contract. The contract requires a ZRX balance in order to + /// function optimally, and this function allows the ZRX to be withdrawn by owner. It may also be + /// used to withdraw assets that were accidentally sent to this contract. + /// @param assetData Byte array encoded for the respective asset proxy. + /// @param amount Amount of asset to withdraw. + function withdrawAsset( + bytes assetData, + uint256 amount + ) + external; + + /// @dev Approves or disapproves an AssetProxy to spend asset. + /// @param assetData Byte array encoded for the respective asset proxy. + /// @param amount Amount of asset to approve for respective proxy. + function approveAssetProxy( + bytes assetData, + uint256 amount + ) + external; +} diff --git a/contracts/extensions/contracts/OrderMatcher/interfaces/IMatchOrders.sol b/contracts/extensions/contracts/OrderMatcher/interfaces/IMatchOrders.sol new file mode 100644 index 000000000..1443c73b9 --- /dev/null +++ b/contracts/extensions/contracts/OrderMatcher/interfaces/IMatchOrders.sol @@ -0,0 +1,43 @@ +/* + + Copyright 2018 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.4.24; +pragma experimental ABIEncoderV2; + +import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; + + +contract IMatchOrders { + + /// @dev Match two complementary orders that have a profitable spread. + /// Each order is filled at their respective price point. However, the calculations are + /// carried out as though the orders are both being filled at the right order's price point. + /// The profit made by the left order is then used to fill the right order as much as possible. + /// This results in a spread being taken in terms of both assets. The spread is held within this contract. + /// @param leftOrder First order to match. + /// @param rightOrder Second order to match. + /// @param leftSignature Proof that order was created by the left maker. + /// @param rightSignature Proof that order was created by the right maker. + function matchOrders( + LibOrder.Order memory leftOrder, + LibOrder.Order memory rightOrder, + bytes memory leftSignature, + bytes memory rightSignature + ) + public; +} diff --git a/contracts/extensions/contracts/OrderMatcher/interfaces/IOrderMatcher.sol b/contracts/extensions/contracts/OrderMatcher/interfaces/IOrderMatcher.sol new file mode 100644 index 000000000..75f26dca6 --- /dev/null +++ b/contracts/extensions/contracts/OrderMatcher/interfaces/IOrderMatcher.sol @@ -0,0 +1,31 @@ +/* + + Copyright 2018 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.4.24; + +import "@0x/contract-utils/contracts/utils/Ownable/IOwnable.sol"; +import "./IMatchOrders.sol"; +import "./IAssets.sol"; + + +// solhint-disable no-empty-blocks +contract IOrderMatcher is + IOwnable, + IMatchOrders, + IAssets +{} diff --git a/contracts/extensions/contracts/OrderMatcher/libs/LibConstants.sol b/contracts/extensions/contracts/OrderMatcher/libs/LibConstants.sol new file mode 100644 index 000000000..c1a86a9c7 --- /dev/null +++ b/contracts/extensions/contracts/OrderMatcher/libs/LibConstants.sol @@ -0,0 +1,56 @@ +/* + + Copyright 2018 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.4.24; + +import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol"; + + +contract LibConstants { + + // bytes4(keccak256("transfer(address,uint256)")) + bytes4 constant internal ERC20_TRANSFER_SELECTOR = 0xa9059cbb; + // bytes4(keccak256("ERC20Token(address)")) + bytes4 constant internal ERC20_DATA_ID = 0xf47261b0; + // bytes4(keccak256("ERC721Token(address,uint256)")) + bytes4 constant internal ERC721_DATA_ID = 0x02571792; + + // solhint-disable var-name-mixedcase + IExchange internal EXCHANGE; + address internal ERC20_PROXY_ADDRESS; + address internal ERC721_PROXY_ADDRESS; + // solhint-enable var-name-mixedcase + + constructor (address _exchange) + public + { + EXCHANGE = IExchange(_exchange); + + ERC20_PROXY_ADDRESS = EXCHANGE.getAssetProxy(ERC20_DATA_ID); + require( + ERC20_PROXY_ADDRESS != address(0), + "UNREGISTERED_ASSET_PROXY" + ); + + ERC721_PROXY_ADDRESS = EXCHANGE.getAssetProxy(ERC721_DATA_ID); + require( + ERC721_PROXY_ADDRESS != address(0), + "UNREGISTERED_ASSET_PROXY" + ); + } +} diff --git a/contracts/extensions/contracts/OrderMatcher/mixins/MAssets.sol b/contracts/extensions/contracts/OrderMatcher/mixins/MAssets.sol new file mode 100644 index 000000000..6ea7a3290 --- /dev/null +++ b/contracts/extensions/contracts/OrderMatcher/mixins/MAssets.sol @@ -0,0 +1,71 @@ +/* + + Copyright 2018 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.4.24; + +import "../interfaces/IAssets.sol"; + + +contract MAssets is + IAssets +{ + /// @dev Transfers given amount of asset to sender. + /// @param assetData Byte array encoded for the respective asset proxy. + /// @param amount Amount of asset to transfer to sender. + function transferAssetToSender( + bytes memory assetData, + uint256 amount + ) + internal; + + /// @dev Decodes ERC20 assetData and transfers given amount to sender. + /// @param assetData Byte array encoded for the respective asset proxy. + /// @param amount Amount of asset to transfer to sender. + function transferERC20Token( + bytes memory assetData, + uint256 amount + ) + internal; + + /// @dev Decodes ERC721 assetData and transfers given amount to sender. + /// @param assetData Byte array encoded for the respective asset proxy. + /// @param amount Amount of asset to transfer to sender. + function transferERC721Token( + bytes memory assetData, + uint256 amount + ) + internal; + + /// @dev Sets approval for ERC20 AssetProxy. + /// @param assetData Byte array encoded for the respective asset proxy. + /// @param amount Amount of asset to approve for respective proxy. + function approveERC20Token( + bytes memory assetData, + uint256 amount + ) + internal; + + /// @dev Sets approval for ERC721 AssetProxy. + /// @param assetData Byte array encoded for the respective asset proxy. + /// @param amount Amount of asset to approve for respective proxy. + function approveERC721Token( + bytes memory assetData, + uint256 amount + ) + internal; +} diff --git a/contracts/protocol/contracts/protocol/OrderValidator/OrderValidator.sol b/contracts/extensions/contracts/OrderValidator/OrderValidator.sol index 33dd1326c..33dd1326c 100644 --- a/contracts/protocol/contracts/protocol/OrderValidator/OrderValidator.sol +++ b/contracts/extensions/contracts/OrderValidator/OrderValidator.sol diff --git a/contracts/extensions/package.json b/contracts/extensions/package.json index 938e1138c..069b5d2d5 100644 --- a/contracts/extensions/package.json +++ b/contracts/extensions/package.json @@ -19,7 +19,8 @@ "test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html", "test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha", "run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit", - "compile": "sol-compiler --contracts-dir contracts", + "compile": "sol-compiler", + "watch": "sol-compiler -w", "clean": "shx rm -rf lib generated-artifacts generated-wrappers", "generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers", "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", @@ -31,7 +32,7 @@ "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol" }, "config": { - "abis": "generated-artifacts/@(DutchAuction|Forwarder).json" + "abis": "generated-artifacts/@(BalanceThresholdFilter|DutchAuction|Forwarder|OrderMatcher|OrderValidator).json" }, "repository": { "type": "git", diff --git a/contracts/extensions/src/artifacts/index.ts b/contracts/extensions/src/artifacts/index.ts index 7588178f0..329d0f3f3 100644 --- a/contracts/extensions/src/artifacts/index.ts +++ b/contracts/extensions/src/artifacts/index.ts @@ -1,9 +1,15 @@ import { ContractArtifact } from 'ethereum-types'; +import * as BalanceThresholdFilter from '../../generated-artifacts/BalanceThresholdFilter.json'; import * as DutchAuction from '../../generated-artifacts/DutchAuction.json'; import * as Forwarder from '../../generated-artifacts/Forwarder.json'; +import * as OrderMatcher from '../../generated-artifacts/OrderMatcher.json'; +import * as OrderValidator from '../../generated-artifacts/OrderValidator.json'; export const artifacts = { + BalanceThresholdFilter: BalanceThresholdFilter as ContractArtifact, DutchAuction: DutchAuction as ContractArtifact, Forwarder: Forwarder as ContractArtifact, + OrderMatcher: OrderMatcher as ContractArtifact, + OrderValidator: OrderValidator as ContractArtifact, }; diff --git a/contracts/extensions/src/wrappers/index.ts b/contracts/extensions/src/wrappers/index.ts index 90880e37f..65aec3ccd 100644 --- a/contracts/extensions/src/wrappers/index.ts +++ b/contracts/extensions/src/wrappers/index.ts @@ -1,2 +1,5 @@ +export * from '../../generated-wrappers/balance_threshold_filter'; export * from '../../generated-wrappers/dutch_auction'; export * from '../../generated-wrappers/forwarder'; +export * from '../../generated-wrappers/order_matcher'; +export * from '../../generated-wrappers/order_validator'; diff --git a/contracts/extensions/test/extensions/balance_threshold_filter.ts b/contracts/extensions/test/extensions/balance_threshold_filter.ts new file mode 100644 index 000000000..07199d60b --- /dev/null +++ b/contracts/extensions/test/extensions/balance_threshold_filter.ts @@ -0,0 +1,1644 @@ +import { BlockchainLifecycle } from '@0x/dev-utils'; +import { assetDataUtils } from '@0x/order-utils'; +import { Order, RevertReason, SignedOrder } from '@0x/types'; +import { BigNumber } from '@0x/utils'; +import { Web3Wrapper } from '@0x/web3-wrapper'; +import * as chai from 'chai'; +import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; +import * as _ from 'lodash'; + +import { + artifacts as protocolArtifacts, + ERC20Wrapper, + ERC721Wrapper, + ExchangeContract, + ExchangeWrapper, +} from '@0x/contracts-protocol'; +import { + chaiSetup, + constants, + ContractName, + ERC20BalancesByOwner, + expectTransactionFailedAsync, + OrderFactory, + OrderStatus, + provider, + TransactionFactory, + txDefaults, + web3Wrapper, +} from '@0x/contracts-test-utils'; +import { DummyERC20TokenContract } from '@0x/contracts-tokens'; + +import { BalanceThresholdFilterContract } from '../../generated-wrappers/balance_threshold_filter'; +import { artifacts } from '../../src/artifacts'; +import { BalanceThresholdWrapper } from '../utils/balance_threshold_wrapper'; + +chaiSetup.configure(); +const expect = chai.expect; +const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); +const DECIMALS_DEFAULT = 18; + +interface ValidatedAddressesLog { + args: { addresses: string[] }; +} + +describe(ContractName.BalanceThresholdFilter, () => { + const takerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(500), DECIMALS_DEFAULT); + const makerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), DECIMALS_DEFAULT); + const takerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(250), DECIMALS_DEFAULT); + + let validMakerAddress: string; + let validMakerAddress2: string; + let owner: string; + let validTakerAddress: string; + let feeRecipientAddress: string; + let invalidAddress: string; + let defaultMakerAssetAddress: string; + let defaultTakerAssetAddress: string; + let zrxAssetData: string; + let zrxToken: DummyERC20TokenContract; + let exchangeInstance: ExchangeContract; + let exchangeWrapper: ExchangeWrapper; + + let orderFactory: OrderFactory; + let orderFactory2: OrderFactory; + let invalidOrderFactory: OrderFactory; + let erc20Wrapper: ERC20Wrapper; + let erc20Balances: ERC20BalancesByOwner; + let erc20TakerBalanceThresholdWrapper: BalanceThresholdWrapper; + let erc721TakerBalanceThresholdWrapper: BalanceThresholdWrapper; + let erc721MakerBalanceThresholdWrapper: BalanceThresholdWrapper; + let erc721NonValidBalanceThresholdWrapper: BalanceThresholdWrapper; + + let defaultOrderParams: Partial<Order>; + let validSignedOrder: SignedOrder; + let validSignedOrder2: SignedOrder; + + let erc721BalanceThresholdFilterInstance: BalanceThresholdFilterContract; + let erc20BalanceThresholdFilterInstance: BalanceThresholdFilterContract; + + const assertValidatedAddressesLog = async ( + txReceipt: TransactionReceiptWithDecodedLogs, + expectedValidatedAddresses: string[], + ) => { + expect(txReceipt.logs.length).to.be.gte(1); + const validatedAddressesLog = (txReceipt.logs[0] as any) as ValidatedAddressesLog; + const validatedAddresses = validatedAddressesLog.args.addresses; + // @HACK-hysz: Nested addresses are not translated to lower-case but this will change once + // the new ABI Encoder/Decoder is used by the contract templates. + const validatedAddressesNormalized: string[] = []; + _.each(validatedAddresses, address => { + const normalizedAddress = _.toLower(address); + validatedAddressesNormalized.push(normalizedAddress); + }); + expect(validatedAddressesNormalized).to.be.deep.equal(expectedValidatedAddresses); + }; + + before(async () => { + // Create accounts + await blockchainLifecycle.startAsync(); + const accounts = await web3Wrapper.getAvailableAddressesAsync(); + const usedAddresses = ([ + owner, + validMakerAddress, + validMakerAddress2, + validTakerAddress, + feeRecipientAddress, + invalidAddress, + ] = accounts); + const takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(validTakerAddress)]; + const makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(validMakerAddress)]; + const secondMakerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(validMakerAddress2)]; + const invalidAddressPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(invalidAddress)]; + // Create wrappers + erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner); + const validAddresses = _.cloneDeepWith(usedAddresses); + _.remove(validAddresses, (address: string) => { + return address === invalidAddress; + }); + const erc721Wrapper = new ERC721Wrapper(provider, validAddresses, owner); + // Deploy ERC20 tokens + const numDummyErc20ToDeploy = 4; + let erc20TokenA: DummyERC20TokenContract; + let erc20TokenB: DummyERC20TokenContract; + let erc20BalanceThresholdAsset: DummyERC20TokenContract; + [erc20TokenA, erc20TokenB, zrxToken, erc20BalanceThresholdAsset] = await erc20Wrapper.deployDummyTokensAsync( + numDummyErc20ToDeploy, + constants.DUMMY_TOKEN_DECIMALS, + ); + defaultMakerAssetAddress = erc20TokenA.address; + defaultTakerAssetAddress = erc20TokenB.address; + zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address); + // Create proxies + const erc20Proxy = await erc20Wrapper.deployProxyAsync(); + await erc20Wrapper.setBalancesAndAllowancesAsync(); + // Deploy Exchange contract + exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync( + protocolArtifacts.Exchange, + provider, + txDefaults, + zrxAssetData, + ); + exchangeWrapper = new ExchangeWrapper(exchangeInstance, provider); + // Register proxies + await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner); + await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, { + from: owner, + }); + // Deploy Balance Threshold Filters + // One uses an ERC721 token as its balance threshold asset; the other uses an ERC20 + const erc721alanceThreshold = new BigNumber(1); + await erc721Wrapper.deployProxyAsync(); + const [erc721BalanceThresholdAsset] = await erc721Wrapper.deployDummyTokensAsync(); + await erc721Wrapper.setBalancesAndAllowancesAsync(); + erc721BalanceThresholdFilterInstance = await BalanceThresholdFilterContract.deployFrom0xArtifactAsync( + artifacts.BalanceThresholdFilter, + provider, + txDefaults, + exchangeInstance.address, + erc721BalanceThresholdAsset.address, + erc721alanceThreshold, + ); + const erc20BalanceThreshold = Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 10); + erc20BalanceThresholdFilterInstance = await BalanceThresholdFilterContract.deployFrom0xArtifactAsync( + artifacts.BalanceThresholdFilter, + provider, + txDefaults, + exchangeInstance.address, + erc20BalanceThresholdAsset.address, + erc20BalanceThreshold, + ); + // Default order parameters + defaultOrderParams = { + exchangeAddress: exchangeInstance.address, + feeRecipientAddress, + makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress), + takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress), + makerAssetAmount, + takerAssetAmount, + makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), DECIMALS_DEFAULT), + takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(150), DECIMALS_DEFAULT), + senderAddress: erc721BalanceThresholdFilterInstance.address, + }; + // Create two order factories with valid makers (who meet the threshold balance), and + // one factory for an invalid address (that does not meet the threshold balance) + // Valid order factory #1 + const defaultOrderParams1 = { + makerAddress: validMakerAddress, + ...defaultOrderParams, + }; + orderFactory = new OrderFactory(makerPrivateKey, defaultOrderParams1); + // Valid order factory #2 + const defaultOrderParams2 = { + makerAddress: validMakerAddress2, + ...defaultOrderParams, + }; + orderFactory2 = new OrderFactory(secondMakerPrivateKey, defaultOrderParams2); + // Invalid order factory + const defaultNonValidOrderParams = { + makerAddress: invalidAddress, + ...defaultOrderParams, + }; + invalidOrderFactory = new OrderFactory(invalidAddressPrivateKey, defaultNonValidOrderParams); + // Create Balance Thresold Wrappers + erc20TakerBalanceThresholdWrapper = new BalanceThresholdWrapper( + erc20BalanceThresholdFilterInstance, + exchangeInstance, + new TransactionFactory(takerPrivateKey, exchangeInstance.address), + provider, + ); + erc721TakerBalanceThresholdWrapper = new BalanceThresholdWrapper( + erc721BalanceThresholdFilterInstance, + exchangeInstance, + new TransactionFactory(takerPrivateKey, exchangeInstance.address), + provider, + ); + erc721MakerBalanceThresholdWrapper = new BalanceThresholdWrapper( + erc721BalanceThresholdFilterInstance, + exchangeInstance, + new TransactionFactory(makerPrivateKey, exchangeInstance.address), + provider, + ); + erc721NonValidBalanceThresholdWrapper = new BalanceThresholdWrapper( + erc721BalanceThresholdFilterInstance, + exchangeInstance, + new TransactionFactory(invalidAddressPrivateKey, exchangeInstance.address), + provider, + ); + }); + beforeEach(async () => { + await blockchainLifecycle.startAsync(); + }); + afterEach(async () => { + await blockchainLifecycle.revertAsync(); + }); + + describe('General Sanity Checks', () => { + beforeEach(async () => { + erc20Balances = await erc20Wrapper.getBalancesAsync(); + validSignedOrder = await orderFactory.newSignedOrderAsync(); + validSignedOrder2 = await orderFactory2.newSignedOrderAsync(); + }); + it('should transfer the correct amounts and validate both maker/taker when both maker and taker exceed the balance threshold of an ERC20 token', async () => { + const validSignedOrderERC20Sender = await orderFactory.newSignedOrderAsync({ + ...defaultOrderParams, + makerAddress: validMakerAddress, + senderAddress: erc20TakerBalanceThresholdWrapper.getBalanceThresholdAddress(), + }); + // Execute a valid fill + const txReceipt = await erc20TakerBalanceThresholdWrapper.fillOrderAsync( + validSignedOrderERC20Sender, + validTakerAddress, + { takerAssetFillAmount }, + ); + // Assert validated addresses + const expectedValidatedAddresseses = [validSignedOrder.makerAddress, validTakerAddress]; + await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); + // Check balances + const newBalances = await erc20Wrapper.getBalancesAsync(); + const makerAssetFillAmount = takerAssetFillAmount + .times(validSignedOrder.makerAssetAmount) + .dividedToIntegerBy(validSignedOrder.takerAssetAmount); + const makerFeePaid = validSignedOrder.makerFee + .times(makerAssetFillAmount) + .dividedToIntegerBy(validSignedOrder.makerAssetAmount); + const takerFeePaid = validSignedOrder.takerFee + .times(makerAssetFillAmount) + .dividedToIntegerBy(validSignedOrder.makerAssetAmount); + expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), + ); + expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount), + ); + expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][zrxToken.address].minus(makerFeePaid), + ); + expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount), + ); + expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount), + ); + expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid), + ); + expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)), + ); + }); + it('should revert if the Exchange transaction function is not supported', async () => { + // Create signed order without the fillOrder function selector + const salt = new BigNumber(0); + const badSelectorHex = '0x00000000'; + const signatureHex = '0x'; + // Call valid forwarder + return expectTransactionFailedAsync( + erc721BalanceThresholdFilterInstance.executeTransaction.sendTransactionAsync( + salt, + validTakerAddress, + badSelectorHex, + signatureHex, + ), + RevertReason.InvalidOrBlockedExchangeSelector, + ); + }); + it('should revert if senderAddress is not set to the valid forwarding contract', async () => { + // Create signed order with incorrect senderAddress + const notBalanceThresholdFilterAddress = zrxToken.address; + const signedOrderWithBadSenderAddress = await orderFactory.newSignedOrderAsync({ + senderAddress: notBalanceThresholdFilterAddress, + }); + // Call valid forwarder + return expectTransactionFailedAsync( + erc721TakerBalanceThresholdWrapper.fillOrderAsync(signedOrderWithBadSenderAddress, validTakerAddress, { + takerAssetFillAmount, + }), + RevertReason.FailedExecution, + ); + }); + }); + + describe('batchFillOrders', () => { + beforeEach(async () => { + erc20Balances = await erc20Wrapper.getBalancesAsync(); + validSignedOrder = await orderFactory.newSignedOrderAsync(); + validSignedOrder2 = await orderFactory2.newSignedOrderAsync(); + }); + it('should transfer the correct amounts and validate both makers/taker when both maker and taker meet the balance threshold', async () => { + // Execute a valid fill + const orders = [validSignedOrder, validSignedOrder2]; + const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount]; + const txReceipt = await erc721TakerBalanceThresholdWrapper.batchFillOrdersAsync(orders, validTakerAddress, { + takerAssetFillAmounts, + }); + // Assert validated addresses + const expectedValidatedAddresseses = [ + validSignedOrder.makerAddress, + validSignedOrder2.makerAddress, + validTakerAddress, + ]; + await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); + // Check balances + const newBalances = await erc20Wrapper.getBalancesAsync(); + const cumulativeTakerAssetFillAmount = takerAssetFillAmount.times(2); + const makerAssetFillAmount = takerAssetFillAmount + .times(validSignedOrder.makerAssetAmount) + .dividedToIntegerBy(validSignedOrder.takerAssetAmount); + const makerFeePaid = validSignedOrder.makerFee + .times(makerAssetFillAmount) + .dividedToIntegerBy(validSignedOrder.makerAssetAmount); + const takerFeePaid = validSignedOrder.takerFee + .times(makerAssetFillAmount) + .dividedToIntegerBy(validSignedOrder.makerAssetAmount) + .times(2); + // Maker #1 + expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), + ); + expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount), + ); + expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][zrxToken.address].minus(makerFeePaid), + ); + // Maker #2 + expect(newBalances[validMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount), + ); + expect(newBalances[validMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount), + ); + expect(newBalances[validMakerAddress2][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[validMakerAddress2][zrxToken.address].minus(makerFeePaid), + ); + // Taker + expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount), + ); + + expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount.times(2)), + ); + expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid), + ); + // Fee recipient + expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.times(2).add(takerFeePaid)), + ); + }); + it('should revert if one maker does not meet the balance threshold', async () => { + // Create order set with one non-valid maker address + const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount]; + const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ + makerAddress: invalidAddress, + }); + const orders = [validSignedOrder, signedOrderWithBadMakerAddress]; + // Execute transaction + return expectTransactionFailedAsync( + erc721TakerBalanceThresholdWrapper.batchFillOrdersAsync(orders, validTakerAddress, { + takerAssetFillAmounts, + }), + RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, + ); + }); + it('should revert if taker does not meet the balance threshold', async () => { + const orders = [validSignedOrder, validSignedOrder2]; + const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount]; + return expectTransactionFailedAsync( + erc721NonValidBalanceThresholdWrapper.batchFillOrdersAsync(orders, invalidAddress, { + takerAssetFillAmounts, + }), + RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, + ); + }); + }); + + describe('batchFillOrdersNoThrow', () => { + beforeEach(async () => { + erc20Balances = await erc20Wrapper.getBalancesAsync(); + validSignedOrder = await orderFactory.newSignedOrderAsync(); + validSignedOrder2 = await orderFactory2.newSignedOrderAsync(); + }); + it('should transfer the correct amounts and validate both makers/taker when both maker and taker meet the balance threshold', async () => { + // Execute a valid fill + const orders = [validSignedOrder, validSignedOrder2]; + const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount]; + const txReceipt = await erc721TakerBalanceThresholdWrapper.batchFillOrdersNoThrowAsync( + orders, + validTakerAddress, + { + takerAssetFillAmounts, + // HACK(albrow): We need to hardcode the gas estimate here because + // the Geth gas estimator doesn't work with the way we use + // delegatecall and swallow errors. + gas: 600000, + }, + ); + // Assert validated addresses + const expectedValidatedAddresseses = [ + validSignedOrder.makerAddress, + validSignedOrder2.makerAddress, + validTakerAddress, + ]; + await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); + // Check balances + const newBalances = await erc20Wrapper.getBalancesAsync(); + const cumulativeTakerAssetFillAmount = takerAssetFillAmount.times(2); + const makerAssetFillAmount = takerAssetFillAmount + .times(validSignedOrder.makerAssetAmount) + .dividedToIntegerBy(validSignedOrder.takerAssetAmount); + const makerFeePaid = validSignedOrder.makerFee + .times(makerAssetFillAmount) + .dividedToIntegerBy(validSignedOrder.makerAssetAmount); + const takerFeePaid = validSignedOrder.takerFee + .times(makerAssetFillAmount) + .dividedToIntegerBy(validSignedOrder.makerAssetAmount) + .times(2); + // Maker #1 + expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), + ); + expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount), + ); + expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][zrxToken.address].minus(makerFeePaid), + ); + // Maker #2 + expect(newBalances[validMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount), + ); + expect(newBalances[validMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount), + ); + expect(newBalances[validMakerAddress2][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[validMakerAddress2][zrxToken.address].minus(makerFeePaid), + ); + // Taker + expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount), + ); + + expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount.times(2)), + ); + expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid), + ); + // Fee recipient + expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.times(2).add(takerFeePaid)), + ); + }); + it('should revert if one maker does not meet the balance threshold', async () => { + // Create order set with one non-valid maker address + const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount]; + const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ + makerAddress: invalidAddress, + }); + const orders = [validSignedOrder, signedOrderWithBadMakerAddress]; + // Execute transaction + return expectTransactionFailedAsync( + erc721TakerBalanceThresholdWrapper.batchFillOrdersNoThrowAsync(orders, validTakerAddress, { + takerAssetFillAmounts, + }), + RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, + ); + }); + it('should revert if taker does not meet the balance threshold', async () => { + const orders = [validSignedOrder, validSignedOrder2]; + const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount]; + return expectTransactionFailedAsync( + erc721NonValidBalanceThresholdWrapper.batchFillOrdersNoThrowAsync(orders, invalidAddress, { + takerAssetFillAmounts, + }), + RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, + ); + }); + }); + + describe('batchFillOrKillOrders', () => { + beforeEach(async () => { + erc20Balances = await erc20Wrapper.getBalancesAsync(); + validSignedOrder = await orderFactory.newSignedOrderAsync(); + validSignedOrder2 = await orderFactory2.newSignedOrderAsync(); + }); + it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => { + // Execute a valid fill + const orders = [validSignedOrder, validSignedOrder2]; + const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount]; + const txReceipt = await erc721TakerBalanceThresholdWrapper.batchFillOrKillOrdersAsync( + orders, + validTakerAddress, + { takerAssetFillAmounts }, + ); + // Assert validated addresses + const expectedValidatedAddresseses = [ + validSignedOrder.makerAddress, + validSignedOrder2.makerAddress, + validTakerAddress, + ]; + await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); + // Check balances + const newBalances = await erc20Wrapper.getBalancesAsync(); + const cumulativeTakerAssetFillAmount = takerAssetFillAmount.times(2); + const makerAssetFillAmount = takerAssetFillAmount + .times(validSignedOrder.makerAssetAmount) + .dividedToIntegerBy(validSignedOrder.takerAssetAmount); + const makerFeePaid = validSignedOrder.makerFee + .times(makerAssetFillAmount) + .dividedToIntegerBy(validSignedOrder.makerAssetAmount); + const takerFeePaid = validSignedOrder.takerFee + .times(makerAssetFillAmount) + .dividedToIntegerBy(validSignedOrder.makerAssetAmount) + .times(2); + // Maker #1 + expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), + ); + expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount), + ); + expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][zrxToken.address].minus(makerFeePaid), + ); + // Maker #2 + expect(newBalances[validMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount), + ); + expect(newBalances[validMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount), + ); + expect(newBalances[validMakerAddress2][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[validMakerAddress2][zrxToken.address].minus(makerFeePaid), + ); + // Taker + expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount), + ); + + expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount.times(2)), + ); + expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid), + ); + // Fee recipient + expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.times(2).add(takerFeePaid)), + ); + }); + it('should revert if one maker does not meet the balance threshold', async () => { + // Create order set with one non-valid maker address + const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount]; + const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ + makerAddress: invalidAddress, + }); + const orders = [validSignedOrder, signedOrderWithBadMakerAddress]; + // Execute transaction + return expectTransactionFailedAsync( + erc721TakerBalanceThresholdWrapper.batchFillOrKillOrdersAsync(orders, validTakerAddress, { + takerAssetFillAmounts, + }), + RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, + ); + }); + it('should revert if taker does not meet the balance threshold', async () => { + const orders = [validSignedOrder, validSignedOrder2]; + const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount]; + return expectTransactionFailedAsync( + erc721NonValidBalanceThresholdWrapper.batchFillOrKillOrdersAsync(orders, invalidAddress, { + takerAssetFillAmounts, + }), + RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, + ); + }); + it('should revert if one takerAssetFillAmount is not fully filled', async () => { + const tooBigTakerAssetFillAmount = validSignedOrder.takerAssetAmount.times(2); + const orders = [validSignedOrder, validSignedOrder2]; + const takerAssetFillAmounts = [takerAssetFillAmount, tooBigTakerAssetFillAmount]; + return expectTransactionFailedAsync( + erc721TakerBalanceThresholdWrapper.batchFillOrKillOrdersAsync(orders, validTakerAddress, { + takerAssetFillAmounts, + }), + RevertReason.FailedExecution, + ); + }); + }); + + describe('fillOrder', () => { + beforeEach(async () => { + erc20Balances = await erc20Wrapper.getBalancesAsync(); + validSignedOrder = await orderFactory.newSignedOrderAsync(); + }); + it('should transfer the correct amounts and validate both maker/taker when both maker and taker meet the balance threshold', async () => { + // Execute a valid fill + const txReceipt = await erc721TakerBalanceThresholdWrapper.fillOrderAsync( + validSignedOrder, + validTakerAddress, + { takerAssetFillAmount }, + ); + // Assert validated addresses + const expectedValidatedAddresseses = [validSignedOrder.makerAddress, validTakerAddress]; + await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); + // Check balances + const newBalances = await erc20Wrapper.getBalancesAsync(); + const makerAssetFillAmount = takerAssetFillAmount + .times(validSignedOrder.makerAssetAmount) + .dividedToIntegerBy(validSignedOrder.takerAssetAmount); + const makerFeePaid = validSignedOrder.makerFee + .times(makerAssetFillAmount) + .dividedToIntegerBy(validSignedOrder.makerAssetAmount); + const takerFeePaid = validSignedOrder.takerFee + .times(makerAssetFillAmount) + .dividedToIntegerBy(validSignedOrder.makerAssetAmount); + expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), + ); + expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount), + ); + expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][zrxToken.address].minus(makerFeePaid), + ); + expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount), + ); + expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount), + ); + expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid), + ); + expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)), + ); + }); + it('should revert if maker does not meet the balance threshold', async () => { + // Create signed order with non-valid maker address + const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ + senderAddress: erc721BalanceThresholdFilterInstance.address, + makerAddress: invalidAddress, + }); + // Execute transaction + return expectTransactionFailedAsync( + erc721TakerBalanceThresholdWrapper.fillOrderAsync(signedOrderWithBadMakerAddress, validTakerAddress, { + takerAssetFillAmount, + }), + RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, + ); + }); + it('should revert if taker does not meet the balance threshold', async () => { + return expectTransactionFailedAsync( + erc721NonValidBalanceThresholdWrapper.fillOrderAsync(validSignedOrder, invalidAddress, { + takerAssetFillAmount, + }), + RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, + ); + }); + }); + + describe('fillOrderNoThrow', () => { + beforeEach(async () => { + erc20Balances = await erc20Wrapper.getBalancesAsync(); + validSignedOrder = await orderFactory.newSignedOrderAsync(); + }); + it('should transfer the correct amounts and validate both maker/taker when both maker and taker meet the balance threshold', async () => { + // Execute a valid fill + const txReceipt = await erc721TakerBalanceThresholdWrapper.fillOrderNoThrowAsync( + validSignedOrder, + validTakerAddress, + { + takerAssetFillAmount, + // HACK(albrow): We need to hardcode the gas estimate here because + // the Geth gas estimator doesn't work with the way we use + // delegatecall and swallow errors. + gas: 600000, + }, + ); + // Assert validated addresses + const expectedValidatedAddresseses = [validSignedOrder.makerAddress, validTakerAddress]; + await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); + // Check balances + const newBalances = await erc20Wrapper.getBalancesAsync(); + const makerAssetFillAmount = takerAssetFillAmount + .times(validSignedOrder.makerAssetAmount) + .dividedToIntegerBy(validSignedOrder.takerAssetAmount); + const makerFeePaid = validSignedOrder.makerFee + .times(makerAssetFillAmount) + .dividedToIntegerBy(validSignedOrder.makerAssetAmount); + const takerFeePaid = validSignedOrder.takerFee + .times(makerAssetFillAmount) + .dividedToIntegerBy(validSignedOrder.makerAssetAmount); + expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), + ); + expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount), + ); + expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][zrxToken.address].minus(makerFeePaid), + ); + expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount), + ); + expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount), + ); + expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid), + ); + expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)), + ); + }); + it('should revert if maker does not meet the balance threshold', async () => { + // Create signed order with non-valid maker address + const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ + senderAddress: erc721BalanceThresholdFilterInstance.address, + makerAddress: invalidAddress, + }); + // Execute transaction + return expectTransactionFailedAsync( + erc721TakerBalanceThresholdWrapper.fillOrderNoThrowAsync( + signedOrderWithBadMakerAddress, + validTakerAddress, + { takerAssetFillAmount }, + ), + RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, + ); + }); + it('should revert if taker does not meet the balance threshold', async () => { + return expectTransactionFailedAsync( + erc721NonValidBalanceThresholdWrapper.fillOrderNoThrowAsync(validSignedOrder, invalidAddress, { + takerAssetFillAmount, + }), + RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, + ); + }); + }); + + describe('fillOrKillOrder', () => { + beforeEach(async () => { + erc20Balances = await erc20Wrapper.getBalancesAsync(); + validSignedOrder = await orderFactory.newSignedOrderAsync(); + }); + it('should transfer the correct amounts and validate both maker/taker when both maker and taker meet the balance threshold', async () => { + // Execute a valid fill + const takerAssetFillAmount_ = validSignedOrder.takerAssetAmount; + const txReceipt = await erc721TakerBalanceThresholdWrapper.fillOrKillOrderAsync( + validSignedOrder, + validTakerAddress, + { takerAssetFillAmount: takerAssetFillAmount_ }, + ); + // Assert validated addresses + const expectedValidatedAddresseses = [validSignedOrder.makerAddress, validTakerAddress]; + await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); + // Check balances + const newBalances = await erc20Wrapper.getBalancesAsync(); + const makerAssetFillAmount = takerAssetFillAmount_ + .times(validSignedOrder.makerAssetAmount) + .dividedToIntegerBy(validSignedOrder.takerAssetAmount); + const makerFeePaid = validSignedOrder.makerFee + .times(makerAssetFillAmount) + .dividedToIntegerBy(validSignedOrder.makerAssetAmount); + const takerFeePaid = validSignedOrder.takerFee + .times(makerAssetFillAmount) + .dividedToIntegerBy(validSignedOrder.makerAssetAmount); + expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), + ); + expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount_), + ); + expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][zrxToken.address].minus(makerFeePaid), + ); + expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount_), + ); + expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount), + ); + expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid), + ); + expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)), + ); + }); + it('should revert if maker does not meet the balance threshold', async () => { + // Create signed order with non-valid maker address + const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ + senderAddress: erc721BalanceThresholdFilterInstance.address, + makerAddress: invalidAddress, + }); + // Execute transaction + return expectTransactionFailedAsync( + erc721TakerBalanceThresholdWrapper.fillOrKillOrderAsync( + signedOrderWithBadMakerAddress, + validTakerAddress, + { takerAssetFillAmount }, + ), + RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, + ); + }); + it('should revert if taker does not meet the balance threshold', async () => { + return expectTransactionFailedAsync( + erc721NonValidBalanceThresholdWrapper.fillOrKillOrderAsync(validSignedOrder, invalidAddress, { + takerAssetFillAmount, + }), + RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, + ); + }); + it('should revert if takerAssetFillAmount is not fully filled', async () => { + const tooBigTakerAssetFillAmount = validSignedOrder.takerAssetAmount.times(2); + return expectTransactionFailedAsync( + erc721TakerBalanceThresholdWrapper.fillOrKillOrderAsync(validSignedOrder, validTakerAddress, { + takerAssetFillAmount: tooBigTakerAssetFillAmount, + }), + RevertReason.FailedExecution, + ); + }); + }); + + describe('marketSellOrders', () => { + beforeEach(async () => { + erc20Balances = await erc20Wrapper.getBalancesAsync(); + validSignedOrder = await orderFactory.newSignedOrderAsync(); + validSignedOrder2 = await orderFactory2.newSignedOrderAsync(); + }); + it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => { + // Execute a valid fill + const orders = [validSignedOrder, validSignedOrder2]; + const cumulativeTakerAssetFillAmount = validSignedOrder.takerAssetAmount.plus(takerAssetFillAmount); + const txReceipt = await erc721TakerBalanceThresholdWrapper.marketSellOrdersAsync( + orders, + validTakerAddress, + { takerAssetFillAmount: cumulativeTakerAssetFillAmount }, + ); + // Assert validated addresses + const expectedValidatedAddresseses = [ + validSignedOrder.makerAddress, + validSignedOrder2.makerAddress, + validTakerAddress, + ]; + await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); + // Check balances + const newBalances = await erc20Wrapper.getBalancesAsync(); + const makerAssetFillAmount2 = takerAssetFillAmount + .times(validSignedOrder.makerAssetAmount) + .dividedToIntegerBy(validSignedOrder.takerAssetAmount); + const makerFeePaid2 = validSignedOrder2.makerFee + .times(makerAssetFillAmount2) + .dividedToIntegerBy(validSignedOrder2.makerAssetAmount); + const takerFeePaid2 = validSignedOrder2.takerFee + .times(makerAssetFillAmount2) + .dividedToIntegerBy(validSignedOrder2.makerAssetAmount); + const takerFeePaid = validSignedOrder.takerFee.plus(takerFeePaid2); + const cumulativeMakerAssetFillAmount = validSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2); + // Maker #1 + expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(validSignedOrder.makerAssetAmount), + ); + expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(validSignedOrder.takerAssetAmount), + ); + expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][zrxToken.address].minus(validSignedOrder.makerFee), + ); + // Maker #2 + expect(newBalances[validMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount2), + ); + expect(newBalances[validMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount), + ); + expect(newBalances[validMakerAddress2][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[validMakerAddress2][zrxToken.address].minus(makerFeePaid2), + ); + // Taker + expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount), + ); + expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][defaultMakerAssetAddress].add(cumulativeMakerAssetFillAmount), + ); + expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid), + ); + // Fee recipient + expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[feeRecipientAddress][zrxToken.address] + .add(validSignedOrder.makerFee) + .add(makerFeePaid2) + .add(takerFeePaid), + ); + }); + it('should revert if one maker does not meet the balance threshold', async () => { + // Create order set with one non-valid maker address + const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ + makerAddress: invalidAddress, + }); + const orders = [validSignedOrder, signedOrderWithBadMakerAddress]; + // Execute transaction + return expectTransactionFailedAsync( + erc721TakerBalanceThresholdWrapper.marketSellOrdersAsync(orders, validTakerAddress, { + takerAssetFillAmount, + }), + RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, + ); + }); + it('should revert if taker does not meet the balance threshold', async () => { + const orders = [validSignedOrder, validSignedOrder2]; + return expectTransactionFailedAsync( + erc721NonValidBalanceThresholdWrapper.marketSellOrdersAsync(orders, invalidAddress, { + takerAssetFillAmount, + }), + RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, + ); + }); + }); + + describe('marketSellOrdersNoThrow', () => { + beforeEach(async () => { + erc20Balances = await erc20Wrapper.getBalancesAsync(); + validSignedOrder = await orderFactory.newSignedOrderAsync(); + validSignedOrder2 = await orderFactory2.newSignedOrderAsync(); + }); + it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => { + // Execute a valid fill + const orders = [validSignedOrder, validSignedOrder2]; + const cumulativeTakerAssetFillAmount = validSignedOrder.takerAssetAmount.plus(takerAssetFillAmount); + const txReceipt = await erc721TakerBalanceThresholdWrapper.marketSellOrdersNoThrowAsync( + orders, + validTakerAddress, + { + takerAssetFillAmount: cumulativeTakerAssetFillAmount, + // HACK(albrow): We need to hardcode the gas estimate here because + // the Geth gas estimator doesn't work with the way we use + // delegatecall and swallow errors. + gas: 600000, + }, + ); + // Assert validated addresses + const expectedValidatedAddresseses = [ + validSignedOrder.makerAddress, + validSignedOrder2.makerAddress, + validTakerAddress, + ]; + await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); + // Check balances + const newBalances = await erc20Wrapper.getBalancesAsync(); + const makerAssetFillAmount2 = takerAssetFillAmount + .times(validSignedOrder.makerAssetAmount) + .dividedToIntegerBy(validSignedOrder.takerAssetAmount); + const makerFeePaid2 = validSignedOrder2.makerFee + .times(makerAssetFillAmount2) + .dividedToIntegerBy(validSignedOrder2.makerAssetAmount); + const takerFeePaid2 = validSignedOrder2.takerFee + .times(makerAssetFillAmount2) + .dividedToIntegerBy(validSignedOrder2.makerAssetAmount); + const takerFeePaid = validSignedOrder.takerFee.plus(takerFeePaid2); + const cumulativeMakerAssetFillAmount = validSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2); + // Maker #1 + expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(validSignedOrder.makerAssetAmount), + ); + expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(validSignedOrder.takerAssetAmount), + ); + expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][zrxToken.address].minus(validSignedOrder.makerFee), + ); + // Maker #2 + expect(newBalances[validMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount2), + ); + expect(newBalances[validMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount), + ); + expect(newBalances[validMakerAddress2][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[validMakerAddress2][zrxToken.address].minus(makerFeePaid2), + ); + // Taker + expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount), + ); + expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][defaultMakerAssetAddress].add(cumulativeMakerAssetFillAmount), + ); + expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid), + ); + // Fee recipient + expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[feeRecipientAddress][zrxToken.address] + .add(validSignedOrder.makerFee) + .add(makerFeePaid2) + .add(takerFeePaid), + ); + }); + it('should revert if one maker does not meet the balance threshold', async () => { + // Create order set with one non-valid maker address + const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ + makerAddress: invalidAddress, + }); + const orders = [validSignedOrder, signedOrderWithBadMakerAddress]; + // Execute transaction + return expectTransactionFailedAsync( + erc721TakerBalanceThresholdWrapper.marketSellOrdersNoThrowAsync(orders, validTakerAddress, { + takerAssetFillAmount, + }), + RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, + ); + }); + it('should revert if taker does not meet the balance threshold', async () => { + const orders = [validSignedOrder, validSignedOrder2]; + return expectTransactionFailedAsync( + erc721NonValidBalanceThresholdWrapper.marketSellOrdersNoThrowAsync(orders, invalidAddress, { + takerAssetFillAmount, + }), + RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, + ); + }); + }); + + describe('marketBuyOrders', () => { + beforeEach(async () => { + erc20Balances = await erc20Wrapper.getBalancesAsync(); + validSignedOrder = await orderFactory.newSignedOrderAsync(); + validSignedOrder2 = await orderFactory2.newSignedOrderAsync(); + }); + it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => { + // Execute a valid fill + const orders = [validSignedOrder, validSignedOrder2]; + const cumulativeTakerAssetFillAmount = validSignedOrder.takerAssetAmount.plus(takerAssetFillAmount); + const makerAssetFillAmount2 = takerAssetFillAmount + .times(validSignedOrder.makerAssetAmount) + .dividedToIntegerBy(validSignedOrder.takerAssetAmount); + const cumulativeMakerAssetFillAmount = validSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2); + const txReceipt = await erc721TakerBalanceThresholdWrapper.marketBuyOrdersAsync(orders, validTakerAddress, { + makerAssetFillAmount: cumulativeMakerAssetFillAmount, + }); + // Assert validated addresses + const expectedValidatedAddresseses = [ + validSignedOrder.makerAddress, + validSignedOrder2.makerAddress, + validTakerAddress, + ]; + await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); + // Check balances + const newBalances = await erc20Wrapper.getBalancesAsync(); + const makerFeePaid2 = validSignedOrder2.makerFee + .times(makerAssetFillAmount2) + .dividedToIntegerBy(validSignedOrder2.makerAssetAmount); + const takerFeePaid2 = validSignedOrder2.takerFee + .times(makerAssetFillAmount2) + .dividedToIntegerBy(validSignedOrder2.makerAssetAmount); + const takerFeePaid = validSignedOrder.takerFee.plus(takerFeePaid2); + // Maker #1 + expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(validSignedOrder.makerAssetAmount), + ); + expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(validSignedOrder.takerAssetAmount), + ); + expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][zrxToken.address].minus(validSignedOrder.makerFee), + ); + // Maker #2 + expect(newBalances[validMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount2), + ); + expect(newBalances[validMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount), + ); + expect(newBalances[validMakerAddress2][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[validMakerAddress2][zrxToken.address].minus(makerFeePaid2), + ); + // Taker + expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount), + ); + expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][defaultMakerAssetAddress].add(cumulativeMakerAssetFillAmount), + ); + expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid), + ); + // Fee recipient + expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[feeRecipientAddress][zrxToken.address] + .add(validSignedOrder.makerFee) + .add(makerFeePaid2) + .add(takerFeePaid), + ); + }); + it('should revert if one maker does not meet the balance threshold', async () => { + // Create order set with one non-valid maker address + const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ + makerAddress: invalidAddress, + }); + const orders = [validSignedOrder, signedOrderWithBadMakerAddress]; + // Execute transaction + const dummyMakerAssetFillAmount = new BigNumber(0); + return expectTransactionFailedAsync( + erc721TakerBalanceThresholdWrapper.marketBuyOrdersAsync(orders, validTakerAddress, { + makerAssetFillAmount: dummyMakerAssetFillAmount, + }), + RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, + ); + }); + it('should revert if taker does not meet the balance threshold', async () => { + const orders = [validSignedOrder, validSignedOrder2]; + const dummyMakerAssetFillAmount = new BigNumber(0); + return expectTransactionFailedAsync( + erc721NonValidBalanceThresholdWrapper.marketBuyOrdersAsync(orders, invalidAddress, { + makerAssetFillAmount: dummyMakerAssetFillAmount, + }), + RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, + ); + }); + }); + + describe('marketBuyOrdersNoThrowAsync', () => { + beforeEach(async () => { + erc20Balances = await erc20Wrapper.getBalancesAsync(); + validSignedOrder = await orderFactory.newSignedOrderAsync(); + validSignedOrder2 = await orderFactory2.newSignedOrderAsync(); + }); + it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => { + // Execute a valid fill + const orders = [validSignedOrder, validSignedOrder2]; + const cumulativeTakerAssetFillAmount = validSignedOrder.takerAssetAmount.plus(takerAssetFillAmount); + const makerAssetFillAmount2 = takerAssetFillAmount + .times(validSignedOrder.makerAssetAmount) + .dividedToIntegerBy(validSignedOrder.takerAssetAmount); + const cumulativeMakerAssetFillAmount = validSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2); + const txReceipt = await erc721TakerBalanceThresholdWrapper.marketBuyOrdersNoThrowAsync( + orders, + validTakerAddress, + { + makerAssetFillAmount: cumulativeMakerAssetFillAmount, + // HACK(albrow): We need to hardcode the gas estimate here because + // the Geth gas estimator doesn't work with the way we use + // delegatecall and swallow errors. + gas: 600000, + }, + ); + // Assert validated addresses + const expectedValidatedAddresseses = [ + validSignedOrder.makerAddress, + validSignedOrder2.makerAddress, + validTakerAddress, + ]; + await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); + // Check balances + const newBalances = await erc20Wrapper.getBalancesAsync(); + const makerFeePaid2 = validSignedOrder2.makerFee + .times(makerAssetFillAmount2) + .dividedToIntegerBy(validSignedOrder2.makerAssetAmount); + const takerFeePaid2 = validSignedOrder2.takerFee + .times(makerAssetFillAmount2) + .dividedToIntegerBy(validSignedOrder2.makerAssetAmount); + const takerFeePaid = validSignedOrder.takerFee.plus(takerFeePaid2); + // Maker #1 + expect(newBalances[validMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][defaultMakerAssetAddress].minus(validSignedOrder.makerAssetAmount), + ); + expect(newBalances[validMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][defaultTakerAssetAddress].add(validSignedOrder.takerAssetAmount), + ); + expect(newBalances[validMakerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[validMakerAddress][zrxToken.address].minus(validSignedOrder.makerFee), + ); + // Maker #2 + expect(newBalances[validMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount2), + ); + expect(newBalances[validMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount), + ); + expect(newBalances[validMakerAddress2][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[validMakerAddress2][zrxToken.address].minus(makerFeePaid2), + ); + // Taker + expect(newBalances[validTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount), + ); + expect(newBalances[validTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][defaultMakerAssetAddress].add(cumulativeMakerAssetFillAmount), + ); + expect(newBalances[validTakerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[validTakerAddress][zrxToken.address].minus(takerFeePaid), + ); + // Fee recipient + expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[feeRecipientAddress][zrxToken.address] + .add(validSignedOrder.makerFee) + .add(makerFeePaid2) + .add(takerFeePaid), + ); + }); + it('should revert if one maker does not meet the balance threshold', async () => { + // Create order set with one non-valid maker address + const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ + makerAddress: invalidAddress, + }); + const orders = [validSignedOrder, signedOrderWithBadMakerAddress]; + // Execute transaction + const dummyMakerAssetFillAmount = new BigNumber(0); + return expectTransactionFailedAsync( + erc721TakerBalanceThresholdWrapper.marketBuyOrdersNoThrowAsync(orders, validTakerAddress, { + makerAssetFillAmount: dummyMakerAssetFillAmount, + }), + RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, + ); + }); + it('should revert if taker does not meet the balance threshold', async () => { + const orders = [validSignedOrder, validSignedOrder2]; + const dummyMakerAssetFillAmount = new BigNumber(0); + return expectTransactionFailedAsync( + erc721NonValidBalanceThresholdWrapper.marketBuyOrdersNoThrowAsync(orders, invalidAddress, { + makerAssetFillAmount: dummyMakerAssetFillAmount, + }), + RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, + ); + }); + }); + + describe('matchOrders', () => { + beforeEach(async () => { + erc20Balances = await erc20Wrapper.getBalancesAsync(); + validSignedOrder = await orderFactory.newSignedOrderAsync(); + validSignedOrder2 = await orderFactory2.newSignedOrderAsync(); + }); + it('Should transfer correct amounts when both makers and taker meet the balance threshold', async () => { + // Test values/results taken from Match Orders test: + // 'Should transfer correct amounts when right order is fully filled and values pass isRoundingErrorFloor but fail isRoundingErrorCeil' + // Create orders to match + const signedOrderLeft = await orderFactory.newSignedOrderAsync({ + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(17), 0), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(98), 0), + makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18), + takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18), + feeRecipientAddress, + }); + const signedOrderRight = await orderFactory2.newSignedOrderAsync({ + makerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress), + takerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress), + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(75), 0), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0), + makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18), + takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18), + feeRecipientAddress, + }); + // Compute expected transfer amounts + const expectedTransferAmounts = { + // Left Maker + amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0), + amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(75), 0), + feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber('76.4705882352941176'), 16), // 76.47% + // Right Maker + amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(75), 0), + amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0), + feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + // Taker + amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 0), + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber('76.5306122448979591'), 16), // 76.53% + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + }; + const txReceipt = await erc721TakerBalanceThresholdWrapper.matchOrdersAsync( + signedOrderLeft, + signedOrderRight, + validTakerAddress, + ); + // Assert validated addresses + const expectedValidatedAddresseses = [ + signedOrderLeft.makerAddress, + signedOrderRight.makerAddress, + validTakerAddress, + ]; + await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); + // Check balances + const newBalances = await erc20Wrapper.getBalancesAsync(); + expect( + newBalances[signedOrderLeft.makerAddress][defaultMakerAssetAddress], + 'Checking left maker egress ERC20 account balance', + ).to.be.bignumber.equal( + erc20Balances[signedOrderLeft.makerAddress][defaultMakerAssetAddress].sub( + expectedTransferAmounts.amountSoldByLeftMaker, + ), + ); + expect( + newBalances[signedOrderRight.makerAddress][defaultTakerAssetAddress], + 'Checking right maker ingress ERC20 account balance', + ).to.be.bignumber.equal( + erc20Balances[signedOrderRight.makerAddress][defaultTakerAssetAddress].sub( + expectedTransferAmounts.amountSoldByRightMaker, + ), + ); + expect( + newBalances[validTakerAddress][defaultMakerAssetAddress], + 'Checking taker ingress ERC20 account balance', + ).to.be.bignumber.equal( + erc20Balances[validTakerAddress][defaultMakerAssetAddress].add( + expectedTransferAmounts.amountReceivedByTaker, + ), + ); + expect( + newBalances[signedOrderLeft.makerAddress][defaultTakerAssetAddress], + 'Checking left maker ingress ERC20 account balance', + ).to.be.bignumber.equal( + erc20Balances[signedOrderLeft.makerAddress][defaultTakerAssetAddress].add( + expectedTransferAmounts.amountBoughtByLeftMaker, + ), + ); + expect( + newBalances[signedOrderRight.makerAddress][defaultMakerAssetAddress], + 'Checking right maker egress ERC20 account balance', + ).to.be.bignumber.equal( + erc20Balances[signedOrderRight.makerAddress][defaultMakerAssetAddress].add( + expectedTransferAmounts.amountBoughtByRightMaker, + ), + ); + // Paid fees + expect( + newBalances[signedOrderLeft.makerAddress][zrxToken.address], + 'Checking left maker egress ERC20 account fees', + ).to.be.bignumber.equal( + erc20Balances[signedOrderLeft.makerAddress][zrxToken.address].minus( + expectedTransferAmounts.feePaidByLeftMaker, + ), + ); + expect( + newBalances[signedOrderRight.makerAddress][zrxToken.address], + 'Checking right maker egress ERC20 account fees', + ).to.be.bignumber.equal( + erc20Balances[signedOrderRight.makerAddress][zrxToken.address].minus( + expectedTransferAmounts.feePaidByRightMaker, + ), + ); + expect( + newBalances[validTakerAddress][zrxToken.address], + 'Checking taker egress ERC20 account fees', + ).to.be.bignumber.equal( + erc20Balances[validTakerAddress][zrxToken.address] + .minus(expectedTransferAmounts.feePaidByTakerLeft) + .sub(expectedTransferAmounts.feePaidByTakerRight), + ); + // Received fees + expect( + newBalances[signedOrderLeft.feeRecipientAddress][zrxToken.address], + 'Checking left fee recipient ingress ERC20 account fees', + ).to.be.bignumber.equal( + erc20Balances[feeRecipientAddress][zrxToken.address] + .add(expectedTransferAmounts.feePaidByLeftMaker) + .add(expectedTransferAmounts.feePaidByRightMaker) + .add(expectedTransferAmounts.feePaidByTakerLeft) + .add(expectedTransferAmounts.feePaidByTakerRight), + ); + }); + it('should revert if left maker does not meet the balance threshold', async () => { + // Create signed order with non-valid maker address + const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ + senderAddress: erc721BalanceThresholdFilterInstance.address, + makerAddress: invalidAddress, + }); + // Execute transaction + return expectTransactionFailedAsync( + erc721TakerBalanceThresholdWrapper.matchOrdersAsync( + validSignedOrder, + signedOrderWithBadMakerAddress, + validTakerAddress, + ), + RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, + ); + }); + it('should revert if right maker does not meet the balance threshold', async () => { + // Create signed order with non-valid maker address + const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ + senderAddress: erc721BalanceThresholdFilterInstance.address, + makerAddress: invalidAddress, + }); + // Execute transaction + return expectTransactionFailedAsync( + erc721TakerBalanceThresholdWrapper.matchOrdersAsync( + signedOrderWithBadMakerAddress, + validSignedOrder, + validTakerAddress, + ), + RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, + ); + }); + it('should revert if taker does not meet the balance threshold', async () => { + return expectTransactionFailedAsync( + erc721NonValidBalanceThresholdWrapper.matchOrdersAsync( + validSignedOrder, + validSignedOrder, + invalidAddress, + ), + RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold, + ); + }); + }); + + describe('cancelOrder', () => { + beforeEach(async () => { + erc20Balances = await erc20Wrapper.getBalancesAsync(); + validSignedOrder = await orderFactory.newSignedOrderAsync(); + validSignedOrder2 = await orderFactory2.newSignedOrderAsync(); + }); + it('Should successfully cancel order if maker meets balance threshold', async () => { + // Verify order is not cancelled + const orderInfoBeforeCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync( + validSignedOrder, + ); + expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE); + // Cancel + const txReceipt = await erc721MakerBalanceThresholdWrapper.cancelOrderAsync( + validSignedOrder, + validSignedOrder.makerAddress, + ); + // Assert validated addresses + const expectedValidatedAddresseses: string[] = []; + await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); + // Check that order was cancelled + const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync( + validSignedOrder, + ); + expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.CANCELLED); + }); + it('Should successfully cancel order if maker does not meet balance threshold', async () => { + // Create order where maker does not meet balance threshold + const signedOrderWithBadMakerAddress = await invalidOrderFactory.newSignedOrderAsync({}); + // Verify order is not cancelled + const orderInfoBeforeCancelling = await erc721NonValidBalanceThresholdWrapper.getOrderInfoAsync( + signedOrderWithBadMakerAddress, + ); + expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE); + // Cancel + const txReceipt = await erc721NonValidBalanceThresholdWrapper.cancelOrderAsync( + signedOrderWithBadMakerAddress, + signedOrderWithBadMakerAddress.makerAddress, + ); + // Assert validated addresses + const expectedValidatedAddresseses: string[] = []; + await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); + // Check that order was cancelled + const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync( + signedOrderWithBadMakerAddress, + ); + expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.CANCELLED); + }); + }); + + describe('batchCancelOrders', () => { + beforeEach(async () => { + erc20Balances = await erc20Wrapper.getBalancesAsync(); + }); + it('Should successfully batch cancel orders if maker meets balance threshold', async () => { + // Create orders to cancel + const validSignedOrders = [ + await orderFactory.newSignedOrderAsync(), + await orderFactory.newSignedOrderAsync(), + await orderFactory.newSignedOrderAsync(), + ]; + // Verify orders are not cancelled + _.each(validSignedOrders, async signedOrder => { + const orderInfoBeforeCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync( + signedOrder, + ); + return expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE); + }); + // Cancel + const txReceipt = await erc721MakerBalanceThresholdWrapper.batchCancelOrdersAsync( + validSignedOrders, + validSignedOrders[0].makerAddress, + ); + // Assert validated addresses + const expectedValidatedAddresseses: string[] = []; + await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); + // Check that order was cancelled + _.each(validSignedOrders, async signedOrder => { + const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync( + signedOrder, + ); + return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.CANCELLED); + }); + }); + it('Should successfully batch cancel order if maker does not meet balance threshold', async () => { + // Create orders to cancel + const invalidSignedOrders = [ + await invalidOrderFactory.newSignedOrderAsync(), + await invalidOrderFactory.newSignedOrderAsync(), + await invalidOrderFactory.newSignedOrderAsync(), + ]; + // Verify orders are not cancelled + _.each(invalidSignedOrders, async signedOrder => { + const orderInfoBeforeCancelling = await erc721NonValidBalanceThresholdWrapper.getOrderInfoAsync( + signedOrder, + ); + return expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE); + }); + // Cancel + const txReceipt = await erc721NonValidBalanceThresholdWrapper.batchCancelOrdersAsync( + invalidSignedOrders, + invalidAddress, + ); + // Assert validated addresses + const expectedValidatedAddresseses: string[] = []; + await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); + // Check that order was cancelled + _.each(invalidSignedOrders, async signedOrder => { + const orderInfoAfterCancelling = await erc721NonValidBalanceThresholdWrapper.getOrderInfoAsync( + signedOrder, + ); + return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.CANCELLED); + }); + }); + }); + + describe('cancelOrdersUpTo', () => { + beforeEach(async () => { + erc20Balances = await erc20Wrapper.getBalancesAsync(); + }); + it('Should successfully batch cancel orders if maker meets balance threshold', async () => { + // Create orders to cancel + const validSignedOrders = [ + await orderFactory.newSignedOrderAsync({ salt: new BigNumber(0) }), + await orderFactory.newSignedOrderAsync({ salt: new BigNumber(1) }), + await orderFactory.newSignedOrderAsync({ salt: new BigNumber(2) }), + ]; + // Verify orders are not cancelled + _.each(validSignedOrders, async signedOrder => { + const orderInfoBeforeCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync( + signedOrder, + ); + return expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE); + }); + // Cancel + const cancelOrdersUpToThisSalt = new BigNumber(1); + const txReceipt = await erc721MakerBalanceThresholdWrapper.cancelOrdersUpToAsync( + cancelOrdersUpToThisSalt, + validSignedOrders[0].makerAddress, + ); + // Assert validated addresses + const expectedValidatedAddresseses: string[] = []; + await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); + // Check that order was cancelled + _.each(validSignedOrders, async (signedOrder, salt: number) => { + const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync( + signedOrder, + ); + const saltAsBigNumber = new BigNumber(salt); + if (saltAsBigNumber.lessThanOrEqualTo(cancelOrdersUpToThisSalt)) { + return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.CANCELLED); + } else { + return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE); + } + }); + }); + it('Should successfully batch cancel order if maker does not meet balance threshold', async () => { + // Create orders to cancel + const invalidSignedOrders = [ + await invalidOrderFactory.newSignedOrderAsync({ salt: new BigNumber(0) }), + await invalidOrderFactory.newSignedOrderAsync({ salt: new BigNumber(1) }), + await invalidOrderFactory.newSignedOrderAsync({ salt: new BigNumber(2) }), + ]; + // Verify orders are not cancelled + _.each(invalidSignedOrders, async signedOrder => { + const orderInfoBeforeCancelling = await erc721NonValidBalanceThresholdWrapper.getOrderInfoAsync( + signedOrder, + ); + return expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE); + }); + // Cancel + const cancelOrdersUpToThisSalt = new BigNumber(1); + const txReceipt = await erc721NonValidBalanceThresholdWrapper.cancelOrdersUpToAsync( + cancelOrdersUpToThisSalt, + invalidAddress, + ); + // Assert validated addresses + const expectedValidatedAddresseses: string[] = []; + await assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); + // Check that order was cancelled + _.each(invalidSignedOrders, async (signedOrder, salt: number) => { + const orderInfoAfterCancelling = await erc721NonValidBalanceThresholdWrapper.getOrderInfoAsync( + signedOrder, + ); + const saltAsBigNumber = new BigNumber(salt); + if (saltAsBigNumber.lessThanOrEqualTo(cancelOrdersUpToThisSalt)) { + return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.CANCELLED); + } else { + return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE); + } + }); + }); + }); +}); +// tslint:disable:max-file-line-count +// tslint:enable:no-unnecessary-type-assertion diff --git a/contracts/extensions/test/extensions/forwarder.ts b/contracts/extensions/test/extensions/forwarder.ts index 4027f493d..69939ed04 100644 --- a/contracts/extensions/test/extensions/forwarder.ts +++ b/contracts/extensions/test/extensions/forwarder.ts @@ -48,7 +48,6 @@ describe(ContractName.Forwarder, () => { let owner: string; let takerAddress: string; let feeRecipientAddress: string; - let otherAddress: string; let defaultMakerAssetAddress: string; let zrxAssetData: string; let wethAssetData: string; @@ -78,7 +77,7 @@ describe(ContractName.Forwarder, () => { before(async () => { await blockchainLifecycle.startAsync(); const accounts = await web3Wrapper.getAvailableAddressesAsync(); - const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress, otherAddress] = accounts); + const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = accounts); const txHash = await web3Wrapper.sendTransactionAsync({ from: accounts[0], to: accounts[0], value: 0 }); const transaction = await web3Wrapper.getTransactionByHashAsync(txHash); diff --git a/contracts/extensions/test/extensions/order_matcher.ts b/contracts/extensions/test/extensions/order_matcher.ts new file mode 100644 index 000000000..acb46ced4 --- /dev/null +++ b/contracts/extensions/test/extensions/order_matcher.ts @@ -0,0 +1,818 @@ +import { + artifacts as protocolArtifacts, + ERC20ProxyContract, + ERC20Wrapper, + ERC721ProxyContract, + ExchangeContract, + ExchangeFillEventArgs, + ExchangeWrapper, +} from '@0x/contracts-protocol'; +import { + chaiSetup, + constants, + ERC20BalancesByOwner, + expectContractCreationFailedAsync, + expectTransactionFailedAsync, + LogDecoder, + OrderFactory, + provider, + sendTransactionResult, + txDefaults, + web3Wrapper, +} from '@0x/contracts-test-utils'; +import { artifacts as tokenArtifacts, DummyERC20TokenContract, DummyERC721TokenContract } from '@0x/contracts-tokens'; +import { BlockchainLifecycle } from '@0x/dev-utils'; +import { assetDataUtils } from '@0x/order-utils'; +import { RevertReason } from '@0x/types'; +import { BigNumber } from '@0x/utils'; +import { Web3Wrapper } from '@0x/web3-wrapper'; +import * as chai from 'chai'; +import { LogWithDecodedArgs } from 'ethereum-types'; +import * as _ from 'lodash'; + +import { OrderMatcherContract } from '../../generated-wrappers/order_matcher'; +import { artifacts } from '../../src/artifacts'; + +const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); +chaiSetup.configure(); +const expect = chai.expect; +// tslint:disable:no-unnecessary-type-assertion +describe('OrderMatcher', () => { + let makerAddressLeft: string; + let makerAddressRight: string; + let owner: string; + let takerAddress: string; + let feeRecipientAddressLeft: string; + let feeRecipientAddressRight: string; + + let erc20TokenA: DummyERC20TokenContract; + let erc20TokenB: DummyERC20TokenContract; + let zrxToken: DummyERC20TokenContract; + let exchange: ExchangeContract; + let erc20Proxy: ERC20ProxyContract; + let erc721Proxy: ERC721ProxyContract; + let orderMatcher: OrderMatcherContract; + + let erc20BalancesByOwner: ERC20BalancesByOwner; + let exchangeWrapper: ExchangeWrapper; + let erc20Wrapper: ERC20Wrapper; + let orderFactoryLeft: OrderFactory; + let orderFactoryRight: OrderFactory; + + let leftMakerAssetData: string; + let leftTakerAssetData: string; + let defaultERC20MakerAssetAddress: string; + let defaultERC20TakerAssetAddress: string; + + before(async () => { + await blockchainLifecycle.startAsync(); + }); + after(async () => { + await blockchainLifecycle.revertAsync(); + }); + before(async () => { + // Create accounts + const accounts = await web3Wrapper.getAvailableAddressesAsync(); + // Hack(albrow): Both Prettier and TSLint insert a trailing comma below + // but that is invalid syntax as of TypeScript version >= 2.8. We don't + // have the right fine-grained configuration options in TSLint, + // Prettier, or TypeScript, to reconcile this, so we will just have to + // wait for them to sort it out. We disable TSLint and Prettier for + // this part of the code for now. This occurs several times in this + // file. See https://github.com/prettier/prettier/issues/4624. + // prettier-ignore + const usedAddresses = ([ + owner, + makerAddressLeft, + makerAddressRight, + takerAddress, + feeRecipientAddressLeft, + // tslint:disable-next-line:trailing-comma + feeRecipientAddressRight + ] = _.slice(accounts, 0, 6)); + // Create wrappers + erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner); + // Deploy ERC20 token & ERC20 proxy + const numDummyErc20ToDeploy = 3; + [erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync( + numDummyErc20ToDeploy, + constants.DUMMY_TOKEN_DECIMALS, + ); + erc20Proxy = await erc20Wrapper.deployProxyAsync(); + await erc20Wrapper.setBalancesAndAllowancesAsync(); + // Deploy ERC721 proxy + erc721Proxy = await ERC721ProxyContract.deployFrom0xArtifactAsync( + protocolArtifacts.ERC721Proxy, + provider, + txDefaults, + ); + // Depoy exchange + exchange = await ExchangeContract.deployFrom0xArtifactAsync( + protocolArtifacts.Exchange, + provider, + txDefaults, + assetDataUtils.encodeERC20AssetData(zrxToken.address), + ); + exchangeWrapper = new ExchangeWrapper(exchange, provider); + await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner); + await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner); + // Authorize ERC20 trades by exchange + await web3Wrapper.awaitTransactionSuccessAsync( + await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { + from: owner, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + // Deploy OrderMatcher + orderMatcher = await OrderMatcherContract.deployFrom0xArtifactAsync( + artifacts.OrderMatcher, + provider, + txDefaults, + exchange.address, + ); + // Set default addresses + defaultERC20MakerAssetAddress = erc20TokenA.address; + defaultERC20TakerAssetAddress = erc20TokenB.address; + leftMakerAssetData = assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress); + leftTakerAssetData = assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress); + // Set OrderMatcher balances and allowances + await web3Wrapper.awaitTransactionSuccessAsync( + await erc20TokenA.setBalance.sendTransactionAsync(orderMatcher.address, constants.INITIAL_ERC20_BALANCE, { + from: owner, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await erc20TokenB.setBalance.sendTransactionAsync(orderMatcher.address, constants.INITIAL_ERC20_BALANCE, { + from: owner, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await orderMatcher.approveAssetProxy.sendTransactionAsync( + leftMakerAssetData, + constants.INITIAL_ERC20_ALLOWANCE, + ), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await orderMatcher.approveAssetProxy.sendTransactionAsync( + leftTakerAssetData, + constants.INITIAL_ERC20_ALLOWANCE, + ), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + // Create default order parameters + const defaultOrderParamsLeft = { + ...constants.STATIC_ORDER_PARAMS, + makerAddress: makerAddressLeft, + exchangeAddress: exchange.address, + makerAssetData: leftMakerAssetData, + takerAssetData: leftTakerAssetData, + feeRecipientAddress: feeRecipientAddressLeft, + makerFee: constants.ZERO_AMOUNT, + takerFee: constants.ZERO_AMOUNT, + }; + const defaultOrderParamsRight = { + ...constants.STATIC_ORDER_PARAMS, + makerAddress: makerAddressRight, + exchangeAddress: exchange.address, + makerAssetData: leftTakerAssetData, + takerAssetData: leftMakerAssetData, + feeRecipientAddress: feeRecipientAddressRight, + makerFee: constants.ZERO_AMOUNT, + takerFee: constants.ZERO_AMOUNT, + }; + const privateKeyLeft = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressLeft)]; + orderFactoryLeft = new OrderFactory(privateKeyLeft, defaultOrderParamsLeft); + const privateKeyRight = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressRight)]; + orderFactoryRight = new OrderFactory(privateKeyRight, defaultOrderParamsRight); + }); + beforeEach(async () => { + await blockchainLifecycle.startAsync(); + }); + afterEach(async () => { + await blockchainLifecycle.revertAsync(); + }); + describe('constructor', () => { + it('should revert if assetProxy is unregistered', async () => { + const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync( + protocolArtifacts.Exchange, + provider, + txDefaults, + constants.NULL_BYTES, + ); + return expectContractCreationFailedAsync( + (OrderMatcherContract.deployFrom0xArtifactAsync( + artifacts.OrderMatcher, + provider, + txDefaults, + exchangeInstance.address, + ) as any) as sendTransactionResult, + RevertReason.UnregisteredAssetProxy, + ); + }); + }); + describe('matchOrders', () => { + beforeEach(async () => { + erc20BalancesByOwner = await erc20Wrapper.getBalancesAsync(); + }); + it('should revert if not called by owner', async () => { + // Create orders to match + const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + }); + const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), + }); + const data = exchange.matchOrders.getABIEncodedTransactionData( + signedOrderLeft, + signedOrderRight, + signedOrderLeft.signature, + signedOrderRight.signature, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + data, + to: orderMatcher.address, + from: takerAddress, + gas: constants.MAX_MATCH_ORDERS_GAS, + }), + RevertReason.OnlyContractOwner, + ); + }); + it('should transfer the correct amounts when orders completely fill each other', async () => { + // Create orders to match + const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + }); + const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), + }); + // Match signedOrderLeft with signedOrderRight + const expectedTransferAmounts = { + // Left Maker + amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount, + amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount, + // Right Maker + amountSoldByRightMaker: signedOrderRight.makerAssetAmount, + amountBoughtByRightMaker: signedOrderRight.takerAssetAmount, + // Taker + leftMakerAssetSpreadAmount: signedOrderLeft.makerAssetAmount.minus(signedOrderRight.takerAssetAmount), + }; + const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address); + const data = exchange.matchOrders.getABIEncodedTransactionData( + signedOrderLeft, + signedOrderRight, + signedOrderLeft.signature, + signedOrderRight.signature, + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await web3Wrapper.sendTransactionAsync({ + data, + to: orderMatcher.address, + from: owner, + gas: constants.MAX_MATCH_ORDERS_GAS, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address); + const newErc20Balances = await erc20Wrapper.getBalancesAsync(); + expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal( + erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus( + expectedTransferAmounts.amountSoldByLeftMaker, + ), + ); + expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal( + erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus( + expectedTransferAmounts.amountSoldByRightMaker, + ), + ); + expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal( + erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus( + expectedTransferAmounts.amountBoughtByLeftMaker, + ), + ); + expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal( + erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus( + expectedTransferAmounts.amountBoughtByRightMaker, + ), + ); + expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal( + initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount), + ); + }); + it('should transfer the correct amounts when orders completely fill each other and taker doesnt take a profit', async () => { + // Create orders to match + const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + }); + const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), + }); + // Match signedOrderLeft with signedOrderRight + const expectedTransferAmounts = { + // Left Maker + amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount, + amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount, + // Right Maker + amountSoldByRightMaker: signedOrderRight.makerAssetAmount, + amountBoughtByRightMaker: signedOrderRight.takerAssetAmount, + }; + const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address); + const data = exchange.matchOrders.getABIEncodedTransactionData( + signedOrderLeft, + signedOrderRight, + signedOrderLeft.signature, + signedOrderRight.signature, + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await web3Wrapper.sendTransactionAsync({ + data, + to: orderMatcher.address, + from: owner, + gas: constants.MAX_MATCH_ORDERS_GAS, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address); + const newErc20Balances = await erc20Wrapper.getBalancesAsync(); + expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal( + erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus( + expectedTransferAmounts.amountSoldByLeftMaker, + ), + ); + expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal( + erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus( + expectedTransferAmounts.amountSoldByRightMaker, + ), + ); + expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal( + erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus( + expectedTransferAmounts.amountBoughtByLeftMaker, + ), + ); + expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal( + erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus( + expectedTransferAmounts.amountBoughtByRightMaker, + ), + ); + expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(initialLeftMakerAssetTakerBalance); + }); + it('should transfer the correct amounts when left order is completely filled and right order would be partially filled', async () => { + // Create orders to match + const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + }); + const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18), + }); + // Match signedOrderLeft with signedOrderRight + const expectedTransferAmounts = { + // Left Maker + amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount, + amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount, + // Right Maker + amountSoldByRightMaker: signedOrderRight.makerAssetAmount, + amountBoughtByRightMaker: signedOrderRight.takerAssetAmount, + // Taker + leftMakerAssetSpreadAmount: signedOrderLeft.makerAssetAmount.minus(signedOrderRight.takerAssetAmount), + leftTakerAssetSpreadAmount: signedOrderRight.makerAssetAmount.minus(signedOrderLeft.takerAssetAmount), + }; + const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address); + const initialLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address); + // Match signedOrderLeft with signedOrderRight + const data = exchange.matchOrders.getABIEncodedTransactionData( + signedOrderLeft, + signedOrderRight, + signedOrderLeft.signature, + signedOrderRight.signature, + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await web3Wrapper.sendTransactionAsync({ + data, + to: orderMatcher.address, + from: owner, + gas: constants.MAX_MATCH_ORDERS_GAS, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address); + const newLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address); + const newErc20Balances = await erc20Wrapper.getBalancesAsync(); + expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal( + erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus( + expectedTransferAmounts.amountSoldByLeftMaker, + ), + ); + expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal( + erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus( + expectedTransferAmounts.amountSoldByRightMaker, + ), + ); + expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal( + erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus( + expectedTransferAmounts.amountBoughtByLeftMaker, + ), + ); + expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal( + erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus( + expectedTransferAmounts.amountBoughtByRightMaker, + ), + ); + expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal( + initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount), + ); + expect(newLeftTakerAssetTakerBalance).to.be.bignumber.equal( + initialLeftTakerAssetTakerBalance.plus(expectedTransferAmounts.leftTakerAssetSpreadAmount), + ); + }); + it('should not call fillOrder when rightOrder is completely filled after matchOrders call and orders were never partially filled', async () => { + // Create orders to match + const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + }); + const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), + }); + const data = exchange.matchOrders.getABIEncodedTransactionData( + signedOrderLeft, + signedOrderRight, + signedOrderLeft.signature, + signedOrderRight.signature, + ); + const logDecoder = new LogDecoder(web3Wrapper, { ...artifacts, ...tokenArtifacts, ...protocolArtifacts }); + const txReceipt = await logDecoder.getTxWithDecodedLogsAsync( + await web3Wrapper.sendTransactionAsync({ + data, + to: orderMatcher.address, + from: owner, + gas: constants.MAX_MATCH_ORDERS_GAS, + }), + ); + const fillLogs = _.filter( + txReceipt.logs, + log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill', + ); + // Only 2 Fill logs should exist for `matchOrders` call. `fillOrder` should not have been called and should not have emitted a Fill event. + expect(fillLogs.length).to.be.equal(2); + }); + it('should not call fillOrder when rightOrder is completely filled after matchOrders call and orders were initially partially filled', async () => { + // Create orders to match + const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + }); + const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), + }); + await exchangeWrapper.fillOrderAsync(signedOrderLeft, takerAddress, { + takerAssetFillAmount: signedOrderLeft.takerAssetAmount.dividedToIntegerBy(5), + }); + await exchangeWrapper.fillOrderAsync(signedOrderRight, takerAddress, { + takerAssetFillAmount: signedOrderRight.takerAssetAmount.dividedToIntegerBy(5), + }); + const data = exchange.matchOrders.getABIEncodedTransactionData( + signedOrderLeft, + signedOrderRight, + signedOrderLeft.signature, + signedOrderRight.signature, + ); + const logDecoder = new LogDecoder(web3Wrapper, { ...artifacts, ...tokenArtifacts, ...protocolArtifacts }); + const txReceipt = await logDecoder.getTxWithDecodedLogsAsync( + await web3Wrapper.sendTransactionAsync({ + data, + to: orderMatcher.address, + from: owner, + gas: constants.MAX_MATCH_ORDERS_GAS, + }), + ); + const fillLogs = _.filter( + txReceipt.logs, + log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill', + ); + // Only 2 Fill logs should exist for `matchOrders` call. `fillOrder` should not have been called and should not have emitted a Fill event. + expect(fillLogs.length).to.be.equal(2); + }); + it('should only take a spread in rightMakerAsset if entire leftMakerAssetSpread amount can be used to fill rightOrder after matchOrders call', async () => { + // Create orders to match + const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(0.9), 18), + }); + const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(990), 18), + }); + const initialLeftMakerAssetSpreadAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1.09), 18); + const leftTakerAssetSpreadAmount = initialLeftMakerAssetSpreadAmount + .times(signedOrderRight.makerAssetAmount) + .dividedToIntegerBy(signedOrderRight.takerAssetAmount); + // Match signedOrderLeft with signedOrderRight + const expectedTransferAmounts = { + // Left Maker + amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount, + amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount, + // Right Maker + amountSoldByRightMaker: signedOrderLeft.takerAssetAmount.plus(leftTakerAssetSpreadAmount), + amountBoughtByRightMaker: signedOrderLeft.makerAssetAmount, + // Taker + leftMakerAssetSpreadAmount: constants.ZERO_AMOUNT, + leftTakerAssetSpreadAmount, + }; + const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address); + const initialLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address); + // Match signedOrderLeft with signedOrderRight + const data = exchange.matchOrders.getABIEncodedTransactionData( + signedOrderLeft, + signedOrderRight, + signedOrderLeft.signature, + signedOrderRight.signature, + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await web3Wrapper.sendTransactionAsync({ + data, + to: orderMatcher.address, + from: owner, + gas: constants.MAX_MATCH_ORDERS_GAS, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address); + const newLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address); + const newErc20Balances = await erc20Wrapper.getBalancesAsync(); + expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal( + erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus( + expectedTransferAmounts.amountSoldByLeftMaker, + ), + ); + expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal( + erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus( + expectedTransferAmounts.amountSoldByRightMaker, + ), + ); + expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal( + erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus( + expectedTransferAmounts.amountBoughtByLeftMaker, + ), + ); + expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal( + erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus( + expectedTransferAmounts.amountBoughtByRightMaker, + ), + ); + expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal( + initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount), + ); + expect(newLeftTakerAssetTakerBalance).to.be.bignumber.equal( + initialLeftTakerAssetTakerBalance.plus(expectedTransferAmounts.leftTakerAssetSpreadAmount), + ); + }); + it("should succeed if rightOrder's makerAssetData and takerAssetData are not provided", async () => { + // Create orders to match + const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + }); + const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18), + }); + // Match signedOrderLeft with signedOrderRight + const expectedTransferAmounts = { + // Left Maker + amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount, + amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount, + // Right Maker + amountSoldByRightMaker: signedOrderRight.makerAssetAmount, + amountBoughtByRightMaker: signedOrderRight.takerAssetAmount, + // Taker + leftMakerAssetSpreadAmount: signedOrderLeft.makerAssetAmount.minus(signedOrderRight.takerAssetAmount), + leftTakerAssetSpreadAmount: signedOrderRight.makerAssetAmount.minus(signedOrderLeft.takerAssetAmount), + }; + const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address); + const initialLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address); + // Match signedOrderLeft with signedOrderRight + signedOrderRight.makerAssetData = constants.NULL_BYTES; + signedOrderRight.takerAssetData = constants.NULL_BYTES; + const data = exchange.matchOrders.getABIEncodedTransactionData( + signedOrderLeft, + signedOrderRight, + signedOrderLeft.signature, + signedOrderRight.signature, + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await web3Wrapper.sendTransactionAsync({ + data, + to: orderMatcher.address, + from: owner, + gas: constants.MAX_MATCH_ORDERS_GAS, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address); + const newLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address); + const newErc20Balances = await erc20Wrapper.getBalancesAsync(); + expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal( + erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus( + expectedTransferAmounts.amountSoldByLeftMaker, + ), + ); + expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal( + erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus( + expectedTransferAmounts.amountSoldByRightMaker, + ), + ); + expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal( + erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus( + expectedTransferAmounts.amountBoughtByLeftMaker, + ), + ); + expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal( + erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus( + expectedTransferAmounts.amountBoughtByRightMaker, + ), + ); + expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal( + initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount), + ); + expect(newLeftTakerAssetTakerBalance).to.be.bignumber.equal( + initialLeftTakerAssetTakerBalance.plus(expectedTransferAmounts.leftTakerAssetSpreadAmount), + ); + }); + it('should revert with the correct reason if matchOrders call reverts', async () => { + // Create orders to match + const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + }); + const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), + }); + signedOrderRight.signature = `0xff${signedOrderRight.signature.slice(4)}`; + const data = exchange.matchOrders.getABIEncodedTransactionData( + signedOrderLeft, + signedOrderRight, + signedOrderLeft.signature, + signedOrderRight.signature, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + data, + to: orderMatcher.address, + from: owner, + gas: constants.MAX_MATCH_ORDERS_GAS, + }), + RevertReason.InvalidOrderSignature, + ); + }); + it('should revert with the correct reason if fillOrder call reverts', async () => { + // Create orders to match + const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + }); + const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18), + }); + // Matcher will not have enough allowance to fill rightOrder + await web3Wrapper.awaitTransactionSuccessAsync( + await orderMatcher.approveAssetProxy.sendTransactionAsync(leftMakerAssetData, constants.ZERO_AMOUNT, { + from: owner, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + const data = exchange.matchOrders.getABIEncodedTransactionData( + signedOrderLeft, + signedOrderRight, + signedOrderLeft.signature, + signedOrderRight.signature, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + data, + to: orderMatcher.address, + from: owner, + gas: constants.MAX_MATCH_ORDERS_GAS, + }), + RevertReason.TransferFailed, + ); + }); + }); + describe('withdrawAsset', () => { + it('should allow owner to withdraw ERC20 tokens', async () => { + const erc20AWithdrawAmount = await erc20TokenA.balanceOf.callAsync(orderMatcher.address); + expect(erc20AWithdrawAmount).to.be.bignumber.gt(constants.ZERO_AMOUNT); + await web3Wrapper.awaitTransactionSuccessAsync( + await orderMatcher.withdrawAsset.sendTransactionAsync(leftMakerAssetData, erc20AWithdrawAmount, { + from: owner, + }), + ); + const newBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address); + expect(newBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); + }); + it('should allow owner to withdraw ERC721 tokens', async () => { + const erc721Token = await DummyERC721TokenContract.deployFrom0xArtifactAsync( + tokenArtifacts.DummyERC721Token, + provider, + txDefaults, + constants.DUMMY_TOKEN_NAME, + constants.DUMMY_TOKEN_SYMBOL, + ); + const tokenId = new BigNumber(1); + await web3Wrapper.awaitTransactionSuccessAsync( + await erc721Token.mint.sendTransactionAsync(orderMatcher.address, tokenId, { from: owner }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + const assetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, tokenId); + const withdrawAmount = new BigNumber(1); + await web3Wrapper.awaitTransactionSuccessAsync( + await orderMatcher.withdrawAsset.sendTransactionAsync(assetData, withdrawAmount, { from: owner }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + const erc721Owner = await erc721Token.ownerOf.callAsync(tokenId); + expect(erc721Owner).to.be.equal(owner); + }); + it('should revert if not called by owner', async () => { + const erc20AWithdrawAmount = await erc20TokenA.balanceOf.callAsync(orderMatcher.address); + expect(erc20AWithdrawAmount).to.be.bignumber.gt(constants.ZERO_AMOUNT); + await expectTransactionFailedAsync( + orderMatcher.withdrawAsset.sendTransactionAsync(leftMakerAssetData, erc20AWithdrawAmount, { + from: takerAddress, + }), + RevertReason.OnlyContractOwner, + ); + }); + }); + describe('approveAssetProxy', () => { + it('should be able to set an allowance for ERC20 tokens', async () => { + const allowance = new BigNumber(55465465426546); + await web3Wrapper.awaitTransactionSuccessAsync( + await orderMatcher.approveAssetProxy.sendTransactionAsync(leftMakerAssetData, allowance, { + from: owner, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + const newAllowance = await erc20TokenA.allowance.callAsync(orderMatcher.address, erc20Proxy.address); + expect(newAllowance).to.be.bignumber.equal(allowance); + }); + it('should be able to approve an ERC721 token by passing in allowance = 1', async () => { + const erc721Token = await DummyERC721TokenContract.deployFrom0xArtifactAsync( + tokenArtifacts.DummyERC721Token, + provider, + txDefaults, + constants.DUMMY_TOKEN_NAME, + constants.DUMMY_TOKEN_SYMBOL, + ); + const assetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, constants.ZERO_AMOUNT); + const allowance = new BigNumber(1); + await web3Wrapper.awaitTransactionSuccessAsync( + await orderMatcher.approveAssetProxy.sendTransactionAsync(assetData, allowance, { from: owner }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + const isApproved = await erc721Token.isApprovedForAll.callAsync(orderMatcher.address, erc721Proxy.address); + expect(isApproved).to.be.equal(true); + }); + it('should be able to approve an ERC721 token by passing in allowance > 1', async () => { + const erc721Token = await DummyERC721TokenContract.deployFrom0xArtifactAsync( + tokenArtifacts.DummyERC721Token, + provider, + txDefaults, + constants.DUMMY_TOKEN_NAME, + constants.DUMMY_TOKEN_SYMBOL, + ); + const assetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, constants.ZERO_AMOUNT); + const allowance = new BigNumber(2); + await web3Wrapper.awaitTransactionSuccessAsync( + await orderMatcher.approveAssetProxy.sendTransactionAsync(assetData, allowance, { from: owner }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + const isApproved = await erc721Token.isApprovedForAll.callAsync(orderMatcher.address, erc721Proxy.address); + expect(isApproved).to.be.equal(true); + }); + it('should revert if not called by owner', async () => { + const approval = new BigNumber(1); + await expectTransactionFailedAsync( + orderMatcher.approveAssetProxy.sendTransactionAsync(leftMakerAssetData, approval, { + from: takerAddress, + }), + RevertReason.OnlyContractOwner, + ); + }); + }); +}); +// tslint:disable:max-file-line-count +// tslint:enable:no-unnecessary-type-assertion diff --git a/contracts/protocol/test/exchange/order_validator.ts b/contracts/extensions/test/extensions/order_validator.ts index 8f53426db..82a6b937f 100644 --- a/contracts/protocol/test/exchange/order_validator.ts +++ b/contracts/extensions/test/extensions/order_validator.ts @@ -1,4 +1,13 @@ import { + artifacts as protocolArtifacts, + ERC20ProxyContract, + ERC20Wrapper, + ERC721ProxyContract, + ERC721Wrapper, + ExchangeContract, + ExchangeWrapper, +} from '@0x/contracts-protocol'; +import { chaiSetup, constants, OrderFactory, @@ -15,16 +24,8 @@ import { BigNumber } from '@0x/utils'; import * as chai from 'chai'; import * as _ from 'lodash'; -import { - artifacts, - ERC20ProxyContract, - ERC20Wrapper, - ERC721ProxyContract, - ERC721Wrapper, - ExchangeContract, - ExchangeWrapper, - OrderValidatorContract, -} from '../../src'; +import { OrderValidatorContract } from '../../generated-wrappers/order_validator'; +import { artifacts } from '../../src/artifacts/index'; chaiSetup.configure(); const expect = chai.expect; @@ -80,7 +81,7 @@ describe('OrderValidator', () => { const zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address); exchange = await ExchangeContract.deployFrom0xArtifactAsync( - artifacts.Exchange, + protocolArtifacts.Exchange, provider, txDefaults, zrxAssetData, diff --git a/contracts/extensions/test/utils/balance_threshold_wrapper.ts b/contracts/extensions/test/utils/balance_threshold_wrapper.ts new file mode 100644 index 000000000..28a4ef011 --- /dev/null +++ b/contracts/extensions/test/utils/balance_threshold_wrapper.ts @@ -0,0 +1,283 @@ +import { artifacts as protocolArtifacts, ExchangeContract } from '@0x/contracts-protocol'; +import { + FillResults, + formatters, + LogDecoder, + OrderInfo, + orderUtils, + TransactionFactory, +} from '@0x/contracts-test-utils'; +import { artifacts as tokensArtifacts } from '@0x/contracts-tokens'; +import { SignedOrder } from '@0x/types'; +import { BigNumber } from '@0x/utils'; +import { Web3Wrapper } from '@0x/web3-wrapper'; +import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; +import * as _ from 'lodash'; + +import { BalanceThresholdFilterContract } from '../../generated-wrappers/balance_threshold_filter'; +import { artifacts } from '../../src/artifacts'; + +export class BalanceThresholdWrapper { + private readonly _balanceThresholdFilter: BalanceThresholdFilterContract; + private readonly _signerTransactionFactory: TransactionFactory; + private readonly _exchange: ExchangeContract; + private readonly _web3Wrapper: Web3Wrapper; + private readonly _logDecoder: LogDecoder; + constructor( + balanceThresholdFilter: BalanceThresholdFilterContract, + exchangeContract: ExchangeContract, + signerTransactionFactory: TransactionFactory, + provider: Provider, + ) { + this._balanceThresholdFilter = balanceThresholdFilter; + this._exchange = exchangeContract; + this._signerTransactionFactory = signerTransactionFactory; + this._web3Wrapper = new Web3Wrapper(provider); + this._logDecoder = new LogDecoder(this._web3Wrapper, { + ...artifacts, + ...tokensArtifacts, + ...protocolArtifacts, + }); + } + public async fillOrderAsync( + signedOrder: SignedOrder, + from: string, + opts: { takerAssetFillAmount?: BigNumber } = {}, + ): Promise<TransactionReceiptWithDecodedLogs> { + const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); + const data = this._exchange.fillOrder.getABIEncodedTransactionData( + params.order, + params.takerAssetFillAmount, + params.signature, + ); + const txReceipt = this._executeTransactionAsync(data, from); + return txReceipt; + } + public async fillOrKillOrderAsync( + signedOrder: SignedOrder, + from: string, + opts: { takerAssetFillAmount?: BigNumber } = {}, + ): Promise<TransactionReceiptWithDecodedLogs> { + const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); + const data = this._exchange.fillOrKillOrder.getABIEncodedTransactionData( + params.order, + params.takerAssetFillAmount, + params.signature, + ); + const txReceipt = this._executeTransactionAsync(data, from); + return txReceipt; + } + public async fillOrderNoThrowAsync( + signedOrder: SignedOrder, + from: string, + opts: { takerAssetFillAmount?: BigNumber; gas?: number } = {}, + ): Promise<TransactionReceiptWithDecodedLogs> { + const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); + const data = this._exchange.fillOrderNoThrow.getABIEncodedTransactionData( + params.order, + params.takerAssetFillAmount, + params.signature, + ); + const txReceipt = this._executeTransactionAsync(data, from, opts.gas); + return txReceipt; + } + public async batchFillOrdersAsync( + orders: SignedOrder[], + from: string, + opts: { takerAssetFillAmounts?: BigNumber[] } = {}, + ): Promise<TransactionReceiptWithDecodedLogs> { + const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts); + const data = this._exchange.batchFillOrders.getABIEncodedTransactionData( + params.orders, + params.takerAssetFillAmounts, + params.signatures, + ); + const txReceipt = this._executeTransactionAsync(data, from); + return txReceipt; + } + public async batchFillOrKillOrdersAsync( + orders: SignedOrder[], + from: string, + opts: { takerAssetFillAmounts?: BigNumber[] } = {}, + ): Promise<TransactionReceiptWithDecodedLogs> { + const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts); + const data = this._exchange.batchFillOrKillOrders.getABIEncodedTransactionData( + params.orders, + params.takerAssetFillAmounts, + params.signatures, + ); + const txReceipt = this._executeTransactionAsync(data, from); + return txReceipt; + } + public async batchFillOrdersNoThrowAsync( + orders: SignedOrder[], + from: string, + opts: { takerAssetFillAmounts?: BigNumber[]; gas?: number } = {}, + ): Promise<TransactionReceiptWithDecodedLogs> { + const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts); + const data = this._exchange.batchFillOrKillOrders.getABIEncodedTransactionData( + params.orders, + params.takerAssetFillAmounts, + params.signatures, + ); + const txReceipt = this._executeTransactionAsync(data, from, opts.gas); + return txReceipt; + } + public async marketSellOrdersAsync( + orders: SignedOrder[], + from: string, + opts: { takerAssetFillAmount: BigNumber }, + ): Promise<TransactionReceiptWithDecodedLogs> { + const params = formatters.createMarketSellOrders(orders, opts.takerAssetFillAmount); + const data = this._exchange.marketSellOrders.getABIEncodedTransactionData( + params.orders, + params.takerAssetFillAmount, + params.signatures, + ); + const txReceipt = this._executeTransactionAsync(data, from); + return txReceipt; + } + public async marketSellOrdersNoThrowAsync( + orders: SignedOrder[], + from: string, + opts: { takerAssetFillAmount: BigNumber; gas?: number }, + ): Promise<TransactionReceiptWithDecodedLogs> { + const params = formatters.createMarketSellOrders(orders, opts.takerAssetFillAmount); + const data = this._exchange.marketSellOrdersNoThrow.getABIEncodedTransactionData( + params.orders, + params.takerAssetFillAmount, + params.signatures, + ); + const txReceipt = this._executeTransactionAsync(data, from, opts.gas); + return txReceipt; + } + public async marketBuyOrdersAsync( + orders: SignedOrder[], + from: string, + opts: { makerAssetFillAmount: BigNumber }, + ): Promise<TransactionReceiptWithDecodedLogs> { + const params = formatters.createMarketBuyOrders(orders, opts.makerAssetFillAmount); + const data = this._exchange.marketBuyOrders.getABIEncodedTransactionData( + params.orders, + params.makerAssetFillAmount, + params.signatures, + ); + const txReceipt = this._executeTransactionAsync(data, from); + return txReceipt; + } + public async marketBuyOrdersNoThrowAsync( + orders: SignedOrder[], + from: string, + opts: { makerAssetFillAmount: BigNumber; gas?: number }, + ): Promise<TransactionReceiptWithDecodedLogs> { + const params = formatters.createMarketBuyOrders(orders, opts.makerAssetFillAmount); + const data = this._exchange.marketBuyOrdersNoThrow.getABIEncodedTransactionData( + params.orders, + params.makerAssetFillAmount, + params.signatures, + ); + const txReceipt = this._executeTransactionAsync(data, from, opts.gas); + return txReceipt; + } + public async cancelOrderAsync(signedOrder: SignedOrder, from: string): Promise<TransactionReceiptWithDecodedLogs> { + const params = orderUtils.createCancel(signedOrder); + const data = this._exchange.cancelOrder.getABIEncodedTransactionData(params.order); + const txReceipt = this._executeTransactionAsync(data, from); + return txReceipt; + } + public async batchCancelOrdersAsync( + orders: SignedOrder[], + from: string, + ): Promise<TransactionReceiptWithDecodedLogs> { + const params = formatters.createBatchCancel(orders); + const data = this._exchange.batchCancelOrders.getABIEncodedTransactionData(params.orders); + const txReceipt = this._executeTransactionAsync(data, from); + return txReceipt; + } + public async cancelOrdersUpToAsync(salt: BigNumber, from: string): Promise<TransactionReceiptWithDecodedLogs> { + const data = this._exchange.cancelOrdersUpTo.getABIEncodedTransactionData(salt); + const txReceipt = this._executeTransactionAsync(data, from); + return txReceipt; + } + public async getTakerAssetFilledAmountAsync(orderHashHex: string): Promise<BigNumber> { + const filledAmount = await this._exchange.filled.callAsync(orderHashHex); + return filledAmount; + } + public async isCancelledAsync(orderHashHex: string): Promise<boolean> { + const isCancelled = await this._exchange.cancelled.callAsync(orderHashHex); + return isCancelled; + } + public async getOrderEpochAsync(makerAddress: string, senderAddress: string): Promise<BigNumber> { + const orderEpoch = await this._exchange.orderEpoch.callAsync(makerAddress, senderAddress); + return orderEpoch; + } + public async getOrderInfoAsync(signedOrder: SignedOrder): Promise<OrderInfo> { + const orderInfo = await this._exchange.getOrderInfo.callAsync(signedOrder); + return orderInfo; + } + public async getOrdersInfoAsync(signedOrders: SignedOrder[]): Promise<OrderInfo[]> { + const ordersInfo = (await this._exchange.getOrdersInfo.callAsync(signedOrders)) as OrderInfo[]; + return ordersInfo; + } + public async matchOrdersAsync( + signedOrderLeft: SignedOrder, + signedOrderRight: SignedOrder, + from: string, + ): Promise<TransactionReceiptWithDecodedLogs> { + const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight); + const data = await this._exchange.matchOrders.getABIEncodedTransactionData( + params.left, + params.right, + params.leftSignature, + params.rightSignature, + ); + const txReceipt = this._executeTransactionAsync(data, from); + return txReceipt; + } + public async getFillOrderResultsAsync( + signedOrder: SignedOrder, + from: string, + opts: { takerAssetFillAmount?: BigNumber } = {}, + ): Promise<FillResults> { + const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); + const fillResults = await this._exchange.fillOrder.callAsync( + params.order, + params.takerAssetFillAmount, + params.signature, + { from }, + ); + return fillResults; + } + public abiEncodeFillOrder(signedOrder: SignedOrder, opts: { takerAssetFillAmount?: BigNumber } = {}): string { + const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); + const data = this._exchange.fillOrder.getABIEncodedTransactionData( + params.order, + params.takerAssetFillAmount, + params.signature, + ); + return data; + } + public getBalanceThresholdAddress(): string { + return this._balanceThresholdFilter.address; + } + public getExchangeAddress(): string { + return this._exchange.address; + } + private async _executeTransactionAsync( + abiEncodedExchangeTxData: string, + from: string, + gas?: number, + ): Promise<TransactionReceiptWithDecodedLogs> { + const signedExchangeTx = this._signerTransactionFactory.newSignedTransaction(abiEncodedExchangeTxData); + const txOpts = _.isUndefined(gas) ? { from } : { from, gas }; + const txHash = await this._balanceThresholdFilter.executeTransaction.sendTransactionAsync( + signedExchangeTx.salt, + signedExchangeTx.signerAddress, + signedExchangeTx.data, + signedExchangeTx.signature, + txOpts, + ); + const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); + return txReceipt; + } +} diff --git a/contracts/extensions/tsconfig.json b/contracts/extensions/tsconfig.json index a4ce1e002..ed9b4fbe1 100644 --- a/contracts/extensions/tsconfig.json +++ b/contracts/extensions/tsconfig.json @@ -6,6 +6,12 @@ "resolveJsonModule": true }, "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], - "files": ["./generated-artifacts/DutchAuction.json", "./generated-artifacts/Forwarder.json"], + "files": [ + "./generated-artifacts/BalanceThresholdFilter.json", + "./generated-artifacts/DutchAuction.json", + "./generated-artifacts/Forwarder.json", + "./generated-artifacts/OrderMatcher.json", + "./generated-artifacts/OrderValidator.json" + ], "exclude": ["./deploy/solc/solc_bin"] } diff --git a/contracts/interfaces/contracts/protocol/AssetProxy/IAssetData.sol b/contracts/interfaces/contracts/protocol/AssetProxy/IAssetData.sol index e2da68919..a130e615f 100644 --- a/contracts/interfaces/contracts/protocol/AssetProxy/IAssetData.sol +++ b/contracts/interfaces/contracts/protocol/AssetProxy/IAssetData.sol @@ -17,7 +17,7 @@ */ // solhint-disable -pragma solidity 0.4.24; +pragma solidity ^0.4.24; pragma experimental ABIEncoderV2; diff --git a/contracts/interfaces/contracts/protocol/AssetProxy/IAssetProxy.sol b/contracts/interfaces/contracts/protocol/AssetProxy/IAssetProxy.sol index b25d2d75a..706412dd0 100644 --- a/contracts/interfaces/contracts/protocol/AssetProxy/IAssetProxy.sol +++ b/contracts/interfaces/contracts/protocol/AssetProxy/IAssetProxy.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; import "./IAuthorizable.sol"; diff --git a/contracts/interfaces/contracts/protocol/AssetProxy/IAuthorizable.sol b/contracts/interfaces/contracts/protocol/AssetProxy/IAuthorizable.sol index 96ee05dee..202173998 100644 --- a/contracts/interfaces/contracts/protocol/AssetProxy/IAuthorizable.sol +++ b/contracts/interfaces/contracts/protocol/AssetProxy/IAuthorizable.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; import "@0x/contracts-utils/contracts/utils/Ownable/IOwnable.sol"; diff --git a/contracts/interfaces/contracts/protocol/Exchange/IAssetProxyDispatcher.sol b/contracts/interfaces/contracts/protocol/Exchange/IAssetProxyDispatcher.sol index 8db8d6f6c..b73881c07 100644 --- a/contracts/interfaces/contracts/protocol/Exchange/IAssetProxyDispatcher.sol +++ b/contracts/interfaces/contracts/protocol/Exchange/IAssetProxyDispatcher.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; contract IAssetProxyDispatcher { diff --git a/contracts/interfaces/contracts/protocol/Exchange/IExchange.sol b/contracts/interfaces/contracts/protocol/Exchange/IExchange.sol index b92abba04..866e4c194 100644 --- a/contracts/interfaces/contracts/protocol/Exchange/IExchange.sol +++ b/contracts/interfaces/contracts/protocol/Exchange/IExchange.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; pragma experimental ABIEncoderV2; import "./IExchangeCore.sol"; diff --git a/contracts/interfaces/contracts/protocol/Exchange/IExchangeCore.sol b/contracts/interfaces/contracts/protocol/Exchange/IExchangeCore.sol index 0da73529c..ab4a62408 100644 --- a/contracts/interfaces/contracts/protocol/Exchange/IExchangeCore.sol +++ b/contracts/interfaces/contracts/protocol/Exchange/IExchangeCore.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; pragma experimental ABIEncoderV2; import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; diff --git a/contracts/interfaces/contracts/protocol/Exchange/IMatchOrders.sol b/contracts/interfaces/contracts/protocol/Exchange/IMatchOrders.sol index b88e158c3..5df46ea80 100644 --- a/contracts/interfaces/contracts/protocol/Exchange/IMatchOrders.sol +++ b/contracts/interfaces/contracts/protocol/Exchange/IMatchOrders.sol @@ -15,7 +15,7 @@ limitations under the License. */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; pragma experimental ABIEncoderV2; import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; diff --git a/contracts/interfaces/contracts/protocol/Exchange/ISignatureValidator.sol b/contracts/interfaces/contracts/protocol/Exchange/ISignatureValidator.sol index 1fd0eccf0..c5a4a57e1 100644 --- a/contracts/interfaces/contracts/protocol/Exchange/ISignatureValidator.sol +++ b/contracts/interfaces/contracts/protocol/Exchange/ISignatureValidator.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; contract ISignatureValidator { diff --git a/contracts/interfaces/contracts/protocol/Exchange/ITransactions.sol b/contracts/interfaces/contracts/protocol/Exchange/ITransactions.sol index 4446c55ce..aaaee389f 100644 --- a/contracts/interfaces/contracts/protocol/Exchange/ITransactions.sol +++ b/contracts/interfaces/contracts/protocol/Exchange/ITransactions.sol @@ -15,7 +15,7 @@ limitations under the License. */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; contract ITransactions { diff --git a/contracts/interfaces/contracts/protocol/Exchange/IValidator.sol b/contracts/interfaces/contracts/protocol/Exchange/IValidator.sol index 2dd69100c..d214e54dd 100644 --- a/contracts/interfaces/contracts/protocol/Exchange/IValidator.sol +++ b/contracts/interfaces/contracts/protocol/Exchange/IValidator.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; contract IValidator { diff --git a/contracts/interfaces/contracts/protocol/Exchange/IWallet.sol b/contracts/interfaces/contracts/protocol/Exchange/IWallet.sol index c97161ca6..c2db4a5b1 100644 --- a/contracts/interfaces/contracts/protocol/Exchange/IWallet.sol +++ b/contracts/interfaces/contracts/protocol/Exchange/IWallet.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; contract IWallet { diff --git a/contracts/interfaces/contracts/protocol/Exchange/IWrapperFunctions.sol b/contracts/interfaces/contracts/protocol/Exchange/IWrapperFunctions.sol index 833bb7e88..0eeaa874b 100644 --- a/contracts/interfaces/contracts/protocol/Exchange/IWrapperFunctions.sol +++ b/contracts/interfaces/contracts/protocol/Exchange/IWrapperFunctions.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; pragma experimental ABIEncoderV2; import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; diff --git a/contracts/interfaces/package.json b/contracts/interfaces/package.json index 4d3e4b7f9..15385a154 100644 --- a/contracts/interfaces/package.json +++ b/contracts/interfaces/package.json @@ -10,7 +10,8 @@ "build": "yarn pre_build && tsc -b", "build:ci": "yarn build", "pre_build": "run-s compile generate_contract_wrappers", - "compile": "sol-compiler --contracts-dir contracts", + "compile": "sol-compiler", + "watch": "sol-compiler -w", "clean": "shx rm -rf lib generated-artifacts generated-wrappers", "generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers", "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", diff --git a/contracts/libs/compiler.json b/contracts/libs/compiler.json index cf7c52a73..349d3063b 100644 --- a/contracts/libs/compiler.json +++ b/contracts/libs/compiler.json @@ -18,5 +18,14 @@ } } }, - "contracts": ["TestLibs", "LibOrder", "LibMath", "LibFillResults", "LibAbiEncoder", "LibEIP712"] + "contracts": [ + "TestLibs", + "LibOrder", + "LibMath", + "LibFillResults", + "LibAbiEncoder", + "LibEIP712", + "LibAssetProxyErrors", + "LibConstants" + ] } diff --git a/contracts/libs/contracts/libs/LibAbiEncoder.sol b/contracts/libs/contracts/libs/LibAbiEncoder.sol index 4aad37709..5422bfeec 100644 --- a/contracts/libs/contracts/libs/LibAbiEncoder.sol +++ b/contracts/libs/contracts/libs/LibAbiEncoder.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; pragma experimental ABIEncoderV2; import "./LibOrder.sol"; diff --git a/contracts/libs/contracts/libs/LibAddressArray.sol b/contracts/libs/contracts/libs/LibAddressArray.sol new file mode 100644 index 000000000..997ce85fa --- /dev/null +++ b/contracts/libs/contracts/libs/LibAddressArray.sol @@ -0,0 +1,84 @@ +/* + + Copyright 2018 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.4.24; + +import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol"; + + +library LibAddressArray { + + /// @dev Append a new address to an array of addresses. + /// The `addressArray` may need to be reallocated to make space + /// for the new address. Because of this we return the resulting + /// memory location of `addressArray`. + /// @param addressToAppend Address to append. + /// @return Array of addresses: [... addressArray, addressToAppend] + function append(address[] memory addressArray, address addressToAppend) + internal pure + returns (address[]) + { + // Get stats on address array and free memory + uint256 freeMemPtr = 0; + uint256 addressArrayBeginPtr = 0; + uint256 addressArrayEndPtr = 0; + uint256 addressArrayLength = addressArray.length; + uint256 addressArrayMemSizeInBytes = 32 + (32 * addressArrayLength); + assembly { + freeMemPtr := mload(0x40) + addressArrayBeginPtr := addressArray + addressArrayEndPtr := add(addressArray, addressArrayMemSizeInBytes) + } + + // Cases for `freeMemPtr`: + // `freeMemPtr` == `addressArrayEndPtr`: Nothing occupies memory after `addressArray` + // `freeMemPtr` > `addressArrayEndPtr`: Some value occupies memory after `addressArray` + // `freeMemPtr` < `addressArrayEndPtr`: Memory has not been managed properly. + require( + freeMemPtr >= addressArrayEndPtr, + "INVALID_FREE_MEMORY_PTR" + ); + + // If free memory begins at the end of `addressArray` + // then we can append `addressToAppend` directly. + // Otherwise, we must copy the array to free memory + // before appending new values to it. + if (freeMemPtr > addressArrayEndPtr) { + LibBytes.memCopy(freeMemPtr, addressArrayBeginPtr, addressArrayMemSizeInBytes); + assembly { + addressArray := freeMemPtr + addressArrayBeginPtr := addressArray + } + } + + // Append `addressToAppend` + addressArrayLength += 1; + addressArrayMemSizeInBytes += 32; + addressArrayEndPtr = addressArrayBeginPtr + addressArrayMemSizeInBytes; + freeMemPtr = addressArrayEndPtr; + assembly { + // Store new array length + mstore(addressArray, addressArrayLength) + + // Update `freeMemPtr` + mstore(0x40, freeMemPtr) + } + addressArray[addressArrayLength - 1] = addressToAppend; + return addressArray; + } +} diff --git a/contracts/libs/contracts/libs/LibAssetProxyErrors.sol b/contracts/libs/contracts/libs/LibAssetProxyErrors.sol index 1d9a70cc1..96c48b5e3 100644 --- a/contracts/libs/contracts/libs/LibAssetProxyErrors.sol +++ b/contracts/libs/contracts/libs/LibAssetProxyErrors.sol @@ -17,7 +17,7 @@ */ // solhint-disable -pragma solidity 0.4.24; +pragma solidity ^0.4.24; /// @dev This contract documents the revert reasons used in the AssetProxy contracts. diff --git a/contracts/libs/contracts/libs/LibConstants.sol b/contracts/libs/contracts/libs/LibConstants.sol index 8d2732cd3..3efa3e1b3 100644 --- a/contracts/libs/contracts/libs/LibConstants.sol +++ b/contracts/libs/contracts/libs/LibConstants.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; // solhint-disable max-line-length diff --git a/contracts/libs/contracts/libs/LibEIP712.sol b/contracts/libs/contracts/libs/LibEIP712.sol index 203edc1fd..3a85ab3c0 100644 --- a/contracts/libs/contracts/libs/LibEIP712.sol +++ b/contracts/libs/contracts/libs/LibEIP712.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; contract LibEIP712 { diff --git a/contracts/libs/contracts/libs/LibExchangeErrors.sol b/contracts/libs/contracts/libs/LibExchangeErrors.sol index a0f75bc06..a160242c9 100644 --- a/contracts/libs/contracts/libs/LibExchangeErrors.sol +++ b/contracts/libs/contracts/libs/LibExchangeErrors.sol @@ -17,7 +17,7 @@ */ // solhint-disable -pragma solidity 0.4.24; +pragma solidity ^0.4.24; /// @dev This contract documents the revert reasons used in the Exchange contract. diff --git a/contracts/libs/contracts/libs/LibExchangeSelectors.sol b/contracts/libs/contracts/libs/LibExchangeSelectors.sol new file mode 100644 index 000000000..71640c609 --- /dev/null +++ b/contracts/libs/contracts/libs/LibExchangeSelectors.sol @@ -0,0 +1,152 @@ +/* + + Copyright 2018 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.4.24; + + +contract LibExchangeSelectors { + + // solhint-disable max-line-length + // allowedValidators + bytes4 constant public ALLOWED_VALIDATORS_SELECTOR = 0x7b8e3514; + bytes4 constant public ALLOWED_VALIDATORS_SELECTOR_GENERATOR = bytes4(keccak256("allowedValidators(address,address)")); + + // assetProxies + bytes4 constant public ASSET_PROXIES_SELECTOR = 0x3fd3c997; + bytes4 constant public ASSET_PROXIES_SELECTOR_GENERATOR = bytes4(keccak256("assetProxies(bytes4)")); + + // batchCancelOrders + bytes4 constant public BATCH_CANCEL_ORDERS_SELECTOR = 0x4ac14782; + bytes4 constant public BATCH_CANCEL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256("batchCancelOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])")); + + // batchFillOrKillOrders + bytes4 constant public BATCH_FILL_OR_KILL_ORDERS_SELECTOR = 0x4d0ae546; + bytes4 constant public BATCH_FILL_OR_KILL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256("batchFillOrKillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])")); + + // batchFillOrders + bytes4 constant public BATCH_FILL_ORDERS_SELECTOR = 0x297bb70b; + bytes4 constant public BATCH_FILL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256("batchFillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])")); + + // batchFillOrdersNoThrow + bytes4 constant public BATCH_FILL_ORDERS_NO_THROW_SELECTOR = 0x50dde190; + bytes4 constant public BATCH_FILL_ORDERS_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256("batchFillOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])")); + + // cancelOrder + bytes4 constant public CANCEL_ORDER_SELECTOR = 0xd46b02c3; + bytes4 constant public CANCEL_ORDER_SELECTOR_GENERATOR = bytes4(keccak256("cancelOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))")); + + // cancelOrdersUpTo + bytes4 constant public CANCEL_ORDERS_UP_TO_SELECTOR = 0x4f9559b1; + bytes4 constant public CANCEL_ORDERS_UP_TO_SELECTOR_GENERATOR = bytes4(keccak256("cancelOrdersUpTo(uint256)")); + + // cancelled + bytes4 constant public CANCELLED_SELECTOR = 0x2ac12622; + bytes4 constant public CANCELLED_SELECTOR_GENERATOR = bytes4(keccak256("cancelled(bytes32)")); + + // currentContextAddress + bytes4 constant public CURRENT_CONTEXT_ADDRESS_SELECTOR = 0xeea086ba; + bytes4 constant public CURRENT_CONTEXT_ADDRESS_SELECTOR_GENERATOR = bytes4(keccak256("currentContextAddress()")); + + // executeTransaction + bytes4 constant public EXECUTE_TRANSACTION_SELECTOR = 0xbfc8bfce; + bytes4 constant public EXECUTE_TRANSACTION_SELECTOR_GENERATOR = bytes4(keccak256("executeTransaction(uint256,address,bytes,bytes)")); + + // fillOrKillOrder + bytes4 constant public FILL_OR_KILL_ORDER_SELECTOR = 0x64a3bc15; + bytes4 constant public FILL_OR_KILL_ORDER_SELECTOR_GENERATOR = bytes4(keccak256("fillOrKillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)")); + + // fillOrder + bytes4 constant public FILL_ORDER_SELECTOR = 0xb4be83d5; + bytes4 constant public FILL_ORDER_SELECTOR_GENERATOR = bytes4(keccak256("fillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)")); + + // fillOrderNoThrow + bytes4 constant public FILL_ORDER_NO_THROW_SELECTOR = 0x3e228bae; + bytes4 constant public FILL_ORDER_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256("fillOrderNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)")); + + // filled + bytes4 constant public FILLED_SELECTOR = 0x288cdc91; + bytes4 constant public FILLED_SELECTOR_GENERATOR = bytes4(keccak256("filled(bytes32)")); + + // getAssetProxy + bytes4 constant public GET_ASSET_PROXY_SELECTOR = 0x60704108; + bytes4 constant public GET_ASSET_PROXY_SELECTOR_GENERATOR = bytes4(keccak256("getAssetProxy(bytes4)")); + + // getOrderInfo + bytes4 constant public GET_ORDER_INFO_SELECTOR = 0xc75e0a81; + bytes4 constant public GET_ORDER_INFO_SELECTOR_GENERATOR = bytes4(keccak256("getOrderInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))")); + + // getOrdersInfo + bytes4 constant public GET_ORDERS_INFO_SELECTOR = 0x7e9d74dc; + bytes4 constant public GET_ORDERS_INFO_SELECTOR_GENERATOR = bytes4(keccak256("getOrdersInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])")); + + // isValidSignature + bytes4 constant public IS_VALID_SIGNATURE_SELECTOR = 0x93634702; + bytes4 constant public IS_VALID_SIGNATURE_SELECTOR_GENERATOR = bytes4(keccak256("isValidSignature(bytes32,address,bytes)")); + + // marketBuyOrders + bytes4 constant public MARKET_BUY_ORDERS_SELECTOR = 0xe5fa431b; + bytes4 constant public MARKET_BUY_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256("marketBuyOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])")); + + // marketBuyOrdersNoThrow + bytes4 constant public MARKET_BUY_ORDERS_NO_THROW_SELECTOR = 0xa3e20380; + bytes4 constant public MARKET_BUY_ORDERS_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256("marketBuyOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])")); + + // marketSellOrders + bytes4 constant public MARKET_SELL_ORDERS_SELECTOR = 0x7e1d9808; + bytes4 constant public MARKET_SELL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256("marketSellOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])")); + + // marketSellOrdersNoThrow + bytes4 constant public MARKET_SELL_ORDERS_NO_THROW_SELECTOR = 0xdd1c7d18; + bytes4 constant public MARKET_SELL_ORDERS_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256("marketSellOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])")); + + // matchOrders + bytes4 constant public MATCH_ORDERS_SELECTOR = 0x3c28d861; + bytes4 constant public MATCH_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256("matchOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),(address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),bytes,bytes)")); + + // orderEpoch + bytes4 constant public ORDER_EPOCH_SELECTOR = 0xd9bfa73e; + bytes4 constant public ORDER_EPOCH_SELECTOR_GENERATOR = bytes4(keccak256("orderEpoch(address,address)")); + + // owner + bytes4 constant public OWNER_SELECTOR = 0x8da5cb5b; + bytes4 constant public OWNER_SELECTOR_GENERATOR = bytes4(keccak256("owner()")); + + // preSign + bytes4 constant public PRE_SIGN_SELECTOR = 0x3683ef8e; + bytes4 constant public PRE_SIGN_SELECTOR_GENERATOR = bytes4(keccak256("preSign(bytes32,address,bytes)")); + + // preSigned + bytes4 constant public PRE_SIGNED_SELECTOR = 0x82c174d0; + bytes4 constant public PRE_SIGNED_SELECTOR_GENERATOR = bytes4(keccak256("preSigned(bytes32,address)")); + + // registerAssetProxy + bytes4 constant public REGISTER_ASSET_PROXY_SELECTOR = 0xc585bb93; + bytes4 constant public REGISTER_ASSET_PROXY_SELECTOR_GENERATOR = bytes4(keccak256("registerAssetProxy(address)")); + + // setSignatureValidatorApproval + bytes4 constant public SET_SIGNATURE_VALIDATOR_APPROVAL_SELECTOR = 0x77fcce68; + bytes4 constant public SET_SIGNATURE_VALIDATOR_APPROVAL_SELECTOR_GENERATOR = bytes4(keccak256("setSignatureValidatorApproval(address,bool)")); + + // transactions + bytes4 constant public TRANSACTIONS_SELECTOR = 0x642f2eaf; + bytes4 constant public TRANSACTIONS_SELECTOR_GENERATOR = bytes4(keccak256("transactions(bytes32)")); + + // transferOwnership + bytes4 constant public TRANSFER_OWNERSHIP_SELECTOR = 0xf2fde38b; + bytes4 constant public TRANSFER_OWNERSHIP_SELECTOR_GENERATOR = bytes4(keccak256("transferOwnership(address)")); +}
\ No newline at end of file diff --git a/contracts/libs/contracts/libs/LibFillResults.sol b/contracts/libs/contracts/libs/LibFillResults.sol index fbd9950bf..74b7f7984 100644 --- a/contracts/libs/contracts/libs/LibFillResults.sol +++ b/contracts/libs/contracts/libs/LibFillResults.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; import "@0x/contracts-utils/contracts/utils/SafeMath/SafeMath.sol"; diff --git a/contracts/libs/contracts/libs/LibMath.sol b/contracts/libs/contracts/libs/LibMath.sol index b24876a9c..f14b1b34d 100644 --- a/contracts/libs/contracts/libs/LibMath.sol +++ b/contracts/libs/contracts/libs/LibMath.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; import "@0x/contracts-utils/contracts/utils/SafeMath/SafeMath.sol"; diff --git a/contracts/libs/contracts/libs/LibOrder.sol b/contracts/libs/contracts/libs/LibOrder.sol index 0fe7c2161..fcf5da5fb 100644 --- a/contracts/libs/contracts/libs/LibOrder.sol +++ b/contracts/libs/contracts/libs/LibOrder.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; import "./LibEIP712.sol"; diff --git a/contracts/libs/package.json b/contracts/libs/package.json index fa4b6e523..ce7b97502 100644 --- a/contracts/libs/package.json +++ b/contracts/libs/package.json @@ -19,7 +19,8 @@ "test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html", "test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha", "run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit", - "compile": "sol-compiler --contracts-dir contracts", + "compile": "sol-compiler", + "watch": "sol-compiler -w", "clean": "shx rm -rf lib generated-artifacts generated-wrappers", "generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers", "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", diff --git a/contracts/multisig/package.json b/contracts/multisig/package.json index b338f67f7..2d7b4aa05 100644 --- a/contracts/multisig/package.json +++ b/contracts/multisig/package.json @@ -19,7 +19,8 @@ "test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html", "test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha", "run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit", - "compile": "sol-compiler --contracts-dir contracts", + "compile": "sol-compiler", + "watch": "sol-compiler -w", "clean": "shx rm -rf lib generated-artifacts generated-wrappers", "generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../packages/abi-gen-templates/contract.handlebars --partials '../../packages/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers", "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", diff --git a/contracts/multisig/src/index.ts b/contracts/multisig/src/index.ts new file mode 100644 index 000000000..d55f08ea2 --- /dev/null +++ b/contracts/multisig/src/index.ts @@ -0,0 +1,2 @@ +export * from './artifacts'; +export * from './wrappers'; diff --git a/contracts/protocol/CHANGELOG.json b/contracts/protocol/CHANGELOG.json index 5c3798a69..e283d7917 100644 --- a/contracts/protocol/CHANGELOG.json +++ b/contracts/protocol/CHANGELOG.json @@ -1,5 +1,22 @@ [ { + "version": "2.2.0", + "changes": [ + { + "note": "Added LibAddressArray", + "pr": 1383 + }, + { + "note": "Add validation and comments to MultiAssetProxy", + "pr": 1455 + }, + { + "note": "Move OrderValidator to extensions", + "pr": 1464 + } + ] + }, + { "timestamp": 1544741676, "version": "2.1.59", "changes": [ diff --git a/contracts/protocol/compiler.json b/contracts/protocol/compiler.json index c05d62aba..10e5bb0a1 100644 --- a/contracts/protocol/compiler.json +++ b/contracts/protocol/compiler.json @@ -25,7 +25,6 @@ "Exchange", "MixinAuthorizable", "MultiAssetProxy", - "OrderValidator", "TestAssetProxyOwner", "TestAssetProxyDispatcher", "TestExchangeInternals", diff --git a/contracts/protocol/contracts/protocol/AssetProxy/MixinAuthorizable.sol b/contracts/protocol/contracts/protocol/AssetProxy/MixinAuthorizable.sol index 08f9b94dc..b610ef709 100644 --- a/contracts/protocol/contracts/protocol/AssetProxy/MixinAuthorizable.sol +++ b/contracts/protocol/contracts/protocol/AssetProxy/MixinAuthorizable.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol"; import "./mixins/MAuthorizable.sol"; diff --git a/contracts/protocol/contracts/protocol/AssetProxy/MultiAssetProxy.sol b/contracts/protocol/contracts/protocol/AssetProxy/MultiAssetProxy.sol index 42231e73b..5f559163c 100644 --- a/contracts/protocol/contracts/protocol/AssetProxy/MultiAssetProxy.sol +++ b/contracts/protocol/contracts/protocol/AssetProxy/MultiAssetProxy.sol @@ -33,6 +33,9 @@ contract MultiAssetProxy is function () external { + // NOTE: The below assembly assumes that clients do some input validation and that the input is properly encoded according to the AbiV2 specification. + // It is technically possible for inputs with very large lengths and offsets to cause overflows. However, this would make the calldata prohibitively + // expensive and we therefore do not check for overflows in these scenarios. assembly { // The first 4 bytes of calldata holds the function selector let selector := and(calldataload(0), 0xffffffff00000000000000000000000000000000000000000000000000000000) @@ -145,7 +148,7 @@ contract MultiAssetProxy is let nestedAssetDataLen := calldataload(sub(nestedAssetDataContentsStart, 32)) // Revert if number of elements in `amounts` differs from number of elements in `nestedAssetData` - if iszero(eq(amountsLen, nestedAssetDataLen)) { + if sub(amountsLen, nestedAssetDataLen) { // Revert with `Error("LENGTH_MISMATCH")` mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) @@ -181,8 +184,11 @@ contract MultiAssetProxy is let amountsElement := calldataload(add(amountsContentsStart, i)) let totalAmount := mul(amountsElement, amount) - // Revert if multiplication resulted in an overflow - if iszero(eq(div(totalAmount, amount), amountsElement)) { + // Revert if `amount` != 0 and multiplication resulted in an overflow + if iszero(or( + iszero(amount), + eq(div(totalAmount, amount), amountsElement) + )) { // Revert with `Error("UINT256_OVERFLOW")` mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) @@ -230,7 +236,7 @@ contract MultiAssetProxy is // Only load `assetProxy` if `currentAssetProxyId` does not equal `assetProxyId` // We do not need to check if `currentAssetProxyId` is 0 since `assetProxy` is also initialized to 0 - if iszero(eq(currentAssetProxyId, assetProxyId)) { + if sub(currentAssetProxyId, assetProxyId) { // Update `assetProxyId` assetProxyId := currentAssetProxyId // To lookup a value in a mapping, we load from the storage location keccak256(k, p), diff --git a/contracts/protocol/contracts/protocol/AssetProxy/mixins/MAuthorizable.sol b/contracts/protocol/contracts/protocol/AssetProxy/mixins/MAuthorizable.sol index fe77048ce..6c3f70500 100644 --- a/contracts/protocol/contracts/protocol/AssetProxy/mixins/MAuthorizable.sol +++ b/contracts/protocol/contracts/protocol/AssetProxy/mixins/MAuthorizable.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; import "@0x/contracts-interfaces/contracts/protocol/AssetProxy/IAuthorizable.sol"; diff --git a/contracts/protocol/contracts/protocol/Exchange/MixinAssetProxyDispatcher.sol b/contracts/protocol/contracts/protocol/Exchange/MixinAssetProxyDispatcher.sol index 36ab39b45..2922a8c1a 100644 --- a/contracts/protocol/contracts/protocol/Exchange/MixinAssetProxyDispatcher.sol +++ b/contracts/protocol/contracts/protocol/Exchange/MixinAssetProxyDispatcher.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol"; import "./mixins/MAssetProxyDispatcher.sol"; diff --git a/contracts/protocol/contracts/protocol/Exchange/MixinExchangeCore.sol b/contracts/protocol/contracts/protocol/Exchange/MixinExchangeCore.sol index 68d6a3897..72bcebc62 100644 --- a/contracts/protocol/contracts/protocol/Exchange/MixinExchangeCore.sol +++ b/contracts/protocol/contracts/protocol/Exchange/MixinExchangeCore.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; pragma experimental ABIEncoderV2; import "@0x/contracts-utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol"; diff --git a/contracts/protocol/contracts/protocol/Exchange/MixinMatchOrders.sol b/contracts/protocol/contracts/protocol/Exchange/MixinMatchOrders.sol index fc6d73482..2627b82fd 100644 --- a/contracts/protocol/contracts/protocol/Exchange/MixinMatchOrders.sol +++ b/contracts/protocol/contracts/protocol/Exchange/MixinMatchOrders.sol @@ -11,7 +11,7 @@ limitations under the License. */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; pragma experimental ABIEncoderV2; import "@0x/contracts-utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol"; diff --git a/contracts/protocol/contracts/protocol/Exchange/MixinSignatureValidator.sol b/contracts/protocol/contracts/protocol/Exchange/MixinSignatureValidator.sol index 80b4c0755..b40aa1412 100644 --- a/contracts/protocol/contracts/protocol/Exchange/MixinSignatureValidator.sol +++ b/contracts/protocol/contracts/protocol/Exchange/MixinSignatureValidator.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol"; import "@0x/contracts-utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol"; diff --git a/contracts/protocol/contracts/protocol/Exchange/MixinTransactions.sol b/contracts/protocol/contracts/protocol/Exchange/MixinTransactions.sol index 87c614382..1ac5b1a5e 100644 --- a/contracts/protocol/contracts/protocol/Exchange/MixinTransactions.sol +++ b/contracts/protocol/contracts/protocol/Exchange/MixinTransactions.sol @@ -15,7 +15,7 @@ limitations under the License. */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; import "@0x/contracts-libs/contracts/libs/LibExchangeErrors.sol"; import "./mixins/MSignatureValidator.sol"; diff --git a/contracts/protocol/contracts/protocol/Exchange/MixinWrapperFunctions.sol b/contracts/protocol/contracts/protocol/Exchange/MixinWrapperFunctions.sol index 2d43432ff..6fc6ee999 100644 --- a/contracts/protocol/contracts/protocol/Exchange/MixinWrapperFunctions.sol +++ b/contracts/protocol/contracts/protocol/Exchange/MixinWrapperFunctions.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; pragma experimental ABIEncoderV2; import "@0x/contracts-utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol"; diff --git a/contracts/protocol/contracts/protocol/Exchange/mixins/MAssetProxyDispatcher.sol b/contracts/protocol/contracts/protocol/Exchange/mixins/MAssetProxyDispatcher.sol index fe3d03326..05c2c4c0b 100644 --- a/contracts/protocol/contracts/protocol/Exchange/mixins/MAssetProxyDispatcher.sol +++ b/contracts/protocol/contracts/protocol/Exchange/mixins/MAssetProxyDispatcher.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; import "@0x/contracts-interfaces/contracts/protocol/Exchange/IAssetProxyDispatcher.sol"; diff --git a/contracts/protocol/contracts/protocol/Exchange/mixins/MExchangeCore.sol b/contracts/protocol/contracts/protocol/Exchange/mixins/MExchangeCore.sol index 215284900..09dc491cd 100644 --- a/contracts/protocol/contracts/protocol/Exchange/mixins/MExchangeCore.sol +++ b/contracts/protocol/contracts/protocol/Exchange/mixins/MExchangeCore.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; pragma experimental ABIEncoderV2; import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; diff --git a/contracts/protocol/contracts/protocol/Exchange/mixins/MMatchOrders.sol b/contracts/protocol/contracts/protocol/Exchange/mixins/MMatchOrders.sol index 1eb4be329..56ee895c4 100644 --- a/contracts/protocol/contracts/protocol/Exchange/mixins/MMatchOrders.sol +++ b/contracts/protocol/contracts/protocol/Exchange/mixins/MMatchOrders.sol @@ -15,7 +15,7 @@ limitations under the License. */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; pragma experimental ABIEncoderV2; import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; diff --git a/contracts/protocol/contracts/protocol/Exchange/mixins/MSignatureValidator.sol b/contracts/protocol/contracts/protocol/Exchange/mixins/MSignatureValidator.sol index a933976d1..6407760d4 100644 --- a/contracts/protocol/contracts/protocol/Exchange/mixins/MSignatureValidator.sol +++ b/contracts/protocol/contracts/protocol/Exchange/mixins/MSignatureValidator.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; import "@0x/contracts-interfaces/contracts/protocol/Exchange/ISignatureValidator.sol"; diff --git a/contracts/protocol/contracts/protocol/Exchange/mixins/MTransactions.sol b/contracts/protocol/contracts/protocol/Exchange/mixins/MTransactions.sol index a6b0fdc85..04dd716d7 100644 --- a/contracts/protocol/contracts/protocol/Exchange/mixins/MTransactions.sol +++ b/contracts/protocol/contracts/protocol/Exchange/mixins/MTransactions.sol @@ -15,7 +15,7 @@ limitations under the License. */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; import "@0x/contracts-interfaces/contracts/protocol/Exchange/ITransactions.sol"; diff --git a/contracts/protocol/contracts/protocol/Exchange/mixins/MWrapperFunctions.sol b/contracts/protocol/contracts/protocol/Exchange/mixins/MWrapperFunctions.sol index 101e7cb82..2ff3b8790 100644 --- a/contracts/protocol/contracts/protocol/Exchange/mixins/MWrapperFunctions.sol +++ b/contracts/protocol/contracts/protocol/Exchange/mixins/MWrapperFunctions.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; pragma experimental ABIEncoderV2; import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; diff --git a/contracts/protocol/package.json b/contracts/protocol/package.json index 838189371..891838e54 100644 --- a/contracts/protocol/package.json +++ b/contracts/protocol/package.json @@ -19,7 +19,8 @@ "test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html", "test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha", "run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit", - "compile": "sol-compiler --contracts-dir contracts", + "compile": "sol-compiler", + "watch": "sol-compiler -w", "clean": "shx rm -rf lib generated-artifacts generated-wrappers", "generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers", "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", @@ -31,7 +32,7 @@ "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol" }, "config": { - "abis": "generated-artifacts/@(AssetProxyOwner|ERC20Proxy|ERC721Proxy|Exchange|MixinAuthorizable|MultiAssetProxy|OrderValidator|TestSignatureValidator|TestAssetProxyOwner|TestAssetProxyDispatcher|TestExchangeInternals|TestStaticCallReceiver).json" + "abis": "generated-artifacts/@(AssetProxyOwner|ERC20Proxy|ERC721Proxy|Exchange|MixinAuthorizable|MultiAssetProxy|TestSignatureValidator|TestAssetProxyOwner|TestAssetProxyDispatcher|TestExchangeInternals|TestStaticCallReceiver).json" }, "repository": { "type": "git", @@ -44,7 +45,6 @@ "homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md", "devDependencies": { "@0x/abi-gen": "^1.0.19", - "@0x/contracts-test-utils": "^1.0.2", "@0x/dev-utils": "^1.0.21", "@0x/sol-compiler": "^1.1.16", "@0x/sol-cov": "^2.1.16", @@ -75,6 +75,7 @@ "@0x/contracts-interfaces": "^1.0.2", "@0x/contracts-libs": "^1.0.2", "@0x/contracts-multisig": "^1.0.2", + "@0x/contracts-test-utils": "^1.0.2", "@0x/contracts-tokens": "^1.0.2", "@0x/contracts-utils": "^1.0.2", "@0x/order-utils": "^3.0.7", diff --git a/contracts/protocol/src/artifacts/index.ts b/contracts/protocol/src/artifacts/index.ts index 1d53ceb04..c5d12f10b 100644 --- a/contracts/protocol/src/artifacts/index.ts +++ b/contracts/protocol/src/artifacts/index.ts @@ -6,7 +6,6 @@ import * as ERC721Proxy from '../../generated-artifacts/ERC721Proxy.json'; import * as Exchange from '../../generated-artifacts/Exchange.json'; import * as MixinAuthorizable from '../../generated-artifacts/MixinAuthorizable.json'; import * as MultiAssetProxy from '../../generated-artifacts/MultiAssetProxy.json'; -import * as OrderValidator from '../../generated-artifacts/OrderValidator.json'; import * as TestAssetProxyDispatcher from '../../generated-artifacts/TestAssetProxyDispatcher.json'; import * as TestAssetProxyOwner from '../../generated-artifacts/TestAssetProxyOwner.json'; import * as TestExchangeInternals from '../../generated-artifacts/TestExchangeInternals.json'; @@ -20,7 +19,6 @@ export const artifacts = { Exchange: Exchange as ContractArtifact, MixinAuthorizable: MixinAuthorizable as ContractArtifact, MultiAssetProxy: MultiAssetProxy as ContractArtifact, - OrderValidator: OrderValidator as ContractArtifact, TestAssetProxyDispatcher: TestAssetProxyDispatcher as ContractArtifact, TestAssetProxyOwner: TestAssetProxyOwner as ContractArtifact, TestExchangeInternals: TestExchangeInternals as ContractArtifact, diff --git a/contracts/protocol/src/wrappers/index.ts b/contracts/protocol/src/wrappers/index.ts index ac951d269..01b121054 100644 --- a/contracts/protocol/src/wrappers/index.ts +++ b/contracts/protocol/src/wrappers/index.ts @@ -3,7 +3,6 @@ export * from '../../generated-wrappers/erc20_proxy'; export * from '../../generated-wrappers/erc721_proxy'; export * from '../../generated-wrappers/exchange'; export * from '../../generated-wrappers/mixin_authorizable'; -export * from '../../generated-wrappers/order_validator'; export * from '../../generated-wrappers/test_asset_proxy_dispatcher'; export * from '../../generated-wrappers/test_asset_proxy_owner'; export * from '../../generated-wrappers/test_exchange_internals'; diff --git a/contracts/protocol/test/asset_proxy/proxies.ts b/contracts/protocol/test/asset_proxy/proxies.ts index c4bd95905..89c8b390c 100644 --- a/contracts/protocol/test/asset_proxy/proxies.ts +++ b/contracts/protocol/test/asset_proxy/proxies.ts @@ -12,6 +12,7 @@ import { import { artifacts as tokensArtifacts, DummyERC20TokenContract, + DummyERC20TokenTransferEventArgs, DummyERC721ReceiverContract, DummyERC721TokenContract, DummyMultipleReturnERC20TokenContract, @@ -22,6 +23,7 @@ import { assetDataUtils } from '@0x/order-utils'; import { RevertReason } from '@0x/types'; import { BigNumber } from '@0x/utils'; import * as chai from 'chai'; +import { LogWithDecodedArgs } from 'ethereum-types'; import * as _ from 'lodash'; import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy'; @@ -738,6 +740,36 @@ describe('Asset Transfer Proxies', () => { erc20Balances[toAddress][erc20TokenA.address].add(totalAmount), ); }); + it('should dispatch an ERC20 transfer when input amount is 0', async () => { + const inputAmount = constants.ZERO_AMOUNT; + const erc20Amount = new BigNumber(10); + const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address); + const amounts = [erc20Amount]; + const nestedAssetData = [erc20AssetData]; + const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + assetData, + fromAddress, + toAddress, + inputAmount, + ); + const erc20Balances = await erc20Wrapper.getBalancesAsync(); + const logDecoder = new LogDecoder(web3Wrapper, { ...artifacts, ...tokensArtifacts }); + const tx = await logDecoder.getTxWithDecodedLogsAsync( + await web3Wrapper.sendTransactionAsync({ + to: multiAssetProxy.address, + data, + from: authorized, + }), + ); + expect(tx.logs.length).to.be.equal(1); + const log = tx.logs[0] as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>; + const transferEventName = 'Transfer'; + expect(log.event).to.equal(transferEventName); + expect(log.args._value).to.be.bignumber.equal(constants.ZERO_AMOUNT); + const newBalances = await erc20Wrapper.getBalancesAsync(); + expect(newBalances).to.deep.equal(erc20Balances); + }); it('should successfully transfer multiple of the same ERC20 token', async () => { const inputAmount = new BigNumber(1); const erc20Amount1 = new BigNumber(10); diff --git a/contracts/protocol/tsconfig.json b/contracts/protocol/tsconfig.json index 989d3ef2b..db872fc32 100644 --- a/contracts/protocol/tsconfig.json +++ b/contracts/protocol/tsconfig.json @@ -13,7 +13,6 @@ "./generated-artifacts/Exchange.json", "./generated-artifacts/MixinAuthorizable.json", "./generated-artifacts/MultiAssetProxy.json", - "./generated-artifacts/OrderValidator.json", "./generated-artifacts/TestAssetProxyDispatcher.json", "./generated-artifacts/TestAssetProxyOwner.json", "./generated-artifacts/TestExchangeInternals.json", diff --git a/contracts/test-utils/src/constants.ts b/contracts/test-utils/src/constants.ts index d2c3ab512..f631dc81a 100644 --- a/contracts/test-utils/src/constants.ts +++ b/contracts/test-utils/src/constants.ts @@ -29,6 +29,7 @@ export const constants = { MAX_TOKEN_TRANSFERFROM_GAS: 80000, MAX_TOKEN_APPROVE_GAS: 60000, MAX_TRANSFER_FROM_GAS: 150000, + MAX_MATCH_ORDERS_GAS: 400000, DUMMY_TOKEN_NAME: '', DUMMY_TOKEN_SYMBOL: '', DUMMY_TOKEN_DECIMALS: new BigNumber(18), diff --git a/contracts/test-utils/src/types.ts b/contracts/test-utils/src/types.ts index d738fcd4e..1630eab0d 100644 --- a/contracts/test-utils/src/types.ts +++ b/contracts/test-utils/src/types.ts @@ -104,6 +104,7 @@ export enum ContractName { Authorizable = 'Authorizable', Whitelist = 'Whitelist', Forwarder = 'Forwarder', + BalanceThresholdFilter = 'BalanceThresholdFilter', } export interface SignedTransaction { diff --git a/contracts/tokens/contracts/tokens/ERC20Token/ERC20Token.sol b/contracts/tokens/contracts/tokens/ERC20Token/ERC20Token.sol index 725d304df..190eead76 100644 --- a/contracts/tokens/contracts/tokens/ERC20Token/ERC20Token.sol +++ b/contracts/tokens/contracts/tokens/ERC20Token/ERC20Token.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; import "./IERC20Token.sol"; diff --git a/contracts/tokens/contracts/tokens/ERC20Token/IERC20Token.sol b/contracts/tokens/contracts/tokens/ERC20Token/IERC20Token.sol index 258d47393..9f9b89585 100644 --- a/contracts/tokens/contracts/tokens/ERC20Token/IERC20Token.sol +++ b/contracts/tokens/contracts/tokens/ERC20Token/IERC20Token.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; contract IERC20Token { diff --git a/contracts/tokens/contracts/tokens/ERC20Token/MintableERC20Token.sol b/contracts/tokens/contracts/tokens/ERC20Token/MintableERC20Token.sol index 58bccb5a1..a66031f03 100644 --- a/contracts/tokens/contracts/tokens/ERC20Token/MintableERC20Token.sol +++ b/contracts/tokens/contracts/tokens/ERC20Token/MintableERC20Token.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; import "@0x/contracts-utils/contracts/utils/SafeMath/SafeMath.sol"; import "./UnlimitedAllowanceERC20Token.sol"; diff --git a/contracts/tokens/contracts/tokens/ERC20Token/UnlimitedAllowanceERC20Token.sol b/contracts/tokens/contracts/tokens/ERC20Token/UnlimitedAllowanceERC20Token.sol index 2e5bd4348..869d16147 100644 --- a/contracts/tokens/contracts/tokens/ERC20Token/UnlimitedAllowanceERC20Token.sol +++ b/contracts/tokens/contracts/tokens/ERC20Token/UnlimitedAllowanceERC20Token.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; import "../ERC20Token/ERC20Token.sol"; diff --git a/contracts/tokens/contracts/tokens/ERC721Token/ERC721Token.sol b/contracts/tokens/contracts/tokens/ERC721Token/ERC721Token.sol index 600cee1ab..c46bd0af4 100644 --- a/contracts/tokens/contracts/tokens/ERC721Token/ERC721Token.sol +++ b/contracts/tokens/contracts/tokens/ERC721Token/ERC721Token.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; import "./IERC721Token.sol"; import "./IERC721Receiver.sol"; diff --git a/contracts/tokens/contracts/tokens/ERC721Token/IERC721Receiver.sol b/contracts/tokens/contracts/tokens/ERC721Token/IERC721Receiver.sol index 8e0e32ab2..c3ad35ede 100644 --- a/contracts/tokens/contracts/tokens/ERC721Token/IERC721Receiver.sol +++ b/contracts/tokens/contracts/tokens/ERC721Token/IERC721Receiver.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; contract IERC721Receiver { diff --git a/contracts/tokens/contracts/tokens/ERC721Token/IERC721Token.sol b/contracts/tokens/contracts/tokens/ERC721Token/IERC721Token.sol index ac992c80d..56a3314df 100644 --- a/contracts/tokens/contracts/tokens/ERC721Token/IERC721Token.sol +++ b/contracts/tokens/contracts/tokens/ERC721Token/IERC721Token.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; contract IERC721Token { diff --git a/contracts/tokens/contracts/tokens/ERC721Token/MintableERC721Token.sol b/contracts/tokens/contracts/tokens/ERC721Token/MintableERC721Token.sol index bc5cd2cc2..27326d857 100644 --- a/contracts/tokens/contracts/tokens/ERC721Token/MintableERC721Token.sol +++ b/contracts/tokens/contracts/tokens/ERC721Token/MintableERC721Token.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; import "./ERC721Token.sol"; diff --git a/contracts/tokens/contracts/tokens/EtherToken/IEtherToken.sol b/contracts/tokens/contracts/tokens/EtherToken/IEtherToken.sol index 9e2e68766..32baa3eb0 100644 --- a/contracts/tokens/contracts/tokens/EtherToken/IEtherToken.sol +++ b/contracts/tokens/contracts/tokens/EtherToken/IEtherToken.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; import "../ERC20Token/IERC20Token.sol"; diff --git a/contracts/tokens/package.json b/contracts/tokens/package.json index 6f8a366dd..79afc4820 100644 --- a/contracts/tokens/package.json +++ b/contracts/tokens/package.json @@ -19,7 +19,8 @@ "test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html", "test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha", "run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit", - "compile": "sol-compiler --contracts-dir contracts", + "compile": "sol-compiler", + "watch": "sol-compiler -w", "clean": "shx rm -rf lib generated-artifacts generated-wrappers", "generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers", "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", diff --git a/contracts/utils/contracts/utils/LibBytes/LibBytes.sol b/contracts/utils/contracts/utils/LibBytes/LibBytes.sol index 369f588ad..4ee6228d5 100644 --- a/contracts/utils/contracts/utils/LibBytes/LibBytes.sol +++ b/contracts/utils/contracts/utils/LibBytes/LibBytes.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; library LibBytes { diff --git a/contracts/utils/contracts/utils/Ownable/IOwnable.sol b/contracts/utils/contracts/utils/Ownable/IOwnable.sol index 5deb13497..c0cbfddfd 100644 --- a/contracts/utils/contracts/utils/Ownable/IOwnable.sol +++ b/contracts/utils/contracts/utils/Ownable/IOwnable.sol @@ -1,4 +1,4 @@ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; contract IOwnable { diff --git a/contracts/utils/contracts/utils/Ownable/Ownable.sol b/contracts/utils/contracts/utils/Ownable/Ownable.sol index 0c830be68..aa74a72d2 100644 --- a/contracts/utils/contracts/utils/Ownable/Ownable.sol +++ b/contracts/utils/contracts/utils/Ownable/Ownable.sol @@ -1,4 +1,4 @@ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; import "./IOwnable.sol"; diff --git a/contracts/utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol b/contracts/utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol index 9f98a7a16..1a02c88a4 100644 --- a/contracts/utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol +++ b/contracts/utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; contract ReentrancyGuard { diff --git a/contracts/utils/contracts/utils/SafeMath/SafeMath.sol b/contracts/utils/contracts/utils/SafeMath/SafeMath.sol index 2855edb9d..d7a4a603e 100644 --- a/contracts/utils/contracts/utils/SafeMath/SafeMath.sol +++ b/contracts/utils/contracts/utils/SafeMath/SafeMath.sol @@ -1,4 +1,4 @@ -pragma solidity 0.4.24; +pragma solidity ^0.4.24; contract SafeMath { diff --git a/contracts/utils/package.json b/contracts/utils/package.json index a776bdfbb..cf94af0f6 100644 --- a/contracts/utils/package.json +++ b/contracts/utils/package.json @@ -19,7 +19,8 @@ "test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html", "test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha", "run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit", - "compile": "sol-compiler --contracts-dir contracts", + "compile": "sol-compiler", + "watch": "sol-compiler -w", "clean": "shx rm -rf lib generated-artifacts generated-wrappers", "generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers", "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", diff --git a/packages/contract-wrappers/CHANGELOG.json b/packages/contract-wrappers/CHANGELOG.json index 9475e5a88..d39027797 100644 --- a/packages/contract-wrappers/CHANGELOG.json +++ b/packages/contract-wrappers/CHANGELOG.json @@ -1,5 +1,13 @@ [ { + "version": "4.1.4", + "changes": [ + { + "note": "Add support for Trust Wallet signature denial error" + } + ] + }, + { "version": "4.1.3", "changes": [ { diff --git a/packages/contract-wrappers/src/utils/constants.ts b/packages/contract-wrappers/src/utils/constants.ts index c587ba526..94afdc112 100644 --- a/packages/contract-wrappers/src/utils/constants.ts +++ b/packages/contract-wrappers/src/utils/constants.ts @@ -14,5 +14,6 @@ export const constants = { ZERO_AMOUNT: new BigNumber(0), ONE_AMOUNT: new BigNumber(1), ETHER_TOKEN_DECIMALS: 18, - USER_DENIED_SIGNATURE_PATTERN: 'User denied transaction signature', + METAMASK_USER_DENIED_SIGNATURE_PATTERN: 'User denied transaction signature', + TRUST_WALLET_USER_DENIED_SIGNATURE_PATTERN: 'cancelled', }; diff --git a/packages/contract-wrappers/src/utils/decorators.ts b/packages/contract-wrappers/src/utils/decorators.ts index a4207ae4c..3acfa3a88 100644 --- a/packages/contract-wrappers/src/utils/decorators.ts +++ b/packages/contract-wrappers/src/utils/decorators.ts @@ -30,7 +30,10 @@ const schemaErrorTransformer = (error: Error) => { }; const signatureRequestErrorTransformer = (error: Error) => { - if (_.includes(error.message, constants.USER_DENIED_SIGNATURE_PATTERN)) { + if ( + _.includes(error.message, constants.METAMASK_USER_DENIED_SIGNATURE_PATTERN) || + _.includes(error.message, constants.TRUST_WALLET_USER_DENIED_SIGNATURE_PATTERN) + ) { const errMsg = ContractWrappersError.SignatureRequestDenied; return new Error(errMsg); } diff --git a/packages/instant/.production.discharge.json b/packages/instant/.production.discharge.json index 1ce39fdd8..c87f8b187 100644 --- a/packages/instant/.production.discharge.json +++ b/packages/instant/.production.discharge.json @@ -1,5 +1,5 @@ { - "domain": "instant.0xproject.com", + "domain": "instant.0x.org", "build_command": "dotenv yarn build -- --env.discharge_target=production", "upload_directory": "umd", "index_key": "instant.js", diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx index 1489b94d4..5c9c28ae4 100644 --- a/packages/instant/src/components/buy_button.tsx +++ b/packages/instant/src/components/buy_button.tsx @@ -10,6 +10,7 @@ import { WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX } from '../constants' import { ColorOption } from '../style/theme'; import { AffiliateInfo, Asset, ZeroExInstantError } from '../types'; import { analytics } from '../util/analytics'; +import { errorReporter } from '../util/error_reporter'; import { gasPriceEstimator } from '../util/gas_price_estimator'; import { util } from '../util/util'; @@ -82,13 +83,18 @@ export class BuyButton extends React.Component<BuyButtonProps> { }); } catch (e) { if (e instanceof Error) { - if (e.message === AssetBuyerError.SignatureRequestDenied) { + if (e.message === AssetBuyerError.TransactionValueTooLow) { + analytics.trackBuySimulationFailed(buyQuote); + this.props.onValidationFail(buyQuote, AssetBuyerError.TransactionValueTooLow); + return; + } else if (e.message === AssetBuyerError.SignatureRequestDenied) { analytics.trackBuySignatureDenied(buyQuote); this.props.onSignatureDenied(buyQuote); return; - } else if (e.message === AssetBuyerError.TransactionValueTooLow) { - analytics.trackBuySimulationFailed(buyQuote); - this.props.onValidationFail(buyQuote, AssetBuyerError.TransactionValueTooLow); + } else { + errorReporter.report(e); + analytics.trackBuyUnknownError(buyQuote, e.message); + this.props.onValidationFail(buyQuote, ZeroExInstantError.CouldNotSubmitTransaction); return; } } diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx index 816cc5c33..5b1f9592d 100644 --- a/packages/instant/src/components/instant_heading.tsx +++ b/packages/instant/src/components/instant_heading.tsx @@ -113,20 +113,23 @@ export class InstantHeading extends React.Component<InstantHeadingProps, {}> { } private readonly _renderEthAmount = (): React.ReactNode => { + const ethAmount = format.ethBaseUnitAmount( + this.props.totalEthBaseUnitAmount, + 4, + <AmountPlaceholder isPulsating={false} color={PLACEHOLDER_COLOR} />, + ); + + const fontSize = _.isString(ethAmount) && ethAmount.length >= 13 ? '14px' : '16px'; return ( <Text - fontSize="16px" + fontSize={fontSize} textAlign="right" width="100%" fontColor={ColorOption.white} fontWeight={500} noWrap={true} > - {format.ethBaseUnitAmount( - this.props.totalEthBaseUnitAmount, - 4, - <AmountPlaceholder isPulsating={false} color={PLACEHOLDER_COLOR} />, - )} + {ethAmount} </Text> ); }; diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx index a8e0e2513..9c10ef9e6 100644 --- a/packages/instant/src/components/order_details.tsx +++ b/packages/instant/src/components/order_details.tsx @@ -4,124 +4,227 @@ import * as _ from 'lodash'; import * as React from 'react'; import { oc } from 'ts-optchain'; -import { BIG_NUMBER_ZERO } from '../constants'; +import { BIG_NUMBER_ZERO, DEFAULT_UNKOWN_ASSET_NAME } from '../constants'; import { ColorOption } from '../style/theme'; +import { BaseCurrency } from '../types'; import { format } from '../util/format'; import { AmountPlaceholder } from './amount_placeholder'; +import { SectionHeader } from './section_header'; import { Container } from './ui/container'; import { Flex } from './ui/flex'; -import { Text } from './ui/text'; +import { Text, TextProps } from './ui/text'; export interface OrderDetailsProps { buyQuoteInfo?: BuyQuoteInfo; selectedAssetUnitAmount?: BigNumber; ethUsdPrice?: BigNumber; isLoading: boolean; + assetName?: string; + baseCurrency: BaseCurrency; + onBaseCurrencySwitchEth: () => void; + onBaseCurrencySwitchUsd: () => void; } export class OrderDetails extends React.Component<OrderDetailsProps> { public render(): React.ReactNode { - const { buyQuoteInfo, ethUsdPrice, selectedAssetUnitAmount } = this.props; - const buyQuoteAccessor = oc(buyQuoteInfo); - const assetEthBaseUnitAmount = buyQuoteAccessor.assetEthAmount(); - const feeEthBaseUnitAmount = buyQuoteAccessor.feeEthAmount(); - const totalEthBaseUnitAmount = buyQuoteAccessor.totalEthAmount(); - const pricePerTokenEth = - !_.isUndefined(assetEthBaseUnitAmount) && - !_.isUndefined(selectedAssetUnitAmount) && - !selectedAssetUnitAmount.eq(BIG_NUMBER_ZERO) - ? assetEthBaseUnitAmount.div(selectedAssetUnitAmount).ceil() - : undefined; + const shouldShowUsdError = this.props.baseCurrency === BaseCurrency.USD && this._hadErrorFetchingUsdPrice(); return ( <Container width="100%" flexGrow={1} padding="20px 20px 0px 20px"> - <Container marginBottom="10px"> - <Text - letterSpacing="1px" - fontColor={ColorOption.primaryColor} - fontWeight={600} - textTransform="uppercase" - fontSize="14px" - > - Order Details - </Text> - </Container> - <EthAmountRow - rowLabel="Token Price" - ethAmount={pricePerTokenEth} - ethUsdPrice={ethUsdPrice} - isLoading={this.props.isLoading} + <Container marginBottom="10px">{this._renderHeader()}</Container> + {shouldShowUsdError ? this._renderErrorFetchingUsdPrice() : this._renderRows()} + </Container> + ); + } + + private _renderRows(): React.ReactNode { + const { buyQuoteInfo } = this.props; + return ( + <React.Fragment> + <OrderDetailsRow + labelText={this._assetAmountLabel()} + primaryValue={this._displayAmountOrPlaceholder(buyQuoteInfo && buyQuoteInfo.assetEthAmount)} /> - <EthAmountRow - rowLabel="Fee" - ethAmount={feeEthBaseUnitAmount} - ethUsdPrice={ethUsdPrice} - isLoading={this.props.isLoading} + <OrderDetailsRow + labelText="Fee" + primaryValue={this._displayAmountOrPlaceholder(buyQuoteInfo && buyQuoteInfo.feeEthAmount)} /> - <EthAmountRow - rowLabel="Total Cost" - ethAmount={totalEthBaseUnitAmount} - ethUsdPrice={ethUsdPrice} - shouldEmphasize={true} - isLoading={this.props.isLoading} + <OrderDetailsRow + labelText="Total Cost" + isLabelBold={true} + primaryValue={this._displayAmountOrPlaceholder(buyQuoteInfo && buyQuoteInfo.totalEthAmount)} + isPrimaryValueBold={true} + secondaryValue={this._totalCostSecondaryValue()} /> - </Container> + </React.Fragment> ); } -} -export interface EthAmountRowProps { - rowLabel: string; - ethAmount?: BigNumber; - isEthAmountInBaseUnits?: boolean; - ethUsdPrice?: BigNumber; - shouldEmphasize?: boolean; - isLoading: boolean; + private _renderErrorFetchingUsdPrice(): React.ReactNode { + return ( + <Text> + There was an error fetching the USD price. + <Text + onClick={this.props.onBaseCurrencySwitchEth} + fontWeight={700} + fontColor={ColorOption.primaryColor} + > + Click here + </Text> + {' to view ETH prices'} + </Text> + ); + } + + private _hadErrorFetchingUsdPrice(): boolean { + return this.props.ethUsdPrice ? this.props.ethUsdPrice.equals(BIG_NUMBER_ZERO) : false; + } + + private _totalCostSecondaryValue(): React.ReactNode { + const secondaryCurrency = this.props.baseCurrency === BaseCurrency.USD ? BaseCurrency.ETH : BaseCurrency.USD; + + const canDisplayCurrency = + secondaryCurrency === BaseCurrency.ETH || + (secondaryCurrency === BaseCurrency.USD && this.props.ethUsdPrice && !this._hadErrorFetchingUsdPrice()); + + if (this.props.buyQuoteInfo && canDisplayCurrency) { + return this._displayAmount(secondaryCurrency, this.props.buyQuoteInfo.totalEthAmount); + } else { + return undefined; + } + } + + private _displayAmountOrPlaceholder(weiAmount?: BigNumber): React.ReactNode { + const { baseCurrency, isLoading } = this.props; + + if (_.isUndefined(weiAmount)) { + return ( + <Container opacity={0.5}> + <AmountPlaceholder color={ColorOption.lightGrey} isPulsating={isLoading} /> + </Container> + ); + } + + return this._displayAmount(baseCurrency, weiAmount); + } + + private _displayAmount(currency: BaseCurrency, weiAmount: BigNumber): React.ReactNode { + switch (currency) { + case BaseCurrency.USD: + return format.ethBaseUnitAmountInUsd(weiAmount, this.props.ethUsdPrice, 2, ''); + case BaseCurrency.ETH: + return format.ethBaseUnitAmount(weiAmount, 4, ''); + } + } + + private _assetAmountLabel(): React.ReactNode { + const { assetName, baseCurrency } = this.props; + const numTokens = this.props.selectedAssetUnitAmount; + + // Display as 0 if we have a selected asset + const displayNumTokens = + assetName && assetName !== DEFAULT_UNKOWN_ASSET_NAME && _.isUndefined(numTokens) + ? new BigNumber(0) + : numTokens; + if (!_.isUndefined(displayNumTokens)) { + let numTokensWithSymbol: React.ReactNode = displayNumTokens.toString(); + if (assetName) { + numTokensWithSymbol += ` ${assetName}`; + } + const pricePerTokenWei = this._pricePerTokenWei(); + if (pricePerTokenWei) { + const atPriceDisplay = ( + <Text fontColor={ColorOption.lightGrey}> + @ {this._displayAmount(baseCurrency, pricePerTokenWei)} + </Text> + ); + numTokensWithSymbol = ( + <React.Fragment> + {numTokensWithSymbol} {atPriceDisplay} + </React.Fragment> + ); + } + return numTokensWithSymbol; + } + return 'Token Amount'; + } + + private _pricePerTokenWei(): BigNumber | undefined { + const buyQuoteAccessor = oc(this.props.buyQuoteInfo); + const assetTotalInWei = buyQuoteAccessor.assetEthAmount(); + const selectedAssetUnitAmount = this.props.selectedAssetUnitAmount; + return !_.isUndefined(assetTotalInWei) && + !_.isUndefined(selectedAssetUnitAmount) && + !selectedAssetUnitAmount.eq(BIG_NUMBER_ZERO) + ? assetTotalInWei.div(selectedAssetUnitAmount).ceil() + : undefined; + } + + private _baseCurrencyChoice(choice: BaseCurrency): React.ReactNode { + const onClick = + choice === BaseCurrency.ETH ? this.props.onBaseCurrencySwitchEth : this.props.onBaseCurrencySwitchUsd; + const isSelected = this.props.baseCurrency === choice; + + const textStyle: TextProps = { onClick, fontSize: '12px' }; + if (isSelected) { + textStyle.fontColor = ColorOption.primaryColor; + textStyle.fontWeight = 700; + } else { + textStyle.fontColor = ColorOption.lightGrey; + } + return <Text {...textStyle}>{choice}</Text>; + } + + private _renderHeader(): React.ReactNode { + return ( + <Flex justify="space-between"> + <SectionHeader>Order Details</SectionHeader> + <Container> + {this._baseCurrencyChoice(BaseCurrency.ETH)} + <Container marginLeft="5px" marginRight="5px" display="inline"> + <Text fontSize="12px" fontColor={ColorOption.feintGrey}> + / + </Text> + </Container> + {this._baseCurrencyChoice(BaseCurrency.USD)} + </Container> + </Flex> + ); + } } -export class EthAmountRow extends React.Component<EthAmountRowProps> { - public static defaultProps = { - shouldEmphasize: false, - isEthAmountInBaseUnits: true, - }; +export interface OrderDetailsRowProps { + labelText: React.ReactNode; + isLabelBold?: boolean; + isPrimaryValueBold?: boolean; + primaryValue: React.ReactNode; + secondaryValue?: React.ReactNode; +} +export class OrderDetailsRow extends React.Component<OrderDetailsRowProps, {}> { public render(): React.ReactNode { - const { rowLabel, ethAmount, isEthAmountInBaseUnits, shouldEmphasize, isLoading } = this.props; - - const fontWeight = shouldEmphasize ? 700 : 400; - const ethFormatter = isEthAmountInBaseUnits ? format.ethBaseUnitAmount : format.ethUnitAmount; return ( <Container padding="10px 0px" borderTop="1px dashed" borderColor={ColorOption.feintGrey}> <Flex justify="space-between"> - <Text fontWeight={fontWeight} fontColor={ColorOption.grey}> - {rowLabel} + <Text fontWeight={this.props.isLabelBold ? 700 : 400} fontColor={ColorOption.grey}> + {this.props.labelText} </Text> - <Container> - {this._renderUsdSection()} - <Text fontWeight={fontWeight} fontColor={ColorOption.grey}> - {ethFormatter( - ethAmount, - 4, - <Container opacity={0.5}> - <AmountPlaceholder color={ColorOption.lightGrey} isPulsating={isLoading} /> - </Container>, - )} - </Text> - </Container> + <Container>{this._renderValues()}</Container> </Flex> </Container> ); } - private _renderUsdSection(): React.ReactNode { - const usdFormatter = this.props.isEthAmountInBaseUnits - ? format.ethBaseUnitAmountInUsd - : format.ethUnitAmountInUsd; - const shouldHideUsdPriceSection = _.isUndefined(this.props.ethUsdPrice) || _.isUndefined(this.props.ethAmount); - return shouldHideUsdPriceSection ? null : ( + + private _renderValues(): React.ReactNode { + const secondaryValueNode: React.ReactNode = this.props.secondaryValue && ( <Container marginRight="3px" display="inline-block"> - <Text fontColor={ColorOption.lightGrey}> - ({usdFormatter(this.props.ethAmount, this.props.ethUsdPrice)}) - </Text> + <Text fontColor={ColorOption.lightGrey}>({this.props.secondaryValue})</Text> </Container> ); + return ( + <React.Fragment> + {secondaryValueNode} + <Text fontWeight={this.props.isPrimaryValueBold ? 700 : 400}>{this.props.primaryValue}</Text> + </React.Fragment> + ); } } diff --git a/packages/instant/src/components/payment_method.tsx b/packages/instant/src/components/payment_method.tsx index 7c93f1d1c..abadf4bd6 100644 --- a/packages/instant/src/components/payment_method.tsx +++ b/packages/instant/src/components/payment_method.tsx @@ -8,6 +8,7 @@ import { envUtil } from '../util/env'; import { CoinbaseWalletLogo } from './coinbase_wallet_logo'; import { MetaMaskLogo } from './meta_mask_logo'; import { PaymentMethodDropdown } from './payment_method_dropdown'; +import { SectionHeader } from './section_header'; import { Circle } from './ui/circle'; import { Container } from './ui/container'; import { Flex } from './ui/flex'; @@ -29,15 +30,7 @@ export class PaymentMethod extends React.Component<PaymentMethodProps> { <Container width="100%" height="120px" padding="20px 20px 0px 20px"> <Container marginBottom="12px"> <Flex justify="space-between"> - <Text - letterSpacing="1px" - fontColor={ColorOption.primaryColor} - fontWeight={600} - textTransform="uppercase" - fontSize="14px" - > - {this._renderTitleText()} - </Text> + <SectionHeader>{this._renderTitleText()}</SectionHeader> {this._renderTitleLabel()} </Flex> </Container> diff --git a/packages/instant/src/components/section_header.tsx b/packages/instant/src/components/section_header.tsx new file mode 100644 index 000000000..d0974ebdc --- /dev/null +++ b/packages/instant/src/components/section_header.tsx @@ -0,0 +1,20 @@ +import * as React from 'react'; + +import { ColorOption } from '../style/theme'; + +import { Text } from './ui/text'; + +export interface SectionHeaderProps {} +export const SectionHeader: React.StatelessComponent<SectionHeaderProps> = props => { + return ( + <Text + letterSpacing="1px" + fontColor={ColorOption.primaryColor} + fontWeight={600} + textTransform="uppercase" + fontSize="12px" + > + {props.children} + </Text> + ); +}; diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index 204115fa9..2de327cd7 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -122,6 +122,7 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider window, state.selectedAsset, this.props.affiliateInfo, + state.baseCurrency, ), ); analytics.trackInstantOpened(); diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index 2417c8615..67558c84a 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -18,6 +18,7 @@ export const GIT_SHA = process.env.GIT_SHA; export const NODE_ENV = process.env.NODE_ENV; export const SLIPPAGE_PERCENTAGE = 0.2; export const NPM_PACKAGE_VERSION = process.env.NPM_PACKAGE_VERSION; +export const DEFAULT_UNKOWN_ASSET_NAME = '???'; 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); @@ -72,5 +73,6 @@ export const PROVIDER_TYPE_TO_NAME: { [key in ProviderType]: string } = { [ProviderType.Mist]: 'Mist', [ProviderType.CoinbaseWallet]: 'Coinbase Wallet', [ProviderType.Parity]: 'Parity', + [ProviderType.TrustWallet]: 'Trust Wallet', [ProviderType.Fallback]: 'Fallback', }; diff --git a/packages/instant/src/containers/latest_buy_quote_order_details.ts b/packages/instant/src/containers/latest_buy_quote_order_details.ts index 5dfe535e7..148735c47 100644 --- a/packages/instant/src/containers/latest_buy_quote_order_details.ts +++ b/packages/instant/src/containers/latest_buy_quote_order_details.ts @@ -1,32 +1,41 @@ -import { BuyQuoteInfo } from '@0x/asset-buyer'; -import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; import * as React from 'react'; import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; import { oc } from 'ts-optchain'; +import { Action, actions } from '../redux/actions'; import { State } from '../redux/reducer'; -import { OrderDetails } from '../components/order_details'; -import { AsyncProcessState } from '../types'; +import { OrderDetails, OrderDetailsProps } from '../components/order_details'; +import { AsyncProcessState, BaseCurrency, Omit } from '../types'; +import { assetUtils } from '../util/asset'; -export interface LatestBuyQuoteOrderDetailsProps {} - -interface ConnectedState { - buyQuoteInfo?: BuyQuoteInfo; - selectedAssetUnitAmount?: BigNumber; - ethUsdPrice?: BigNumber; - isLoading: boolean; -} +type DispatchProperties = 'onBaseCurrencySwitchEth' | 'onBaseCurrencySwitchUsd'; +interface ConnectedState extends Omit<OrderDetailsProps, DispatchProperties> {} const mapStateToProps = (state: State, _ownProps: LatestBuyQuoteOrderDetailsProps): ConnectedState => ({ // use the worst case quote info buyQuoteInfo: oc(state).latestBuyQuote.worstCaseQuoteInfo(), selectedAssetUnitAmount: state.selectedAssetUnitAmount, ethUsdPrice: state.ethUsdPrice, isLoading: state.quoteRequestState === AsyncProcessState.Pending, + assetName: assetUtils.bestNameForAsset(state.selectedAsset), + baseCurrency: state.baseCurrency, }); +interface ConnectedDispatch extends Pick<OrderDetailsProps, DispatchProperties> {} +const mapDispatchToProps = (dispatch: Dispatch<Action>): ConnectedDispatch => ({ + onBaseCurrencySwitchEth: () => { + dispatch(actions.updateBaseCurrency(BaseCurrency.ETH)); + }, + onBaseCurrencySwitchUsd: () => { + dispatch(actions.updateBaseCurrency(BaseCurrency.USD)); + }, +}); + +export interface LatestBuyQuoteOrderDetailsProps {} export const LatestBuyQuoteOrderDetails: React.ComponentClass<LatestBuyQuoteOrderDetailsProps> = connect( mapStateToProps, + mapDispatchToProps, )(OrderDetails); diff --git a/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts b/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts index 80943a96f..4da99cf04 100644 --- a/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts +++ b/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts @@ -95,6 +95,9 @@ const mapDispatchToProps = ( if (error === ZeroExInstantError.InsufficientETH) { const errorMessage = "You don't have enough ETH"; errorFlasher.flashNewErrorMessage(dispatch, errorMessage); + } else if (error === ZeroExInstantError.CouldNotSubmitTransaction) { + const errorMessage = 'Could not submit transaction'; + errorFlasher.flashNewErrorMessage(dispatch, errorMessage); } else { errorFlasher.flashNewErrorMessage(dispatch); } diff --git a/packages/instant/src/redux/actions.ts b/packages/instant/src/redux/actions.ts index 77e3dec12..9d7a61fc7 100644 --- a/packages/instant/src/redux/actions.ts +++ b/packages/instant/src/redux/actions.ts @@ -2,7 +2,7 @@ import { BuyQuote } from '@0x/asset-buyer'; import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; -import { ActionsUnion, AddressAndEthBalanceInWei, Asset, StandardSlidingPanelContent } from '../types'; +import { ActionsUnion, AddressAndEthBalanceInWei, Asset, BaseCurrency, StandardSlidingPanelContent } from '../types'; export interface PlainAction<T extends string> { type: T; @@ -43,6 +43,7 @@ export enum ActionTypes { RESET_AMOUNT = 'RESET_AMOUNT', OPEN_STANDARD_SLIDING_PANEL = 'OPEN_STANDARD_SLIDING_PANEL', CLOSE_STANDARD_SLIDING_PANEL = 'CLOSE_STANDARD_SLIDING_PANEL', + UPDATE_BASE_CURRENCY = 'UPDATE_BASE_CURRENCY', } export const actions = { @@ -72,4 +73,5 @@ export const actions = { openStandardSlidingPanel: (content: StandardSlidingPanelContent) => createAction(ActionTypes.OPEN_STANDARD_SLIDING_PANEL, content), closeStandardSlidingPanel: () => createAction(ActionTypes.CLOSE_STANDARD_SLIDING_PANEL), + updateBaseCurrency: (baseCurrency: BaseCurrency) => createAction(ActionTypes.UPDATE_BASE_CURRENCY, baseCurrency), }; diff --git a/packages/instant/src/redux/analytics_middleware.ts b/packages/instant/src/redux/analytics_middleware.ts index 3f7a51707..a86a16b1a 100644 --- a/packages/instant/src/redux/analytics_middleware.ts +++ b/packages/instant/src/redux/analytics_middleware.ts @@ -99,6 +99,9 @@ export const analyticsMiddleware: Middleware = store => next => middlewareAction analytics.trackInstallWalletModalClosed(); } break; + case ActionTypes.UPDATE_BASE_CURRENCY: + analytics.trackBaseCurrencyChanged(curState.baseCurrency); + analytics.addEventProperties({ baseCurrency: curState.baseCurrency }); } return nextAction; diff --git a/packages/instant/src/redux/async_data.ts b/packages/instant/src/redux/async_data.ts index 932eb93e9..884ab103d 100644 --- a/packages/instant/src/redux/async_data.ts +++ b/packages/instant/src/redux/async_data.ts @@ -4,7 +4,7 @@ import * as _ from 'lodash'; import { Dispatch } from 'redux'; import { BIG_NUMBER_ZERO } from '../constants'; -import { AccountState, ERC20Asset, OrderProcessState, ProviderState, QuoteFetchOrigin } from '../types'; +import { AccountState, BaseCurrency, ERC20Asset, OrderProcessState, ProviderState, QuoteFetchOrigin } from '../types'; import { analytics } from '../util/analytics'; import { assetUtils } from '../util/asset'; import { buyQuoteUpdater } from '../util/buy_quote_updater'; @@ -24,7 +24,9 @@ export const asyncData = { const errorMessage = 'Error fetching ETH/USD price'; errorFlasher.flashNewErrorMessage(dispatch, errorMessage); dispatch(actions.updateEthUsdPrice(BIG_NUMBER_ZERO)); + dispatch(actions.updateBaseCurrency(BaseCurrency.ETH)); errorReporter.report(e); + analytics.trackUsdPriceFailed(); } }, fetchAvailableAssetDatasAndDispatchToStore: async (state: State, dispatch: Dispatch) => { diff --git a/packages/instant/src/redux/reducer.ts b/packages/instant/src/redux/reducer.ts index a9a407b7d..8c13c9c72 100644 --- a/packages/instant/src/redux/reducer.ts +++ b/packages/instant/src/redux/reducer.ts @@ -14,6 +14,7 @@ import { Asset, AssetMetaData, AsyncProcessState, + BaseCurrency, DisplayStatus, Network, OrderProcessState, @@ -33,6 +34,7 @@ export interface DefaultState { latestErrorDisplayStatus: DisplayStatus; quoteRequestState: AsyncProcessState; standardSlidingPanelSettings: StandardSlidingPanelSettings; + baseCurrency: BaseCurrency; } // State that is required but needs to be derived from the props @@ -64,6 +66,7 @@ export const DEFAULT_STATE: DefaultState = { animationState: 'none', content: StandardSlidingPanelContent.None, }, + baseCurrency: BaseCurrency.USD, }; export const createReducer = (initialState: State) => { @@ -243,6 +246,11 @@ export const createReducer = (initialState: State) => { animationState: 'slidOut', }, }; + case ActionTypes.UPDATE_BASE_CURRENCY: + return { + ...state, + baseCurrency: action.data, + }; default: return state; } diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts index 1c7490e63..ae672c919 100644 --- a/packages/instant/src/types.ts +++ b/packages/instant/src/types.ts @@ -26,6 +26,11 @@ export enum QuoteFetchOrigin { Heartbeat = 'Heartbeat', } +export enum BaseCurrency { + USD = 'USD', + ETH = 'ETH', +} + export interface SimulatedProgress { startTimeUnix: number; expectedEndTimeUnix: number; @@ -91,6 +96,7 @@ export enum Network { export enum ZeroExInstantError { AssetMetaDataNotAvailable = 'ASSET_META_DATA_NOT_AVAILABLE', InsufficientETH = 'INSUFFICIENT_ETH', + CouldNotSubmitTransaction = 'COULD_NOT_SUBMIT_TRANSACTION', } export type SimpleHandler = () => void; @@ -176,6 +182,7 @@ export enum ProviderType { Mist = 'MIST', CoinbaseWallet = 'COINBASE_WALLET', Cipher = 'CIPHER', + TrustWallet = 'TRUST_WALLET', Fallback = 'FALLBACK', } diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index e6128f857..4faeaaf5a 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -6,6 +6,7 @@ import { GIT_SHA, HEAP_ENABLED, INSTANT_DISCHARGE_TARGET, NODE_ENV, NPM_PACKAGE_ import { AffiliateInfo, Asset, + BaseCurrency, Network, OrderProcessState, OrderSource, @@ -37,6 +38,7 @@ enum EventNames { ACCOUNT_UNLOCK_REQUESTED = 'Account - Unlock Requested', ACCOUNT_UNLOCK_DENIED = 'Account - Unlock Denied', ACCOUNT_ADDRESS_CHANGED = 'Account - Address Changed', + BASE_CURRENCY_CHANGED = 'Base Currency - Changed', PAYMENT_METHOD_DROPDOWN_OPENED = 'Payment Method - Dropdown Opened', PAYMENT_METHOD_OPENED_ETHERSCAN = 'Payment Method - Opened Etherscan', PAYMENT_METHOD_COPIED_ADDRESS = 'Payment Method - Copied Address', @@ -44,9 +46,11 @@ enum EventNames { BUY_STARTED = 'Buy - Started', BUY_SIGNATURE_DENIED = 'Buy - Signature Denied', BUY_SIMULATION_FAILED = 'Buy - Simulation Failed', + BUY_UNKNOWN_ERROR = 'Buy - Unknown Error', BUY_TX_SUBMITTED = 'Buy - Tx Submitted', BUY_TX_SUCCEEDED = 'Buy - Tx Succeeded', BUY_TX_FAILED = 'Buy - Tx Failed', + USD_PRICE_FETCH_FAILED = 'USD Price - Fetch Failed', INSTALL_WALLET_CLICKED = 'Install Wallet - Clicked', INSTALL_WALLET_MODAL_OPENED = 'Install Wallet - Modal - Opened', INSTALL_WALLET_MODAL_CLICKED_EXPLANATION = 'Install Wallet - Modal - Clicked Explanation', @@ -118,6 +122,7 @@ export interface AnalyticsEventOptions { selectedAssetSymbol?: string; selectedAssetData?: string; selectedAssetDecimals?: number; + baseCurrency?: string; } export enum TokenSelectorClosedVia { ClickedX = 'Clicked X', @@ -141,6 +146,7 @@ export const analytics = { window: Window, selectedAsset?: Asset, affiliateInfo?: AffiliateInfo, + baseCurrency?: BaseCurrency, ): AnalyticsEventOptions => { const affiliateAddress = affiliateInfo ? affiliateInfo.feeRecipient : 'none'; const affiliateFeePercent = affiliateInfo ? parseFloat(affiliateInfo.feePercentage.toFixed(4)) : 0; @@ -159,6 +165,7 @@ export const analytics = { selectedAssetName: selectedAsset ? selectedAsset.metaData.name : 'none', selectedAssetData: selectedAsset ? selectedAsset.assetData : 'none', instantEnvironment: INSTANT_DISCHARGE_TARGET || `Local ${NODE_ENV}`, + baseCurrency, }; return eventOptions; }, @@ -170,6 +177,8 @@ export const analytics = { trackAccountUnlockDenied: trackingEventFnWithoutPayload(EventNames.ACCOUNT_UNLOCK_DENIED), trackAccountAddressChanged: (address: string) => trackingEventFnWithPayload(EventNames.ACCOUNT_ADDRESS_CHANGED)({ address }), + trackBaseCurrencyChanged: (currencyChangedTo: BaseCurrency) => + trackingEventFnWithPayload(EventNames.BASE_CURRENCY_CHANGED)({ currencyChangedTo }), trackPaymentMethodDropdownOpened: trackingEventFnWithoutPayload(EventNames.PAYMENT_METHOD_DROPDOWN_OPENED), trackPaymentMethodOpenedEtherscan: trackingEventFnWithoutPayload(EventNames.PAYMENT_METHOD_OPENED_ETHERSCAN), trackPaymentMethodCopiedAddress: trackingEventFnWithoutPayload(EventNames.PAYMENT_METHOD_COPIED_ADDRESS), @@ -181,6 +190,11 @@ export const analytics = { trackingEventFnWithPayload(EventNames.BUY_SIGNATURE_DENIED)(buyQuoteEventProperties(buyQuote)), trackBuySimulationFailed: (buyQuote: BuyQuote) => trackingEventFnWithPayload(EventNames.BUY_SIMULATION_FAILED)(buyQuoteEventProperties(buyQuote)), + trackBuyUnknownError: (buyQuote: BuyQuote, errorMessage: string) => + trackingEventFnWithPayload(EventNames.BUY_UNKNOWN_ERROR)({ + ...buyQuoteEventProperties(buyQuote), + errorMessage, + }), trackBuyTxSubmitted: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => trackingEventFnWithPayload(EventNames.BUY_TX_SUBMITTED)({ ...buyQuoteEventProperties(buyQuote), @@ -230,4 +244,5 @@ export const analytics = { fetchOrigin, }); }, + trackUsdPriceFailed: trackingEventFnWithoutPayload(EventNames.USD_PRICE_FETCH_FAILED), }; diff --git a/packages/instant/src/util/asset.ts b/packages/instant/src/util/asset.ts index 756194f1f..e7aa55c88 100644 --- a/packages/instant/src/util/asset.ts +++ b/packages/instant/src/util/asset.ts @@ -4,7 +4,7 @@ import { BigNumber } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import * as _ from 'lodash'; -import { BIG_NUMBER_ZERO } from '../constants'; +import { BIG_NUMBER_ZERO, DEFAULT_UNKOWN_ASSET_NAME } from '../constants'; import { assetDataNetworkMapping } from '../data/asset_data_network_mapping'; import { Asset, AssetMetaData, ERC20Asset, Network, ZeroExInstantError } from '../types'; @@ -74,7 +74,7 @@ export const assetUtils = { } return metaData; }, - bestNameForAsset: (asset?: Asset, defaultName: string = '???'): string => { + bestNameForAsset: (asset?: Asset, defaultName: string = DEFAULT_UNKOWN_ASSET_NAME): string => { if (_.isUndefined(asset)) { return defaultName; } diff --git a/packages/instant/src/util/env.ts b/packages/instant/src/util/env.ts index 0fda0cc0e..aedf4f5d6 100644 --- a/packages/instant/src/util/env.ts +++ b/packages/instant/src/util/env.ts @@ -44,6 +44,8 @@ export const envUtil = { getProviderType(provider: Provider): ProviderType | undefined { if (provider.constructor.name === 'EthereumProvider') { return ProviderType.Mist; + } else if ((provider as any).isTrust) { + return ProviderType.TrustWallet; } else if ((provider as any).isParity) { return ProviderType.Parity; } else if ((provider as any).isMetaMask) { diff --git a/packages/instant/src/util/format.ts b/packages/instant/src/util/format.ts index e9c432b2f..4adb63e21 100644 --- a/packages/instant/src/util/format.ts +++ b/packages/instant/src/util/format.ts @@ -2,7 +2,7 @@ import { BigNumber } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import * as _ from 'lodash'; -import { ETH_DECIMALS } from '../constants'; +import { BIG_NUMBER_ZERO, ETH_DECIMALS } from '../constants'; export const format = { ethBaseUnitAmount: ( @@ -20,24 +20,38 @@ export const format = { ethUnitAmount?: BigNumber, decimalPlaces: number = 4, defaultText: React.ReactNode = '0 ETH', + minUnitAmountToDisplay: BigNumber = new BigNumber('0.00001'), ): React.ReactNode => { if (_.isUndefined(ethUnitAmount)) { return defaultText; } - const roundedAmount = ethUnitAmount.round(decimalPlaces).toDigits(decimalPlaces); - return `${roundedAmount} ETH`; + let roundedAmount = ethUnitAmount.round(decimalPlaces).toDigits(decimalPlaces); + + if (roundedAmount.eq(BIG_NUMBER_ZERO) && ethUnitAmount.greaterThan(BIG_NUMBER_ZERO)) { + // Sometimes for small ETH amounts (i.e. 0.000045) the amount rounded to 4 decimalPlaces is 0 + // If that is the case, show to 1 significant digit + roundedAmount = new BigNumber(ethUnitAmount.toPrecision(1)); + } + + const displayAmount = + roundedAmount.greaterThan(BIG_NUMBER_ZERO) && roundedAmount.lessThan(minUnitAmountToDisplay) + ? `< ${minUnitAmountToDisplay.toString()}` + : roundedAmount.toString(); + + return `${displayAmount} ETH`; }, ethBaseUnitAmountInUsd: ( ethBaseUnitAmount?: BigNumber, ethUsdPrice?: BigNumber, decimalPlaces: number = 2, defaultText: React.ReactNode = '$0.00', + minUnitAmountToDisplay: BigNumber = new BigNumber('0.00001'), ): React.ReactNode => { if (_.isUndefined(ethBaseUnitAmount) || _.isUndefined(ethUsdPrice)) { return defaultText; } const ethUnitAmount = Web3Wrapper.toUnitAmount(ethBaseUnitAmount, ETH_DECIMALS); - return format.ethUnitAmountInUsd(ethUnitAmount, ethUsdPrice, decimalPlaces); + return format.ethUnitAmountInUsd(ethUnitAmount, ethUsdPrice, decimalPlaces, minUnitAmountToDisplay); }, ethUnitAmountInUsd: ( ethUnitAmount?: BigNumber, @@ -48,7 +62,13 @@ export const format = { if (_.isUndefined(ethUnitAmount) || _.isUndefined(ethUsdPrice)) { return defaultText; } - return `$${ethUnitAmount.mul(ethUsdPrice).toFixed(decimalPlaces)}`; + const rawUsdPrice = ethUnitAmount.mul(ethUsdPrice); + const roundedUsdPrice = rawUsdPrice.toFixed(decimalPlaces); + if (roundedUsdPrice === '0.00' && rawUsdPrice.gt(BIG_NUMBER_ZERO)) { + return '<$0.01'; + } else { + return `$${roundedUsdPrice}`; + } }, ethAddress: (address: string): string => { return `0x${address.slice(2, 7)}…${address.slice(-5)}`; diff --git a/packages/instant/test/util/format.test.ts b/packages/instant/test/util/format.test.ts index fe0a63e6e..38bf356ec 100644 --- a/packages/instant/test/util/format.test.ts +++ b/packages/instant/test/util/format.test.ts @@ -41,6 +41,18 @@ describe('format', () => { it('converts BigNumber(5.3014059295032) to the string `5.301 ETH`', () => { expect(format.ethUnitAmount(BIG_NUMBER_IRRATIONAL)).toBe('5.301 ETH'); }); + it('shows 1 significant digit when rounded amount would be 0', () => { + expect(format.ethUnitAmount(new BigNumber(0.00003))).toBe('0.00003 ETH'); + expect(format.ethUnitAmount(new BigNumber(0.000034))).toBe('0.00003 ETH'); + expect(format.ethUnitAmount(new BigNumber(0.000035))).toBe('0.00004 ETH'); + }); + it('shows < 0.00001 when hits threshold', () => { + expect(format.ethUnitAmount(new BigNumber(0.000011))).toBe('0.00001 ETH'); + expect(format.ethUnitAmount(new BigNumber(0.00001))).toBe('0.00001 ETH'); + expect(format.ethUnitAmount(new BigNumber(0.000009))).toBe('< 0.00001 ETH'); + expect(format.ethUnitAmount(new BigNumber(0.0000000009))).toBe('< 0.00001 ETH'); + expect(format.ethUnitAmount(new BigNumber(0))).toBe('0 ETH'); + }); it('returns defaultText param when ethUnitAmount is not defined', () => { const defaultText = 'defaultText'; expect(format.ethUnitAmount(undefined, 4, defaultText)).toBe(defaultText); @@ -86,6 +98,12 @@ describe('format', () => { it('correctly formats 5.3014059295032 ETH to usd according to some price', () => { expect(format.ethUnitAmountInUsd(BIG_NUMBER_IRRATIONAL, BIG_NUMBER_FAKE_ETH_USD_PRICE)).toBe('$13.43'); }); + it('correctly formats amount that is less than 1 cent', () => { + expect(format.ethUnitAmountInUsd(new BigNumber(0.000001), BIG_NUMBER_FAKE_ETH_USD_PRICE)).toBe('<$0.01'); + }); + it('correctly formats exactly 1 cent', () => { + expect(format.ethUnitAmountInUsd(new BigNumber(0.0039), BIG_NUMBER_FAKE_ETH_USD_PRICE)).toBe('$0.01'); + }); it('returns defaultText param when ethUnitAmountInUsd or ethUsdPrice is not defined', () => { const defaultText = 'defaultText'; expect(format.ethUnitAmountInUsd(undefined, undefined, 2, defaultText)).toBe(defaultText); diff --git a/packages/json-schemas/schemas/order_watcher_web_socket_request_schema.json b/packages/json-schemas/schemas/order_watcher_web_socket_request_schema.json new file mode 100644 index 000000000..b0c419f94 --- /dev/null +++ b/packages/json-schemas/schemas/order_watcher_web_socket_request_schema.json @@ -0,0 +1,52 @@ +{ + "id": "/orderWatcherWebSocketRequestSchema", + "type": "object", + "definitions": { + "signedOrderParam": { + "type": "object", + "properties": { + "signedOrder": { "$ref": "/signedOrderSchema" } + }, + "required": ["signedOrder"] + }, + "orderHashParam": { + "type": "object", + "properties": { + "orderHash": { "$ref": "/hexSchema" } + }, + "required": ["orderHash"] + } + }, + "oneOf": [ + { + "type": "object", + "properties": { + "id": { "type": "number" }, + "jsonrpc": { "type": "string" }, + "method": { "enum": ["ADD_ORDER"] }, + "params": { "$ref": "#/definitions/signedOrderParam" } + }, + "required": ["id", "jsonrpc", "method", "params"] + }, + { + "type": "object", + "properties": { + "id": { "type": "number" }, + "jsonrpc": { "type": "string" }, + "method": { "enum": ["REMOVE_ORDER"] }, + "params": { "$ref": "#/definitions/orderHashParam" } + }, + "required": ["id", "jsonrpc", "method", "params"] + }, + { + "type": "object", + "properties": { + "id": { "type": "number" }, + "jsonrpc": { "type": "string" }, + "method": { "enum": ["GET_STATS"] }, + "params": {} + }, + "required": ["id", "jsonrpc", "method"] + } + ] +}
\ No newline at end of file diff --git a/packages/json-schemas/schemas/order_watcher_web_socket_utf8_message_schema.json b/packages/json-schemas/schemas/order_watcher_web_socket_utf8_message_schema.json new file mode 100644 index 000000000..154d6d754 --- /dev/null +++ b/packages/json-schemas/schemas/order_watcher_web_socket_utf8_message_schema.json @@ -0,0 +1,10 @@ +{ + "id": "/orderWatcherWebSocketUtf8MessageSchema", + "properties": { + "utf8Data": { "type": "string" } + }, + "required": [ + "utf8Data" + ], + "type": "object" +} diff --git a/packages/json-schemas/src/schemas.ts b/packages/json-schemas/src/schemas.ts index 21a6f424c..050f4e625 100644 --- a/packages/json-schemas/src/schemas.ts +++ b/packages/json-schemas/src/schemas.ts @@ -16,6 +16,8 @@ import * as orderFillOrKillRequestsSchema from '../schemas/order_fill_or_kill_re import * as orderFillRequestsSchema from '../schemas/order_fill_requests_schema.json'; import * as orderHashSchema from '../schemas/order_hash_schema.json'; import * as orderSchema from '../schemas/order_schema.json'; +import * as orderWatcherWebSocketRequestSchema from '../schemas/order_watcher_web_socket_request_schema.json'; +import * as orderWatcherWebSocketUtf8MessageSchema from '../schemas/order_watcher_web_socket_utf8_message_schema.json'; import * as orderBookRequestSchema from '../schemas/orderbook_request_schema.json'; import * as ordersRequestOptsSchema from '../schemas/orders_request_opts_schema.json'; import * as ordersSchema from '../schemas/orders_schema.json'; @@ -66,6 +68,8 @@ export const schemas = { jsNumber, requestOptsSchema, pagedRequestOptsSchema, + orderWatcherWebSocketRequestSchema, + orderWatcherWebSocketUtf8MessageSchema, ordersRequestOptsSchema, orderBookRequestSchema, orderConfigRequestSchema, diff --git a/packages/json-schemas/tsconfig.json b/packages/json-schemas/tsconfig.json index a79d54385..ec573290c 100644 --- a/packages/json-schemas/tsconfig.json +++ b/packages/json-schemas/tsconfig.json @@ -23,6 +23,8 @@ "./schemas/order_schema.json", "./schemas/signed_order_schema.json", "./schemas/orders_schema.json", + "./schemas/order_watcher_web_socket_request_schema.json", + "./schemas/order_watcher_web_socket_utf8_message_schema.json", "./schemas/paginated_collection_schema.json", "./schemas/relayer_api_asset_data_pairs_response_schema.json", "./schemas/relayer_api_asset_data_pairs_schema.json", diff --git a/packages/order-watcher/CHANGELOG.json b/packages/order-watcher/CHANGELOG.json index c1fd8d4a9..304dc45fd 100644 --- a/packages/order-watcher/CHANGELOG.json +++ b/packages/order-watcher/CHANGELOG.json @@ -1,5 +1,15 @@ [ { + "version": "2.3.0", + "changes": [ + { + "note": + "Added a WebSocket interface to OrderWatcher so that it can be used by a client written in any language", + "pr": 1427 + } + ] + }, + { "version": "2.2.8", "changes": [ { diff --git a/packages/order-watcher/README.md b/packages/order-watcher/README.md index c0b99b272..385fe4715 100644 --- a/packages/order-watcher/README.md +++ b/packages/order-watcher/README.md @@ -4,6 +4,9 @@ An order watcher daemon that watches for order validity. #### Read the wiki [article](https://0xproject.com/wiki#0x-OrderWatcher). +OrderWatcher also comes with a WebSocket server to provide language-agnostic access +to order watching functionality. We used the [WebSocket Client and Server Implementation for Node](https://www.npmjs.com/package/websocket). The server sends and receives messages that conform to the [JSON RPC specifications](https://www.jsonrpc.org/specification). + ## Installation **Install** @@ -26,6 +29,91 @@ If your project is in [TypeScript](https://www.typescriptlang.org/), add the fol } ``` +## Using the WebSocket Server + +**Setup** + +**Environmental Variables** +Several environmental variables can be set to configure the server: + +* `ORDER_WATCHER_HTTP_PORT` specifies the port that the http server will listen on + and accept connections from. When this is not set, we default to 8080. + +**Requests** +The server accepts three types of requests: `ADD_ORDER`, `REMOVE_ORDER` and `GET_STATS`. These mirror what the underlying OrderWatcher does. You can read more in the [wiki](https://0xproject.com/wiki#0x-OrderWatcher). Unlike the OrderWatcher, it does not expose any `subscribe` or `unsubscribe` functionality because the WebSocket server keeps a single subscription open for all clients. + +The first step for making a request is establishing a connection with the server. In Javascript: + +``` +var W3CWebSocket = require('websocket').w3cwebsocket; +wsClient = new W3CWebSocket('ws://127.0.0.1:8080'); +``` + +In Python, you could use the [websocket-client library](http://pypi.python.org/pypi/websocket-client/) and run: + +``` +from websocket import create_connection +wsClient = create_connection("ws://127.0.0.1:8080") +``` + +With the connection established, you prepare the payload for your request. The payload is a json object with a format established by the [JSON RPC specification](https://www.jsonrpc.org/specification): + +* `id`: All requests require you to specify a numerical `id`. When the server responds to the request, the response will have the same `id` as the one supplied with your request. +* `jsonrpc`: This is always the string `'2.0'`. +* `method`: This specifies the OrderWatcher method you want to call. I.e., `'ADD_ORDER'`, `'REMOVE_ORDER'` or `'GET_STATS'`. +* `params`: These contain the parameters needed by OrderWatcher to execute the method you called. For `ADD_ORDER`, provide `{ signedOrder: <your signedOrder> }`. For `REMOVE_ORDER`, provide `{ orderHash: <your orderHash> }`. For `GET_STATS`, no parameters are needed, so you may leave this empty. + +Next, convert the payload to a string and send it through the connection. +In Javascript: + +``` +const addOrderPayload = { + id: 1, + jsonrpc: '2.0', + method: 'ADD_ORDER', + params: { signedOrder: <your signedOrder> }, +}; +wsClient.send(JSON.stringify(addOrderPayload)); +``` + +In Python: + +``` +import json +remove_order_payload = { + 'id': 1, + 'jsonrpc': '2.0', + 'method': 'REMOVE_ORDER', + 'params': {'orderHash': '0x6edc16bf37fde79f5012088c33784c730e2f103d9ab1caf73060c386ad107b7e'}, +} +wsClient.send(json.dumps(remove_order_payload)); +``` + +**Response** +The server responds to all requests in a similar format. In the data field, you'll find another object containing the following fields: + +* `id`: The id corresponding to the request that the server is responding to. `UPDATE` responses are not based on any requests so the `id` field is omitted`. +* `jsonrpc`: Always `'2.0'`. +* `method`: The method the server is responding to. Eg. `ADD_ORDER`. When order states change the server may also initiate a response. In this case, method will be listed as `UPDATE`. +* `result`: This field varies based on the method. `UPDATE` responses contain the new order state. `GET_STATS` responses contain the current order count. When there are errors, this field is omitted. +* `error`: When there is an error executing a request, the [JSON RPC](https://www.jsonrpc.org/specification) error object is listed here. When the server responds successfully, this field is omitted. + +In Javascript, the responses can be parsed using the `onmessage` callback: + +``` +wsClient.onmessage = (msg) => { + const responseData = JSON.parse(msg.data); + const method = responseData.method +}; +``` + +In Python, `recv` is a lightweight way to receive a response: + +``` +result = wsClient.recv() +method = result.method +``` + ## Contributing We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository. diff --git a/packages/order-watcher/package.json b/packages/order-watcher/package.json index 499d4cead..16a46294e 100644 --- a/packages/order-watcher/package.json +++ b/packages/order-watcher/package.json @@ -74,7 +74,8 @@ "ethereum-types": "^1.1.4", "ethereumjs-blockstream": "6.0.0", "ethers": "~4.0.4", - "lodash": "^4.17.5" + "lodash": "^4.17.5", + "websocket": "^1.0.25" }, "publishConfig": { "access": "public" diff --git a/packages/order-watcher/src/index.ts b/packages/order-watcher/src/index.ts index 5eeba3e87..e275a0c6a 100644 --- a/packages/order-watcher/src/index.ts +++ b/packages/order-watcher/src/index.ts @@ -1,4 +1,5 @@ export { OrderWatcher } from './order_watcher/order_watcher'; +export { OrderWatcherWebSocketServer } from './order_watcher/order_watcher_web_socket_server'; export { ExpirationWatcher } from './order_watcher/expiration_watcher'; export { diff --git a/packages/order-watcher/src/order_watcher/order_watcher_web_socket_server.ts b/packages/order-watcher/src/order_watcher/order_watcher_web_socket_server.ts new file mode 100644 index 000000000..b75b07603 --- /dev/null +++ b/packages/order-watcher/src/order_watcher/order_watcher_web_socket_server.ts @@ -0,0 +1,200 @@ +import { ContractAddresses } from '@0x/contract-addresses'; +import { schemas } from '@0x/json-schemas'; +import { OrderStateInvalid, OrderStateValid, SignedOrder } from '@0x/types'; +import { BigNumber, logUtils } from '@0x/utils'; +import { Provider } from 'ethereum-types'; +import * as http from 'http'; +import * as WebSocket from 'websocket'; + +import { GetStatsResult, OrderWatcherConfig, OrderWatcherMethod, WebSocketRequest, WebSocketResponse } from '../types'; +import { assert } from '../utils/assert'; + +import { OrderWatcher } from './order_watcher'; + +const DEFAULT_HTTP_PORT = 8080; +const JSON_RPC_VERSION = '2.0'; + +// Wraps the OrderWatcher functionality in a WebSocket server. Motivations: +// 1) Users can watch orders via non-typescript programs. +// 2) Better encapsulation so that users can work +export class OrderWatcherWebSocketServer { + private readonly _orderWatcher: OrderWatcher; + private readonly _httpServer: http.Server; + private readonly _connectionStore: Set<WebSocket.connection>; + private readonly _wsServer: WebSocket.server; + private readonly _isVerbose: boolean; + /** + * Recover types lost when the payload is stringified. + */ + private static _parseSignedOrder(rawRequest: any): SignedOrder { + const bigNumberFields = [ + 'salt', + 'makerFee', + 'takerFee', + 'makerAssetAmount', + 'takerAssetAmount', + 'expirationTimeSeconds', + ]; + for (const field of bigNumberFields) { + rawRequest[field] = new BigNumber(rawRequest[field]); + } + return rawRequest; + } + + /** + * Instantiate a new WebSocket server which provides OrderWatcher functionality + * @param provider Web3 provider to use for JSON RPC calls. + * @param networkId NetworkId to watch orders on. + * @param contractAddresses Optional contract addresses. Defaults to known + * addresses based on networkId. + * @param orderWatcherConfig OrderWatcher configurations. isVerbose sets the verbosity for the WebSocket server aswell. + * @param isVerbose Whether to enable verbose logging. Defaults to true. + */ + constructor( + provider: Provider, + networkId: number, + contractAddresses?: ContractAddresses, + orderWatcherConfig?: Partial<OrderWatcherConfig>, + ) { + this._isVerbose = + orderWatcherConfig !== undefined && orderWatcherConfig.isVerbose !== undefined + ? orderWatcherConfig.isVerbose + : true; + this._orderWatcher = new OrderWatcher(provider, networkId, contractAddresses, orderWatcherConfig); + this._connectionStore = new Set(); + this._httpServer = http.createServer(); + this._wsServer = new WebSocket.server({ + httpServer: this._httpServer, + // Avoid setting autoAcceptConnections to true as it defeats all + // standard cross-origin protection facilities built into the protocol + // and the browser. + // Source: https://www.npmjs.com/package/websocket#server-example + // Also ensures that a request event is emitted by + // the server whenever a new WebSocket request is made. + autoAcceptConnections: false, + }); + + this._wsServer.on('request', async (request: any) => { + // Designed for usage pattern where client and server are run on the same + // machine by the same user. As such, no security checks are in place. + const connection: WebSocket.connection = request.accept(null, request.origin); + this._log(`${new Date()} [Server] Accepted connection from origin ${request.origin}.`); + connection.on('message', this._onMessageCallbackAsync.bind(this, connection)); + connection.on('close', this._onCloseCallback.bind(this, connection)); + this._connectionStore.add(connection); + }); + } + + /** + * Activates the WebSocket server by subscribing to the OrderWatcher and + * starting the WebSocket's HTTP server + */ + public start(): void { + // Have the WebSocket server subscribe to the OrderWatcher to receive updates. + // These updates are then broadcast to clients in the _connectionStore. + this._orderWatcher.subscribe(this._broadcastCallback.bind(this)); + + const port = process.env.ORDER_WATCHER_HTTP_PORT || DEFAULT_HTTP_PORT; + this._httpServer.listen(port, () => { + this._log(`${new Date()} [Server] Listening on port ${port}`); + }); + } + + /** + * Deactivates the WebSocket server by stopping the HTTP server from accepting + * new connections and unsubscribing from the OrderWatcher + */ + public stop(): void { + this._httpServer.close(); + this._orderWatcher.unsubscribe(); + } + + private _log(...args: any[]): void { + if (this._isVerbose) { + logUtils.log(...args); + } + } + + private async _onMessageCallbackAsync(connection: WebSocket.connection, message: any): Promise<void> { + let response: WebSocketResponse; + let id: number | null = null; + try { + assert.doesConformToSchema('message', message, schemas.orderWatcherWebSocketUtf8MessageSchema); + const request: WebSocketRequest = JSON.parse(message.utf8Data); + id = request.id; + assert.doesConformToSchema('request', request, schemas.orderWatcherWebSocketRequestSchema); + assert.isString(request.jsonrpc, JSON_RPC_VERSION); + response = { + id, + jsonrpc: JSON_RPC_VERSION, + method: request.method, + result: await this._routeRequestAsync(request), + }; + } catch (err) { + response = { + id, + jsonrpc: JSON_RPC_VERSION, + method: null, + error: err.toString(), + }; + } + this._log(`${new Date()} [Server] OrderWatcher output: ${JSON.stringify(response)}`); + connection.sendUTF(JSON.stringify(response)); + } + + private _onCloseCallback(connection: WebSocket.connection): void { + this._connectionStore.delete(connection); + this._log(`${new Date()} [Server] Client ${connection.remoteAddress} disconnected.`); + } + + private async _routeRequestAsync(request: WebSocketRequest): Promise<GetStatsResult | undefined> { + this._log(`${new Date()} [Server] Request received: ${request.method}`); + switch (request.method) { + case OrderWatcherMethod.AddOrder: { + const signedOrder: SignedOrder = OrderWatcherWebSocketServer._parseSignedOrder( + request.params.signedOrder, + ); + await this._orderWatcher.addOrderAsync(signedOrder); + break; + } + case OrderWatcherMethod.RemoveOrder: { + this._orderWatcher.removeOrder(request.params.orderHash || 'undefined'); + break; + } + case OrderWatcherMethod.GetStats: { + return this._orderWatcher.getStats(); + } + default: + // Should never reach here. Should be caught by JSON schema check. + throw new Error(`Unexpected default case hit for request.method`); + } + return undefined; + } + + /** + * Broadcasts OrderState changes to ALL connected clients. At the moment, + * we do not support clients subscribing to only a subset of orders. As such, + * Client B will be notified of changes to an order that Client A added. + */ + private _broadcastCallback(err: Error | null, orderState?: OrderStateValid | OrderStateInvalid | undefined): void { + const method = OrderWatcherMethod.Update; + const response = + err === null + ? { + jsonrpc: JSON_RPC_VERSION, + method, + result: orderState, + } + : { + jsonrpc: JSON_RPC_VERSION, + method, + error: { + code: -32000, + message: err.message, + }, + }; + this._connectionStore.forEach((connection: WebSocket.connection) => { + connection.sendUTF(JSON.stringify(response)); + }); + } +} diff --git a/packages/order-watcher/src/types.ts b/packages/order-watcher/src/types.ts index 8078dd971..2b529a939 100644 --- a/packages/order-watcher/src/types.ts +++ b/packages/order-watcher/src/types.ts @@ -1,4 +1,4 @@ -import { OrderState } from '@0x/types'; +import { OrderState, SignedOrder } from '@0x/types'; import { LogEntryEvent } from 'ethereum-types'; export enum OrderWatcherError { @@ -31,3 +31,67 @@ export enum InternalOrderWatcherError { ZrxNotInTokenRegistry = 'ZRX_NOT_IN_TOKEN_REGISTRY', WethNotInTokenRegistry = 'WETH_NOT_IN_TOKEN_REGISTRY', } + +export enum OrderWatcherMethod { + // Methods initiated by the user. + GetStats = 'GET_STATS', + AddOrder = 'ADD_ORDER', + RemoveOrder = 'REMOVE_ORDER', + // These are spontaneous; they are primarily orderstate changes. + Update = 'UPDATE', + // `subscribe` and `unsubscribe` are methods of OrderWatcher, but we don't + // need to expose them to the WebSocket server user because the user implicitly + // subscribes and unsubscribes by connecting and disconnecting from the server. +} + +// Users have to create a json object of this format and attach it to +// the data field of their WebSocket message to interact with the server. +export type WebSocketRequest = AddOrderRequest | RemoveOrderRequest | GetStatsRequest; + +export interface AddOrderRequest { + id: number; + jsonrpc: string; + method: OrderWatcherMethod.AddOrder; + params: { signedOrder: SignedOrder }; +} + +export interface RemoveOrderRequest { + id: number; + jsonrpc: string; + method: OrderWatcherMethod.RemoveOrder; + params: { orderHash: string }; +} + +export interface GetStatsRequest { + id: number; + jsonrpc: string; + method: OrderWatcherMethod.GetStats; +} + +// Users should expect a json object of this format in the data field +// of the WebSocket messages that the server sends out. +export type WebSocketResponse = SuccessfulWebSocketResponse | ErrorWebSocketResponse; + +export interface SuccessfulWebSocketResponse { + id: number; + jsonrpc: string; + method: OrderWatcherMethod; + result: OrderState | GetStatsResult | undefined; // result is undefined for ADD_ORDER and REMOVE_ORDER +} + +export interface ErrorWebSocketResponse { + id: number | null; + jsonrpc: string; + method: null; + error: JSONRPCError; +} + +export interface JSONRPCError { + code: number; + message: string; + data?: string | object; +} + +export interface GetStatsResult { + orderCount: number; +} diff --git a/packages/order-watcher/test/order_watcher_web_socket_server_test.ts b/packages/order-watcher/test/order_watcher_web_socket_server_test.ts new file mode 100644 index 000000000..578e0de61 --- /dev/null +++ b/packages/order-watcher/test/order_watcher_web_socket_server_test.ts @@ -0,0 +1,308 @@ +import { ContractWrappers } from '@0x/contract-wrappers'; +import { tokenUtils } from '@0x/contract-wrappers/lib/test/utils/token_utils'; +import { BlockchainLifecycle } from '@0x/dev-utils'; +import { FillScenarios } from '@0x/fill-scenarios'; +import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; +import { ExchangeContractErrs, OrderStateInvalid, OrderStateValid, SignedOrder } from '@0x/types'; +import { BigNumber, logUtils } from '@0x/utils'; +import { Web3Wrapper } from '@0x/web3-wrapper'; +import * as chai from 'chai'; +import 'mocha'; +import * as WebSocket from 'websocket'; + +import { OrderWatcherWebSocketServer } from '../src/order_watcher/order_watcher_web_socket_server'; +import { AddOrderRequest, OrderWatcherMethod, RemoveOrderRequest } from '../src/types'; + +import { chaiSetup } from './utils/chai_setup'; +import { constants } from './utils/constants'; +import { migrateOnceAsync } from './utils/migrate'; +import { provider, web3Wrapper } from './utils/web3_wrapper'; + +chaiSetup.configure(); +const expect = chai.expect; +const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); + +interface WsMessage { + data: string; +} + +describe.only('OrderWatcherWebSocketServer', async () => { + let contractWrappers: ContractWrappers; + let wsServer: OrderWatcherWebSocketServer; + let wsClient: WebSocket.w3cwebsocket; + let wsClientTwo: WebSocket.w3cwebsocket; + let fillScenarios: FillScenarios; + let userAddresses: string[]; + let makerAssetData: string; + let takerAssetData: string; + let makerTokenAddress: string; + let takerTokenAddress: string; + let makerAddress: string; + let takerAddress: string; + let zrxTokenAddress: string; + let signedOrder: SignedOrder; + let orderHash: string; + let addOrderPayload: AddOrderRequest; + let removeOrderPayload: RemoveOrderRequest; + const decimals = constants.ZRX_DECIMALS; + const fillableAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(5), decimals); + + before(async () => { + // Set up constants + const contractAddresses = await migrateOnceAsync(); + await blockchainLifecycle.startAsync(); + const networkId = constants.TESTRPC_NETWORK_ID; + const config = { + networkId, + contractAddresses, + }; + contractWrappers = new ContractWrappers(provider, config); + userAddresses = await web3Wrapper.getAvailableAddressesAsync(); + zrxTokenAddress = contractAddresses.zrxToken; + [makerAddress, takerAddress] = userAddresses; + [makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses(); + [makerAssetData, takerAssetData] = [ + assetDataUtils.encodeERC20AssetData(makerTokenAddress), + assetDataUtils.encodeERC20AssetData(takerTokenAddress), + ]; + fillScenarios = new FillScenarios( + provider, + userAddresses, + zrxTokenAddress, + contractAddresses.exchange, + contractAddresses.erc20Proxy, + contractAddresses.erc721Proxy, + ); + signedOrder = await fillScenarios.createFillableSignedOrderAsync( + makerAssetData, + takerAssetData, + makerAddress, + takerAddress, + fillableAmount, + ); + orderHash = orderHashUtils.getOrderHashHex(signedOrder); + addOrderPayload = { + id: 1, + jsonrpc: '2.0', + method: OrderWatcherMethod.AddOrder, + params: { signedOrder }, + }; + removeOrderPayload = { + id: 1, + jsonrpc: '2.0', + method: OrderWatcherMethod.RemoveOrder, + params: { orderHash }, + }; + + // Prepare OrderWatcher WebSocket server + const orderWatcherConfig = { + isVerbose: true, + }; + wsServer = new OrderWatcherWebSocketServer(provider, networkId, contractAddresses, orderWatcherConfig); + }); + after(async () => { + await blockchainLifecycle.revertAsync(); + }); + beforeEach(async () => { + wsServer.start(); + await blockchainLifecycle.startAsync(); + wsClient = new WebSocket.w3cwebsocket('ws://127.0.0.1:8080/'); + logUtils.log(`${new Date()} [Client] Connected.`); + }); + afterEach(async () => { + wsClient.close(); + await blockchainLifecycle.revertAsync(); + wsServer.stop(); + logUtils.log(`${new Date()} [Client] Closed.`); + }); + + it('responds to getStats requests correctly', (done: any) => { + const payload = { + id: 1, + jsonrpc: '2.0', + method: 'GET_STATS', + }; + wsClient.onopen = () => wsClient.send(JSON.stringify(payload)); + wsClient.onmessage = (msg: any) => { + const responseData = JSON.parse(msg.data); + expect(responseData.id).to.be.eq(1); + expect(responseData.jsonrpc).to.be.eq('2.0'); + expect(responseData.method).to.be.eq('GET_STATS'); + expect(responseData.result.orderCount).to.be.eq(0); + done(); + }; + }); + + it('throws an error when an invalid method is attempted', async () => { + const invalidMethodPayload = { + id: 1, + jsonrpc: '2.0', + method: 'BAD_METHOD', + }; + wsClient.onopen = () => wsClient.send(JSON.stringify(invalidMethodPayload)); + const errorMsg = await onMessageAsync(wsClient, null); + const errorData = JSON.parse(errorMsg.data); + // tslint:disable-next-line:no-unused-expression + expect(errorData.id).to.be.null; + // tslint:disable-next-line:no-unused-expression + expect(errorData.method).to.be.null; + expect(errorData.jsonrpc).to.be.eq('2.0'); + expect(errorData.error).to.match(/^Error: Expected request to conform to schema/); + }); + + it('throws an error when jsonrpc field missing from request', async () => { + const noJsonRpcPayload = { + id: 1, + method: 'GET_STATS', + }; + wsClient.onopen = () => wsClient.send(JSON.stringify(noJsonRpcPayload)); + const errorMsg = await onMessageAsync(wsClient, null); + const errorData = JSON.parse(errorMsg.data); + // tslint:disable-next-line:no-unused-expression + expect(errorData.method).to.be.null; + expect(errorData.jsonrpc).to.be.eq('2.0'); + expect(errorData.error).to.match(/^Error: Expected request to conform to schema/); + }); + + it('throws an error when we try to add an order without a signedOrder', async () => { + const noSignedOrderAddOrderPayload = { + id: 1, + jsonrpc: '2.0', + method: 'ADD_ORDER', + orderHash: '0x7337e2f2a9aa2ed6afe26edc2df7ad79c3ffa9cf9b81a964f707ea63f5272355', + }; + wsClient.onopen = () => wsClient.send(JSON.stringify(noSignedOrderAddOrderPayload)); + const errorMsg = await onMessageAsync(wsClient, null); + const errorData = JSON.parse(errorMsg.data); + // tslint:disable-next-line:no-unused-expression + expect(errorData.id).to.be.null; + // tslint:disable-next-line:no-unused-expression + expect(errorData.method).to.be.null; + expect(errorData.jsonrpc).to.be.eq('2.0'); + expect(errorData.error).to.match(/^Error: Expected request to conform to schema/); + }); + + it('throws an error when we try to add a bad signedOrder', async () => { + const invalidAddOrderPayload = { + id: 1, + jsonrpc: '2.0', + method: 'ADD_ORDER', + signedOrder: { + makerAddress: '0x0', + }, + }; + wsClient.onopen = () => wsClient.send(JSON.stringify(invalidAddOrderPayload)); + const errorMsg = await onMessageAsync(wsClient, null); + const errorData = JSON.parse(errorMsg.data); + // tslint:disable-next-line:no-unused-expression + expect(errorData.id).to.be.null; + // tslint:disable-next-line:no-unused-expression + expect(errorData.method).to.be.null; + expect(errorData.error).to.match(/^Error: Expected request to conform to schema/); + }); + + it('executes addOrder and removeOrder requests correctly', async () => { + wsClient.onopen = () => wsClient.send(JSON.stringify(addOrderPayload)); + const addOrderMsg = await onMessageAsync(wsClient, OrderWatcherMethod.AddOrder); + const addOrderData = JSON.parse(addOrderMsg.data); + expect(addOrderData.method).to.be.eq('ADD_ORDER'); + expect((wsServer as any)._orderWatcher._orderByOrderHash).to.deep.include({ + [orderHash]: signedOrder, + }); + + const clientOnMessagePromise = onMessageAsync(wsClient, OrderWatcherMethod.RemoveOrder); + wsClient.send(JSON.stringify(removeOrderPayload)); + const removeOrderMsg = await clientOnMessagePromise; + const removeOrderData = JSON.parse(removeOrderMsg.data); + expect(removeOrderData.method).to.be.eq('REMOVE_ORDER'); + expect((wsServer as any)._orderWatcher._orderByOrderHash).to.not.deep.include({ + [orderHash]: signedOrder, + }); + }); + + it('broadcasts orderStateInvalid message when makerAddress allowance set to 0 for watched order', async () => { + // Add the regular order + wsClient.onopen = () => wsClient.send(JSON.stringify(addOrderPayload)); + + // We register the onMessage callback before calling `setProxyAllowanceAsync` which we + // expect will cause a message to be emitted. We do now "await" here, since we want to + // check for messages _after_ calling `setProxyAllowanceAsync` + const clientOnMessagePromise = onMessageAsync(wsClient, OrderWatcherMethod.Update); + + // Set the allowance to 0 + await contractWrappers.erc20Token.setProxyAllowanceAsync(makerTokenAddress, makerAddress, new BigNumber(0)); + + // We now await the `onMessage` promise to check for the message + const orderWatcherUpdateMsg = await clientOnMessagePromise; + const orderWatcherUpdateData = JSON.parse(orderWatcherUpdateMsg.data); + expect(orderWatcherUpdateData.method).to.be.eq('UPDATE'); + const invalidOrderState = orderWatcherUpdateData.result as OrderStateInvalid; + expect(invalidOrderState.isValid).to.be.false(); + expect(invalidOrderState.orderHash).to.be.eq(orderHash); + expect(invalidOrderState.error).to.be.eq(ExchangeContractErrs.InsufficientMakerAllowance); + }); + + it('broadcasts to multiple clients when an order backing ZRX allowance changes', async () => { + // Prepare order + const makerFee = Web3Wrapper.toBaseUnitAmount(new BigNumber(2), decimals); + const takerFee = Web3Wrapper.toBaseUnitAmount(new BigNumber(0), decimals); + const nonZeroMakerFeeSignedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( + makerAssetData, + takerAssetData, + makerFee, + takerFee, + makerAddress, + takerAddress, + fillableAmount, + takerAddress, + ); + const nonZeroMakerFeeOrderPayload = { + id: 1, + jsonrpc: '2.0', + method: 'ADD_ORDER', + signedOrder: nonZeroMakerFeeSignedOrder, + }; + + // Set up a second client and have it add the order + wsClientTwo = new WebSocket.w3cwebsocket('ws://127.0.0.1:8080/'); + logUtils.log(`${new Date()} [Client] Connected.`); + wsClientTwo.onopen = () => wsClientTwo.send(JSON.stringify(nonZeroMakerFeeOrderPayload)); + + // Setup the onMessage callbacks, but don't await them yet + const clientOneOnMessagePromise = onMessageAsync(wsClient, OrderWatcherMethod.Update); + const clientTwoOnMessagePromise = onMessageAsync(wsClientTwo, OrderWatcherMethod.Update); + + // Change the allowance + await contractWrappers.erc20Token.setProxyAllowanceAsync(zrxTokenAddress, makerAddress, new BigNumber(0)); + + // Check that both clients receive the emitted event by awaiting the onMessageAsync promises + let updateMsg = await clientOneOnMessagePromise; + let updateData = JSON.parse(updateMsg.data); + let orderState = updateData.result as OrderStateValid; + expect(orderState.isValid).to.be.true(); + expect(orderState.orderRelevantState.makerFeeProxyAllowance).to.be.eq('0'); + + updateMsg = await clientTwoOnMessagePromise; + updateData = JSON.parse(updateMsg.data); + orderState = updateData.result as OrderStateValid; + expect(orderState.isValid).to.be.true(); + expect(orderState.orderRelevantState.makerFeeProxyAllowance).to.be.eq('0'); + + wsClientTwo.close(); + logUtils.log(`${new Date()} [Client] Closed.`); + }); +}); + +// HACK: createFillableSignedOrderAsync is Promise-based, which forces us +// to use Promises instead of the done() callbacks for tests. +// onmessage callback must thus be wrapped as a Promise. +async function onMessageAsync(client: WebSocket.w3cwebsocket, method: string | null): Promise<WsMessage> { + return new Promise<WsMessage>(resolve => { + client.onmessage = (msg: WsMessage) => { + const data = JSON.parse(msg.data); + if (data.method === method) { + resolve(msg); + } + }; + }); +} diff --git a/packages/pipeline/src/scripts/pull_erc20_events.ts b/packages/pipeline/src/scripts/pull_erc20_events.ts index 0ad12c97a..bd520c610 100644 --- a/packages/pipeline/src/scripts/pull_erc20_events.ts +++ b/packages/pipeline/src/scripts/pull_erc20_events.ts @@ -1,10 +1,10 @@ -// tslint:disable:no-console import { getContractAddressesForNetworkOrThrow } from '@0x/contract-addresses'; import { web3Factory } from '@0x/dev-utils'; import { Web3ProviderEngine } from '@0x/subproviders'; +import { logUtils } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import 'reflect-metadata'; -import { Connection, ConnectionOptions, createConnection, Repository } from 'typeorm'; +import { Connection, ConnectionOptions, createConnection } from 'typeorm'; import { ERC20EventsSource } from '../data_sources/contract-wrappers/erc20_events'; import { ERC20ApprovalEvent } from '../entities'; @@ -16,33 +16,63 @@ const NETWORK_ID = 1; const START_BLOCK_OFFSET = 100; // Number of blocks before the last known block to consider when updating fill events. const BATCH_SAVE_SIZE = 1000; // Number of events to save at once. const BLOCK_FINALITY_THRESHOLD = 10; // When to consider blocks as final. Used to compute default endBlock. -const WETH_START_BLOCK = 4719568; // Block number when the WETH contract was deployed. let connection: Connection; +interface Token { + // name is used for logging only. + name: string; + address: string; + defaultStartBlock: number; +} + +const tokensToGetApprovalEvents: Token[] = [ + { + name: 'WETH', + address: getContractAddressesForNetworkOrThrow(NETWORK_ID).etherToken, + defaultStartBlock: 4719568, // Block when the WETH contract was deployed. + }, + { + name: 'ZRX', + address: getContractAddressesForNetworkOrThrow(NETWORK_ID).zrxToken, + defaultStartBlock: 4145415, // Block when the ZRX contract was deployed. + }, + { + name: 'DAI', + address: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', + defaultStartBlock: 4752008, // Block when the DAI contract was deployed. + }, +]; + (async () => { connection = await createConnection(ormConfig as ConnectionOptions); const provider = web3Factory.getRpcProvider({ rpcUrl: INFURA_ROOT_URL, }); const endBlock = await calculateEndBlockAsync(provider); - await getAndSaveWETHApprovalEventsAsync(provider, endBlock); + for (const token of tokensToGetApprovalEvents) { + await getAndSaveApprovalEventsAsync(provider, token, endBlock); + } process.exit(0); })().catch(handleError); -async function getAndSaveWETHApprovalEventsAsync(provider: Web3ProviderEngine, endBlock: number): Promise<void> { - console.log('Checking existing approval events...'); +async function getAndSaveApprovalEventsAsync( + provider: Web3ProviderEngine, + token: Token, + endBlock: number, +): Promise<void> { + logUtils.log(`Getting approval events for ${token.name}...`); + logUtils.log('Checking existing approval events...'); const repository = connection.getRepository(ERC20ApprovalEvent); - const startBlock = (await getStartBlockAsync(repository)) || WETH_START_BLOCK; + const startBlock = (await getStartBlockAsync(token)) || token.defaultStartBlock; - console.log(`Getting WETH approval events starting at ${startBlock}...`); - const wethTokenAddress = getContractAddressesForNetworkOrThrow(NETWORK_ID).etherToken; - const eventsSource = new ERC20EventsSource(provider, NETWORK_ID, wethTokenAddress); + logUtils.log(`Getting approval events starting at ${startBlock}...`); + const eventsSource = new ERC20EventsSource(provider, NETWORK_ID, token.address); const eventLogs = await eventsSource.getApprovalEventsAsync(startBlock, endBlock); - console.log(`Parsing ${eventLogs.length} WETH approval events...`); + logUtils.log(`Parsing ${eventLogs.length} approval events...`); const events = parseERC20ApprovalEvents(eventLogs); - console.log(`Retrieved and parsed ${events.length} total WETH approval events.`); + logUtils.log(`Retrieved and parsed ${events.length} total approval events.`); await repository.save(events, { chunk: Math.ceil(events.length / BATCH_SAVE_SIZE) }); } @@ -52,15 +82,15 @@ async function calculateEndBlockAsync(provider: Web3ProviderEngine): Promise<num return currentBlock - BLOCK_FINALITY_THRESHOLD; } -async function getStartBlockAsync(repository: Repository<ERC20ApprovalEvent>): Promise<number | null> { - const fillEventCount = await repository.count(); - if (fillEventCount === 0) { - console.log(`No existing approval events found.`); - return null; - } +async function getStartBlockAsync(token: Token): Promise<number | null> { const queryResult = await connection.query( - `SELECT block_number FROM raw.erc20_approval_events ORDER BY block_number DESC LIMIT 1`, + `SELECT block_number FROM raw.erc20_approval_events WHERE token_address = $1 ORDER BY block_number DESC LIMIT 1`, + [token.address], ); + if (queryResult.length === 0) { + logUtils.log(`No existing approval events found for ${token.name}.`); + return null; + } const lastKnownBlock = queryResult[0].block_number; return lastKnownBlock - START_BLOCK_OFFSET; } diff --git a/packages/pipeline/src/scripts/pull_missing_blocks.ts b/packages/pipeline/src/scripts/pull_missing_blocks.ts index a5203824c..bb5385126 100644 --- a/packages/pipeline/src/scripts/pull_missing_blocks.ts +++ b/packages/pipeline/src/scripts/pull_missing_blocks.ts @@ -9,7 +9,7 @@ import { Web3Source } from '../data_sources/web3'; import { Block } from '../entities'; import * as ormConfig from '../ormconfig'; import { parseBlock } from '../parsers/web3'; -import { EXCHANGE_START_BLOCK, handleError, INFURA_ROOT_URL } from '../utils'; +import { handleError, INFURA_ROOT_URL } from '../utils'; // Number of blocks to save at once. const BATCH_SAVE_SIZE = 1000; @@ -37,22 +37,19 @@ interface MissingBlocksResponse { async function getAllMissingBlocksAsync(web3Source: Web3Source): Promise<void> { const blocksRepository = connection.getRepository(Block); - let fromBlock = EXCHANGE_START_BLOCK; while (true) { - const blockNumbers = await getMissingBlockNumbersAsync(fromBlock); + const blockNumbers = await getMissingBlockNumbersAsync(); if (blockNumbers.length === 0) { // There are no more missing blocks. We're done. break; } await getAndSaveBlocksAsync(web3Source, blocksRepository, blockNumbers); - fromBlock = Math.max(...blockNumbers) + 1; } const totalBlocks = await blocksRepository.count(); console.log(`Done saving blocks. There are now ${totalBlocks} total blocks.`); } -async function getMissingBlockNumbersAsync(fromBlock: number): Promise<number[]> { - console.log(`Checking for missing blocks starting at ${fromBlock}...`); +async function getMissingBlockNumbersAsync(): Promise<number[]> { // Note(albrow): The easiest way to get all the blocks we need is to // consider all the events tables together in a single query. If this query // gets too slow, we should consider re-architecting so that we can work on @@ -66,13 +63,12 @@ async function getMissingBlockNumbersAsync(fromBlock: number): Promise<number[]> ) SELECT DISTINCT(block_number) FROM all_events WHERE block_number NOT IN (SELECT number FROM raw.blocks) - AND block_number >= $1 - ORDER BY block_number ASC LIMIT $2`, - [fromBlock, MAX_BLOCKS_PER_QUERY], + ORDER BY block_number ASC LIMIT $1`, + [MAX_BLOCKS_PER_QUERY], )) as MissingBlocksResponse[]; const blockNumberStrings = R.pluck('block_number', response); const blockNumbers = R.map(parseInt, blockNumberStrings); - console.log(`Found ${blockNumbers.length} missing blocks in the given range.`); + console.log(`Found ${blockNumbers.length} missing blocks.`); return blockNumbers; } diff --git a/packages/react-shared/CHANGELOG.json b/packages/react-shared/CHANGELOG.json index 23e0d7f7e..9ef0d079f 100644 --- a/packages/react-shared/CHANGELOG.json +++ b/packages/react-shared/CHANGELOG.json @@ -1,5 +1,15 @@ [ { + "version": "1.1.0", + "changes": [ + { + "note": + "Change implementation to use react-router-dom NavLink instead of Link. Expose `activeStyle` prop.", + "pr": 1448 + } + ] + }, + { "version": "1.0.25", "changes": [ { diff --git a/packages/react-shared/src/components/link.tsx b/packages/react-shared/src/components/link.tsx index 089e6e2ba..2fb19ac11 100644 --- a/packages/react-shared/src/components/link.tsx +++ b/packages/react-shared/src/components/link.tsx @@ -1,13 +1,13 @@ import * as _ from 'lodash'; import * as React from 'react'; -import { Link as ReactRounterLink } from 'react-router-dom'; +import { NavLink as ReactRounterLink } from 'react-router-dom'; import { Link as ScrollLink } from 'react-scroll'; import * as validUrl from 'valid-url'; import { LinkType } from '../types'; import { constants } from '../utils/constants'; -interface BaseLinkProps { +export interface BaseLinkProps { to: string; shouldOpenInNewTab?: boolean; className?: string; @@ -18,11 +18,15 @@ interface BaseLinkProps { fontColor?: string; } -interface ScrollLinkProps extends BaseLinkProps { +export interface ScrollLinkProps extends BaseLinkProps { onActivityChanged?: (isActive: boolean) => void; } -type LinkProps = BaseLinkProps & ScrollLinkProps; +export interface ReactLinkProps extends BaseLinkProps { + activeStyle?: React.CSSProperties; +} + +export type LinkProps = ReactLinkProps & ScrollLinkProps; export interface LinkState {} @@ -94,6 +98,7 @@ export class Link extends React.Component<LinkProps, LinkState> { onMouseOver={this.props.onMouseOver} onMouseEnter={this.props.onMouseEnter} onMouseLeave={this.props.onMouseLeave} + activeStyle={this.props.activeStyle} > {this.props.children} </ReactRounterLink> diff --git a/packages/react-shared/src/index.ts b/packages/react-shared/src/index.ts index a693f2a36..285e1c6b4 100644 --- a/packages/react-shared/src/index.ts +++ b/packages/react-shared/src/index.ts @@ -3,7 +3,7 @@ export { MarkdownLinkBlock } from './components/markdown_link_block'; export { MarkdownCodeBlock } from './components/markdown_code_block'; export { MarkdownSection } from './components/markdown_section'; export { SectionHeader } from './components/section_header'; -export { Link } from './components/link'; +export { Link, LinkProps } from './components/link'; export { HeaderSizes, Styles, EtherscanLinkSuffixes, Networks, ALink } from './types'; diff --git a/packages/sol-compiler/CHANGELOG.json b/packages/sol-compiler/CHANGELOG.json index 0a757f519..8548fd73f 100644 --- a/packages/sol-compiler/CHANGELOG.json +++ b/packages/sol-compiler/CHANGELOG.json @@ -1,5 +1,18 @@ [ { + "version": "2.0.0", + "changes": [ + { + "note": "Add sol-compiler watch mode with -w flag", + "pr": 1461 + }, + { + "note": "Make error and warning colouring more visually pleasant and consistent with other compilers", + "pr": 1461 + } + ] + }, + { "version": "1.1.16", "changes": [ { diff --git a/packages/sol-compiler/package.json b/packages/sol-compiler/package.json index 0ad620b1f..86167a603 100644 --- a/packages/sol-compiler/package.json +++ b/packages/sol-compiler/package.json @@ -44,7 +44,9 @@ "devDependencies": { "@0x/dev-utils": "^1.0.21", "@0x/tslint-config": "^2.0.0", + "@types/chokidar": "^1.7.5", "@types/mkdirp": "^0.5.2", + "@types/pluralize": "^0.0.29", "@types/require-from-string": "^1.2.0", "@types/semver": "^5.5.0", "chai": "^4.0.1", @@ -74,10 +76,12 @@ "@0x/web3-wrapper": "^3.2.1", "@types/yargs": "^11.0.0", "chalk": "^2.3.0", + "chokidar": "^2.0.4", "ethereum-types": "^1.1.4", "ethereumjs-util": "^5.1.1", "lodash": "^4.17.5", "mkdirp": "^0.5.1", + "pluralize": "^7.0.0", "require-from-string": "^2.0.1", "semver": "5.5.0", "solc": "^0.4.23", diff --git a/packages/sol-compiler/src/cli.ts b/packages/sol-compiler/src/cli.ts index 0a9db6e05..18cc68aaf 100644 --- a/packages/sol-compiler/src/cli.ts +++ b/packages/sol-compiler/src/cli.ts @@ -25,6 +25,10 @@ const SEPARATOR = ','; type: 'string', description: 'comma separated list of contracts to compile', }) + .option('watch', { + alias: 'w', + default: false, + }) .help().argv; const contracts = _.isUndefined(argv.contracts) ? undefined @@ -37,7 +41,11 @@ const SEPARATOR = ','; contracts, }; const compiler = new Compiler(opts); - await compiler.compileAsync(); + if (argv.watch) { + await compiler.watchAsync(); + } else { + await compiler.compileAsync(); + } })().catch(err => { logUtils.log(err); process.exit(1); diff --git a/packages/sol-compiler/src/compiler.ts b/packages/sol-compiler/src/compiler.ts index 85df8209e..d38ccbf39 100644 --- a/packages/sol-compiler/src/compiler.ts +++ b/packages/sol-compiler/src/compiler.ts @@ -6,26 +6,29 @@ import { NPMResolver, RelativeFSResolver, Resolver, + SpyResolver, URLResolver, } from '@0x/sol-resolver'; -import { fetchAsync, logUtils } from '@0x/utils'; -import chalk from 'chalk'; +import { logUtils } from '@0x/utils'; +import * as chokidar from 'chokidar'; import { CompilerOptions, ContractArtifact, ContractVersionData, StandardOutput } from 'ethereum-types'; -import * as ethUtil from 'ethereumjs-util'; import * as fs from 'fs'; import * as _ from 'lodash'; import * as path from 'path'; -import * as requireFromString from 'require-from-string'; +import * as pluralize from 'pluralize'; import * as semver from 'semver'; import solc = require('solc'); import { compilerOptionsSchema } from './schemas/compiler_options_schema'; import { binPaths } from './solc/bin_paths'; import { + addHexPrefixToContractBytecode, + compile, createDirIfDoesNotExistAsync, getContractArtifactIfExistsAsync, - getNormalizedErrMsg, - parseDependencies, + getSolcAsync, + getSourcesWithDependencies, + getSourceTreeHash, parseSolidityVersionRange, } from './utils/compiler'; import { constants } from './utils/constants'; @@ -35,7 +38,6 @@ import { utils } from './utils/utils'; type TYPE_ALL_FILES_IDENTIFIER = '*'; const ALL_CONTRACTS_IDENTIFIER = '*'; const ALL_FILES_IDENTIFIER = '*'; -const SOLC_BIN_DIR = path.join(__dirname, '..', '..', 'solc_bin'); const DEFAULT_CONTRACTS_DIR = path.resolve('contracts'); const DEFAULT_ARTIFACTS_DIR = path.resolve('artifacts'); // Solc compiler settings cannot be configured from the commandline. @@ -82,49 +84,6 @@ export class Compiler { private readonly _artifactsDir: string; private readonly _solcVersionIfExists: string | undefined; private readonly _specifiedContracts: string[] | TYPE_ALL_FILES_IDENTIFIER; - private static async _getSolcAsync( - solcVersion: string, - ): Promise<{ solcInstance: solc.SolcInstance; fullSolcVersion: string }> { - const fullSolcVersion = binPaths[solcVersion]; - if (_.isUndefined(fullSolcVersion)) { - throw new Error(`${solcVersion} is not a known compiler version`); - } - const compilerBinFilename = path.join(SOLC_BIN_DIR, fullSolcVersion); - let solcjs: string; - if (await fsWrapper.doesFileExistAsync(compilerBinFilename)) { - solcjs = (await fsWrapper.readFileAsync(compilerBinFilename)).toString(); - } else { - logUtils.warn(`Downloading ${fullSolcVersion}...`); - const url = `${constants.BASE_COMPILER_URL}${fullSolcVersion}`; - const response = await fetchAsync(url); - const SUCCESS_STATUS = 200; - if (response.status !== SUCCESS_STATUS) { - throw new Error(`Failed to load ${fullSolcVersion}`); - } - solcjs = await response.text(); - await fsWrapper.writeFileAsync(compilerBinFilename, solcjs); - } - if (solcjs.length === 0) { - throw new Error('No compiler available'); - } - const solcInstance = solc.setupMethods(requireFromString(solcjs, compilerBinFilename)); - return { solcInstance, fullSolcVersion }; - } - private static _addHexPrefixToContractBytecode(compiledContract: solc.StandardContractOutput): void { - if (!_.isUndefined(compiledContract.evm)) { - if (!_.isUndefined(compiledContract.evm.bytecode) && !_.isUndefined(compiledContract.evm.bytecode.object)) { - compiledContract.evm.bytecode.object = ethUtil.addHexPrefix(compiledContract.evm.bytecode.object); - } - if ( - !_.isUndefined(compiledContract.evm.deployedBytecode) && - !_.isUndefined(compiledContract.evm.deployedBytecode.object) - ) { - compiledContract.evm.deployedBytecode.object = ethUtil.addHexPrefix( - compiledContract.evm.deployedBytecode.object, - ); - } - } - } /** * Instantiates a new instance of the Compiler class. * @param opts Optional compiler options @@ -158,7 +117,7 @@ export class Compiler { */ public async compileAsync(): Promise<void> { await createDirIfDoesNotExistAsync(this._artifactsDir); - await createDirIfDoesNotExistAsync(SOLC_BIN_DIR); + await createDirIfDoesNotExistAsync(constants.SOLC_BIN_DIR); await this._compileContractsAsync(this._getContractNamesToCompile(), true); } /** @@ -173,6 +132,54 @@ export class Compiler { const promisedOutputs = this._compileContractsAsync(this._getContractNamesToCompile(), false); return promisedOutputs; } + public async watchAsync(): Promise<void> { + console.clear(); // tslint:disable-line:no-console + logUtils.logWithTime('Starting compilation in watch mode...'); + const MATCH_NOTHING_REGEX = '^$'; + const IGNORE_DOT_FILES_REGEX = /(^|[\/\\])\../; + // Initially we watch nothing. We'll add the paths later. + const watcher = chokidar.watch(MATCH_NOTHING_REGEX, { ignored: IGNORE_DOT_FILES_REGEX }); + const onFileChangedAsync = async () => { + watcher.unwatch('*'); // Stop watching + try { + await this.compileAsync(); + logUtils.logWithTime('Found 0 errors. Watching for file changes.'); + } catch (err) { + if (err.typeName === 'CompilationError') { + logUtils.logWithTime( + `Found ${err.errorsCount} ${pluralize('error', err.errorsCount)}. Watching for file changes.`, + ); + } else { + logUtils.logWithTime('Found errors. Watching for file changes.'); + } + } + + const pathsToWatch = this._getPathsToWatch(); + watcher.add(pathsToWatch); + }; + await onFileChangedAsync(); + watcher.on('change', (changedFilePath: string) => { + console.clear(); // tslint:disable-line:no-console + logUtils.logWithTime('File change detected. Starting incremental compilation...'); + // NOTE: We can't await it here because that's a callback. + // Instead we stop watching inside of it and start it again when we're finished. + onFileChangedAsync(); // tslint:disable-line no-floating-promises + }); + } + private _getPathsToWatch(): string[] { + const contractNames = this._getContractNamesToCompile(); + const spyResolver = new SpyResolver(this._resolver); + for (const contractName of contractNames) { + const contractSource = spyResolver.resolve(contractName); + // NOTE: We ignore the return value here. We don't want to compute the source tree hash. + // We just want to call a SpyResolver on each contracts and it's dependencies and + // this is a convenient way to reuse the existing code that does that. + // We can then get all the relevant paths from the `spyResolver` below. + getSourceTreeHash(spyResolver, contractSource.path); + } + const pathsToWatch = _.uniq(spyResolver.resolvedContractSources.map(cs => cs.absolutePath)); + return pathsToWatch; + } private _getContractNamesToCompile(): string[] { let contractNamesToCompile; if (this._specifiedContracts === ALL_CONTRACTS_IDENTIFIER) { @@ -201,12 +208,14 @@ export class Compiler { for (const contractName of contractNames) { const contractSource = this._resolver.resolve(contractName); + const sourceTreeHashHex = getSourceTreeHash( + this._resolver, + path.join(this._contractsDir, contractSource.path), + ).toString('hex'); const contractData = { contractName, currentArtifactIfExists: await getContractArtifactIfExistsAsync(this._artifactsDir, contractName), - sourceTreeHashHex: `0x${this._getSourceTreeHash( - path.join(this._contractsDir, contractSource.path), - ).toString('hex')}`, + sourceTreeHashHex: `0x${sourceTreeHashHex}`, }; if (!this._shouldCompile(contractData)) { continue; @@ -244,9 +253,8 @@ export class Compiler { }) with Solidity v${solcVersion}...`, ); - const { solcInstance, fullSolcVersion } = await Compiler._getSolcAsync(solcVersion); - - const compilerOutput = this._compile(solcInstance, input.standardInput); + const { solcInstance, fullSolcVersion } = await getSolcAsync(solcVersion); + const compilerOutput = compile(this._resolver, solcInstance, input.standardInput); compilerOutputs.push(compilerOutput); for (const contractPath of input.contractsToCompile) { @@ -259,7 +267,7 @@ export class Compiler { ); } - Compiler._addHexPrefixToContractBytecode(compiledContract); + addHexPrefixToContractBytecode(compiledContract); if (shouldPersist) { await this._persistCompiledContractAsync( @@ -298,10 +306,14 @@ export class Compiler { const compiledContract = compilerOutput.contracts[contractPath][contractName]; // need to gather sourceCodes for this artifact, but compilerOutput.sources (the list of contract modules) - // contains listings for for every contract compiled during the compiler invocation that compiled the contract + // contains listings for every contract compiled during the compiler invocation that compiled the contract // to be persisted, which could include many that are irrelevant to the contract at hand. So, gather up only // the relevant sources: - const { sourceCodes, sources } = this._getSourcesWithDependencies(contractPath, compilerOutput.sources); + const { sourceCodes, sources } = getSourcesWithDependencies( + this._resolver, + contractPath, + compilerOutput.sources, + ); const contractVersion: ContractVersionData = { compilerOutput: compiledContract, @@ -336,130 +348,4 @@ export class Compiler { await fsWrapper.writeFileAsync(currentArtifactPath, artifactString); logUtils.warn(`${contractName} artifact saved!`); } - /** - * For the given @param contractPath, populates JSON objects to be used in the ContractVersionData interface's - * properties `sources` (source code file names mapped to ID numbers) and `sourceCodes` (source code content of - * contracts) for that contract. The source code pointed to by contractPath is read and parsed directly (via - * `this._resolver.resolve().source`), as are its imports, recursively. The ID numbers for @return `sources` are - * taken from the corresponding ID's in @param fullSources, and the content for @return sourceCodes is read from - * disk (via the aforementioned `resolver.source`). - */ - private _getSourcesWithDependencies( - contractPath: string, - fullSources: { [sourceName: string]: { id: number } }, - ): { sourceCodes: { [sourceName: string]: string }; sources: { [sourceName: string]: { id: number } } } { - const sources = { [contractPath]: { id: fullSources[contractPath].id } }; - const sourceCodes = { [contractPath]: this._resolver.resolve(contractPath).source }; - this._recursivelyGatherDependencySources( - contractPath, - sourceCodes[contractPath], - fullSources, - sources, - sourceCodes, - ); - return { sourceCodes, sources }; - } - private _recursivelyGatherDependencySources( - contractPath: string, - contractSource: string, - fullSources: { [sourceName: string]: { id: number } }, - sourcesToAppendTo: { [sourceName: string]: { id: number } }, - sourceCodesToAppendTo: { [sourceName: string]: string }, - ): void { - const importStatementMatches = contractSource.match(/\nimport[^;]*;/g); - if (importStatementMatches === null) { - return; - } - for (const importStatementMatch of importStatementMatches) { - const importPathMatches = importStatementMatch.match(/\"([^\"]*)\"/); - if (importPathMatches === null || importPathMatches.length === 0) { - continue; - } - - let importPath = importPathMatches[1]; - // HACK(ablrow): We have, e.g.: - // - // importPath = "../../utils/LibBytes/LibBytes.sol" - // contractPath = "2.0.0/protocol/AssetProxyOwner/AssetProxyOwner.sol" - // - // Resolver doesn't understand "../" so we want to pass - // "2.0.0/utils/LibBytes/LibBytes.sol" to resolver. - // - // This hack involves using path.resolve. But path.resolve returns - // absolute directories by default. We trick it into thinking that - // contractPath is a root directory by prepending a '/' and then - // removing the '/' the end. - // - // path.resolve("/a/b/c", ""../../d/e") === "/a/d/e" - // - const lastPathSeparatorPos = contractPath.lastIndexOf('/'); - const contractFolder = lastPathSeparatorPos === -1 ? '' : contractPath.slice(0, lastPathSeparatorPos + 1); - if (importPath.startsWith('.')) { - /** - * Some imports path are relative ("../Token.sol", "./Wallet.sol") - * while others are absolute ("Token.sol", "@0x/contracts/Wallet.sol") - * And we need to append the base path for relative imports. - */ - importPath = path.resolve(`/${contractFolder}`, importPath).replace('/', ''); - } - - if (_.isUndefined(sourcesToAppendTo[importPath])) { - sourcesToAppendTo[importPath] = { id: fullSources[importPath].id }; - sourceCodesToAppendTo[importPath] = this._resolver.resolve(importPath).source; - - this._recursivelyGatherDependencySources( - importPath, - this._resolver.resolve(importPath).source, - fullSources, - sourcesToAppendTo, - sourceCodesToAppendTo, - ); - } - } - } - private _compile(solcInstance: solc.SolcInstance, standardInput: solc.StandardInput): solc.StandardOutput { - const compiled: solc.StandardOutput = JSON.parse( - solcInstance.compileStandardWrapper(JSON.stringify(standardInput), importPath => { - const sourceCodeIfExists = this._resolver.resolve(importPath); - return { contents: sourceCodeIfExists.source }; - }), - ); - if (!_.isUndefined(compiled.errors)) { - const SOLIDITY_WARNING = 'warning'; - const errors = _.filter(compiled.errors, entry => entry.severity !== SOLIDITY_WARNING); - const warnings = _.filter(compiled.errors, entry => entry.severity === SOLIDITY_WARNING); - if (!_.isEmpty(errors)) { - errors.forEach(error => { - const normalizedErrMsg = getNormalizedErrMsg(error.formattedMessage || error.message); - logUtils.warn(chalk.red(normalizedErrMsg)); - }); - throw new Error('Compilation errors encountered'); - } else { - warnings.forEach(warning => { - const normalizedWarningMsg = getNormalizedErrMsg(warning.formattedMessage || warning.message); - logUtils.warn(chalk.yellow(normalizedWarningMsg)); - }); - } - } - return compiled; - } - /** - * Gets the source tree hash for a file and its dependencies. - * @param fileName Name of contract file. - */ - private _getSourceTreeHash(importPath: string): Buffer { - const contractSource = this._resolver.resolve(importPath); - const dependencies = parseDependencies(contractSource); - const sourceHash = ethUtil.sha3(contractSource.source); - if (dependencies.length === 0) { - return sourceHash; - } else { - const dependencySourceTreeHashes = _.map(dependencies, (dependency: string) => - this._getSourceTreeHash(dependency), - ); - const sourceTreeHashesBuffer = Buffer.concat([sourceHash, ...dependencySourceTreeHashes]); - const sourceTreeHash = ethUtil.sha3(sourceTreeHashesBuffer); - return sourceTreeHash; - } - } } diff --git a/packages/sol-compiler/src/utils/compiler.ts b/packages/sol-compiler/src/utils/compiler.ts index cda67a414..db308f2b5 100644 --- a/packages/sol-compiler/src/utils/compiler.ts +++ b/packages/sol-compiler/src/utils/compiler.ts @@ -1,10 +1,18 @@ -import { ContractSource } from '@0x/sol-resolver'; -import { logUtils } from '@0x/utils'; +import { ContractSource, Resolver } from '@0x/sol-resolver'; +import { fetchAsync, logUtils } from '@0x/utils'; +import chalk from 'chalk'; import { ContractArtifact } from 'ethereum-types'; +import * as ethUtil from 'ethereumjs-util'; import * as _ from 'lodash'; import * as path from 'path'; +import * as requireFromString from 'require-from-string'; +import * as solc from 'solc'; +import { binPaths } from '../solc/bin_paths'; + +import { constants } from './constants'; import { fsWrapper } from './fs_wrapper'; +import { CompilationError } from './types'; /** * Gets contract data on network or returns if an artifact does not exist. @@ -106,3 +114,208 @@ export function parseDependencies(contractSource: ContractSource): string[] { }); return dependencies; } + +/** + * Compiles the contracts and prints errors/warnings + * @param resolver Resolver + * @param solcInstance Instance of a solc compiler + * @param standardInput Solidity standard JSON input + */ +export function compile( + resolver: Resolver, + solcInstance: solc.SolcInstance, + standardInput: solc.StandardInput, +): solc.StandardOutput { + const standardInputStr = JSON.stringify(standardInput); + const standardOutputStr = solcInstance.compileStandardWrapper(standardInputStr, importPath => { + const sourceCodeIfExists = resolver.resolve(importPath); + return { contents: sourceCodeIfExists.source }; + }); + const compiled: solc.StandardOutput = JSON.parse(standardOutputStr); + if (!_.isUndefined(compiled.errors)) { + printCompilationErrorsAndWarnings(compiled.errors); + } + return compiled; +} +/** + * Separates errors from warnings, formats the messages and prints them. Throws if there is any compilation error (not warning). + * @param solcErrors The errors field of standard JSON output that contains errors and warnings. + */ +function printCompilationErrorsAndWarnings(solcErrors: solc.SolcError[]): void { + const SOLIDITY_WARNING = 'warning'; + const errors = _.filter(solcErrors, entry => entry.severity !== SOLIDITY_WARNING); + const warnings = _.filter(solcErrors, entry => entry.severity === SOLIDITY_WARNING); + if (!_.isEmpty(errors)) { + errors.forEach(error => { + const normalizedErrMsg = getNormalizedErrMsg(error.formattedMessage || error.message); + logUtils.log(chalk.red('error'), normalizedErrMsg); + }); + throw new CompilationError(errors.length); + } else { + warnings.forEach(warning => { + const normalizedWarningMsg = getNormalizedErrMsg(warning.formattedMessage || warning.message); + logUtils.log(chalk.yellow('warning'), normalizedWarningMsg); + }); + } +} + +/** + * Gets the source tree hash for a file and its dependencies. + * @param fileName Name of contract file. + */ +export function getSourceTreeHash(resolver: Resolver, importPath: string): Buffer { + const contractSource = resolver.resolve(importPath); + const dependencies = parseDependencies(contractSource); + const sourceHash = ethUtil.sha3(contractSource.source); + if (dependencies.length === 0) { + return sourceHash; + } else { + const dependencySourceTreeHashes = _.map(dependencies, (dependency: string) => + getSourceTreeHash(resolver, dependency), + ); + const sourceTreeHashesBuffer = Buffer.concat([sourceHash, ...dependencySourceTreeHashes]); + const sourceTreeHash = ethUtil.sha3(sourceTreeHashesBuffer); + return sourceTreeHash; + } +} + +/** + * For the given @param contractPath, populates JSON objects to be used in the ContractVersionData interface's + * properties `sources` (source code file names mapped to ID numbers) and `sourceCodes` (source code content of + * contracts) for that contract. The source code pointed to by contractPath is read and parsed directly (via + * `resolver.resolve().source`), as are its imports, recursively. The ID numbers for @return `sources` are + * taken from the corresponding ID's in @param fullSources, and the content for @return sourceCodes is read from + * disk (via the aforementioned `resolver.source`). + */ +export function getSourcesWithDependencies( + resolver: Resolver, + contractPath: string, + fullSources: { [sourceName: string]: { id: number } }, +): { sourceCodes: { [sourceName: string]: string }; sources: { [sourceName: string]: { id: number } } } { + const sources = { [contractPath]: { id: fullSources[contractPath].id } }; + const sourceCodes = { [contractPath]: resolver.resolve(contractPath).source }; + recursivelyGatherDependencySources( + resolver, + contractPath, + sourceCodes[contractPath], + fullSources, + sources, + sourceCodes, + ); + return { sourceCodes, sources }; +} + +function recursivelyGatherDependencySources( + resolver: Resolver, + contractPath: string, + contractSource: string, + fullSources: { [sourceName: string]: { id: number } }, + sourcesToAppendTo: { [sourceName: string]: { id: number } }, + sourceCodesToAppendTo: { [sourceName: string]: string }, +): void { + const importStatementMatches = contractSource.match(/\nimport[^;]*;/g); + if (importStatementMatches === null) { + return; + } + for (const importStatementMatch of importStatementMatches) { + const importPathMatches = importStatementMatch.match(/\"([^\"]*)\"/); + if (importPathMatches === null || importPathMatches.length === 0) { + continue; + } + + let importPath = importPathMatches[1]; + // HACK(albrow): We have, e.g.: + // + // importPath = "../../utils/LibBytes/LibBytes.sol" + // contractPath = "2.0.0/protocol/AssetProxyOwner/AssetProxyOwner.sol" + // + // Resolver doesn't understand "../" so we want to pass + // "2.0.0/utils/LibBytes/LibBytes.sol" to resolver. + // + // This hack involves using path.resolve. But path.resolve returns + // absolute directories by default. We trick it into thinking that + // contractPath is a root directory by prepending a '/' and then + // removing the '/' the end. + // + // path.resolve("/a/b/c", ""../../d/e") === "/a/d/e" + // + const lastPathSeparatorPos = contractPath.lastIndexOf('/'); + const contractFolder = lastPathSeparatorPos === -1 ? '' : contractPath.slice(0, lastPathSeparatorPos + 1); + if (importPath.startsWith('.')) { + /** + * Some imports path are relative ("../Token.sol", "./Wallet.sol") + * while others are absolute ("Token.sol", "@0x/contracts/Wallet.sol") + * And we need to append the base path for relative imports. + */ + importPath = path.resolve(`/${contractFolder}`, importPath).replace('/', ''); + } + + if (_.isUndefined(sourcesToAppendTo[importPath])) { + sourcesToAppendTo[importPath] = { id: fullSources[importPath].id }; + sourceCodesToAppendTo[importPath] = resolver.resolve(importPath).source; + + recursivelyGatherDependencySources( + resolver, + importPath, + resolver.resolve(importPath).source, + fullSources, + sourcesToAppendTo, + sourceCodesToAppendTo, + ); + } + } +} + +/** + * Gets the solidity compiler instance and full version name. If the compiler is already cached - gets it from FS, + * otherwise - fetches it and caches it. + * @param solcVersion The compiler version. e.g. 0.5.0 + */ +export async function getSolcAsync( + solcVersion: string, +): Promise<{ solcInstance: solc.SolcInstance; fullSolcVersion: string }> { + const fullSolcVersion = binPaths[solcVersion]; + if (_.isUndefined(fullSolcVersion)) { + throw new Error(`${solcVersion} is not a known compiler version`); + } + const compilerBinFilename = path.join(constants.SOLC_BIN_DIR, fullSolcVersion); + let solcjs: string; + if (await fsWrapper.doesFileExistAsync(compilerBinFilename)) { + solcjs = (await fsWrapper.readFileAsync(compilerBinFilename)).toString(); + } else { + logUtils.warn(`Downloading ${fullSolcVersion}...`); + const url = `${constants.BASE_COMPILER_URL}${fullSolcVersion}`; + const response = await fetchAsync(url); + const SUCCESS_STATUS = 200; + if (response.status !== SUCCESS_STATUS) { + throw new Error(`Failed to load ${fullSolcVersion}`); + } + solcjs = await response.text(); + await fsWrapper.writeFileAsync(compilerBinFilename, solcjs); + } + if (solcjs.length === 0) { + throw new Error('No compiler available'); + } + const solcInstance = solc.setupMethods(requireFromString(solcjs, compilerBinFilename)); + return { solcInstance, fullSolcVersion }; +} + +/** + * Solidity compiler emits the bytecode without a 0x prefix for a hex. This function fixes it if bytecode is present. + * @param compiledContract The standard JSON output section for a contract. Geth modified in place. + */ +export function addHexPrefixToContractBytecode(compiledContract: solc.StandardContractOutput): void { + if (!_.isUndefined(compiledContract.evm)) { + if (!_.isUndefined(compiledContract.evm.bytecode) && !_.isUndefined(compiledContract.evm.bytecode.object)) { + compiledContract.evm.bytecode.object = ethUtil.addHexPrefix(compiledContract.evm.bytecode.object); + } + if ( + !_.isUndefined(compiledContract.evm.deployedBytecode) && + !_.isUndefined(compiledContract.evm.deployedBytecode.object) + ) { + compiledContract.evm.deployedBytecode.object = ethUtil.addHexPrefix( + compiledContract.evm.deployedBytecode.object, + ); + } + } +} diff --git a/packages/sol-compiler/src/utils/constants.ts b/packages/sol-compiler/src/utils/constants.ts index df2ddb3b2..433897f8a 100644 --- a/packages/sol-compiler/src/utils/constants.ts +++ b/packages/sol-compiler/src/utils/constants.ts @@ -1,5 +1,8 @@ +import * as path from 'path'; + export const constants = { SOLIDITY_FILE_EXTENSION: '.sol', BASE_COMPILER_URL: 'https://ethereum.github.io/solc-bin/bin/', LATEST_ARTIFACT_VERSION: '2.0.0', + SOLC_BIN_DIR: path.join(__dirname, '..', '..', 'solc_bin'), }; diff --git a/packages/sol-compiler/src/utils/types.ts b/packages/sol-compiler/src/utils/types.ts index b211cfcbc..64328899d 100644 --- a/packages/sol-compiler/src/utils/types.ts +++ b/packages/sol-compiler/src/utils/types.ts @@ -29,3 +29,12 @@ export interface Token { } export type DoneCallback = (err?: Error) => void; + +export class CompilationError extends Error { + public errorsCount: number; + public typeName = 'CompilationError'; + constructor(errorsCount: number) { + super('Compilation errors encountered'); + this.errorsCount = errorsCount; + } +} diff --git a/packages/sol-compiler/test/compiler_utils_test.ts b/packages/sol-compiler/test/compiler_utils_test.ts index 4fe7b994e..b8c18110c 100644 --- a/packages/sol-compiler/test/compiler_utils_test.ts +++ b/packages/sol-compiler/test/compiler_utils_test.ts @@ -52,7 +52,7 @@ describe('Compiler utils', () => { const source = await fsWrapper.readFileAsync(path, { encoding: 'utf8', }); - const dependencies = parseDependencies({ source, path }); + const dependencies = parseDependencies({ source, path, absolutePath: path }); const expectedDependencies = [ 'zeppelin-solidity/contracts/token/ERC20/ERC20.sol', 'packages/sol-compiler/lib/test/fixtures/contracts/TokenTransferProxy.sol', @@ -68,7 +68,7 @@ describe('Compiler utils', () => { const source = await fsWrapper.readFileAsync(path, { encoding: 'utf8', }); - expect(parseDependencies({ source, path })).to.be.deep.equal([ + expect(parseDependencies({ source, path, absolutePath: path })).to.be.deep.equal([ 'zeppelin-solidity/contracts/ownership/Ownable.sol', 'zeppelin-solidity/contracts/token/ERC20/ERC20.sol', ]); @@ -77,7 +77,7 @@ describe('Compiler utils', () => { it.skip('correctly parses commented out dependencies', async () => { const path = ''; const source = `// import "./TokenTransferProxy.sol";`; - expect(parseDependencies({ path, source })).to.be.deep.equal([]); + expect(parseDependencies({ path, source, absolutePath: path })).to.be.deep.equal([]); }); }); }); diff --git a/packages/sol-resolver/CHANGELOG.json b/packages/sol-resolver/CHANGELOG.json index 85398e624..74c4d39c5 100644 --- a/packages/sol-resolver/CHANGELOG.json +++ b/packages/sol-resolver/CHANGELOG.json @@ -1,5 +1,18 @@ [ { + "version": "1.2.1", + "changes": [ + { + "note": "Add `absolutePath` to `ContractSource` type", + "pr": 1461 + }, + { + "note": "Add `SpyResolver` that records all resolved contracts data", + "pr": 1461 + } + ] + }, + { "version": "1.1.1", "changes": [ { diff --git a/packages/sol-resolver/src/index.ts b/packages/sol-resolver/src/index.ts index a86053259..f55aca070 100644 --- a/packages/sol-resolver/src/index.ts +++ b/packages/sol-resolver/src/index.ts @@ -5,5 +5,6 @@ export { NPMResolver } from './resolvers/npm_resolver'; export { FSResolver } from './resolvers/fs_resolver'; export { RelativeFSResolver } from './resolvers/relative_fs_resolver'; export { NameResolver } from './resolvers/name_resolver'; +export { SpyResolver } from './resolvers/spy_resolver'; export { EnumerableResolver } from './resolvers/enumerable_resolver'; export { Resolver } from './resolvers/resolver'; diff --git a/packages/sol-resolver/src/resolvers/fs_resolver.ts b/packages/sol-resolver/src/resolvers/fs_resolver.ts index 63fc3448e..86128023d 100644 --- a/packages/sol-resolver/src/resolvers/fs_resolver.ts +++ b/packages/sol-resolver/src/resolvers/fs_resolver.ts @@ -9,10 +9,7 @@ export class FSResolver extends Resolver { public resolveIfExists(importPath: string): ContractSource | undefined { if (fs.existsSync(importPath) && fs.lstatSync(importPath).isFile()) { const fileContent = fs.readFileSync(importPath).toString(); - return { - source: fileContent, - path: importPath, - }; + return { source: fileContent, path: importPath, absolutePath: importPath }; } return undefined; } diff --git a/packages/sol-resolver/src/resolvers/name_resolver.ts b/packages/sol-resolver/src/resolvers/name_resolver.ts index d6ac6a499..aee326fb7 100644 --- a/packages/sol-resolver/src/resolvers/name_resolver.ts +++ b/packages/sol-resolver/src/resolvers/name_resolver.ts @@ -20,10 +20,7 @@ export class NameResolver extends EnumerableResolver { if (contractName === lookupContractName) { const absoluteContractPath = path.join(this._contractsDir, filePath); const source = fs.readFileSync(absoluteContractPath).toString(); - contractSource = { - source, - path: filePath, - }; + contractSource = { source, path: filePath, absolutePath: absoluteContractPath }; return true; } return undefined; @@ -36,10 +33,7 @@ export class NameResolver extends EnumerableResolver { const onFile = (filePath: string) => { const absoluteContractPath = path.join(this._contractsDir, filePath); const source = fs.readFileSync(absoluteContractPath).toString(); - const contractSource = { - source, - path: filePath, - }; + const contractSource = { source, path: filePath, absolutePath: absoluteContractPath }; contractSources.push(contractSource); }; this._traverseContractsDir(this._contractsDir, onFile); diff --git a/packages/sol-resolver/src/resolvers/npm_resolver.ts b/packages/sol-resolver/src/resolvers/npm_resolver.ts index eeb2b5493..3c1d09557 100644 --- a/packages/sol-resolver/src/resolvers/npm_resolver.ts +++ b/packages/sol-resolver/src/resolvers/npm_resolver.ts @@ -32,10 +32,7 @@ export class NPMResolver extends Resolver { const lookupPath = path.join(currentPath, 'node_modules', packagePath, pathWithinPackage); if (fs.existsSync(lookupPath) && fs.lstatSync(lookupPath).isFile()) { const fileContent = fs.readFileSync(lookupPath).toString(); - return { - source: fileContent, - path: lookupPath, - }; + return { source: fileContent, path: importPath, absolutePath: lookupPath }; } currentPath = path.dirname(currentPath); } diff --git a/packages/sol-resolver/src/resolvers/relative_fs_resolver.ts b/packages/sol-resolver/src/resolvers/relative_fs_resolver.ts index ed96040d3..cfff145f9 100644 --- a/packages/sol-resolver/src/resolvers/relative_fs_resolver.ts +++ b/packages/sol-resolver/src/resolvers/relative_fs_resolver.ts @@ -13,13 +13,10 @@ export class RelativeFSResolver extends Resolver { } // tslint:disable-next-line:prefer-function-over-method public resolveIfExists(importPath: string): ContractSource | undefined { - const filePath = path.join(this._contractsDir, importPath); + const filePath = path.resolve(path.join(this._contractsDir, importPath)); if (fs.existsSync(filePath) && !fs.lstatSync(filePath).isDirectory()) { const fileContent = fs.readFileSync(filePath).toString(); - return { - source: fileContent, - path: importPath, - }; + return { source: fileContent, path: importPath, absolutePath: filePath }; } return undefined; } diff --git a/packages/sol-resolver/src/resolvers/spy_resolver.ts b/packages/sol-resolver/src/resolvers/spy_resolver.ts new file mode 100644 index 000000000..5582d771a --- /dev/null +++ b/packages/sol-resolver/src/resolvers/spy_resolver.ts @@ -0,0 +1,25 @@ +import * as _ from 'lodash'; + +import { ContractSource } from '../types'; + +import { Resolver } from './resolver'; + +/** + * This resolver is a passthrough proxy to any resolver that records all the resolved contracts sources. + * You can access them later using the `resolvedContractSources` public field. + */ +export class SpyResolver extends Resolver { + public resolvedContractSources: ContractSource[] = []; + private readonly _resolver: Resolver; + constructor(resolver: Resolver) { + super(); + this._resolver = resolver; + } + public resolveIfExists(importPath: string): ContractSource | undefined { + const contractSourceIfExists = this._resolver.resolveIfExists(importPath); + if (!_.isUndefined(contractSourceIfExists)) { + this.resolvedContractSources.push(contractSourceIfExists); + } + return contractSourceIfExists; + } +} diff --git a/packages/sol-resolver/src/resolvers/url_resolver.ts b/packages/sol-resolver/src/resolvers/url_resolver.ts index 180b0c9f6..ef300e6db 100644 --- a/packages/sol-resolver/src/resolvers/url_resolver.ts +++ b/packages/sol-resolver/src/resolvers/url_resolver.ts @@ -11,10 +11,7 @@ export class URLResolver extends Resolver { if (importPath.startsWith(FILE_URL_PREXIF)) { const filePath = importPath.substr(FILE_URL_PREXIF.length); const fileContent = fs.readFileSync(filePath).toString(); - return { - source: fileContent, - path: importPath, - }; + return { source: fileContent, path: importPath, absolutePath: filePath }; } return undefined; } diff --git a/packages/sol-resolver/src/types.ts b/packages/sol-resolver/src/types.ts index 41492622d..b4ba164c8 100644 --- a/packages/sol-resolver/src/types.ts +++ b/packages/sol-resolver/src/types.ts @@ -1,6 +1,7 @@ export interface ContractSource { source: string; path: string; + absolutePath: string; } export interface ContractSources { diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 6b728af71..4470dd501 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -243,6 +243,10 @@ export enum RevertReason { AuctionNotStarted = 'AUCTION_NOT_STARTED', AuctionInvalidBeginTime = 'INVALID_BEGIN_TIME', InvalidAssetData = 'INVALID_ASSET_DATA', + // Balance Threshold Filter + InvalidOrBlockedExchangeSelector = 'INVALID_OR_BLOCKED_EXCHANGE_SELECTOR', + BalanceQueryFailed = 'BALANCE_QUERY_FAILED', + AtLeastOneAddressDoesNotMeetBalanceThreshold = 'AT_LEAST_ONE_ADDRESS_DOES_NOT_MEET_BALANCE_THRESHOLD', } export enum StatusCodes { diff --git a/packages/typescript-typings/tsconfig.json b/packages/typescript-typings/tsconfig.json index 7f0fe2f7a..8ea3bfb0c 100644 --- a/packages/typescript-typings/tsconfig.json +++ b/packages/typescript-typings/tsconfig.json @@ -3,5 +3,6 @@ "compilerOptions": { "outDir": "lib", "rootDir": "." - } + }, + "include": ["types"] } diff --git a/packages/utils/CHANGELOG.json b/packages/utils/CHANGELOG.json index fe66d3f31..605151fb6 100644 --- a/packages/utils/CHANGELOG.json +++ b/packages/utils/CHANGELOG.json @@ -1,5 +1,14 @@ [ { + "version": "2.1.0", + "changes": [ + { + "note": "Add `logWithTime` to `logUtils`", + "pr": 1461 + } + ] + }, + { "version": "2.0.8", "changes": [ { diff --git a/packages/utils/package.json b/packages/utils/package.json index a25dc9cff..5ffec049a 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -49,6 +49,7 @@ "@types/node": "*", "abortcontroller-polyfill": "^1.1.9", "bignumber.js": "~4.1.0", + "chalk": "^2.4.1", "detect-node": "2.0.3", "ethereum-types": "^1.1.4", "ethereumjs-util": "^5.1.1", diff --git a/packages/utils/src/log_utils.ts b/packages/utils/src/log_utils.ts index 87f8479b5..6d9996c67 100644 --- a/packages/utils/src/log_utils.ts +++ b/packages/utils/src/log_utils.ts @@ -1,3 +1,5 @@ +import chalk from 'chalk'; + export const logUtils = { log(...args: any[]): void { console.log(...args); // tslint:disable-line:no-console @@ -5,4 +7,7 @@ export const logUtils = { warn(...args: any[]): void { console.warn(...args); // tslint:disable-line:no-console }, + logWithTime(arg: string): void { + logUtils.log(`[${chalk.gray(new Date().toLocaleTimeString())}] ${arg}`); + }, }; diff --git a/packages/website/.gitignore b/packages/website/.gitignore new file mode 100644 index 000000000..1e8d1ceb4 --- /dev/null +++ b/packages/website/.gitignore @@ -0,0 +1 @@ +.awcache diff --git a/packages/website/README.md b/packages/website/README.md index f735b0df5..a9145cb6c 100644 --- a/packages/website/README.md +++ b/packages/website/README.md @@ -2,8 +2,8 @@ This repository contains our website and [0x Portal DApp][portal-url] (over-the-counter exchange), facilitating trustless over-the-counter trading of Ethereum-based tokens using 0x protocol. -[website-url]: https://0xproject.com/ -[portal-url]: https://0xproject.com/portal +[website-url]: https://0x.org/ +[portal-url]: https://0x.org/portal ## Contributing diff --git a/packages/website/less/all.less b/packages/website/less/all.less index 3747e4860..5d1dccc98 100644 --- a/packages/website/less/all.less +++ b/packages/website/less/all.less @@ -75,7 +75,7 @@ code { border: 1px solid #e3eefe; border-radius: 4px; font-family: 'Roboto Mono'; - background-color: #f2f6ff !important; // lightBlue + //background-color: #f2f6ff !important; // lightBlue } #wiki { diff --git a/packages/website/less/normalize.less b/packages/website/less/normalize.less new file mode 100644 index 000000000..c45a85f89 --- /dev/null +++ b/packages/website/less/normalize.less @@ -0,0 +1,349 @@ +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ + +/* Document + ========================================================================== */ + +/** + * 1. Correct the line height in all browsers. + * 2. Prevent adjustments of font size after orientation changes in iOS. + */ + + html { + line-height: 1.15; /* 1 */ + -webkit-text-size-adjust: 100%; /* 2 */ + } + + /* Sections + ========================================================================== */ + + /** + * Remove the margin in all browsers. + */ + + body { + margin: 0; + } + + /** + * Render the `main` element consistently in IE. + */ + + main { + display: block; + } + + /** + * Correct the font size and margin on `h1` elements within `section` and + * `article` contexts in Chrome, Firefox, and Safari. + */ + + h1 { + font-size: 2em; + margin: 0.67em 0; + } + + /* Grouping content + ========================================================================== */ + + /** + * 1. Add the correct box sizing in Firefox. + * 2. Show the overflow in Edge and IE. + */ + + hr { + box-sizing: content-box; /* 1 */ + height: 0; /* 1 */ + overflow: visible; /* 2 */ + } + + /** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + + pre { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ + } + + /* Text-level semantics + ========================================================================== */ + + /** + * Remove the gray background on active links in IE 10. + */ + + a { + background-color: transparent; + } + + /** + * 1. Remove the bottom border in Chrome 57- + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. + */ + + abbr[title] { + border-bottom: none; /* 1 */ + text-decoration: underline; /* 2 */ + text-decoration: underline dotted; /* 2 */ + } + + /** + * Add the correct font weight in Chrome, Edge, and Safari. + */ + + b, + strong { + font-weight: bolder; + } + + /** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + + code, + kbd, + samp { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ + } + + /** + * Add the correct font size in all browsers. + */ + + small { + font-size: 80%; + } + + /** + * Prevent `sub` and `sup` elements from affecting the line height in + * all browsers. + */ + + sub, + sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; + } + + sub { + bottom: -0.25em; + } + + sup { + top: -0.5em; + } + + /* Embedded content + ========================================================================== */ + + /** + * Remove the border on images inside links in IE 10. + */ + + img { + border-style: none; + } + + /* Forms + ========================================================================== */ + + /** + * 1. Change the font styles in all browsers. + * 2. Remove the margin in Firefox and Safari. + */ + + button, + input, + optgroup, + select, + textarea { + font-family: inherit; /* 1 */ + font-size: 100%; /* 1 */ + line-height: 1.15; /* 1 */ + margin: 0; /* 2 */ + } + + /** + * Show the overflow in IE. + * 1. Show the overflow in Edge. + */ + + button, + input { /* 1 */ + overflow: visible; + } + + /** + * Remove the inheritance of text transform in Edge, Firefox, and IE. + * 1. Remove the inheritance of text transform in Firefox. + */ + + button, + select { /* 1 */ + text-transform: none; + } + + /** + * Correct the inability to style clickable types in iOS and Safari. + */ + + button, + [type="button"], + [type="reset"], + [type="submit"] { + -webkit-appearance: button; + } + + /** + * Remove the inner border and padding in Firefox. + */ + + button::-moz-focus-inner, + [type="button"]::-moz-focus-inner, + [type="reset"]::-moz-focus-inner, + [type="submit"]::-moz-focus-inner { + border-style: none; + padding: 0; + } + + /** + * Restore the focus styles unset by the previous rule. + */ + + button:-moz-focusring, + [type="button"]:-moz-focusring, + [type="reset"]:-moz-focusring, + [type="submit"]:-moz-focusring { + outline: 1px dotted ButtonText; + } + + /** + * Correct the padding in Firefox. + */ + + fieldset { + padding: 0.35em 0.75em 0.625em; + } + + /** + * 1. Correct the text wrapping in Edge and IE. + * 2. Correct the color inheritance from `fieldset` elements in IE. + * 3. Remove the padding so developers are not caught out when they zero out + * `fieldset` elements in all browsers. + */ + + legend { + box-sizing: border-box; /* 1 */ + color: inherit; /* 2 */ + display: table; /* 1 */ + max-width: 100%; /* 1 */ + padding: 0; /* 3 */ + white-space: normal; /* 1 */ + } + + /** + * Add the correct vertical alignment in Chrome, Firefox, and Opera. + */ + + progress { + vertical-align: baseline; + } + + /** + * Remove the default vertical scrollbar in IE 10+. + */ + + textarea { + overflow: auto; + } + + /** + * 1. Add the correct box sizing in IE 10. + * 2. Remove the padding in IE 10. + */ + + [type="checkbox"], + [type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ + } + + /** + * Correct the cursor style of increment and decrement buttons in Chrome. + */ + + [type="number"]::-webkit-inner-spin-button, + [type="number"]::-webkit-outer-spin-button { + height: auto; + } + + /** + * 1. Correct the odd appearance in Chrome and Safari. + * 2. Correct the outline style in Safari. + */ + + [type="search"] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ + } + + /** + * Remove the inner padding in Chrome and Safari on macOS. + */ + + [type="search"]::-webkit-search-decoration { + -webkit-appearance: none; + } + + /** + * 1. Correct the inability to style clickable types in iOS and Safari. + * 2. Change font properties to `inherit` in Safari. + */ + + ::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ + } + + /* Interactive + ========================================================================== */ + + /* + * Add the correct display in Edge, IE 10+, and Firefox. + */ + + details { + display: block; + } + + /* + * Add the correct display in all browsers. + */ + + summary { + display: list-item; + } + + /* Misc + ========================================================================== */ + + /** + * Add the correct display in IE 10+. + */ + + template { + display: none; + } + + /** + * Add the correct display in IE 10. + */ + + [hidden] { + display: none; + }
\ No newline at end of file diff --git a/packages/website/md/docs/0xjs/0.0.1/installation.md b/packages/website/md/docs/0xjs/0.0.1/installation.md index ac0a47699..3860df1cc 100644 --- a/packages/website/md/docs/0xjs/0.0.1/installation.md +++ b/packages/website/md/docs/0xjs/0.0.1/installation.md @@ -28,4 +28,4 @@ Download the UMD module from our [releases page](https://github.com/0xProject/0x ### Wiki -Check out our [wiki](https://0xproject.com/wiki) for articles on how to get 0x.js setup with TestRPC, Infura and more! +Check out our [wiki](https://0x.org/wiki) for articles on how to get 0x.js setup with TestRPC, Infura and more! diff --git a/packages/website/md/docs/0xjs/1.0.1/installation.md b/packages/website/md/docs/0xjs/1.0.1/installation.md index 74c902afd..d5c13e710 100644 --- a/packages/website/md/docs/0xjs/1.0.1/installation.md +++ b/packages/website/md/docs/0xjs/1.0.1/installation.md @@ -37,4 +37,4 @@ Download the UMD module from our [releases page](https://github.com/0xProject/0x ### Wiki -Check out our [wiki](https://0xproject.com/wiki) for articles on how to get 0x.js setup with Ganache, Infura and more! +Check out our [wiki](https://0x.org/wiki) for articles on how to get 0x.js setup with Ganache, Infura and more! diff --git a/packages/website/md/docs/0xjs/2.0.0/installation.md b/packages/website/md/docs/0xjs/2.0.0/installation.md index aaac263d0..87d763572 100644 --- a/packages/website/md/docs/0xjs/2.0.0/installation.md +++ b/packages/website/md/docs/0xjs/2.0.0/installation.md @@ -35,4 +35,4 @@ Download the UMD module from our [releases page](https://github.com/0xProject/0x ### Wiki -Check out our [wiki](https://0xproject.com/wiki) for articles on how to get 0x.js setup with TestRPC, Infura and more! +Check out our [wiki](https://0x.org/wiki) for articles on how to get 0x.js setup with TestRPC, Infura and more! diff --git a/packages/website/md/docs/asset_buyer/introduction.md b/packages/website/md/docs/asset_buyer/introduction.md index a59539ac6..bac81c760 100644 --- a/packages/website/md/docs/asset_buyer/introduction.md +++ b/packages/website/md/docs/asset_buyer/introduction.md @@ -1 +1 @@ -Welcome to the [asset-buyer](https://github.com/0xProject/0x-monorepo/tree/development/packages/asset-buyer) documentation! AssetBuyer is a library that provides an easy way to buy any asset with ETH in one click, leveraging 0x liquidity and the [Forwarder contract](https://0xproject.com/docs/contracts#Forwarder). +Welcome to the [asset-buyer](https://github.com/0xProject/0x-monorepo/tree/development/packages/asset-buyer) documentation! AssetBuyer is a library that provides an easy way to buy any asset with ETH in one click, leveraging 0x liquidity and the [Forwarder contract](https://0x.org/docs/contracts#Forwarder). diff --git a/packages/website/md/docs/connect/1/installation.md b/packages/website/md/docs/connect/1/installation.md index 950bf92ca..d457b0577 100644 --- a/packages/website/md/docs/connect/1/installation.md +++ b/packages/website/md/docs/connect/1/installation.md @@ -12,4 +12,4 @@ import { HttpClient } from '@0xproject/connect'; ### Wiki -Check out our [0x Connect introduction tutorial](https://0xproject.com/wiki#Intro-Tutorial) for information on how to integrate relayers into your application. +Check out our [0x Connect introduction tutorial](https://0x.org/wiki#Intro-Tutorial) for information on how to integrate relayers into your application. diff --git a/packages/website/md/docs/connect/3/installation.md b/packages/website/md/docs/connect/3/installation.md index 6797d9633..8ed6172bf 100644 --- a/packages/website/md/docs/connect/3/installation.md +++ b/packages/website/md/docs/connect/3/installation.md @@ -12,4 +12,4 @@ import { HttpClient } from '@0x/connect'; ### Wiki -Check out our [0x Connect introduction tutorial](https://0xproject.com/wiki#Intro-Tutorial) for information on how to integrate relayers into your application. +Check out our [0x Connect introduction tutorial](https://0x.org/wiki#Intro-Tutorial) for information on how to integrate relayers into your application. diff --git a/packages/website/md/docs/migrations/1/introduction.md b/packages/website/md/docs/migrations/1/introduction.md index 82ae3a0ab..70b13c5f8 100644 --- a/packages/website/md/docs/migrations/1/introduction.md +++ b/packages/website/md/docs/migrations/1/introduction.md @@ -1 +1 @@ -Welcome to the [@0x/migrations](https://github.com/0xProject/0x-monorepo/tree/development/packages/migrations) documentation! This package is intended for developers who would like to deploy the 0x protocol system of smart contracts to a custom testnet. If you want to test against existing testnets, check out our pre-deployed [Ganache snapshot](https://0xproject.com/wiki#Ganache-Setup-Guide) or where 0x is already deployed on [popular testnets](https://0xproject.com/wiki#Deployed-Addresses). +Welcome to the [@0x/migrations](https://github.com/0xProject/0x-monorepo/tree/development/packages/migrations) documentation! This package is intended for developers who would like to deploy the 0x protocol system of smart contracts to a custom testnet. If you want to test against existing testnets, check out our pre-deployed [Ganache snapshot](https://0x.org/wiki#Ganache-Setup-Guide) or where 0x is already deployed on [popular testnets](https://0x.org/wiki#Deployed-Addresses). diff --git a/packages/website/md/docs/smart_contracts/2/introduction.md b/packages/website/md/docs/smart_contracts/2/introduction.md index 0b4e2aac6..4a3a73027 100644 --- a/packages/website/md/docs/smart_contracts/2/introduction.md +++ b/packages/website/md/docs/smart_contracts/2/introduction.md @@ -2,5 +2,5 @@ Welcome to the [0x smart contracts](https://github.com/0xProject/0x-monorepo/tre ### Helpful wiki articles: -* [Deployed smart contract addresses](https://0xproject.com/wiki#Deployed-Addresses) +* [Deployed smart contract addresses](https://0x.org/wiki#Deployed-Addresses) * [0x Protocol Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md) diff --git a/packages/website/md/docs/sol_cov/1/usage.md b/packages/website/md/docs/sol_cov/1/usage.md index c747005fb..c2b8404af 100644 --- a/packages/website/md/docs/sol_cov/1/usage.md +++ b/packages/website/md/docs/sol_cov/1/usage.md @@ -1,4 +1,4 @@ -Sol-cov uses transaction traces in order to figure out which lines of Solidity source code have been covered by your tests. In order for it to gather these traces, you must add the `CoverageSubprovider` to the [ProviderEngine](https://github.com/MetaMask/provider-engine) instance you use when running your Solidity tests. If you're unfamiliar with ProviderEngine, please read the [Web3 Provider explained](https://0xproject.com/wiki#Web3-Provider-Explained) wiki article. +Sol-cov uses transaction traces in order to figure out which lines of Solidity source code have been covered by your tests. In order for it to gather these traces, you must add the `CoverageSubprovider` to the [ProviderEngine](https://github.com/MetaMask/provider-engine) instance you use when running your Solidity tests. If you're unfamiliar with ProviderEngine, please read the [Web3 Provider explained](https://0x.org/wiki#Web3-Provider-Explained) wiki article. The CoverageSubprovider eavesdrops on the `eth_sendTransaction` and `eth_call` RPC calls and collects traces after each call using `debug_traceTransaction`. `eth_call`'s' don't generate traces - so we take a snapshot, re-submit it as a transaction, get the trace and then revert the snapshot. @@ -8,7 +8,7 @@ In order to use `CoverageSubprovider` with your favorite framework you need to p ### Sol-compiler -If you are generating your artifacts with [@0xproject/sol-compiler](https://0xproject.com/docs/sol-compiler) you can use the `SolCompilerArtifactsAdapter` we've implemented for you. +If you are generating your artifacts with [@0xproject/sol-compiler](https://0x.org/docs/sol-compiler) you can use the `SolCompilerArtifactsAdapter` we've implemented for you. ```typescript import { SolCompilerArtifactsAdapter } from '@0xproject/sol-cov'; diff --git a/packages/website/md/docs/sol_cov/2/usage.md b/packages/website/md/docs/sol_cov/2/usage.md index d1c76474b..8e33f3bf5 100644 --- a/packages/website/md/docs/sol_cov/2/usage.md +++ b/packages/website/md/docs/sol_cov/2/usage.md @@ -1,4 +1,4 @@ -Sol-cov uses transaction traces in order to figure out which lines of Solidity source code have been covered by your tests. In order for it to gather these traces, you must add the `CoverageSubprovider` to the [ProviderEngine](https://github.com/MetaMask/provider-engine) instance you use when running your Solidity tests. If you're unfamiliar with ProviderEngine, please read the [Web3 Provider explained](https://0xproject.com/wiki#Web3-Provider-Explained) wiki article. +Sol-cov uses transaction traces in order to figure out which lines of Solidity source code have been covered by your tests. In order for it to gather these traces, you must add the `CoverageSubprovider` to the [ProviderEngine](https://github.com/MetaMask/provider-engine) instance you use when running your Solidity tests. If you're unfamiliar with ProviderEngine, please read the [Web3 Provider explained](https://0x.org/wiki#Web3-Provider-Explained) wiki article. The CoverageSubprovider eavesdrops on the `eth_sendTransaction` and `eth_call` RPC calls and collects traces after each call using `debug_traceTransaction`. `eth_call`'s' don't generate traces - so we take a snapshot, re-submit it as a transaction, get the trace and then revert the snapshot. @@ -8,7 +8,7 @@ In order to use `CoverageSubprovider` with your favorite framework you need to p ### Sol-compiler -If you are generating your artifacts with [@0x/sol-compiler](https://0xproject.com/docs/sol-compiler) you can use the `SolCompilerArtifactsAdapter` we've implemented for you. +If you are generating your artifacts with [@0x/sol-compiler](https://0x.org/docs/sol-compiler) you can use the `SolCompilerArtifactsAdapter` we've implemented for you. ```typescript import { SolCompilerArtifactsAdapter } from '@0x/sol-cov'; diff --git a/packages/website/md/docs/subproviders/1/introduction.md b/packages/website/md/docs/subproviders/1/introduction.md index 835201064..fe7fb6a8d 100644 --- a/packages/website/md/docs/subproviders/1/introduction.md +++ b/packages/website/md/docs/subproviders/1/introduction.md @@ -1 +1 @@ -Welcome to the [Subproviders](https://github.com/0xProject/0x-monorepo/tree/development/packages/subproviders) documentation! Subproviders is a package containing useful [subproviders](https://0xproject.com/wiki#Web3-Provider-Explained) that can be used with the [Web3 Provider Engine](https://github.com/MetaMask/provider-engine) library. +Welcome to the [Subproviders](https://github.com/0xProject/0x-monorepo/tree/development/packages/subproviders) documentation! Subproviders is a package containing useful [subproviders](https://0x.org/wiki#Web3-Provider-Explained) that can be used with the [Web3 Provider Engine](https://github.com/MetaMask/provider-engine) library. diff --git a/packages/website/package.json b/packages/website/package.json index c24a0ba6e..bb97ea4e8 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -13,25 +13,30 @@ "clean": "shx rm -f public/bundle*", "lint": "tslint --format stylish --project . 'ts/**/*.ts' 'ts/**/*.tsx'", "dev": "webpack-dev-server --mode development --content-base public --https", - "deploy_dogfood": "npm run build:prod; aws s3 sync ./public/. s3://dogfood.0xproject.com --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers", + "deploy_dogfood": "npm run build:prod; aws s3 sync ./public/. s3://dogfood.0x.org --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers", "deploy_staging": "npm run build:prod; aws s3 sync ./public/. s3://staging-0xproject --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers", - "deploy_live": "DEPLOY_ROLLBAR_SOURCEMAPS=true npm run build:prod; aws s3 sync ./public/. s3://0xproject.com --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --exclude *.map.js" + "deploy_live": "DEPLOY_ROLLBAR_SOURCEMAPS=true npm run build:prod; aws s3 sync ./public/. s3://0x.org --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --exclude *.map.js" }, "author": "Fabio Berger", "license": "Apache-2.0", "dependencies": { "@0x/asset-buyer": "^3.0.4", "@0x/contract-addresses": "^2.0.0", - "@0x/contract-wrappers": "^4.1.3", - "@0x/json-schemas": "^2.1.4", - "@0x/order-utils": "^3.0.7", - "@0x/react-docs": "^1.0.22", - "@0x/react-shared": "^1.0.25", - "@0x/subproviders": "^2.1.8", - "@0x/types": "^1.4.1", - "@0x/typescript-typings": "^3.0.6", - "@0x/utils": "^2.0.8", - "@0x/web3-wrapper": "^3.2.1", + "@0x/contract-wrappers": "^4.1.1", + "@0x/json-schemas": "^2.1.2", + "@0x/order-utils": "^3.0.4", + "@0x/react-docs": "^1.0.20", + "@0x/react-shared": "^1.0.23", + "@0x/subproviders": "^2.1.6", + "@0x/types": "^1.3.0", + "@0x/typescript-typings": "^3.0.4", + "@0x/utils": "^2.0.6", + "@0x/web3-wrapper": "^3.1.6", + "@reach/dialog": "^0.1.2", + "@types/react-lazyload": "^2.3.1", + "@types/react-loadable": "^5.4.2", + "@types/react-syntax-highlighter": "^0.0.8", + "@types/styled-components": "^4.1.1", "accounting": "^0.4.1", "basscss": "^8.0.3", "blockies": "^0.0.2", @@ -53,10 +58,16 @@ "react-copy-to-clipboard": "^5.0.0", "react-document-title": "^2.0.3", "react-dom": "^16.4.2", + "react-flickity-component": "^3.1.0", + "react-headroom": "2.2.2", "react-helmet": "^5.2.0", + "react-lazyload": "^2.3.0", + "react-loadable": "^5.5.0", "react-popper": "^1.0.0-beta.6", "react-redux": "^5.0.3", + "react-responsive": "^6.0.1", "react-scroll": "0xproject/react-scroll#pr-330-and-replace-state", + "react-scrollable-anchor": "^0.6.1", "react-syntax-highlighter": "^10.1.1", "react-tooltip": "^3.2.7", "react-typist": "^2.0.4", @@ -64,7 +75,7 @@ "redux-devtools-extension": "^2.13.2", "rollbar": "^2.4.7", "semver-sort": "0.0.4", - "styled-components": "^3.3.0", + "styled-components": "^4.1.1", "thenby": "^1.2.3", "truffle-contract": "2.0.1", "web3-provider-engine": "14.0.6", @@ -82,7 +93,7 @@ "@types/numeral": "^0.0.22", "@types/query-string": "^5.1.0", "@types/rc-slider": "^8.6.0", - "@types/react": "^16.4.2", + "@types/react": "^16.7.7", "@types/react-copy-to-clipboard": "^4.2.0", "@types/react-dom": "^16.0.7", "@types/react-helmet": "^5.0.6", @@ -97,6 +108,7 @@ "less-loader": "^4.1.0", "make-promises-safe": "^1.1.0", "raw-loader": "^0.5.1", + "react-svg-loader": "^2.1.0", "rollbar-sourcemap-webpack-plugin": "^2.4.0", "shx": "^0.2.2", "source-map-loader": "^0.2.4", @@ -107,6 +119,7 @@ "typescript": "3.0.1", "uglifyjs-webpack-plugin": "^2.0.1", "webpack": "^4.20.2", + "webpack-bundle-analyzer": "^3.0.3", "webpack-cli": "3.1.2", "webpack-dev-server": "^3.1.9" } diff --git a/packages/website/public/css/formular.css b/packages/website/public/css/formular.css new file mode 100644 index 000000000..85549f8c8 --- /dev/null +++ b/packages/website/public/css/formular.css @@ -0,0 +1,45 @@ +/** + * @license + * MyFonts Webfont Build ID 3678880, 2018-11-27T05:59:35-0500 + * + * The fonts listed in this notice are subject to the End User License + * Agreement(s) entered into by the website owner. All other parties are + * explicitly restricted from using the Licensed Webfonts(s). + * + * You may obtain a valid license at the URLs below. + * + * Webfont: Formular-Light by Brownfox + * URL: https://www.myfonts.com/fonts/brownfox/formular/light/ + * + * Webfont: Formular by Brownfox + * URL: https://www.myfonts.com/fonts/brownfox/formular/regular/ + * + * + * License: https://www.myfonts.com/viewlicense?type=web&buildid=3678880 + * Licensed pageviews: 200,000 + * Webfonts copyright: Copyright (c) 2014 by Vyacheslav Kirilenko, Gayane Bagdasaryan. All rights reserved. + * + * © 2018 MyFonts Inc +*/ + + +/* @import must be at top of file, otherwise CSS will not work */ +@import url("//hello.myfonts.net/count/3822a0"); + + +@font-face { + font-family: 'Formular'; + font-weight: 300; + src: url('../fonts/Formular-Light.woff2'); + src: url('../fonts/Formular-Light.woff2') format('woff2'), url('../fonts/Formular-Light.woff') format('woff'); + font-display: swap; +} + + +@font-face { + font-family: 'Formular'; + font-weight: 400; + src: url('../fonts/Formular-Regular.woff2'); + src: url('../fonts/Formular-Regular.woff2') format('woff2'), url('../fonts/Formular-Regular.woff') format('woff'); + font-display: swap; +} diff --git a/packages/website/public/fonts/Formular-Light.woff b/packages/website/public/fonts/Formular-Light.woff Binary files differnew file mode 100644 index 000000000..79c774b40 --- /dev/null +++ b/packages/website/public/fonts/Formular-Light.woff diff --git a/packages/website/public/fonts/Formular-Light.woff2 b/packages/website/public/fonts/Formular-Light.woff2 Binary files differnew file mode 100644 index 000000000..6502d5da1 --- /dev/null +++ b/packages/website/public/fonts/Formular-Light.woff2 diff --git a/packages/website/public/fonts/Formular-Regular.woff b/packages/website/public/fonts/Formular-Regular.woff Binary files differnew file mode 100644 index 000000000..651364b9b --- /dev/null +++ b/packages/website/public/fonts/Formular-Regular.woff diff --git a/packages/website/public/fonts/Formular-Regular.woff2 b/packages/website/public/fonts/Formular-Regular.woff2 Binary files differnew file mode 100644 index 000000000..91cdbf29f --- /dev/null +++ b/packages/website/public/fonts/Formular-Regular.woff2 diff --git a/packages/website/public/images/@next/0x-instant/0x-instant-widgets.png b/packages/website/public/images/@next/0x-instant/0x-instant-widgets.png Binary files differnew file mode 100644 index 000000000..707f0eccc --- /dev/null +++ b/packages/website/public/images/@next/0x-instant/0x-instant-widgets.png diff --git a/packages/website/public/images/@next/0x-instant/0x-instant-widgets@2x.png b/packages/website/public/images/@next/0x-instant/0x-instant-widgets@2x.png Binary files differnew file mode 100644 index 000000000..35d51387c --- /dev/null +++ b/packages/website/public/images/@next/0x-instant/0x-instant-widgets@2x.png diff --git a/packages/website/public/images/@next/0x-instant/widget-1.png b/packages/website/public/images/@next/0x-instant/widget-1.png Binary files differnew file mode 100755 index 000000000..622c1f42c --- /dev/null +++ b/packages/website/public/images/@next/0x-instant/widget-1.png diff --git a/packages/website/public/images/@next/0x-instant/widget-2.png b/packages/website/public/images/@next/0x-instant/widget-2.png Binary files differnew file mode 100755 index 000000000..7fec16cfb --- /dev/null +++ b/packages/website/public/images/@next/0x-instant/widget-2.png diff --git a/packages/website/public/images/@next/0x-instant/widget-3.png b/packages/website/public/images/@next/0x-instant/widget-3.png Binary files differnew file mode 100755 index 000000000..91ac7d36a --- /dev/null +++ b/packages/website/public/images/@next/0x-instant/widget-3.png diff --git a/packages/website/public/images/@next/0x-instant/widget-4.png b/packages/website/public/images/@next/0x-instant/widget-4.png Binary files differnew file mode 100755 index 000000000..3db35e068 --- /dev/null +++ b/packages/website/public/images/@next/0x-instant/widget-4.png diff --git a/packages/website/public/images/@next/0x-instant/widget-5.png b/packages/website/public/images/@next/0x-instant/widget-5.png Binary files differnew file mode 100755 index 000000000..05cebf28b --- /dev/null +++ b/packages/website/public/images/@next/0x-instant/widget-5.png diff --git a/packages/website/public/images/@next/0x-instant/widget-6.png b/packages/website/public/images/@next/0x-instant/widget-6.png Binary files differnew file mode 100755 index 000000000..33def6e04 --- /dev/null +++ b/packages/website/public/images/@next/0x-instant/widget-6.png diff --git a/packages/website/public/images/@next/about/about-office.png b/packages/website/public/images/@next/about/about-office.png Binary files differnew file mode 100755 index 000000000..432d18a8b --- /dev/null +++ b/packages/website/public/images/@next/about/about-office.png diff --git a/packages/website/public/images/@next/banner/bottomofcta.png b/packages/website/public/images/@next/banner/bottomofcta.png Binary files differnew file mode 100644 index 000000000..910022a28 --- /dev/null +++ b/packages/website/public/images/@next/banner/bottomofcta.png diff --git a/packages/website/public/images/@next/banner/topofcta.png b/packages/website/public/images/@next/banner/topofcta.png Binary files differnew file mode 100644 index 000000000..710c390ab --- /dev/null +++ b/packages/website/public/images/@next/banner/topofcta.png diff --git a/packages/website/public/images/@next/clients/bamboo.svg b/packages/website/public/images/@next/clients/bamboo.svg new file mode 100644 index 000000000..702b7d5aa --- /dev/null +++ b/packages/website/public/images/@next/clients/bamboo.svg @@ -0,0 +1,17 @@ +<svg width="70" height="55" viewBox="0 0 70 55" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M44.2922 11.0005C44.2962 10.9978 44.299 10.9951 44.303 10.9924C43.188 10.5459 41.9506 10.3193 40.5868 10.3193C37.1329 10.3193 34.5249 11.6898 32.7657 14.4281H32.4698C32.5599 13.2896 32.6272 12.3008 32.6769 11.4456C32.2358 11.4793 31.7933 11.4996 31.3495 11.4996C30.0798 11.4996 28.8007 11.3606 27.5297 11.0787C26.0812 10.7577 24.7012 10.2626 23.4087 9.61108L24.4685 26.3337C27.3535 27.1592 30.3878 26.6115 32.7738 24.9996C32.7711 24.8566 32.7657 24.7203 32.7657 24.5733V23.7572C32.798 21.1174 33.2419 19.2248 34.0972 18.0783C34.9527 16.9303 36.3097 16.3584 38.1699 16.3584C38.954 16.3584 39.6574 16.5243 40.2801 16.8548C40.9916 14.5522 42.385 12.4964 44.2922 11.0005Z" fill="white"/> +<path d="M27.9314 9.26574C29.5387 9.62185 31.1634 9.72033 32.7586 9.57464C32.7626 9.35342 32.7667 9.14299 32.7667 8.95818V-9.39018e-08H22.8017L23.2711 7.41367C24.6968 8.26619 26.2623 8.89613 27.9314 9.26574Z" fill="white"/> +<path d="M48.2361 14.1434C47.608 13.2747 46.8951 12.5571 46.1029 11.9851C43.9079 13.4285 42.3746 15.6919 41.8232 18.2387C41.8635 18.294 41.9052 18.3426 41.9442 18.3992C42.8656 19.7603 43.3269 21.8026 43.3269 24.5247C43.3269 27.2455 42.8696 29.3214 41.9564 30.7473C41.0444 32.1744 39.8138 32.888 38.2684 32.888C36.3599 32.888 34.9651 32.2445 34.0855 30.9577C33.4803 30.0728 33.0889 28.7778 32.8993 27.0944C31.1588 28.0548 29.1911 28.5741 27.1817 28.5741C26.3209 28.5741 25.4521 28.4757 24.5927 28.2801L25.2409 38.5062H30.9894L32.2469 35.4617H32.7661C34.6087 37.821 37.1494 38.9999 40.3908 38.9999C43.6631 38.9999 46.2509 37.7468 48.15 35.2392C50.0505 32.7315 51 29.1933 51 24.6231C51 20.1852 50.0787 16.6915 48.2361 14.1434Z" fill="white"/> +<path d="M11.4923 11.5399C14.6059 11.5426 17.5366 10.7386 20.3234 9.40857C21.2568 8.96208 22.1042 8.33078 22.9918 7.78447C23.3308 7.57539 23.4195 7.28402 23.3873 6.88609C23.1734 4.32179 21.8486 2.37799 20.0019 0.720171C19.928 0.652725 19.811 0.631142 19.6724 0.569092C19.663 0.729613 19.6375 0.832131 19.6563 0.923857C19.9293 2.30245 20.2992 3.64463 21.1264 4.81415C21.2434 4.98276 21.3039 5.19184 21.3913 5.38069L21.2851 5.46567C18.3059 3.95353 15.1519 3.51379 11.8917 3.71612C11.8742 3.80785 11.8567 3.89958 11.8393 3.9913C13.1116 4.58888 14.3624 5.24175 15.6631 5.76514C16.9609 6.28852 18.31 6.68105 19.6361 7.13159C15.5904 7.36496 11.9133 8.39688 9 11.432C9.83793 11.5196 10.6651 11.5385 11.4923 11.5399Z" fill="white"/> +<path d="M25.6998 43.0121C25.6998 44.114 25.6998 45.2159 25.6998 46.4026C26.3626 45.6155 27.1068 45.3007 28.0254 45.5187C28.7463 45.6882 29.2347 46.1362 29.5254 46.8264C30.0487 48.11 30.072 49.4299 29.5952 50.7134C28.9905 52.3724 27.1766 52.7962 25.8975 51.6216C25.8393 51.5732 25.7812 51.5247 25.7114 51.4642C25.4091 51.6337 25.5021 52.1665 25.0719 52.1665C24.7463 52.1544 24.4207 52.2149 24.1067 52.1302C23.9207 51.9243 24.0021 51.6942 24.0021 51.4763C24.0021 48.8729 24.0021 46.2694 24.0021 43.666C24.0021 43.448 23.9788 43.2301 23.9788 43C24.537 43.0121 25.1184 43.0121 25.6998 43.0121ZM28.1417 48.8729C28.1766 48.4248 28.1068 47.9889 27.9208 47.5772C27.7114 47.0807 27.3161 46.8385 26.8161 46.8991C26.3044 46.9596 25.9556 47.2624 25.8277 47.7709C25.6649 48.4612 25.6765 49.1635 25.8277 49.8537C25.9556 50.4107 26.3161 50.7497 26.8161 50.774C27.3975 50.8103 27.758 50.5681 27.9673 49.9869C28.0952 49.6357 28.1649 49.2603 28.1417 48.8729Z" fill="white"/> +<path d="M1.74422 43.0122C1.6977 44.1141 1.80236 45.2282 1.65119 46.3301C1.83724 46.3422 1.88375 46.1848 1.97678 46.1C3.00005 45.0707 4.6745 45.2766 5.36056 46.5722C6.11639 48.0011 6.12802 49.5268 5.45358 50.9799C4.79078 52.433 3.10471 52.7115 1.93027 51.6459C1.8605 51.5854 1.79073 51.5006 1.68608 51.4885C1.65119 51.5006 1.59305 51.5127 1.59305 51.5369C1.46514 52.0576 1.12793 52.215 0.639546 52.1303C0.43024 52.0939 0.209306 52.1061 0 52.0939C0 49.0667 0 46.0395 0 43.0122C0.581406 43.0122 1.16281 43.0122 1.74422 43.0122ZM1.73259 48.8124C1.72096 49.2604 1.73259 49.6964 1.90701 50.1202C2.08143 50.5561 2.39539 50.7741 2.84889 50.7862C3.30238 50.8104 3.65123 50.653 3.8489 50.2171C4.23263 49.3452 4.20938 48.4491 3.90705 47.5773C3.74425 47.1172 3.29076 46.8629 2.83726 46.8871C2.32562 46.9113 2.01166 47.2019 1.82561 47.7347C1.72096 48.0859 1.74422 48.4491 1.73259 48.8124Z" fill="white"/> +<path d="M64.0688 54.9999C64.0688 54.6608 64.0688 54.3218 64.0688 53.9827C64.3247 53.8374 64.5572 53.9222 64.7782 53.9101C65.2433 53.8859 65.6154 53.7042 65.8479 53.2925C66.1735 52.7234 66.3945 52.1664 66.0805 51.4398C65.3712 49.7688 64.7549 48.0493 64.1037 46.3541C64.0223 46.1482 63.8944 45.9666 63.9642 45.7002C64.3828 45.6154 64.8014 45.6639 65.2898 45.676C65.8363 47.2986 66.4526 48.9091 66.941 50.5922C67.1503 50.3985 67.1154 50.1321 67.1852 49.9141C67.6154 48.6427 68.034 47.3712 68.441 46.0877C68.5457 45.7728 68.6736 45.6154 69.0108 45.6396C69.3364 45.676 69.6736 45.6517 69.9992 45.6517C69.9992 45.7365 69.9992 45.8092 69.9992 45.8939C69.8945 45.9424 69.8945 46.0513 69.8596 46.1361C69.1038 48.2188 68.3131 50.2895 67.5922 52.3843C67.2201 53.4741 66.7433 54.4429 65.6968 54.9757C65.1503 54.9999 64.6154 54.9999 64.0688 54.9999Z" fill="white"/> +<path d="M56.6293 43.0122C56.6293 46.0273 56.6293 49.0425 56.6293 52.0939C56.1991 52.1545 55.827 52.1303 55.3502 52.1061C55.3502 49.0788 55.3502 46.0516 55.3502 43.0243C55.7805 43.0122 56.1991 43.0122 56.6293 43.0122Z" fill="white"/> +<path d="M14.9528 46.3544C15.9761 45.1798 17.7203 45.0829 18.8482 46.4391C19.2436 45.9064 19.7436 45.5915 20.3831 45.4704C21.8483 45.2161 22.8832 46.0517 22.9064 47.5895C22.9297 48.9578 22.918 50.3261 22.918 51.7066C22.918 51.8276 22.9413 51.9487 22.825 52.0819C22.325 52.0819 21.7901 52.0819 21.2669 52.0819C21.1273 51.8761 21.1855 51.6702 21.1855 51.4644C21.1738 50.3503 21.1855 49.2484 21.1738 48.1344C21.1622 47.2989 20.8715 46.9114 20.2901 46.8751C19.6622 46.8387 19.1505 47.311 19.0691 48.0618C18.9761 48.9094 19.0343 49.757 19.0226 50.6046C19.0226 51.089 19.0226 51.5612 19.0226 52.0819C18.418 52.1062 17.8947 52.1183 17.29 52.0698C17.29 51.7792 17.3017 51.5249 17.29 51.2585C17.2552 50.1082 17.3714 48.9578 17.2203 47.8196C17.1389 47.2504 16.9063 46.9598 16.4644 46.8751C15.9877 46.7903 15.5342 47.0325 15.3133 47.5047C15.1505 47.8559 15.0923 48.2313 15.0923 48.6188C15.0923 49.7449 15.0923 50.871 15.0923 52.0335C14.4993 52.1425 13.9644 52.094 13.383 52.0698C13.383 49.9023 13.383 47.7711 13.383 45.6157C13.7086 45.4704 14.0574 45.5552 14.3946 45.5552C14.9179 45.5673 14.6853 46.1606 14.9528 46.3544Z" fill="white"/> +<path d="M10.5367 48.1098C10.6065 47.0805 10.2111 46.6809 9.35062 46.7899C8.83898 46.8504 8.33897 47.0199 7.83896 47.25C7.6064 46.8746 7.43198 46.5114 7.30407 46.1118C7.46686 45.8212 7.76919 45.7969 8.01338 45.7122C8.83898 45.4458 9.6762 45.3368 10.5251 45.5305C11.653 45.7969 12.2344 46.3903 12.2925 47.5891C12.3507 49.0785 12.3042 50.5679 12.3042 52.0573C11.9437 52.251 11.5948 52.1905 11.2576 52.142C10.8506 52.0815 10.9902 51.5608 10.7227 51.3671C10.6065 51.355 10.5483 51.4518 10.4785 51.5245C9.7576 52.3237 8.83898 52.3963 7.90873 52.1663C7.11802 51.9725 6.76917 51.3186 6.66452 50.5194C6.54824 49.6476 6.8622 48.9332 7.50175 48.5578C8.03664 48.243 8.62967 48.1461 9.22271 48.1098C9.65295 48.0855 10.0716 48.1098 10.5367 48.1098ZM10.5134 49.0785C10.025 49.1753 9.55992 49.1148 9.10643 49.2722C8.54828 49.466 8.33897 49.8777 8.46688 50.4468C8.5599 50.8585 8.97852 51.0522 9.51341 50.9311C10.3506 50.7495 10.6646 50.2046 10.5134 49.0785Z" fill="white"/> +<path d="M33.7683 52.2389C32.0124 52.3358 30.8147 51.0522 30.7101 49.1874C30.6868 48.7515 30.7101 48.3156 30.7915 47.8676C31.1636 45.8817 32.8148 45.2762 34.2683 45.4942C36.3381 45.809 36.9079 47.6133 36.8148 49.1874C36.78 49.7929 36.6404 50.3741 36.3265 50.9069C35.8148 51.7909 34.9776 52.2389 33.7683 52.2389ZM35.0241 48.8847C35.0241 48.4609 35.0357 48.0371 34.8729 47.6375C34.6636 47.141 34.2799 46.9231 33.7799 46.8989C33.2683 46.8746 32.8613 47.1168 32.6752 47.6012C32.3496 48.4125 32.3729 49.248 32.6636 50.0714C32.8613 50.6284 33.2101 50.8222 33.8613 50.7858C34.4195 50.7616 34.6985 50.5437 34.8962 49.9987C35.0241 49.6476 35.0241 49.2601 35.0241 48.8847Z" fill="white"/> +<path d="M40.6856 52.2391C39.0344 52.3238 37.7669 51.1371 37.6506 49.3087C37.5925 48.3884 37.639 47.4923 38.1623 46.7053C38.8832 45.6154 39.953 45.349 41.1275 45.4822C42.3833 45.6276 43.2205 46.3662 43.581 47.6376C43.8135 48.4611 43.8135 49.3208 43.581 50.1442C43.2089 51.4278 42.2205 52.2996 40.6856 52.2391ZM41.9647 48.8243C41.9996 48.5216 41.9414 48.2068 41.86 47.8919C41.6856 47.238 41.3368 46.9353 40.7088 46.899C40.1158 46.8748 39.7088 47.1291 39.5228 47.7466C39.3018 48.4974 39.3135 49.2602 39.5344 49.9989C39.6972 50.5559 40.1158 50.8223 40.6856 50.8223C41.2437 50.8223 41.6391 50.5317 41.8135 49.9626C41.9298 49.6114 42.0112 49.236 41.9647 48.8243Z" fill="white"/> +<path d="M54.5122 49.1998C53.1052 49.1998 51.768 49.1998 50.4424 49.1998C50.3377 50.3381 50.9656 51.0888 52.0122 51.1373C52.7331 51.1736 53.4308 51.0525 54.082 50.7498C54.1401 50.8103 54.1866 50.8467 54.1866 50.8709C54.2099 51.9849 54.3843 51.8638 53.2796 52.1544C52.5936 52.3361 51.8494 52.324 51.1401 52.1544C50.0703 51.888 49.3842 51.1494 49.1168 50.0475C48.8958 49.1514 48.9424 48.2432 49.2447 47.3714C49.7098 46.0152 50.9191 45.3371 52.4308 45.5671C53.5703 45.7367 54.4076 46.7296 54.5238 48.0495C54.5471 48.4006 54.5122 48.7639 54.5122 49.1998ZM53.1982 48.1948C53.0587 46.9355 52.5936 46.4995 51.5703 46.6327C50.861 46.7175 50.3959 47.3956 50.5122 48.1948C51.3959 48.1948 52.2796 48.1948 53.1982 48.1948Z" fill="white"/> +<path d="M58.9435 46.9957C58.7458 46.7656 58.6876 46.4387 58.5597 46.1481C58.99 45.809 59.4551 45.7121 59.9319 45.6274C60.583 45.5063 61.2458 45.4942 61.8854 45.7C62.6296 45.9422 63.1063 46.4871 63.1296 47.2742C63.1877 48.8605 63.1412 50.4468 63.1412 52.033C62.3156 52.2389 62.3156 52.2389 61.9551 51.3307C61.8621 51.3065 61.8156 51.367 61.7691 51.4276C61.083 52.3358 60.1295 52.3358 59.176 52.1783C58.5248 52.0694 58.0132 51.4276 57.9202 50.7495C57.7923 49.7686 58.0597 49.0784 58.769 48.6788C59.2807 48.3761 59.8505 48.2429 60.4319 48.2308C60.897 48.2187 61.3505 48.2308 61.7923 48.2308C61.9668 47.0562 61.6063 46.6203 60.5946 46.6203C60.2225 46.6203 59.8737 46.693 59.5249 46.8383C59.3388 46.9109 59.176 47.0441 58.9435 46.9957ZM61.8272 49.0663C61.1412 49.0542 60.5016 49.03 59.897 49.2964C59.3853 49.5144 59.1993 49.9261 59.2923 50.5194C59.3621 50.9432 59.7109 51.2096 60.2458 51.2096C60.5714 51.2096 60.897 51.137 61.1877 50.9432C61.8389 50.5073 61.897 49.8534 61.8272 49.0663Z" fill="white"/> +<path d="M46.1743 52.0816C45.7208 52.1301 45.3371 52.1301 44.9185 52.0816C44.9185 49.9626 44.9185 47.8556 44.9185 45.7244C45.2092 45.5912 45.5347 45.6639 45.872 45.6881C45.9417 46.0393 46.0115 46.3662 46.0813 46.7416C46.4417 46.3904 46.6976 45.9666 47.1511 45.7486C47.6162 45.5307 48.0697 45.5186 48.6046 45.5912C48.6627 46.0272 48.6046 46.4267 48.5813 46.8142C48.2906 46.9353 48.0813 46.7779 47.8371 46.8142C46.7906 46.9595 46.2092 47.6255 46.1859 48.7759C46.1743 49.6598 46.1859 50.5438 46.1859 51.4399C46.1743 51.6215 46.1743 51.8274 46.1743 52.0816Z" fill="white"/> +</svg> diff --git a/packages/website/public/images/@next/clients/emoon.svg b/packages/website/public/images/@next/clients/emoon.svg new file mode 100644 index 000000000..1b14c41b0 --- /dev/null +++ b/packages/website/public/images/@next/clients/emoon.svg @@ -0,0 +1,8 @@ +<svg width="56" height="57" viewBox="0 0 56 57" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M45.9154 25.5331C40.1112 25.5331 34.2797 25.5331 28.2302 25.5331C28.2302 29.7282 28.2302 33.7069 28.2302 37.6585C23.2979 38.281 14.7414 34.9519 10.9537 27.0487C7.1932 19.1727 9.50944 9.34786 16.4309 4.01594C23.5432 -1.47838 33.6802 -1.37011 40.6562 4.55725C46.9509 9.8621 48.9129 18.9832 45.9154 25.5331ZM16.5672 18.5772C24.3607 18.5772 31.9907 18.5772 39.8114 18.5772C39.6479 14.7068 38.0402 11.7296 35.0699 9.61851C31.1732 6.83076 26.9494 6.50597 22.6712 8.83361C18.8562 10.8635 16.9759 14.1655 16.5672 18.5772Z" fill="white"/> +<path d="M8.85624 52.382H2.86125C3.13375 53.3564 3.84225 53.8977 4.82324 53.8977C5.55899 53.8977 6.26749 53.6 6.83974 53.0316L8.31124 54.4931C7.43924 55.4675 6.13124 56.0088 4.55074 56.0088C1.71675 56.0088 0 54.2766 0 51.6783C0 49.0259 1.7985 47.2666 4.49624 47.2666C7.52099 47.2396 9.04699 49.2424 8.85624 52.382ZM6.10399 50.8663C6.10399 49.892 5.47724 49.2153 4.49624 49.2153C3.56975 49.2153 2.97025 49.892 2.7795 50.8663H6.10399Z" fill="white"/> +<path d="M24.9048 50.4874V55.8734H22.0708V51.2723C22.0708 50.2979 21.5258 49.7025 20.6538 49.7025C19.6456 49.7296 19.0188 50.5145 19.0188 51.6241V55.8464H16.1848V51.2452C16.1848 50.2709 15.6398 49.6754 14.7678 49.6754C13.7596 49.7025 13.1328 50.4874 13.1328 51.5971V55.8193H10.2988V47.2666H13.1328V48.674C13.7323 47.6726 14.6861 47.1583 15.9396 47.1583C17.3293 47.1583 18.3921 47.862 18.8008 49.08C19.3458 47.8079 20.4086 47.1583 21.8256 47.1583C23.6786 47.2125 24.9048 48.4845 24.9048 50.4874Z" fill="white"/> +<path d="M35.5633 51.5971C35.5633 54.2495 33.683 55.9817 30.849 55.9817C28.015 55.9817 26.1348 54.2495 26.1348 51.5971C26.1348 48.9717 27.9878 47.2395 30.849 47.2395C33.7103 47.2395 35.5633 48.9717 35.5633 51.5971ZM28.996 51.6512C28.996 52.9233 29.759 53.7894 30.849 53.7894C31.9663 53.7894 32.702 52.9233 32.702 51.6512C32.702 50.3791 31.9663 49.5401 30.849 49.5401C29.759 49.513 28.996 50.3791 28.996 51.6512Z" fill="white"/> +<path d="M45.7254 51.5971C45.7254 54.2495 43.8451 55.9817 41.0111 55.9817C38.1771 55.9817 36.2969 54.2495 36.2969 51.5971C36.2969 48.9717 38.1499 47.2395 41.0111 47.2395C43.8724 47.2395 45.7254 48.9717 45.7254 51.5971ZM39.1581 51.6512C39.1581 52.9233 39.9211 53.7894 41.0111 53.7894C42.1284 53.7894 42.8641 52.9233 42.8641 51.6512C42.8641 50.3791 42.1284 49.5401 41.0111 49.5401C39.9211 49.513 39.1581 50.3791 39.1581 51.6512Z" fill="white"/> +<path d="M56.0009 50.4874V55.8734H53.1669V51.2723C53.1669 50.2979 52.5946 49.7025 51.6954 49.7025C50.7416 49.7296 50.1149 50.3791 50.0059 51.3264V55.8464H47.1719V47.2937H50.0059V48.674C50.6054 47.6996 51.6136 47.1583 52.8671 47.1583C54.7474 47.2125 56.0009 48.4845 56.0009 50.4874Z" fill="white"/> +</svg> diff --git a/packages/website/public/images/@next/clients/ercdex.svg b/packages/website/public/images/@next/clients/ercdex.svg new file mode 100644 index 000000000..41a0ff3b0 --- /dev/null +++ b/packages/website/public/images/@next/clients/ercdex.svg @@ -0,0 +1,16 @@ +<svg width="33" height="48" viewBox="0 0 33 48" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M2.16152 21.0377C2.1613 23.4544 2.16546 25.8711 2.1567 28.288C2.15538 28.6091 2.30283 29.0977 1.96829 29.202C1.56255 29.3284 1.20567 28.9928 0.973885 28.6151C0.501547 27.8461 0.13415 27.0646 0.138093 26.1145C0.159563 20.8668 0.138312 15.619 0.1554 10.3711C0.159344 9.16291 0.21981 9.12677 1.28695 9.63525C5.56493 11.6742 9.8278 13.7439 14.1045 15.7853C14.8239 16.1288 15.429 16.5203 15.5061 17.4008C15.5692 18.1211 15.2474 18.4863 14.5404 18.2975C14.0173 18.1577 13.53 17.8755 13.0349 17.6398C9.74783 16.0747 6.45308 14.5253 3.18462 12.9226C2.34314 12.5098 2.1326 12.6693 2.14772 13.5807C2.18847 16.0659 2.16152 18.552 2.16152 21.0377" fill="white"/> +<mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="17" y="9" width="16" height="27"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M17.5312 9.59204H32.9286V35.2771H17.5312V9.59204Z" fill="white"/> +</mask> +<g mask="url(#mask0)"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M17.5488 25.3121C17.5488 22.8275 17.5799 20.3425 17.5324 17.859C17.5151 16.9481 17.689 16.3417 18.6181 15.9169C22.8626 13.9771 27.0738 11.964 31.2972 9.97869C31.7776 9.75281 32.3431 9.27566 32.7512 9.90486C33.1142 10.4646 32.8827 11.0857 32.3961 11.5826C31.9457 12.0431 31.3539 12.2411 30.8019 12.5062C27.5847 14.0499 24.3806 15.6233 21.1266 17.0859C19.8779 17.6472 19.4552 18.3837 19.4885 19.7705C19.5935 24.1157 19.5273 28.4653 19.5269 32.813C19.5269 33.2961 19.5433 33.7802 19.5157 34.262C19.4861 34.7762 19.3181 35.2231 18.7066 35.2735C18.0888 35.3243 17.8479 34.8237 17.6991 34.3967C17.5462 33.9579 17.5569 33.4503 17.5547 32.9727C17.5427 30.4193 17.549 27.8655 17.5488 25.3121" fill="white"/> +</g> +<path fill-rule="evenodd" clip-rule="evenodd" d="M31.5424 7.52054C31.5145 7.78979 31.3307 7.86997 31.1704 7.99616C30.3475 8.64508 29.6074 8.1872 28.8704 7.83689C25.6554 6.30837 22.4468 4.7667 19.234 3.23379C18.7406 2.99828 18.2135 2.82477 17.7442 2.55092C16.8795 2.04616 16.1101 2.17651 15.236 2.60963C11.9848 4.22119 8.70081 5.76702 5.42491 7.32841C4.74598 7.65221 4.0493 7.9392 3.35876 8.23825C2.94776 8.41658 2.49054 8.46324 2.28658 8.01237C2.08546 7.56764 2.09423 7.05959 2.6347 6.76033C2.87547 6.62713 3.10594 6.47334 3.35394 6.35635C7.5031 4.39974 11.6597 2.45891 15.7992 0.482144C16.4076 0.191644 16.8819 0.174774 17.5087 0.481487C21.8126 2.58751 26.1438 4.6381 30.4577 6.72396C30.8641 6.92048 31.3794 7.02432 31.5424 7.52054" fill="white"/> +<path fill-rule="evenodd" clip-rule="evenodd" d="M22.7216 31.8144C22.4408 31.7018 22.2732 31.4792 22.2309 31.1979C22.1091 30.3845 22.2666 29.6725 23.0855 29.2807C25.998 27.8867 28.9054 26.482 31.8349 25.1252C32.5575 24.7907 33.0103 25.2308 32.8745 26.0445C32.7674 26.6879 32.4532 27.1876 31.8363 27.4808C28.9196 28.8651 26.0072 30.2585 23.093 31.6481C22.9705 31.7068 22.8452 31.7599 22.7216 31.8144" fill="white"/> +<path fill-rule="evenodd" clip-rule="evenodd" d="M25.3483 10.558C25.2596 10.6741 25.1682 10.8647 25.0184 10.978C24.4579 11.4008 23.8897 11.2926 23.276 11.0323C20.2472 9.74786 17.3273 8.23905 14.3851 6.77538C14.1441 6.65576 13.8244 6.5942 13.8481 6.25374C13.8759 5.85392 14.2457 5.70823 14.5408 5.58007C14.9992 5.38159 15.4555 5.45016 15.9252 5.67756C18.8206 7.07902 21.7311 8.44915 24.6271 9.84973C24.9077 9.98534 25.3097 10.0528 25.3483 10.558" fill="white"/> +<path fill-rule="evenodd" clip-rule="evenodd" d="M7.66389 9.32442C7.61438 8.98528 7.81111 8.88451 7.98747 8.79403C8.5297 8.51645 9.00882 8.23274 9.70572 8.57911C12.5794 10.0066 15.4932 11.3533 18.3824 12.75C18.7121 12.9092 19.278 12.9982 19.0979 13.5603C18.9652 13.9753 18.5588 14.1871 18.1112 14.1615C17.7771 14.1422 17.4173 14.1052 17.1214 13.9656C14.0959 12.5368 11.08 11.0874 8.06546 9.63573C7.89896 9.55555 7.76598 9.40526 7.66389 9.32442" fill="white"/> +<path fill-rule="evenodd" clip-rule="evenodd" d="M10.4641 44.7585C10.4641 44.1654 10.4604 43.5722 10.4669 42.9791C10.4685 42.8461 10.4249 42.7688 10.3092 42.7046C10.0297 42.5497 9.73455 42.4448 9.42192 42.3834C9.07468 42.3151 8.7213 42.2791 8.37801 42.3609C7.75757 42.5083 7.2653 42.8483 6.95595 43.421C6.63281 44.0189 6.55285 44.6586 6.63062 45.3268C6.70335 45.9525 6.92068 46.5056 7.39609 46.9396C7.87675 47.3785 8.45118 47.5152 9.07556 47.4245C9.54483 47.3561 9.95451 47.1353 10.318 46.8253C10.4264 46.733 10.4685 46.6423 10.4669 46.5032C10.4604 45.9218 10.4641 45.3401 10.4641 44.7585M10.445 42.2412C10.4779 42.1709 10.4641 42.1008 10.4641 42.0329C10.4652 41.1277 10.4687 40.2226 10.4608 39.3176C10.4597 39.1743 10.5024 39.1034 10.6387 39.0795C10.7439 39.0611 10.8378 38.9868 10.9621 39.012V47.7669C10.8004 47.7873 10.6426 47.7816 10.4779 47.7706C10.4409 47.6019 10.4895 47.4332 10.4483 47.2746C10.3703 47.2547 10.3331 47.3079 10.2901 47.3408C9.83423 47.6904 9.32115 47.9032 8.74606 47.9056C7.95365 47.9093 7.27165 47.6348 6.7544 47.0111C6.30616 46.4706 6.11578 45.8353 6.07722 45.1467C6.04392 44.5523 6.11841 43.9733 6.37561 43.4302C6.79931 42.5361 7.49423 42.0033 8.4836 41.8743C9.13164 41.7897 9.74156 41.9192 10.3208 42.2123C10.3552 42.2296 10.3865 42.2621 10.445 42.2412" fill="white"/> +<path fill-rule="evenodd" clip-rule="evenodd" d="M13.9915 39.773C14.0598 39.747 14.1181 39.7544 14.1753 39.7544C15.5701 39.754 16.9648 39.754 18.3595 39.7542C18.5547 39.7542 18.5562 39.7548 18.5547 39.9542C18.554 40.0458 18.5667 40.1387 18.5418 40.2296C18.4819 40.2646 18.4169 40.2478 18.3551 40.2478C17.1449 40.2489 15.9345 40.2486 14.7243 40.2486C14.5216 40.2486 14.5218 40.2491 14.5218 40.4577C14.5218 41.4258 14.5218 42.3941 14.5216 43.3624C14.5216 43.527 14.5216 43.5274 14.6921 43.5274C15.6891 43.5276 16.6861 43.5274 17.6832 43.5276C17.8858 43.5276 17.8858 43.5281 17.8856 43.7362C17.8856 43.8216 17.8856 43.9066 17.8856 43.9798C17.8335 44.03 17.7848 44.0118 17.741 44.0118C16.7324 44.0129 15.7237 44.0124 14.7151 44.0127C14.5216 44.0127 14.5218 44.0131 14.5218 44.2118C14.5218 45.1801 14.5216 46.1483 14.5225 47.1166C14.5225 47.167 14.5076 47.22 14.5446 47.2853H18.5332C18.5713 47.4511 18.5549 47.6025 18.5457 47.7653H13.9915V39.773Z" fill="white"/> +<path fill-rule="evenodd" clip-rule="evenodd" d="M20.6225 39.7707C20.8164 39.7411 20.9831 39.7597 21.1489 39.7547C21.235 39.752 21.2644 39.8219 21.3027 39.8765C21.6811 40.4132 22.0579 40.9506 22.4354 41.4878C22.8323 42.0533 23.2298 42.6185 23.6267 43.1839C23.6532 43.2216 23.6754 43.2624 23.7214 43.2856C23.7959 43.2464 23.8292 43.1695 23.8743 43.1053C24.6264 42.0359 25.3781 40.9664 26.1251 39.8938C26.2428 39.7271 26.2666 39.7562 26.3922 39.7518C26.5499 39.7463 26.6875 39.7463 26.8198 39.7463C26.7738 39.8302 26.7526 39.8727 26.7219 39.9155C25.8697 41.097 25.0161 42.2774 24.1639 43.4591C24.0088 43.6742 24.0046 43.6085 24.1694 43.8361C25.074 45.0864 25.9814 46.3345 26.8871 47.5842C26.9237 47.6348 26.9721 47.6784 26.9968 47.7743C26.7981 47.7743 26.6071 47.7791 26.4167 47.7697C26.3852 47.7682 26.3532 47.7077 26.3269 47.6705C25.5531 46.5814 24.7804 45.4919 24.0071 44.4027C23.9111 44.2675 23.814 44.1336 23.7205 44.0033C23.6397 44.0173 23.6215 44.0784 23.5897 44.1236C22.76 45.2998 21.9299 46.4758 21.104 47.6549C21.0403 47.7461 20.9756 47.7866 20.8641 47.7787C20.7226 47.7686 20.5795 47.7763 20.4211 47.7763C20.4389 47.6884 20.4891 47.64 20.527 47.5874C21.4258 46.3472 22.3267 45.1083 23.2245 43.8675C23.4263 43.5888 23.4116 43.6801 23.2262 43.4199C22.404 42.2664 21.5779 41.1156 20.7537 39.9637C20.7138 39.9078 20.6766 39.8502 20.6225 39.7707" fill="white"/> +</svg> diff --git a/packages/website/public/images/@next/clients/godsUnchained.svg b/packages/website/public/images/@next/clients/godsUnchained.svg new file mode 100644 index 000000000..f039b00f9 --- /dev/null +++ b/packages/website/public/images/@next/clients/godsUnchained.svg @@ -0,0 +1,16 @@ +<svg width="64" height="56" viewBox="0 0 64 56" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M49.6638 13.9894C49.7509 13.7863 49.7654 13.5106 49.6929 13.3075C49.3011 12.1903 48.8948 11.0875 48.4741 9.98483C48.4015 9.7962 48.2564 9.56405 48.0823 9.50602C46.7765 9.0127 45.4706 8.54839 44.1503 8.06958C43.7585 7.92449 43.1491 7.44568 42.975 6.90883C42.4382 5.24024 41.9884 4.05047 41.437 2.38189C41.3209 2.01915 41.1033 1.83053 40.7551 1.71446C39.6669 1.3227 38.5641 0.945456 37.4904 0.510173C36.9536 0.292532 36.4893 0.33606 35.967 0.568211C34.7772 1.10506 33.5729 1.61289 32.3686 2.0917C32.122 2.19327 31.7447 2.17876 31.4981 2.07719C30.0036 1.45329 28.4946 0.800362 27.0001 0.118419C26.6229 -0.0556942 26.3327 -0.0266754 25.9845 0.132928C24.9253 0.59723 23.8516 1.03251 22.8069 1.52583C22.5748 1.6274 22.3571 1.87406 22.241 2.10621C21.5881 3.48461 20.9642 4.863 20.3693 6.2559C20.1952 6.67668 19.9486 6.90883 19.5278 7.06843C18.2655 7.53273 17.0177 8.05507 15.7408 8.51937C15.291 8.67898 15.0154 8.92564 14.8412 9.37543C14.4495 10.3911 13.9852 11.3632 13.6079 12.3789C13.5064 12.6401 13.5064 12.9883 13.5934 13.264C14.0142 14.4392 14.493 15.6 14.9138 16.7897C15.0008 17.0364 15.0008 17.3556 14.9138 17.6023C14.2899 19.1548 13.637 20.7073 12.955 22.2598C12.8099 22.579 12.8244 22.8257 12.955 23.1449C13.4483 24.3492 13.9271 25.5679 14.3624 26.7867C14.493 27.164 14.7107 27.3526 15.0879 27.4977C16.5098 28.0491 17.9172 28.6294 19.3101 29.2388C19.5858 29.3549 19.847 29.6451 19.9631 29.9208C20.5725 31.4152 21.1383 32.9387 21.7042 34.4477C21.8493 34.8395 22.0814 35.0861 22.4732 35.2312C23.3583 35.5649 24.2143 35.9277 25.0849 36.3049C25.5347 36.4935 25.9555 36.5081 26.4052 36.3049C27.7111 35.7245 29.0169 35.1587 30.3373 34.6218C30.5695 34.5203 30.9177 34.4767 31.1353 34.5783C32.6733 35.2312 34.1823 35.9277 35.7058 36.6096C35.8944 36.6967 36.112 36.7547 36.2717 36.8127C36.4603 36.7547 36.6054 36.7402 36.736 36.6822C37.6936 36.2904 38.6512 35.8696 39.6088 35.4924C40.0151 35.3328 40.2763 35.0861 40.4504 34.6799C41.0017 33.3885 41.5966 32.1262 42.1335 30.8349C42.3076 30.4141 42.5542 30.1819 42.975 30.0223C44.484 29.4275 45.7898 28.8035 47.2988 28.2087C47.6761 28.0636 47.9517 27.8604 48.1113 27.4542C48.4741 26.5546 49.1125 25.684 49.4027 24.7699C49.5333 24.3492 49.5042 23.8123 49.3446 23.3915C48.9094 22.2163 48.387 21.07 47.8792 19.9238C47.647 19.4014 47.6325 18.9371 47.8647 18.4003C48.4886 16.9494 49.0835 15.4694 49.6638 13.9894ZM35.227 2.23679C35.8509 1.99013 36.3442 2.17876 36.9681 2.3964C37.7516 2.67208 38.5496 2.90423 39.3477 3.19442C39.5073 3.25245 39.6959 3.39755 39.7684 3.55715C40.0006 4.03596 40.3488 5.03711 40.3488 5.03711C40.3488 5.03711 41.1468 7.05392 41.1323 7.11196C40.8856 7.06843 38.0998 5.84964 36.9681 5.37083C36.823 5.31279 36.5909 5.31279 36.4313 5.38534C35.5027 5.82062 30.1777 7.90998 30.1777 7.90998C30.1777 7.90998 29.6844 8.62094 29.4087 9.07073C29.4087 9.07073 29.1185 9.62209 29.0024 9.9413C28.6542 10.8554 28.277 11.7695 27.9142 12.6691L26.3907 16.3109C25.6072 18.1681 24.7947 20.0253 24.0112 21.8971C23.9386 22.0857 23.8081 22.2453 23.7065 22.4194C23.6485 22.4049 23.6049 22.4049 23.5469 22.3904C23.4598 22.0276 23.4018 21.6504 23.2567 21.3167C23.0826 20.8814 22.8214 20.5042 22.6183 20.0834C22.2556 19.3289 21.8058 18.6324 22.212 17.6893C23.7936 13.9314 25.3461 10.1589 26.8695 6.37198C27.0872 5.83513 27.4064 5.51592 27.9432 5.29828C30.3373 4.36968 32.8329 3.20893 35.227 2.23679ZM30.0906 10.3911C32.4992 11.4067 34.8207 12.3789 37.1712 13.3655L35.7783 16.6882L28.6687 13.7283L29.9455 10.6523C30.0181 10.5652 30.0471 10.4781 30.0906 10.3911ZM34.7627 19.1548L34.3709 20.0834C34.2548 20.301 34.1388 20.5042 34.0952 20.7363L33.8776 21.2732L26.768 18.3132L28.1174 15.0921L35.227 18.0521L35.1544 18.2117C35.0238 18.5309 34.8933 18.8501 34.7627 19.1548ZM24.9253 22.7386L26.1731 19.7497C28.5381 20.7508 30.8451 21.7229 33.2247 22.7096C32.7459 23.8558 32.3106 24.886 31.8463 25.9887C31.6286 25.9307 31.3239 25.8872 31.0483 25.7711C29.2346 25.0021 27.4209 24.2041 25.6072 23.4206C25.1429 23.2319 24.9398 23.0433 24.9253 22.7386ZM19.847 11.2617C21.0077 8.72251 22.0669 6.12532 23.1551 3.54264C23.3873 2.97678 23.8806 2.78815 24.3739 2.61404C24.4755 2.58502 25.6798 1.88857 26.5649 1.71446C27.0292 1.6274 27.2178 1.85955 27.5515 1.99013C28.2479 2.28032 28.9299 2.58502 29.6118 2.88972C29.6989 2.91874 29.7569 2.99128 29.9601 3.13638C29.0605 3.52813 27.4354 4.21008 27.4354 4.21008C27.4354 4.21008 26.5358 4.60183 26.3472 4.81947C25.999 5.21123 25.5782 5.76258 25.4186 6.19787C24.1128 9.57856 22.6908 12.9157 21.3124 16.2674C21.2979 16.3109 21.2399 16.3254 21.1383 16.427C20.9497 16.0933 20.7611 15.7886 20.6015 15.4549C20.3548 14.918 20.0936 14.3667 19.905 13.8008C19.7744 13.4091 19.5568 12.7416 19.5133 12.3354C19.4697 11.9001 19.6293 11.7405 19.847 11.2617ZM15.262 12.9302C15.5087 12.495 16.031 11.5083 16.031 11.5083C16.031 11.5083 16.4518 10.4636 16.7275 10.0574C16.9306 9.75268 17.7141 9.53503 17.7141 9.53503C17.7141 9.53503 19.2086 8.88211 19.5423 8.63545C19.4262 8.96917 19.2666 9.43347 19.0925 9.89777C18.8458 10.5217 18.6137 11.1601 18.3235 11.7695C18.1349 12.1612 18.1784 12.4804 18.3525 12.8722C19.8035 16.3254 21.2399 19.7787 22.6763 23.2319C22.7344 23.377 22.7779 23.5511 22.8359 23.7398C22.241 23.8994 22.212 23.8413 21.3995 23.3915C21.2979 23.3335 19.4552 22.7096 18.6862 22.4049C18.5121 22.3323 18.3235 22.1002 18.309 21.9261C18.251 20.9975 17.7431 20.2575 17.3949 19.445C17.0757 18.6905 16.829 17.9215 16.5098 17.1815C16.0455 16.1368 15.7698 15.0341 15.32 13.9894C15.0879 13.5541 15.0444 13.293 15.262 12.9302ZM18.8168 27.2075C17.9898 26.8593 15.6247 25.9887 15.6247 25.9887L14.522 23.2755C14.4495 23.1013 14.464 22.8982 14.5656 22.7241C15.0008 21.9696 16.0455 19.5465 16.1906 19.3869C16.4663 19.9963 17.2643 22.0131 17.511 22.608C17.6851 23.0433 17.9608 23.3045 18.396 23.4931C21.7767 24.857 25.1429 26.2499 28.5091 27.6428C28.7268 27.7298 28.9154 27.8459 29.2781 28.0345C28.9009 28.1942 28.6687 28.3102 28.4366 28.3973C27.537 28.76 26.6519 29.1228 25.7523 29.5C25.23 29.7322 24.7512 29.6886 24.2143 29.4565C22.4297 28.6875 20.616 27.962 18.8168 27.2075ZM28.9299 33.2144C28.3205 33.4756 25.8394 34.5058 25.7233 34.4767C25.5492 34.4332 22.9665 33.7513 22.7489 33.5336C22.6618 33.4466 21.472 29.8627 21.1528 29.6451C21.1964 29.5725 22.4732 30.1384 22.5022 30.0659C23.2277 30.3561 23.9677 30.6317 24.6786 30.9655C25.0994 31.1686 25.4621 31.1831 25.9119 30.98C27.8127 30.1384 29.7279 29.3404 31.6431 28.5424C32.151 28.3392 32.4992 28.0781 32.7168 27.5122C32.949 26.8883 33.1957 26.2644 33.4423 25.6405H33.4568L38.361 13.9024C38.4045 13.9459 38.4626 14.0039 38.5351 14.062C38.5496 14.0765 38.5641 14.091 38.5641 14.1055L40.1312 17.907C40.1602 18.1391 40.1457 18.4003 40.0731 18.6034C38.5061 22.4194 36.8956 26.2209 35.3285 30.0514C35.1254 30.5302 34.8497 30.8349 34.3564 31.0235C32.5427 31.7345 30.7291 32.4599 28.9299 33.2144ZM42.5107 24.7554C41.5821 27.0044 39.5218 33.1419 38.7092 33.5917C37.8242 34.085 35.8219 35.1732 35.8219 35.1732C35.8219 35.1732 32.92 33.8964 32.4121 33.6207C32.3106 33.5626 32.1945 33.5191 32.0059 33.4321C32.1945 33.3015 32.2961 33.1854 32.4267 33.1274C33.5294 32.6485 34.6321 32.1552 35.7493 31.6909C36.112 31.5458 36.3297 31.3427 36.4748 30.9655C37.592 28.1361 38.7528 25.3213 39.8845 22.4919C40.0296 22.1292 40.1602 21.7665 40.3053 21.4183C40.2908 21.4473 40.2617 21.4763 40.2472 21.5053L40.9002 19.8222C40.9582 19.9093 42.1625 22.7966 42.1625 22.7966C42.2786 23.1013 42.3946 23.406 42.4672 23.7252C42.5687 24.059 42.6268 24.4652 42.5107 24.7554ZM47.4729 24.059C47.1392 24.7554 46.2832 26.7867 46.2832 26.7867C46.2832 26.7867 43.4683 28.0781 42.7429 28.1942C42.975 27.5702 43.6715 25.1762 43.9762 24.5523C44.2373 24.0009 44.0487 23.5947 43.7585 23.1739L39.3477 12.4514C39.5653 12.4659 39.7829 12.5675 40.0006 12.6546C41.0453 13.0753 42.0899 13.5251 43.1491 13.9459C43.5409 14.1055 43.773 14.3522 43.9181 14.7439C44.8903 17.167 45.8769 19.5756 46.878 21.9841C47.1392 22.608 47.7776 23.4206 47.4729 24.059ZM46.5298 15.658C46.3412 16.1513 46.022 17.2686 45.9639 17.2831C45.8479 17.138 44.9048 14.8745 44.4985 13.8734C44.3389 13.4671 44.0777 13.2204 43.6715 13.0463C40.3778 11.7114 37.0987 10.3766 33.8196 9.0272C33.5004 8.89662 33.1811 8.72251 32.8764 8.5629C32.8764 8.47585 32.8764 8.38879 32.8619 8.30173C34.2984 7.72136 35.7348 7.12647 37.1857 6.5606C37.3018 6.51707 37.4759 6.60413 37.6065 6.64766C39.7974 7.57626 42.0319 8.46134 44.1793 9.50602C44.8177 9.81071 45.8624 10.0138 46.4282 10.5942C46.8925 11.073 47.5455 13.2785 47.5455 13.2785C47.5455 13.2785 46.6314 15.3823 46.5298 15.658Z" fill="white"/> +<path d="M0 55.3291V46.5164L0.638921 45.8995H3.15054L3.76743 46.5164V47.7943L3.92165 48.4112H2.3574L2.53365 47.7943V47.2875L2.37943 47.1333H1.41003L1.27784 47.2875V54.536L1.43206 54.6902H2.40146L2.55568 54.536V52.1786H2.15911L1.8727 50.9007H3.89962L3.7454 51.5397V55.3291L3.12851 55.946H0.638921L0 55.3291Z" fill="white"/> +<path d="M8.61313 46.5164V55.3291L7.99624 55.946H5.46259L4.8457 55.3291V46.5164L5.46259 45.8995H7.97421L8.61313 46.5164ZM7.18107 47.1774H6.2337L6.07948 47.3316V54.558L6.2337 54.7122H7.18107L7.33529 54.558V47.3096L7.18107 47.1774Z" fill="white"/> +<path d="M9.51758 45.8995H12.8003L13.4392 46.5164V55.3291L12.8003 55.946H9.51758L9.6718 55.3291V46.5164L9.51758 45.8995ZM10.9276 54.536L11.0818 54.6902H12.0512L12.2055 54.536V47.2875L12.0512 47.1333H11.0818L10.9276 47.2875V54.536Z" fill="white"/> +<path d="M18.4182 48.4112H16.854L17.0082 47.7943V47.3096L16.854 47.1553H15.8846L15.7303 47.3096V50.1517L15.8846 50.3059H17.6251L18.242 50.9228V55.3291L17.6251 55.946H15.1135L14.4745 55.3291V54.0513L14.3203 53.4564H15.8846L15.7303 54.0513V54.536L15.8846 54.6902H16.854L17.0082 54.536V51.6939L16.854 51.5397H15.1135L14.4745 50.9007V46.4944L15.1135 45.8995H17.6251L18.242 46.5164V47.7943L18.4182 48.4112Z" fill="white"/> +<path d="M26.1072 46.5164V55.3291L25.4683 55.946H22.9567L22.3398 55.3291V46.5164L22.1855 45.8995H23.7498L23.5735 46.5164V54.536L23.7278 54.6902H24.6972L24.8514 54.536V46.5164L24.6972 45.8995H26.2614L26.1072 46.5164Z" fill="white"/> +<path d="M28.6404 55.946H27.0762L27.2304 55.3291V46.5164L27.0762 45.8995H28.4862L30.0505 51.804V46.5164L29.8962 45.8995H31.4605L31.3063 46.5164V55.3291L31.4605 55.946H30.0505L28.4862 50.0415V55.3512L28.6404 55.946Z" fill="white"/> +<path d="M32.3652 55.3291V46.5164L33.0042 45.8995H35.5158L36.1327 46.5164V47.7943L36.2869 48.4112H34.7226L34.8989 47.7943V47.2875L34.7447 47.1333H33.7753L33.621 47.2875V54.536L33.7753 54.6902H34.7447L34.8989 54.536V54.0513L34.7226 53.4344H36.2869L36.1327 54.0513V55.3291L35.5158 55.946H33.0042L32.3652 55.3291Z" fill="white"/> +<path d="M37.0787 45.8995H38.6429L38.4887 46.5164V50.1517L38.6429 50.3059H39.6123L39.7665 50.1517V46.5164L39.5903 45.8995H41.1545L41.0003 46.5164V55.3291L41.1545 55.946H39.5903L39.7445 55.3291V51.6939L39.5903 51.5397H38.6209L38.4667 51.6939V55.3291L38.6209 55.946H37.0566L37.2109 55.3291V46.5164L37.0787 45.8995Z" fill="white"/> +<path d="M46.7068 55.946H45.1426L45.2527 55.5274L44.9223 53.6106L44.746 53.4344H43.6444L43.4682 53.6106L43.1597 55.5274L43.2478 55.946H41.6836L41.97 55.0868L43.4461 46.4724L43.3139 45.8995H45.0324L44.9002 46.4724L46.3984 55.0868L46.7068 55.946ZM43.8427 52.1566H44.5257L44.6579 52.0464L44.1952 49.3585L43.7105 52.0684L43.8427 52.1566Z" fill="white"/> +<path d="M48.8006 55.946H47.2363L47.3906 55.3291V46.5164L47.2363 45.8995H48.8006L48.6464 46.5164V55.3291L48.8006 55.946Z" fill="white"/> +<path d="M51.1795 55.946H49.6152L49.7695 55.3291V46.5164L49.6152 45.8995H51.0253L52.5895 51.804V46.5164L52.4353 45.8995H53.9996L53.8453 46.5164V55.3291L53.9996 55.946H52.5895L51.0253 50.0415V55.3512L51.1795 55.946Z" fill="white"/> +<path d="M54.8164 55.946L54.9706 55.3291V46.5164L54.8164 45.8995H58.5838L58.8042 47.2875L58.1652 47.1333H56.3586L56.2044 47.2875V50.1517L56.3586 50.3059H56.8654L57.4822 50.1517V51.7159L56.8654 51.5617H56.3586L56.2044 51.7159V54.558L56.3586 54.7122H58.1652L58.8042 54.558L58.5838 55.968H54.8164V55.946Z" fill="white"/> +<path d="M59.3965 45.8995H62.6792L63.3181 46.5164V55.3291L62.6792 55.946H59.3965L59.5507 55.3291V46.5164L59.3965 45.8995ZM60.8065 54.536L60.9607 54.6902H61.9301L62.0844 54.536V47.2875L61.9081 47.1333H60.9387L60.8065 47.2875V54.536Z" fill="white"/> +</svg> diff --git a/packages/website/public/images/@next/clients/instex.svg b/packages/website/public/images/@next/clients/instex.svg new file mode 100644 index 000000000..c92033b93 --- /dev/null +++ b/packages/website/public/images/@next/clients/instex.svg @@ -0,0 +1,40 @@ +<svg width="43" height="55" viewBox="0 0 43 55" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M5.36442 47.6098C5.31169 47.7017 5.33806 47.7804 5.33806 47.8461C5.33806 49.9726 5.33806 52.0859 5.33806 54.2124C5.33806 54.3831 5.29851 54.4356 5.12714 54.4224C4.77122 54.4093 4.4153 54.4093 4.05938 54.4224C3.88801 54.4224 3.83529 54.3699 3.83529 54.1993C3.84847 53.2804 3.83529 52.3616 3.83529 51.4427C3.83529 49.0406 3.83529 46.6516 3.83529 44.2494C3.83529 44.1706 3.80892 44.0919 3.87483 44C6.23444 46.4547 8.59406 48.9093 10.9932 51.4033C10.9932 51.2721 10.9932 51.2064 10.9932 51.1277C10.9932 49.0406 10.9932 46.9535 10.9932 44.8663C10.9932 44.6957 11.0459 44.6301 11.2041 44.6432C11.5732 44.6432 11.9292 44.6432 12.2983 44.6432C12.4169 44.6432 12.496 44.6563 12.496 44.827C12.496 48.1874 12.496 51.5346 12.496 54.895C12.496 54.9081 12.496 54.9344 12.4828 55C10.0836 52.5191 7.73721 50.0644 5.36442 47.6098Z" fill="#FBFBFB"/> +<path d="M28.9219 49.5394C28.9219 47.9774 28.9219 46.4285 28.9219 44.8664C28.9219 44.6826 28.9746 44.6301 29.146 44.6301C30.8069 44.6301 32.4547 44.6301 34.1157 44.6301C34.2738 44.6301 34.3661 44.6695 34.3529 44.8533C34.3398 45.1289 34.3529 45.4046 34.3529 45.6934C34.3529 46.0478 34.3529 46.0478 34.0102 46.0478C32.9029 46.0478 31.8088 46.0478 30.7015 46.0478C30.3851 46.0478 30.4378 46.0215 30.4378 46.3234C30.4378 46.9273 30.451 47.5442 30.4378 48.148C30.4378 48.3449 30.4906 48.3712 30.6751 48.3712C31.7956 48.358 32.9161 48.3712 34.0497 48.3581C34.2211 48.3581 34.2738 48.4106 34.2607 48.5681C34.2475 48.8962 34.2475 49.2113 34.2607 49.5394C34.2738 49.7101 34.2211 49.7626 34.0497 49.7626C32.9161 49.7495 31.7956 49.7626 30.6619 49.7495C30.4774 49.7495 30.4378 49.802 30.4378 49.9726C30.451 50.9177 30.451 51.8628 30.4378 52.8079C30.4378 52.9917 30.4906 53.018 30.6487 53.018C31.822 53.0048 32.982 53.018 34.1552 53.0048C34.3134 53.0048 34.3661 53.0442 34.3661 53.2017C34.3529 53.5561 34.3529 53.8974 34.3661 54.2518C34.3661 54.37 34.3266 54.4094 34.2079 54.4094C32.4942 54.4094 30.7937 54.4094 29.0801 54.4094C28.9087 54.4094 28.9351 54.3175 28.9351 54.2125C28.9219 52.6635 28.9219 51.1015 28.9219 49.5394Z" fill="#FCFCFC"/> +<path d="M35.3016 54.4094C35.2884 54.2125 35.4466 54.1075 35.5257 53.9762C35.7629 53.5299 36.0134 53.0968 36.2902 52.6767C36.5275 52.3223 36.7252 51.9416 36.9625 51.5741C37.1602 51.259 37.358 50.9309 37.5425 50.6158C37.7534 50.2614 37.9644 49.907 38.1885 49.5526C38.2939 49.382 38.3071 49.2376 38.2016 49.0538C37.9907 48.7256 37.7666 48.3843 37.5953 48.0299C37.4107 47.6493 37.1866 47.2948 36.9757 46.9404C36.7516 46.5729 36.5539 46.2053 36.3298 45.8378C36.1057 45.4571 35.8552 45.0896 35.6707 44.6695C35.7366 44.6039 35.8157 44.6302 35.8816 44.6302C36.2375 44.6302 36.5934 44.6433 36.9493 44.6302C37.2393 44.617 37.4107 44.7089 37.5425 44.9583C37.793 45.4834 38.1094 45.9559 38.3862 46.4679C38.6235 46.901 38.8871 47.3211 39.098 47.7674C39.1244 47.8199 39.1903 47.8199 39.1903 47.8855C39.4012 47.7018 39.4803 47.4524 39.6253 47.2292C39.8758 46.8485 40.0867 46.4416 40.3372 46.0478C40.4822 45.8378 40.5876 45.5884 40.7194 45.3652C40.8381 45.1552 40.9963 44.9583 41.1017 44.7483C41.1676 44.6302 41.2467 44.617 41.3522 44.617C41.7872 44.617 42.2222 44.617 42.6572 44.617C42.7231 44.617 42.8022 44.6039 42.8286 44.6695C42.8681 44.7483 42.7759 44.7746 42.7363 44.8271C42.5781 45.1027 42.4068 45.3652 42.2486 45.6409C42.0772 45.9034 41.919 46.1791 41.7608 46.4547C41.5499 46.8092 41.3258 47.1505 41.1281 47.5049C40.9831 47.7674 40.8249 48.0037 40.6667 48.2531C40.469 48.5812 40.2581 48.8963 40.0735 49.2244C39.9944 49.382 40.1526 49.5132 40.2317 49.6182C40.4162 49.8939 40.5481 50.1958 40.7326 50.4715C40.8908 50.734 41.049 50.9965 41.194 51.2722C41.4181 51.6791 41.6686 52.0729 41.9058 52.4667C42.1431 52.8736 42.3936 53.2936 42.6177 53.7137C42.7363 53.9368 42.9209 54.1206 43 54.3831C42.4595 54.3831 41.9454 54.3831 41.4445 54.3831C41.2335 54.3831 41.2467 54.1994 41.194 54.0944C40.9172 53.5956 40.6272 53.1099 40.3503 52.6111C40.034 52.0466 39.678 51.4953 39.3749 50.9178C39.2299 50.6421 39.1903 50.6421 39.0321 50.9046C38.6762 51.4953 38.3466 52.0991 37.9775 52.6898C37.648 53.228 37.3052 53.7531 37.0152 54.3175C36.9757 54.3963 36.9098 54.3831 36.8439 54.3831C36.3298 54.4094 35.8288 54.4094 35.3016 54.4094Z" fill="#FCFCFC"/> +<path d="M15.833 51.4034C15.9385 51.7315 15.978 52.0991 16.1362 52.4141C16.3076 52.7554 16.5844 52.9917 16.9535 53.123C17.1908 53.2017 17.4412 53.2542 17.6917 53.228C18.1267 53.1886 18.4958 53.0048 18.7858 52.6635C19.1154 52.2829 19.2076 51.8366 19.1549 51.3771C19.1154 51.049 18.9835 50.7602 18.7199 50.5239C18.4035 50.2351 18.0344 50.0514 17.6521 49.8938C17.0853 49.6576 16.5185 49.4607 16.0044 49.1194C15.5957 48.8437 15.2398 48.5024 15.0157 48.043C14.8575 47.728 14.8048 47.3998 14.8048 47.0848C14.8048 46.7697 14.8048 46.4284 14.9893 46.1397C15.1212 45.9034 15.2266 45.6409 15.4243 45.4571C15.7539 45.142 16.0966 44.8664 16.5317 44.7089C16.848 44.5776 17.1776 44.5514 17.5203 44.4988C17.8631 44.4463 18.2058 44.4988 18.5353 44.5645C18.799 44.617 19.0626 44.7483 19.2867 44.8926C19.5504 45.0633 19.7877 45.2602 19.9854 45.5096C20.1172 45.6802 20.249 45.864 20.3677 46.0478C20.4336 46.1397 20.3413 46.179 20.2886 46.2053C20.1568 46.2972 20.0249 46.3891 19.8667 46.4547C19.6954 46.5203 19.5636 46.6516 19.4054 46.7304C19.2076 46.8222 19.1681 46.8354 19.0758 46.6516C18.9308 46.3759 18.7067 46.179 18.4431 46.0215C18.2453 45.9034 18.0212 45.9296 17.8103 45.9034C17.3094 45.864 16.8744 46.0215 16.558 46.4284C16.1626 46.9272 16.268 47.5048 16.7557 47.8724C17.0194 48.0824 17.3226 48.2136 17.6258 48.3318C18.0081 48.4762 18.364 48.6731 18.7463 48.8175C19.1813 48.9881 19.5372 49.2506 19.8667 49.5657C20.3018 49.9857 20.5522 50.4845 20.6313 51.1015C20.6972 51.5215 20.6445 51.9284 20.5654 52.3222C20.4599 52.9129 20.1436 53.4117 19.6822 53.8187C19.4317 54.0418 19.1549 54.2125 18.8649 54.37C18.7331 54.4487 18.5881 54.4881 18.4563 54.5144C17.784 54.6588 17.1117 54.685 16.4394 54.475C15.688 54.2387 15.1475 53.753 14.7784 53.0704C14.5675 52.6898 14.4357 52.2697 14.3698 51.8366C14.3566 51.7709 14.3961 51.7447 14.4357 51.7447C14.528 51.7315 14.6202 51.679 14.7125 51.6659C15.0157 51.6397 15.2925 51.5084 15.5957 51.5084C15.688 51.469 15.7407 51.3771 15.833 51.4034Z" fill="#FCFCFC"/> +<path d="M25.3497 50.2351C25.3497 51.5608 25.3497 52.8866 25.3497 54.2124C25.3497 54.3699 25.3101 54.4224 25.152 54.4224C24.7829 54.4093 24.4269 54.4093 24.0578 54.4224C23.8997 54.4224 23.8337 54.383 23.8337 54.2124C23.8469 52.5453 23.8337 50.8783 23.8337 49.2112C23.8337 48.2267 23.8337 47.2422 23.8337 46.2577C23.8337 46.1002 23.7942 46.0477 23.6228 46.0477C23.0164 46.0608 22.4101 46.0477 21.8169 46.0477C21.5796 46.0477 21.5664 46.0346 21.5664 45.7983C21.5664 45.4702 21.5664 45.142 21.5664 44.8138C21.5664 44.6957 21.6191 44.6563 21.7246 44.6432C21.7773 44.6432 21.8301 44.6432 21.8828 44.6432C23.6887 44.6432 25.4947 44.6432 27.3007 44.6432C27.6039 44.6432 27.6038 44.6432 27.6038 44.9582C27.6038 45.247 27.5907 45.5358 27.6038 45.8246C27.617 46.0083 27.5248 46.0609 27.3666 46.0609C26.7734 46.0609 26.1802 46.0609 25.6002 46.0609C25.3497 46.0609 25.3497 46.0608 25.3497 46.3103C25.3497 47.6098 25.3497 48.9224 25.3497 50.2351Z" fill="#FBFBFB"/> +<path d="M0 49.5394C0 47.9905 0 46.4416 0 44.8795C0 44.6301 0 44.6301 0.263644 44.6301C0.606381 44.6301 0.935936 44.6301 1.27867 44.6301C1.43686 44.6301 1.51595 44.6826 1.51595 44.8664C1.51595 47.9774 1.51595 51.0884 1.51595 54.1993C1.51595 54.37 1.47641 54.4225 1.30504 54.4225C0.949118 54.4094 0.606381 54.4094 0.250462 54.4225C0.065911 54.4225 0 54.3831 0 54.1731C0.0131822 52.6373 0 51.0884 0 49.5394Z" fill="#FBFBFB"/> +<path opacity="0.5" d="M37.9992 14.1879C37.9992 19.2408 37.9992 24.3186 37.9752 29.3715C37.9752 29.5458 38.0232 29.7449 37.9033 29.8943C37.8314 29.8445 37.7595 29.7698 37.6636 29.72C36.8724 29.2471 36.0572 28.7741 35.266 28.2763C34.5227 27.8283 33.7795 27.3802 33.0362 26.9322C32.5567 26.6584 32.0772 26.3846 31.6217 26.0859C31.1661 25.7872 30.6866 25.5383 30.2311 25.2396C29.8954 25.0156 29.5118 24.8413 29.1522 24.6173C28.337 24.0946 27.4739 23.6217 26.6587 23.099C26.2751 22.8749 25.8435 22.7505 25.5318 22.3771C25.5078 22.3771 25.5078 22.3771 25.4839 22.3771C25.5558 22.2776 25.6277 22.1531 25.6757 22.0535C25.6997 22.0286 25.6997 22.0038 25.7236 21.954C25.7476 21.9291 25.7716 21.9042 25.7956 21.8544C26.0113 21.5059 26.1792 21.257 26.2751 21.0828C26.299 21.0579 26.299 21.033 26.323 21.0081C26.347 20.9583 26.371 20.9334 26.371 20.9085C26.347 20.9085 26.323 20.9085 26.323 20.9334C26.2031 20.9832 26.0833 21.0579 25.9874 21.1077C25.9634 21.1326 25.9154 21.1326 25.8915 21.1575C25.8675 21.1575 25.8675 21.1823 25.8435 21.1823C25.8195 21.1823 25.7956 21.2072 25.7716 21.2321C25.7476 21.257 25.6997 21.2819 25.6517 21.3068C25.4359 21.4313 25.1003 21.6553 24.7166 21.8793C24.6927 21.8793 24.6927 21.8793 24.6687 21.9042C24.381 21.8046 24.1652 21.5059 23.8535 21.4313C24.357 21.1077 24.8605 20.809 25.34 20.4356C25.7236 20.1618 26.2271 20.0622 26.4909 19.5893C26.4909 19.5893 26.4908 19.5644 26.4669 19.5644C26.4429 19.5146 26.4189 19.4898 26.3949 19.44C26.371 19.4151 26.371 19.3902 26.347 19.3653C26.2271 19.1413 26.1072 18.9173 26.0113 18.743C25.5558 17.9465 25.2441 17.3242 24.8125 16.6771C24.7886 16.6273 24.7646 16.5775 24.7166 16.5526C24.4529 16.1792 24.333 15.7063 24.0213 15.3578C24.0933 15.3329 24.1892 15.308 24.2371 15.2583C25.364 14.4368 26.5628 13.7897 27.7136 13.0181C28.0493 12.794 28.1452 12.57 28.1452 12.1966C28.1212 9.73242 28.1452 7.24331 28.1452 4.77908C28.1452 4.60485 28.0972 4.43061 28.2651 4.30615C29.2241 4.90354 30.1831 5.47604 31.1422 6.04853C32.0532 6.59614 32.9643 7.11885 33.8754 7.66646C34.6666 8.13939 35.4818 8.63721 36.273 9.13503C36.7285 9.43373 37.184 9.75731 37.6875 9.98133C37.9033 10.0809 37.9513 10.2551 37.9513 10.4792C37.9992 11.7237 37.9992 12.9683 37.9992 14.1879Z" fill="white"/> +<path opacity="0.39" d="M18.7722 21.5556C18.4845 21.8294 18.3646 21.929 18.1728 22.1032L18.1488 22.1281C18.1249 22.1281 18.1249 22.153 18.1249 22.153C18.1009 22.1281 18.0769 22.1281 18.0529 22.1032C18.0529 22.1032 18.0529 22.1032 18.029 22.1032C18.005 22.0784 17.981 22.0784 17.957 22.0535C17.7413 21.9041 17.5494 21.8045 17.4775 21.7299C17.4535 21.705 17.4296 21.705 17.4296 21.705C17.046 21.4561 16.6623 21.1823 16.2068 21.0329C16.5664 21.5805 16.9021 22.1281 17.2617 22.6509C17.1419 22.7255 17.022 22.8002 16.9021 22.8749C16.9021 22.8749 16.9021 22.8749 16.8781 22.8749C16.7582 22.9495 16.6384 23.0242 16.5185 23.074C15.7273 23.5469 14.9361 24.0696 14.1209 24.5177C13.2578 24.9906 12.4426 25.5133 11.5795 26.036C10.7883 26.509 9.9731 26.957 9.1819 27.4797C8.12697 28.1518 7.04806 28.7492 5.99312 29.3964C5.72939 29.5706 5.39373 29.6453 5.17794 29.944C4.93819 29.9191 5.01012 29.7199 5.01012 29.5706C5.01012 28.5749 5.01012 27.5793 5.01012 26.5836C5.01012 21.2818 5.01012 16.0049 5.01012 10.7031C5.01012 10.3048 5.15397 10.1057 5.44168 9.93147C6.54456 9.2843 7.6954 8.68692 8.75034 7.96507C9.39768 7.54192 10.093 7.16856 10.7643 6.74541C11.6514 6.1978 12.5145 5.6502 13.4256 5.17727C13.8812 4.92835 14.3127 4.65455 14.7443 4.40564C14.7443 6.89475 14.7683 9.40876 14.7443 11.8979C14.7443 11.9477 14.7443 11.9974 14.7443 12.0472C14.7443 12.1717 14.7443 12.2961 14.7443 12.4206C14.7443 12.4455 14.7443 12.4455 14.7443 12.4704C14.7922 12.7691 14.9361 13.018 15.4636 13.2669L15.4875 13.2918C16.0869 13.69 16.7103 14.0634 17.2857 14.4368C17.2857 14.4368 17.3097 14.4368 17.3097 14.4617C17.4775 14.5612 17.6214 14.6608 17.7652 14.7355C17.7892 14.7604 17.8372 14.7852 17.8611 14.8101C17.8851 14.835 17.9091 14.8599 17.957 14.8599C17.981 14.8848 18.005 14.8848 18.029 14.9097C18.1488 14.9844 18.2687 15.059 18.3406 15.1088C18.3646 15.1337 18.4126 15.1586 18.4365 15.1835C18.4605 15.2084 18.4845 15.2084 18.4845 15.2084C18.5085 15.2333 18.5325 15.2582 18.5564 15.2582C18.0769 16.0796 17.5974 17.0006 17.1179 17.822C16.7582 18.4194 16.3986 19.0416 16.1349 19.6888C16.1109 19.7884 16.1589 19.863 16.2548 19.9128C16.8062 20.2613 17.3576 20.5849 17.8851 20.9583C18.1728 21.1325 18.3646 21.2818 18.7722 21.5556Z" fill="white"/> +<path opacity="0.39" d="M18.0758 22.1283C18.0519 22.1034 18.0279 22.1034 18.0039 22.0785C18.0279 22.1034 18.0519 22.1283 18.0758 22.1283Z" fill="white"/> +<path opacity="0.56" d="M37.9062 29.8944C37.6664 30.218 37.2828 30.2926 36.9711 30.4918C36.0121 31.0891 35.0291 31.6616 34.0461 32.2341C33.3508 32.6324 32.6794 33.0555 32.0081 33.4538C31.5526 33.7276 31.097 34.0014 30.6415 34.2752C29.7784 34.7979 28.9152 35.3206 28.0521 35.8434C28.0521 33.1551 28.0521 30.4669 28.0521 27.7537C28.0521 27.6293 28.0761 27.4799 27.9322 27.4053C27.9083 27.3306 27.8363 27.2808 27.7644 27.231C27.165 26.8576 26.5656 26.5092 25.9662 26.1109C25.2949 25.6629 24.5756 25.2397 23.9043 24.8166C23.9283 24.7917 23.9522 24.7419 23.9762 24.717C24.0002 24.6921 24.0242 24.6672 24.0242 24.6423C24.0721 24.5428 24.1441 24.4432 24.216 24.3436C24.216 24.3436 24.216 24.3188 24.24 24.3188C24.5277 23.8707 24.8394 23.4227 25.1031 23.0244C25.151 22.9497 25.199 22.8751 25.2469 22.8253C25.2709 22.8004 25.2949 22.7506 25.3189 22.7257C25.3668 22.6262 25.4387 22.5515 25.4867 22.4768C25.5107 22.4768 25.5107 22.4768 25.5346 22.4768C25.8224 22.8502 26.2779 22.9746 26.6615 23.1986C27.5007 23.7214 28.3398 24.1943 29.155 24.717C29.4907 24.941 29.8743 25.0904 30.2339 25.3393C30.6894 25.638 31.169 25.8869 31.6245 26.1856C32.08 26.4843 32.5835 26.7581 33.0391 27.0319C33.7823 27.4799 34.5256 27.928 35.2688 28.376C36.06 28.8489 36.8512 29.3219 37.6664 29.8197C37.7623 29.7948 37.8342 29.8446 37.9062 29.8944Z" fill="white"/> +<path opacity="0.32" d="M21.4588 8.46298C21.4588 8.81146 21.4588 9.18483 21.4588 9.5333C21.4588 10.2551 21.4588 10.977 21.4348 11.6988L21.4108 13.3168C21.4108 13.8644 21.4108 14.412 21.3868 14.9347C21.3868 15.6565 21.3868 16.3784 21.3868 17.0753C20.8594 16.7766 20.1401 16.229 19.6126 15.9054C19.5647 15.8805 19.5167 15.8557 19.4928 15.8308C19.2051 15.6316 18.9173 15.4574 18.5817 15.2583C18.5577 15.2334 18.5337 15.2334 18.5098 15.2085C18.4858 15.2085 18.4858 15.1836 18.4618 15.1836C18.4378 15.1587 18.3899 15.1338 18.3659 15.1089C18.27 15.0591 18.1741 14.9845 18.0542 14.9098C18.0302 14.8849 18.0063 14.8849 17.9823 14.86C17.9583 14.8351 17.9343 14.8351 17.8864 14.8102C17.8624 14.7853 17.8145 14.7604 17.7905 14.7356C17.6466 14.636 17.5028 14.5613 17.3349 14.4618C17.3349 14.4618 17.311 14.4618 17.311 14.4369C16.7355 14.0635 16.1122 13.6901 15.5128 13.2919L15.4888 13.267C14.9853 12.9932 14.8175 12.7692 14.7695 12.4705C14.7695 12.4456 14.7695 12.4456 14.7695 12.4207C14.7695 12.2962 14.7695 12.1718 14.7695 12.0473C14.7695 11.9975 14.7695 11.9477 14.7695 11.898C14.7935 9.40885 14.7695 6.89484 14.7695 4.40573C14.7935 4.38084 14.8175 4.35595 14.8415 4.33105C15.8724 4.97822 16.9034 5.65029 17.9583 6.29746C18.7255 6.77039 19.4928 7.21843 20.236 7.71625C20.5956 7.96516 21.0032 8.23896 21.4588 8.46298Z" fill="white"/> +<path opacity="0.32" d="M18.5566 15.2583C18.9163 15.4574 19.18 15.6317 19.4677 15.8308C19.18 15.6566 18.8923 15.4574 18.5566 15.2583Z" fill="white"/> +<path opacity="0.32" d="M21.4093 17.1252C21.4093 17.1003 21.4093 17.1003 21.4093 17.1252C21.3853 17.1252 21.3853 17.1003 21.3853 17.1003C21.3853 17.1003 21.3853 17.1003 21.3613 17.1003L21.4093 17.1252C21.4093 17.1003 21.4093 17.1003 21.4093 17.1252C21.4093 17.1003 21.4093 17.1003 21.4093 17.1252C21.4093 17.1003 21.4093 17.1003 21.4093 17.1252Z" fill="white"/> +<path opacity="0.21" d="M28.1939 4.82888C28.1939 7.2931 28.1939 9.78222 28.1939 12.2464C28.1939 12.6198 28.098 12.8438 27.7623 13.0678C26.6115 13.8146 25.4127 14.4866 24.2858 15.308C24.2139 15.3578 24.142 15.3827 24.0701 15.4076C23.2069 15.9552 22.2719 16.5526 21.3848 17.1002C21.3848 16.3784 21.3848 15.6814 21.3848 14.9596C21.3848 14.412 21.3848 13.8644 21.4087 13.3416L21.4327 11.7237C21.4327 11.0019 21.4567 10.28 21.4567 9.5582C21.4567 9.20972 21.4567 8.83635 21.4567 8.48788C22.104 8.08962 22.7514 7.71625 23.3748 7.31799C24.118 6.84506 24.8373 6.37213 25.5566 5.8992C26.108 5.55072 26.6834 5.27692 27.2109 4.87866C27.5226 4.65464 27.8582 4.50529 28.1939 4.33105C28.2418 4.35595 28.2898 4.38084 28.3138 4.40573C28.1459 4.4804 28.1939 4.67953 28.1939 4.82888Z" fill="white"/> +<path opacity="0.21" d="M28.0996 27.7536C28.0996 30.4419 28.0996 33.1301 28.0996 35.8433C27.1645 36.4406 26.2295 37.0131 25.2944 37.5856C24.5272 38.0337 23.8079 38.5315 23.0407 38.9795C22.5852 39.2533 22.1057 39.5271 21.6741 39.8507C21.5542 39.9254 21.4583 40.0001 21.3145 40.0001C21.3145 37.1874 21.3145 34.3747 21.3145 31.562C21.4104 31.5371 21.5063 31.4873 21.6022 31.4375C21.9378 31.1886 22.2975 30.9646 22.6811 30.7406C23.5202 30.2427 24.3354 29.72 25.1506 29.1973C26.0856 28.5999 27.0207 28.0025 27.9797 27.4052C28.1236 27.4798 28.0996 27.6292 28.0996 27.7536Z" fill="white"/> +<path opacity="0.7" d="M28.1954 4.28128C27.8598 4.45552 27.5241 4.60486 27.2124 4.82888C26.685 5.22714 26.1095 5.50094 25.5581 5.84942C24.8148 6.32235 24.0956 6.79528 23.3763 7.26822C22.7529 7.66647 22.1056 8.06473 21.4582 8.4381C21.0267 8.21408 20.5951 7.94028 20.1875 7.66647C19.4443 7.16865 18.6531 6.72061 17.9098 6.24768C16.8789 5.60051 15.8239 4.92845 14.793 4.28128C15.0807 3.90791 15.5122 3.78345 15.8719 3.53454C16.6631 3.01183 17.4783 2.48911 18.2934 1.99129C19.0367 1.51836 19.7799 1.07032 20.5232 0.597388C20.7629 0.448041 21.0027 0.298694 21.2185 0.124456C21.4343 -0.0497823 21.6021 -0.0248911 21.7939 0.0995646C22.8488 0.821408 23.9517 1.46858 25.0546 2.16553C25.9177 2.71314 26.7809 3.23585 27.62 3.80835C27.8118 3.98258 28.0995 3.98258 28.1954 4.28128Z" fill="white"/> +<path opacity="0.32" d="M21.3146 31.5371C21.3146 34.3498 21.3146 37.1625 21.3146 39.9752C20.8111 39.7512 20.3316 39.4276 19.876 39.1289C19.5164 38.9049 19.1328 38.6809 18.7731 38.4319C18.3176 38.1084 17.8381 37.8346 17.3586 37.5359C16.5674 37.038 15.7762 36.5153 14.961 36.0175C14.7932 35.9179 14.7212 35.8184 14.6973 35.6192C14.6973 33.4039 14.6973 31.2135 14.7212 28.9982C14.7212 28.4755 14.7212 27.9528 14.7212 27.4301C15.1288 27.6541 15.5124 27.903 15.92 28.1519C16.4954 28.5004 17.0709 28.8488 17.6223 29.2222C18.4135 29.7449 19.2527 30.2179 20.0439 30.7157C20.4754 31.0144 20.859 31.338 21.3146 31.5371Z" fill="white"/> +<path opacity="0.12" d="M26.5172 19.689C26.2535 20.1371 25.75 20.2366 25.3664 20.5353C24.8868 20.8838 24.3834 21.1825 23.8799 21.531C23.2805 21.9043 22.6811 22.2777 22.0817 22.6262C21.8419 22.7755 21.6261 22.9249 21.3145 23.0493C21.3145 21.1327 21.3864 19.017 21.3864 17.1003C21.3864 17.1003 21.3864 17.1003 21.4104 17.1003C22.8489 17.7973 24.4313 18.7183 25.8459 19.4152C25.8459 19.4152 25.8699 19.4152 25.8699 19.4401C25.8938 19.4401 25.9178 19.465 25.9418 19.465C26.1336 19.5646 26.3494 19.6392 26.5172 19.689Z" fill="white"/> +<path opacity="0.24" d="M21.3875 17.1003C21.3875 17.1003 21.3594 17.1293 21.3875 17.1003V17.1003Z" fill="white"/> +<path opacity="0.24" d="M26.5156 19.689C26.3478 19.6392 26.132 19.5645 25.9641 19.4899C25.9402 19.4899 25.9162 19.465 25.8922 19.465C25.8922 19.465 25.8682 19.465 25.8682 19.4401C24.4297 18.7431 22.8473 17.8222 21.4327 17.1252C21.4327 17.1252 21.4327 17.1252 21.4087 17.1252C21.4087 17.1252 21.4087 17.1252 21.3848 17.1252C22.2719 16.5776 23.1829 15.9802 24.0701 15.4326C24.4057 15.7562 24.5256 16.254 24.7654 16.6274C24.7893 16.6772 24.8133 16.727 24.8613 16.7518C25.2928 17.399 25.6045 18.0462 26.06 18.8178C26.1559 18.9672 26.2758 19.2161 26.3957 19.4401C26.4197 19.465 26.4197 19.4899 26.4437 19.5148C26.4676 19.5645 26.4916 19.6143 26.5156 19.6392C26.4916 19.6641 26.5156 19.6641 26.5156 19.689Z" fill="white"/> +<path opacity="0.56" d="M20.8359 23.572C20.9079 23.5222 20.9798 23.4724 21.0277 23.4475C20.9798 23.4724 20.9079 23.5222 20.8359 23.572Z" fill="white"/> +<path opacity="0.56" d="M21.3145 23.2483C21.3384 23.2234 21.3624 23.1986 21.4104 23.2234C21.3864 23.2234 21.3624 23.2234 21.3145 23.2483Z" fill="white"/> +<path opacity="0.56" d="M22.1496 23.5966C22.0297 23.5468 21.9098 23.4721 21.8379 23.4224C21.9338 23.497 22.0297 23.5468 22.1496 23.5966Z" fill="white"/> +<path opacity="0.24" d="M21.3857 17.1003C21.3857 19.017 21.3138 21.1327 21.3138 23.0493C21.2658 23.0244 21.2179 22.9995 21.1699 22.9747C21.122 22.9498 21.098 22.9249 21.0501 22.9249C20.9781 22.8751 20.9062 22.8502 20.8343 22.8004C20.7863 22.7755 20.7623 22.7506 20.7144 22.7257C20.6904 22.7257 20.6664 22.7008 20.6664 22.7008C20.6185 22.676 20.5466 22.6262 20.4986 22.6013C19.9232 22.2528 19.3957 21.8546 18.7724 21.5559C18.3887 21.3069 18.1969 21.1576 17.8852 20.9336C17.3578 20.5602 16.8063 20.2366 16.2549 19.8881C16.159 19.8384 16.111 19.7637 16.135 19.6641C16.7824 19.3903 17.3818 19.0419 18.0291 18.768C18.101 18.7432 18.173 18.6934 18.2449 18.6685C19.2519 18.1956 20.3548 17.5982 21.3857 17.1003Z" fill="white"/> +<path opacity="0.24" d="M21.3875 17.1003C21.3875 17.1003 21.3594 17.1293 21.3875 17.1003V17.1003Z" fill="white"/> +<path opacity="0.6" d="M21.384 17.1001C20.3531 17.573 19.2502 18.1953 18.2192 18.6683C18.1473 18.6931 18.0754 18.7429 18.0035 18.7678C17.3801 19.0665 16.7567 19.3901 16.1094 19.6639C16.3971 19.0167 16.7567 18.4193 17.0924 17.7971C17.5719 16.9757 18.0514 16.0547 18.5309 15.2333C18.8906 15.4324 19.1543 15.6066 19.442 15.8058C19.49 15.8307 19.5139 15.8556 19.5619 15.8804C20.1133 16.2289 20.8326 16.8014 21.384 17.1001C21.384 17.1001 21.3601 17.1001 21.384 17.1001Z" fill="white"/> +<path opacity="0.6" d="M21.4087 17.1252C21.4087 17.1003 21.4087 17.1003 21.4087 17.1252C21.3848 17.1003 21.3848 17.1003 21.3848 17.1003C21.4327 17.1003 21.4567 17.1252 21.4087 17.1252Z" fill="white"/> +<path opacity="0.7" d="M27.9553 27.4051C27.0203 28.0025 26.0852 28.5998 25.1262 29.1972C24.311 29.72 23.4958 30.2427 22.6567 30.7405C22.297 30.9645 21.9374 31.1885 21.5778 31.4374C21.4819 31.5121 21.386 31.537 21.2901 31.5619C20.8345 31.3628 20.4509 31.0392 20.0433 30.7654C19.2282 30.2676 18.413 29.7697 17.6218 29.2719C17.0464 28.8985 16.4709 28.575 15.9195 28.2016C15.5359 27.9527 15.1283 27.7038 14.7207 27.4797C14.8166 27.4051 14.8885 27.3304 14.9844 27.2557C15.0324 27.2308 15.0803 27.1811 15.1283 27.1562C15.2242 27.0815 15.3201 27.0317 15.416 26.957C15.9435 26.6086 16.4949 26.3099 17.0224 25.9614C17.1902 25.8618 17.382 25.7374 17.5738 25.6129C17.6457 25.5631 17.7177 25.5133 17.8136 25.4636C17.9335 25.3889 18.0533 25.3142 18.1732 25.2395C18.2451 25.1898 18.3171 25.14 18.413 25.1151C18.4849 25.0653 18.5808 25.0404 18.6527 24.9906C18.6527 24.9906 18.6527 24.9906 18.6767 24.9906C18.7007 24.9657 18.7247 24.9657 18.7486 24.9409C18.9884 25.2893 19.2281 25.6627 19.4679 26.0112C19.5638 26.1605 19.6597 26.285 19.7556 26.4343C20.0433 26.8575 20.331 27.2806 20.6187 27.7038C20.6427 27.7287 20.6667 27.7784 20.6907 27.8033C20.7146 27.8531 20.7386 27.9029 20.7866 27.9278C20.8585 28.0522 20.9304 28.1518 20.9784 28.2016C21.0503 28.326 21.1222 28.4505 21.2421 28.5501C21.2901 28.575 21.314 28.5999 21.386 28.6247C21.4339 28.6247 21.4819 28.5998 21.5298 28.575C21.5538 28.5501 21.5778 28.5252 21.6018 28.5003C21.6257 28.4505 21.6497 28.4256 21.6737 28.3758C21.7936 28.2016 22.0333 27.8531 22.321 27.4051C22.369 27.3304 22.4169 27.2557 22.4889 27.1562C22.5608 27.0317 22.6567 26.9073 22.7526 26.7579C23.0403 26.3348 23.352 25.8618 23.6876 25.364C23.7835 25.2395 23.8555 25.1151 23.9514 24.9657C23.9514 24.9409 23.9754 24.9409 23.9754 24.916C23.9993 24.8662 24.0233 24.8413 24.0473 24.7915C24.7186 25.2147 25.4379 25.6378 26.1092 26.0858C26.6846 26.4841 27.308 26.8326 27.9074 27.2059C27.8594 27.2806 27.9314 27.3304 27.9553 27.4051Z" fill="white"/> +<path opacity="0.7" d="M23.9528 24.7915C23.9288 24.8413 23.9048 24.8662 23.8809 24.916C23.8809 24.8662 23.9048 24.8164 23.9528 24.7915Z" fill="white"/> +<path opacity="0.24" d="M26.395 20.9832C26.395 21.008 26.371 21.0329 26.3471 21.0827C26.3471 21.1076 26.3231 21.1325 26.2991 21.1574C26.2032 21.3316 26.0354 21.5805 25.8196 21.929C25.7956 21.9539 25.7717 21.9788 25.7477 22.0286C25.7237 22.0535 25.6997 22.0784 25.6997 22.1281C25.6278 22.2277 25.5798 22.3273 25.5079 22.4517C25.46 22.5264 25.388 22.626 25.3401 22.7006C25.3161 22.7255 25.2921 22.7504 25.2682 22.8002C25.2202 22.8749 25.1723 22.9247 25.1243 22.9993C24.8606 23.3976 24.5729 23.8456 24.2612 24.2937C24.2612 24.2937 24.2612 24.3186 24.2372 24.3186C24.1653 24.4181 24.0934 24.5177 24.0454 24.6173C24.0214 24.6422 23.9975 24.667 23.9975 24.6919C23.9735 24.7168 23.9495 24.7666 23.9255 24.7915C23.8776 24.8164 23.8776 24.8662 23.8536 24.916C23.8536 24.9408 23.8296 24.9408 23.8296 24.9657C23.7337 25.0902 23.6618 25.2146 23.5659 25.364C23.2302 25.8618 22.9185 26.3348 22.6308 26.7579C22.5349 26.8824 22.463 27.0317 22.3671 27.1562C22.3191 27.2308 22.2712 27.3055 22.1993 27.4051C21.8876 27.8531 21.6478 28.2265 21.5519 28.3758C21.5279 28.4256 21.504 28.4505 21.48 28.5003C21.456 28.5252 21.432 28.5501 21.4081 28.575C21.3841 28.5998 21.3361 28.6247 21.2642 28.6247C21.2642 27.1562 21.2642 25.6876 21.2402 24.219C21.2642 24.1941 21.2882 24.1941 21.3122 24.1692C21.3361 24.1692 21.3361 24.1443 21.3601 24.1443C21.3841 24.1194 21.4081 24.1194 21.432 24.0945C21.432 24.0945 21.432 24.0945 21.456 24.0945C21.48 24.0697 21.504 24.0697 21.5279 24.0448C21.5999 23.995 21.6478 23.9701 21.7198 23.9203C21.8157 23.8705 21.9116 23.7959 22.0075 23.7461C22.0314 23.7461 22.0554 23.7212 22.0554 23.7212C22.0554 23.7212 22.0794 23.7212 22.0794 23.6963C22.0794 23.6963 22.1034 23.6963 22.1034 23.6714C22.1753 23.6216 22.2712 23.5718 22.3431 23.5221C22.3431 23.5221 22.3431 23.5221 22.3671 23.5221C23.0624 23.074 23.9255 22.5264 24.6448 22.0784C24.6688 22.0784 24.6927 22.0535 24.6927 22.0535C25.0764 21.8046 25.412 21.6054 25.6278 21.481C25.6758 21.4561 25.6997 21.4312 25.7477 21.4063C25.7717 21.3814 25.7956 21.3814 25.8196 21.3565C25.8436 21.3565 25.8676 21.3316 25.8676 21.3316C25.8915 21.3067 25.9155 21.3067 25.9635 21.2818C26.0594 21.2321 26.1792 21.1574 26.2991 21.1076C26.371 21.008 26.3711 20.9832 26.395 20.9832Z" fill="white"/> +<path opacity="0.24" d="M22.1536 23.5969C22.1536 23.5969 22.1289 23.5969 22.1289 23.6227C22.1289 23.6227 22.1536 23.6227 22.1536 23.5969Z" fill="white"/> +<path opacity="0.24" d="M23.9528 24.7915C23.9288 24.8413 23.9048 24.8662 23.8809 24.916C23.8809 24.8662 23.9048 24.8164 23.9528 24.7915Z" fill="white"/> +<path d="M21.7696 23.8706C21.6977 23.9204 21.6497 23.9453 21.5778 23.9951C21.5538 24.02 21.5298 24.02 21.5059 24.0448C21.5298 24.02 21.5778 23.9951 21.6257 23.9702C21.6497 23.9702 21.6497 23.9453 21.6737 23.9453C21.6977 23.9204 21.7216 23.9204 21.7456 23.8955C21.7456 23.8706 21.7456 23.8706 21.7696 23.8706Z" fill="white"/> +<path opacity="0.7" d="M22.1516 23.5969C22.1516 23.5969 22.1277 23.5969 22.1277 23.6218C22.1277 23.6218 22.1037 23.6218 22.1037 23.6467C22.0797 23.6467 22.0557 23.6716 22.0557 23.6716C21.9359 23.7463 21.84 23.8209 21.744 23.8707C21.7201 23.8956 21.6961 23.8956 21.6721 23.9205C21.6481 23.9205 21.6481 23.9454 21.6242 23.9454L21.6002 23.9703C21.5762 23.9952 21.5522 23.9952 21.5283 24.0201C21.5283 24.0201 21.5283 24.0201 21.5043 24.0201C21.4803 24.045 21.4563 24.045 21.4324 24.0699C21.4084 24.0699 21.4084 24.0947 21.3844 24.0947C21.3604 24.1196 21.3365 24.1196 21.3125 24.1445C21.3125 24.1445 21.2885 24.1196 21.2645 24.1196C21.1686 24.045 20.9289 23.9205 20.6412 23.7214C20.6412 23.7214 20.6172 23.7214 20.6172 23.6965C20.6891 23.6467 20.7371 23.5969 20.785 23.572C20.809 23.5471 20.833 23.5223 20.8569 23.5223C20.9289 23.4725 21.0008 23.4227 21.0488 23.3978C21.0727 23.3729 21.0967 23.3729 21.1207 23.348C21.1686 23.3231 21.2166 23.2982 21.2885 23.2484C21.3125 23.2484 21.3125 23.2236 21.3365 23.2236C21.3604 23.1987 21.3844 23.1738 21.4324 23.1987H21.4563C21.5043 23.1987 21.5522 23.2236 21.6242 23.2733C21.6481 23.2733 21.6481 23.2982 21.6721 23.2982C21.7201 23.3231 21.792 23.3729 21.84 23.3978C21.9359 23.4974 22.0318 23.5471 22.1516 23.5969Z" fill="white"/> +<path opacity="0.6" d="M21.3146 28.6C21.2667 28.5751 21.2187 28.5751 21.1708 28.5253C21.0509 28.4507 20.9789 28.3013 20.907 28.1769C20.8591 28.1022 20.7871 28.0275 20.7152 27.903C20.6912 27.8533 20.6673 27.8035 20.6193 27.7786C20.5953 27.7537 20.5714 27.7288 20.5474 27.679C20.2597 27.2559 19.9959 26.8327 19.6843 26.4096C19.5884 26.2851 19.4924 26.1358 19.3965 25.9864C19.1568 25.638 18.917 25.2646 18.6773 24.9161C18.6533 24.9161 18.6293 24.941 18.6053 24.9659C18.6293 24.941 18.6533 24.941 18.6773 24.9161C18.6053 24.8165 18.4615 24.5676 18.2697 24.3187C18.2217 24.2689 18.1978 24.1943 18.1498 24.1196C18.0779 24.02 18.006 23.9205 17.934 23.8209C17.9101 23.7711 17.8861 23.7462 17.8621 23.6964C17.8621 23.6964 17.8621 23.6964 17.8621 23.6716C17.8381 23.6467 17.8141 23.5969 17.7902 23.572C17.7662 23.5471 17.7422 23.4973 17.7182 23.4724C17.5984 23.2733 17.4785 23.0991 17.3826 22.9497C17.3586 22.9248 17.3586 22.9248 17.3346 22.8999C17.3107 22.875 17.3107 22.8501 17.2867 22.8501C17.2867 22.8253 17.2627 22.8253 17.2627 22.8004C17.2627 22.8004 17.2627 22.7755 17.2387 22.7755C17.2387 22.7755 17.2387 22.7506 17.2148 22.7506L17.1908 22.7257C17.1908 22.7257 17.1908 22.7008 17.1668 22.7008C17.1668 22.6759 17.1428 22.6759 17.1428 22.6759C16.7832 22.1283 16.4475 21.5807 16.0879 21.058C16.5434 21.2073 16.927 21.4811 17.3107 21.73C17.3107 21.73 17.3346 21.7549 17.3586 21.7549C17.4545 21.8047 17.6223 21.9292 17.8381 22.0785C17.8621 22.1034 17.8861 22.1034 17.91 22.1283C17.91 22.1283 17.9101 22.1283 17.934 22.1283C17.958 22.1283 17.982 22.1532 18.006 22.1781C18.006 22.1781 18.0299 22.1781 18.0299 22.203C18.0539 22.2279 18.0779 22.2279 18.1019 22.2528C18.1498 22.2776 18.1738 22.3025 18.2217 22.3274C18.2937 22.3772 18.3656 22.4021 18.4375 22.4519C18.5094 22.5017 18.5814 22.5515 18.6533 22.5763C18.7492 22.651 18.8451 22.7008 18.941 22.7755C18.989 22.8004 19.0369 22.8501 19.0849 22.875C19.1808 22.9497 19.3006 22.9995 19.3965 23.0742C19.5884 23.1986 19.7802 23.3231 19.972 23.4475C20.0199 23.4724 20.0679 23.4973 20.1158 23.5471C20.2597 23.6218 20.3796 23.7213 20.4994 23.796C20.4994 23.796 20.5234 23.796 20.5234 23.8209C20.8111 23.9951 21.0509 24.1445 21.1468 24.2192C21.1708 24.244 21.1947 24.244 21.1947 24.244C21.2906 25.638 21.2906 27.1314 21.3146 28.6Z" fill="white"/> +<path opacity="0.6" d="M18.0758 22.1283C18.0519 22.1034 18.0279 22.1034 18.0039 22.0785C18.0279 22.1034 18.0519 22.1283 18.0758 22.1283Z" fill="white"/> +<path opacity="0.6" d="M24.6944 21.9788C23.9751 22.4517 23.088 22.9993 22.4167 23.4474C22.4167 23.4474 22.4167 23.4474 22.3927 23.4474C22.2968 23.4971 22.2249 23.5469 22.1529 23.5967C22.0331 23.5469 21.9372 23.4722 21.8412 23.4225C21.7933 23.3976 21.7214 23.3478 21.6734 23.3229C21.6494 23.3229 21.6494 23.298 21.6255 23.298C21.5775 23.2731 21.5056 23.2233 21.4576 23.2233H21.4337C21.3857 23.2233 21.3617 23.2233 21.3378 23.2482C21.3378 23.2482 21.3138 23.2731 21.2898 23.2731C21.2179 23.3229 21.1699 23.3478 21.122 23.3727C21.098 23.3976 21.074 23.3976 21.05 23.4225C21.0021 23.4474 20.9302 23.4971 20.8582 23.5469C20.8343 23.5718 20.8103 23.5718 20.7863 23.5967C20.7384 23.6216 20.6904 23.6714 20.6185 23.7212C20.4986 23.6465 20.3787 23.5718 20.2349 23.4722C20.1869 23.4474 20.139 23.4225 20.091 23.3727C19.8992 23.2482 19.7074 23.1238 19.5156 22.9993C19.4197 22.9246 19.2998 22.8749 19.2039 22.8002C19.156 22.7753 19.108 22.7255 19.0601 22.7006C18.9642 22.6259 18.8682 22.5762 18.7723 22.5015C18.7004 22.4517 18.6285 22.4019 18.5566 22.377C18.4846 22.3273 18.4127 22.2775 18.3408 22.2526C18.2928 22.2277 18.2689 22.2028 18.2209 22.1779C18.1969 22.153 18.173 22.153 18.149 22.1281L18.125 22.1032L18.149 22.0783L18.173 22.0535C18.3648 21.8792 18.5086 21.7797 18.7723 21.5058C19.3717 21.7797 19.9232 22.2028 20.4986 22.5513C20.5466 22.5762 20.6185 22.626 20.6664 22.6508C20.6904 22.6508 20.7144 22.6757 20.7144 22.6757C20.7623 22.7006 20.7863 22.7255 20.8343 22.7504C20.9062 22.8002 20.9781 22.8251 21.05 22.8749C21.098 22.8998 21.122 22.9246 21.1699 22.9246C21.2179 22.9495 21.2658 22.9744 21.3138 22.9993C21.6255 22.8749 21.8412 22.7255 22.081 22.5762C22.6804 22.2028 23.2798 21.8294 23.8792 21.481C24.1909 21.5556 24.4067 21.8543 24.6944 21.9788Z" fill="white"/> +<path opacity="0.6" d="M18.7237 24.9409C18.6997 24.9658 18.6758 24.9658 18.6518 24.9906C18.6518 24.9906 18.6518 24.9906 18.6278 24.9906C18.5559 25.0404 18.46 25.0653 18.388 25.1151C18.3161 25.1649 18.2202 25.1898 18.1483 25.2396C18.0284 25.3142 17.9085 25.3889 17.7887 25.4636C17.7167 25.5134 17.6208 25.5631 17.5489 25.6129C17.3571 25.7374 17.1653 25.8618 16.9975 25.9614C16.47 26.3099 15.9185 26.6086 15.3911 26.957C15.2952 27.0317 15.1993 27.0815 15.1034 27.1562C15.0554 27.1811 15.0075 27.2309 14.9595 27.2557C14.8636 27.3304 14.7677 27.4051 14.6958 27.4798C14.6958 28.0025 14.6958 28.5252 14.6958 29.0479C14.6958 31.2632 14.6958 33.4536 14.6718 35.6689C14.1923 35.5196 13.7847 35.1711 13.3531 34.9471C12.3462 34.3746 11.3631 33.7772 10.3801 33.1798C9.75677 32.8065 9.15737 32.4082 8.534 32.0348C7.43112 31.3877 6.35221 30.7405 5.24932 30.0933C5.1774 30.0684 5.12945 30.0435 5.10547 29.944C5.32125 29.6702 5.65691 29.5706 5.92064 29.3964C6.97558 28.7243 8.07847 28.1518 9.10942 27.4798C9.90062 26.9819 10.7158 26.509 11.507 26.0361C12.3462 25.5383 13.1613 24.9906 14.0484 24.5177C14.8636 24.0697 15.6548 23.547 16.446 23.074C16.5659 22.9994 16.6858 22.9247 16.8057 22.8749C16.8057 22.8749 16.8056 22.8749 16.8296 22.8749C16.9495 22.8002 17.0694 22.7504 17.1893 22.6509C17.1893 22.6509 17.1893 22.6509 17.2132 22.6758L17.2372 22.7007L17.2612 22.7256C17.2612 22.7504 17.2852 22.7504 17.2852 22.7753C17.2852 22.7753 17.3091 22.8002 17.3091 22.8251C17.3331 22.85 17.3571 22.8998 17.3811 22.9496C17.477 23.0989 17.5968 23.2732 17.7167 23.4723C17.7887 23.5967 17.8846 23.7212 17.9565 23.8457C18.0284 23.9452 18.1003 24.0448 18.1723 24.1443C18.2202 24.219 18.2442 24.2688 18.2921 24.3435C18.5079 24.5924 18.6518 24.8164 18.7237 24.9409Z" fill="white"/> +</svg> diff --git a/packages/website/public/images/@next/clients/laketrade.svg b/packages/website/public/images/@next/clients/laketrade.svg new file mode 100644 index 000000000..6ab08bcec --- /dev/null +++ b/packages/website/public/images/@next/clients/laketrade.svg @@ -0,0 +1,13 @@ +<svg width="78" height="53" viewBox="0 0 78 53" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M0 52.4754H5.63871V50.785H1.93548V43.7012H0V52.4754Z" fill="white"/> +<path d="M6.54294 52.4754H8.50423L9.05907 50.7076H11.8204L12.3752 52.4754H14.4268L11.4849 43.7012H9.48488L6.54294 52.4754ZM9.53649 49.0947L10.4397 45.8947L11.3429 49.0947H9.53649Z" fill="white"/> +<path d="M16.2298 52.4754H18.1653V50.1528L19.1976 48.8367L21.1976 52.4754H23.404L20.5395 47.3012L23.3653 43.7012H21.146L18.1653 47.5334V43.7012H16.2298V52.4754Z" fill="white"/> +<path d="M25.063 52.4754H31.2049V50.8108H26.9985V48.8367H30.4307V47.185H26.9985V45.3657H31.0759V43.7012H25.063V52.4754Z" fill="white"/> +<path d="M39.0649 52.4754H40.2262V44.7721H42.8198V43.7012H36.4714V44.7721H39.0649V52.4754Z" fill="white"/> +<path d="M44.9018 52.4754H46.0631V48.9141H47.9857L50.076 52.4754H51.4179L49.276 48.8367C50.5534 48.5915 51.0954 47.8044 51.0954 46.3076C51.0954 44.4625 50.2696 43.7012 48.2696 43.7012H44.9018V52.4754ZM46.0631 47.856V44.7592H48.1663C49.4825 44.7592 49.9341 45.185 49.9341 46.3076C49.9341 47.4302 49.4825 47.856 48.1663 47.856H46.0631Z" fill="white"/> +<path d="M52.7774 52.4754H53.9774L54.7774 50.2302H58.3129L59.1129 52.4754H60.3516L57.1516 43.7012H55.9774L52.7774 52.4754ZM55.1516 49.1721L56.5452 45.185L57.9387 49.1721H55.1516Z" fill="white"/> +<path d="M62.4673 52.4754H65.4867C67.7835 52.4754 68.8157 51.4044 68.8157 49.0689V47.1076C68.8157 44.7721 67.7835 43.7012 65.4867 43.7012H62.4673V52.4754ZM63.6286 51.4173V44.7592H65.3448C66.9964 44.7592 67.6544 45.4302 67.6544 47.1205V49.056C67.6544 50.7463 66.9964 51.4173 65.3448 51.4173H63.6286Z" fill="white"/> +<path d="M71.6155 52.4754H77.4865V51.4173H72.7768V48.5141H76.7123V47.456H72.7768V44.7592H77.3575V43.7012H71.6155V52.4754Z" fill="white"/> +<path d="M38.5883 16.5883H37.9916C29.1604 16.5883 22 9.42787 22 0.5967V0H38.5883V16.5883Z" fill="white"/> +<path d="M39.1846 33.1765H38.5879V16.5883H55.1762V17.185C55.1762 26.0161 48.0158 33.1765 39.1846 33.1765Z" fill="white"/> +</svg> diff --git a/packages/website/public/images/@next/clients/ledgerdex.svg b/packages/website/public/images/@next/clients/ledgerdex.svg new file mode 100644 index 000000000..44126012e --- /dev/null +++ b/packages/website/public/images/@next/clients/ledgerdex.svg @@ -0,0 +1,19 @@ +<svg width="69" height="55" viewBox="0 0 69 55" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g clip-path="url(#clip0)"> +<path d="M43.2016 50.8792C43.1515 50.6793 43.1515 50.5793 43.3268 50.4543C44.0531 50.0045 44.2785 49.3047 44.2785 48.48C44.2785 47.2054 44.2785 45.9308 44.2785 44.6562C44.2785 43.3066 43.452 42.5068 42.1247 42.5068C40.8725 42.5068 39.6202 42.5068 38.368 42.5068C37.817 42.5068 37.792 42.5068 37.792 43.0817V52.5787C37.792 53.2035 37.792 53.8283 37.792 54.4531C37.792 54.803 37.9423 54.9779 38.2929 54.9529C38.6685 54.9529 39.0442 54.9529 39.4199 54.9529C39.8707 54.9529 39.9458 54.878 39.9458 54.4031C39.9458 53.3534 39.9458 52.3038 39.9458 51.2791C39.9458 51.1041 39.8957 50.9292 40.046 50.7792H41.0478C41.3733 52.0289 41.724 53.2535 42.0245 54.4781C42.1247 54.828 42.2499 55.0279 42.6506 54.9779C43.0012 54.9529 43.3268 54.9779 43.6774 54.9779C44.1533 54.9779 44.2284 54.878 44.1282 54.4281C43.8277 53.2285 43.5272 52.0538 43.2016 50.8792ZM42.0996 48.1301C42.0996 48.455 41.8993 48.6549 41.5737 48.6799C41.0728 48.7049 40.5469 48.6799 39.9709 48.6799V44.5562C40.5469 44.5562 41.0979 44.5312 41.6739 44.5562C41.9243 44.5812 42.0996 44.7811 42.0996 45.081C42.0996 46.1057 42.0996 47.1304 42.0996 48.1301Z" fill="white"/> +<path d="M51.9679 44.7561C51.9679 43.2816 51.1915 42.5068 49.7139 42.5068C48.5618 42.5068 47.4348 42.5068 46.2828 42.5068C45.7068 42.5068 45.7068 42.5068 45.7068 43.0817C45.7068 44.9811 45.7068 46.8555 45.7068 48.7549C45.7068 50.6543 45.7068 52.5537 45.7068 54.4531C45.7068 54.828 45.7819 54.9779 46.2077 54.9779C47.3848 54.9529 48.5869 54.9779 49.764 54.9779C51.1915 54.9779 51.9679 54.2032 51.9679 52.7786C51.9679 50.0795 51.9679 47.4053 51.9679 44.7561ZM49.8892 52.1288C49.8892 52.7036 49.7139 52.8786 49.1379 52.8786C48.7121 52.8786 48.3114 52.8786 47.8606 52.8786V44.5562C48.3615 44.5562 48.8373 44.5312 49.3132 44.5562C49.7389 44.5812 49.8892 44.7811 49.8892 45.281C49.8892 46.5806 49.8892 47.8801 49.8892 49.1548C49.8892 50.1794 49.8892 51.1541 49.8892 52.1288Z" fill="white"/> +<path d="M20.9879 44.6063C20.9879 43.3317 20.1615 42.5069 18.8842 42.4819C17.657 42.4819 16.4549 42.4819 15.2277 42.4819C14.7268 42.4819 14.7018 42.5069 14.7018 43.0068C14.7018 44.9062 14.7018 46.8056 14.7018 48.705C14.7018 50.6044 14.7018 52.4788 14.7018 54.3782C14.7018 54.903 14.7018 54.928 15.2528 54.928C16.4549 54.928 17.657 54.928 18.8592 54.928C20.1364 54.928 20.9629 54.1033 20.9629 52.8287C20.9879 50.1045 20.9879 47.3554 20.9879 44.6063ZM18.9343 47.4304C18.9343 48.9799 18.9343 50.5044 18.9343 52.0539C18.9343 52.7037 18.759 52.8787 18.1078 52.8787C17.7572 52.8787 17.4316 52.8787 17.081 52.8787C17.0309 52.8787 16.9808 52.8537 16.9057 52.8287V44.5813C17.4066 44.5063 17.9075 44.5313 18.3833 44.5563C18.784 44.5813 18.9343 44.8562 18.9343 45.2311C18.9343 45.9808 18.9343 46.7056 18.9343 47.4304Z" fill="white"/> +<path d="M28.851 52.9786C28.801 54.0283 28.3752 54.778 27.0979 54.903C26.021 55.0279 24.9191 55.0529 23.8422 54.853C23.0658 54.703 22.615 54.2032 22.4397 53.4784C22.3645 53.1285 22.3145 52.7787 22.3145 52.4288C22.3145 49.9046 22.3145 47.4053 22.3145 44.8811C22.3145 44.5062 22.3896 44.1314 22.4898 43.7815C22.7152 42.9817 23.3162 42.5818 24.0676 42.5319C25.1445 42.4569 26.2214 42.4069 27.2983 42.5818C28.3502 42.7318 28.801 43.5066 28.8761 44.4563C28.9262 45.0561 28.8761 45.6309 28.8761 46.2307C28.8761 46.5056 28.7759 46.6306 28.5004 46.6306C28.0747 46.6306 27.6239 46.6306 27.1981 46.6306C26.9477 46.6306 26.8224 46.5306 26.8224 46.2557C26.8224 45.9058 26.8224 45.5809 26.8224 45.231C26.7974 44.7812 26.597 44.5812 26.1462 44.5562C25.7956 44.5562 25.42 44.5562 25.0693 44.5562C24.6937 44.5562 24.4683 44.7562 24.4683 45.131C24.4683 47.5053 24.4683 49.8796 24.4683 52.2538C24.4683 52.6787 24.6937 52.8786 25.0944 52.9036C25.445 52.9286 25.8207 52.9036 26.1713 52.9036C26.5219 52.9036 26.7724 52.7287 26.7974 52.3788C26.8224 51.679 26.7974 50.9542 26.7974 50.2794C26.597 50.1545 26.4217 50.1795 26.2464 50.2045C25.9208 50.2295 25.7455 50.1045 25.7706 49.7546C25.7956 49.3547 25.7956 48.9798 25.7706 48.58C25.7706 48.2551 25.8708 48.1301 26.1963 48.1301C26.9477 48.1551 27.699 48.1301 28.4503 48.1301C28.7509 48.1301 28.8761 48.2301 28.8761 48.53C28.8761 50.0045 28.9262 51.5041 28.851 52.9786Z" fill="white"/> +<path d="M67.4444 54.9532C67.0688 54.9532 66.6931 54.9282 66.3174 54.9532C65.9418 54.9782 65.7665 54.8033 65.6412 54.4784C65.2405 53.4037 64.8148 52.354 64.389 51.3044C64.364 51.2294 64.3139 51.1794 64.2387 51.0045C63.7629 52.2041 63.3121 53.2788 62.9114 54.3534C62.7361 54.8033 62.5107 55.0032 62.0348 54.9532C61.6842 54.9032 61.3085 54.9532 60.9579 54.9532C60.4821 54.9532 60.432 54.8533 60.6073 54.4284C61.3586 52.604 62.0849 50.8045 62.8613 48.9801C62.9865 48.7052 62.9865 48.4803 62.8613 48.1804C62.135 46.4809 61.4338 44.7564 60.7325 43.057C60.5071 42.5321 60.5572 42.4821 61.1332 42.4821C61.4839 42.4821 61.8595 42.5071 62.2101 42.4821C62.6109 42.4571 62.7862 42.6321 62.9364 42.982C63.2871 43.9567 63.6878 44.9064 64.0634 45.8561C64.1135 46.006 64.1386 46.156 64.3139 46.2809C64.7396 45.2063 65.1904 44.1566 65.5661 43.057C65.7164 42.6071 65.9668 42.4322 66.4176 42.4821C66.7682 42.5071 67.1439 42.4821 67.4945 42.4821C67.9453 42.4821 67.9954 42.5571 67.8201 42.982C67.0938 44.7064 66.3926 46.4309 65.6663 48.1554C65.541 48.4553 65.516 48.6802 65.6663 48.9801C66.4176 50.7545 67.1439 52.554 67.8952 54.3284C68.0956 54.8783 68.0455 54.9532 67.4444 54.9532Z" fill="white"/> +<path d="M59.5306 54.5532C59.5306 54.8531 59.4304 54.9781 59.1299 54.9781C57.3267 54.9781 55.4985 54.9781 53.6953 54.9781C53.3947 54.9781 53.2946 54.8781 53.2946 54.5532C53.2946 50.6795 53.2946 46.7807 53.2946 42.9069C53.2946 42.657 53.3446 42.482 53.6452 42.507C55.5235 42.507 57.4269 42.507 59.3303 42.507C59.3803 42.507 59.4304 42.532 59.5056 42.557C59.6057 43.1568 59.5557 43.7566 59.5306 44.3564C59.5056 44.6313 59.2802 44.5814 59.0798 44.5814C58.028 44.5814 56.951 44.5814 55.8992 44.5814H55.3983V47.6804C56.2999 47.6804 57.1764 47.6804 58.078 47.6804C58.604 47.6804 58.629 47.7054 58.629 48.2302C58.629 48.5551 58.629 48.88 58.629 49.2049C58.629 49.7298 58.629 49.7547 58.078 49.7547C57.2015 49.7547 56.3249 49.7547 55.4233 49.7547V52.9287C56.6255 52.9287 57.8025 52.9287 59.0047 52.9287C59.5807 52.9287 59.5807 52.9287 59.5807 53.5036C59.5306 53.8285 59.5056 54.1784 59.5306 54.5532Z" fill="white"/> +<path d="M13.5004 53.3284C13.5004 53.7283 13.5004 54.1032 13.5004 54.5031C13.5004 54.803 13.3752 54.9529 13.0496 54.9529C11.2464 54.9529 9.46823 54.9529 7.66503 54.9529C7.33946 54.9529 7.21423 54.853 7.21423 54.5281C7.21423 50.6543 7.21423 46.8055 7.21423 42.9317C7.21423 42.6068 7.3645 42.5068 7.66503 42.5068C9.46823 42.5068 11.2464 42.5068 13.0496 42.5068C13.2499 42.5068 13.4503 42.5568 13.4753 42.7817C13.5004 43.3566 13.6006 43.9564 13.3501 44.5812H9.29292V47.6052C9.66859 47.7052 10.0443 47.6302 10.4199 47.6552C10.9709 47.6552 11.5469 47.6552 12.0979 47.6552C12.4235 47.6552 12.5487 47.7552 12.5487 48.0801C12.5236 48.48 12.5236 48.8548 12.5487 49.2547C12.5737 49.6046 12.4235 49.7296 12.0728 49.7296C11.2965 49.7046 10.5451 49.7296 9.76876 49.7296C9.6185 49.7296 9.46823 49.7046 9.26787 49.8045V52.8036C9.41814 52.9286 9.59345 52.8786 9.76876 52.8786C10.8206 52.8786 11.8975 52.9036 12.9494 52.8786C13.3251 52.8786 13.5004 53.0035 13.5004 53.3284Z" fill="white"/> +<path d="M36.5656 53.3534C36.5656 53.7283 36.5656 54.1032 36.5656 54.4781C36.5656 54.803 36.4654 54.9529 36.0897 54.9529C34.3116 54.9529 32.5334 54.9529 30.7553 54.9529C30.4297 54.9529 30.2794 54.853 30.2794 54.5031C30.2794 50.6543 30.2794 46.8055 30.2794 42.9567C30.2794 42.6068 30.4046 42.5068 30.7553 42.5068C32.5334 42.5068 34.3116 42.5068 36.0897 42.5068C36.3151 42.5068 36.5405 42.5318 36.5405 42.7817C36.5656 43.3566 36.6657 43.9564 36.4153 44.5562H32.3831V47.5553C32.5084 47.6802 32.6837 47.6302 32.859 47.6302C33.6103 47.6302 34.3617 47.6552 35.113 47.6302C35.4887 47.6302 35.664 47.7302 35.6389 48.1301C35.6139 48.48 35.6389 48.8049 35.6389 49.1548C35.6389 49.6546 35.6139 49.6796 35.113 49.6796C34.2114 49.6796 33.3348 49.6796 32.3831 49.6796C32.308 50.7293 32.3581 51.7789 32.3581 52.8536H33.7606C34.537 52.8536 35.3133 52.8786 36.1148 52.8536C36.4403 52.8786 36.5656 53.0285 36.5656 53.3534Z" fill="white"/> +<path d="M6.08579 54.603C6.08579 54.828 5.96057 54.9529 5.73517 54.9529C3.93197 54.9529 2.12877 54.9529 0.350622 54.9529C0.0500888 54.9529 0 54.778 0 54.5281C0 53.9033 0 53.2785 0 52.6537V43.1066C0 42.5068 0 42.5068 0.601066 42.5068C0.951688 42.5068 1.27726 42.5068 1.62789 42.5068C2.12877 42.5068 2.15382 42.5318 2.15382 43.0317C2.15382 44.9311 2.15382 46.8055 2.15382 48.7049V52.9036H4.55808C4.95879 52.9036 5.33446 52.9036 5.73517 52.9036C5.98561 52.9036 6.11084 53.0035 6.11084 53.2785C6.06075 53.7033 6.06075 54.1532 6.08579 54.603Z" fill="white"/> +<path d="M41.3723 17.8194C39.8947 17.8194 38.5172 18.2193 37.3401 18.9191L35.1863 16.3949C35.9377 15.5701 36.3885 14.4705 36.3885 13.2708C36.3885 12.3711 36.138 11.5464 35.6872 10.8216L39.2936 6.62292C39.7945 6.89784 40.3705 7.04779 40.9966 7.04779C42.9501 7.04779 44.5279 5.47329 44.5279 3.5239C44.5529 1.57451 42.9751 0 41.0217 0C39.0682 0 37.4904 1.57451 37.4904 3.5239C37.4904 4.24867 37.7158 4.89847 38.0664 5.44829L34.5352 9.54701C33.7588 8.9472 32.7821 8.59731 31.7302 8.59731C30.8036 8.59731 29.952 8.87222 29.2258 9.32208L27.673 7.49765C27.9234 7.09778 28.0737 6.62292 28.0737 6.09809C28.0737 4.64854 26.8966 3.47391 25.444 3.47391C23.9915 3.47391 22.8144 4.64854 22.8144 6.09809C22.8144 7.54764 23.9915 8.72227 25.444 8.72227C25.7446 8.72227 26.0201 8.67228 26.2956 8.57231L27.9485 10.5217C27.3975 11.2965 27.0719 12.2212 27.0719 13.2458C27.0719 13.4458 27.097 13.6457 27.122 13.8457L24.0416 16.02C23.3904 15.3702 22.5139 14.9953 21.5371 14.9953C19.5837 14.9953 18.0059 16.5698 18.0059 18.5192C18.0059 20.4686 19.5837 22.0431 21.5371 22.0431C23.4906 22.0431 25.0684 20.4686 25.0684 18.5192C25.0684 18.1693 25.0183 17.8194 24.9181 17.4945L27.673 15.5451C28.4744 16.9447 30.0021 17.9194 31.7302 17.9194C32.4815 17.9194 33.1577 17.7444 33.7838 17.4445L35.9377 19.9687C34.435 21.3933 33.4833 23.4177 33.4833 25.667C33.4833 30.0156 37.0146 33.5395 41.3723 33.5395C45.73 33.5395 49.2613 30.0156 49.2613 25.667C49.2613 21.3183 45.705 17.8194 41.3723 17.8194Z" fill="white"/> +</g> +<defs> +<clipPath id="clip0"> +<rect width="69" height="55" fill="white"/> +</clipPath> +</defs> +</svg> diff --git a/packages/website/public/images/@next/clients/openrelay.svg b/packages/website/public/images/@next/clients/openrelay.svg new file mode 100644 index 000000000..21e32cc18 --- /dev/null +++ b/packages/website/public/images/@next/clients/openrelay.svg @@ -0,0 +1,22 @@ +<svg width="64" height="52" viewBox="0 0 64 52" fill="none" xmlns="http://www.w3.org/2000/svg"> +<mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="15" y="0" width="33" height="36"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M15.9592 0.240479H47.5748V35.1917H15.9592V0.240479Z" fill="white"/> +</mask> +<g mask="url(#mask0)"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M29.5768 30.5355C29.5208 30.4346 29.4727 30.3452 29.4219 30.2572C28.9351 29.4126 28.448 28.568 27.9605 27.7238C26.4156 25.0481 24.8706 22.3725 23.3258 19.6967C23.2905 19.6355 23.2543 19.5742 23.2253 19.51C23.0158 19.0477 23.2174 18.5524 23.527 18.3231C23.9571 18.0045 24.5702 18.0907 24.8939 18.5213C24.9503 18.5965 24.9975 18.6791 25.0446 18.7606C25.8588 20.1697 26.6724 21.5791 27.486 22.9885C28.7006 25.0925 29.9154 27.1962 31.1301 29.3C31.1617 29.3546 31.1941 29.4081 31.2262 29.4625C31.2616 29.5229 31.3156 29.5469 31.3843 29.5431C31.4471 29.5397 31.5102 29.5342 31.5728 29.5354C31.7692 29.5397 31.9686 29.526 32.1612 29.5556C32.9428 29.6754 33.5783 30.0487 34.0519 30.6876C34.0847 30.7317 34.1177 30.7759 34.1471 30.8224C34.1955 30.8985 34.2644 30.9217 34.3498 30.9086C34.3886 30.9024 34.4279 30.8987 34.4664 30.8911C34.6358 30.857 34.8056 30.8242 34.9746 30.7871C36.1347 30.5325 37.2313 30.1105 38.2708 29.5377C39.6658 28.7688 40.8629 27.7657 41.8505 26.5146C42.8969 25.1889 43.6297 23.703 44.1116 22.0889C44.4689 20.8922 44.655 19.6665 44.7153 18.4216C44.7517 17.6675 44.7368 16.9121 44.6675 16.1597C44.6113 15.5492 44.5255 14.9421 44.3982 14.3414C44.0858 12.8685 43.5671 11.4744 42.8031 10.175C41.9921 8.79579 40.9569 7.61379 39.6708 6.6586C38.2628 5.61297 36.7021 4.89506 34.9899 4.51033C34.7984 4.46722 34.6046 4.43318 34.4116 4.39733C34.3349 4.38322 34.2783 4.41143 34.2321 4.47931C34.1215 4.64146 34.0037 4.79838 33.8897 4.95831C33.872 4.98309 33.8593 5.01169 33.8399 5.04594C33.8764 5.09851 33.9113 5.14967 33.9469 5.20043C34.1322 5.46391 34.3282 5.72073 34.5012 5.99206C35.3765 7.36563 35.8651 8.87113 35.9862 10.4917C36.0392 11.1977 36.0182 11.9053 35.9135 12.6091C35.7676 13.5883 35.4895 14.5253 35.0655 15.4205C34.6032 16.3964 33.9818 17.2606 33.2443 18.0445C33.064 18.2361 32.8398 18.3477 32.5772 18.3545C32.184 18.3646 31.8679 18.2065 31.678 17.8572C31.4854 17.5031 31.506 17.146 31.7354 16.8092C31.7793 16.7449 31.8351 16.6881 31.8889 16.6309C32.5417 15.9374 33.0658 15.1592 33.4401 14.2816C33.8111 13.4112 34.014 12.5025 34.0587 11.5594C34.1006 10.6723 33.9868 9.80195 33.731 8.9513C33.4115 7.88935 32.8858 6.9396 32.1606 6.10144C31.963 5.87302 31.991 5.91169 31.7408 5.90424C30.7522 5.87483 29.9755 5.45323 29.4121 4.63985C29.3762 4.58828 29.3422 4.53531 29.3097 4.48132C29.2682 4.41263 29.2086 4.38564 29.1307 4.39692C29.0841 4.40377 29.0378 4.41243 28.9915 4.42089C27.6969 4.65899 26.4742 5.10032 25.3194 5.7298C24.4665 6.1947 23.6771 6.75045 22.963 7.40974C21.6426 8.62921 20.655 10.0805 19.9564 11.7333C19.2851 13.3222 18.9289 14.9832 18.8379 16.7004C18.7889 17.6191 18.8045 18.5387 18.9088 19.4558C18.9847 20.1207 19.0923 20.7792 19.2524 21.4286C19.6634 23.095 20.3376 24.6427 21.3373 26.043C22.0509 27.0427 22.8955 27.9153 23.8832 28.6457C25.3661 29.7423 27.0122 30.4757 28.8205 30.8427C28.9435 30.8677 29.0678 30.8874 29.1919 30.9074C29.2686 30.9197 29.3287 30.8937 29.3732 30.8262C29.4336 30.7346 29.4989 30.6463 29.5768 30.5355M15.9592 17.91C15.9721 15.9986 16.1546 14.3622 16.6099 12.7634C17.2053 10.6731 18.1635 8.76739 19.5361 7.07738C20.7773 5.54932 22.2786 4.3375 24.0199 3.42098C25.4433 2.67166 26.9451 2.15216 28.5276 1.86512C28.7208 1.83007 28.9143 1.79563 29.1091 1.77005C29.2213 1.75534 29.2924 1.70156 29.349 1.60608C29.5309 1.29769 29.7688 1.03784 30.0536 0.8209C31.3462 -0.162491 33.1923 0.135225 34.1111 1.47535C34.1199 1.48845 34.1316 1.50033 34.1371 1.51483C34.215 1.7205 34.3834 1.76823 34.582 1.79805C36.8159 2.13303 38.8774 2.92466 40.7698 4.15601C41.4237 4.58103 42.0342 5.06286 42.6075 5.59222C43.7971 6.69023 44.7696 7.95542 45.5466 9.37431C46.4115 10.9541 46.9955 12.6319 47.3049 14.4051C47.4048 14.9783 47.4711 15.5557 47.5172 16.1362C47.5847 16.9844 47.5901 17.8338 47.548 18.6815C47.3957 21.7463 46.5302 24.5877 44.8218 27.1515C43.3669 29.3352 41.4464 30.9888 39.0816 32.1261C37.7334 32.7741 36.321 33.2184 34.8455 33.4615C34.7369 33.4795 34.6284 33.4974 34.5192 33.5117C34.4106 33.526 34.3306 33.5711 34.2789 33.6751C34.2265 33.78 34.1636 33.8813 34.0944 33.9764C33.5239 34.7588 32.7522 35.1858 31.7855 35.1916C30.7296 35.1979 29.915 34.7245 29.3474 33.832C29.322 33.7921 29.296 33.752 29.2777 33.7089C29.2223 33.5806 29.1266 33.524 28.9881 33.5043C28.7002 33.4638 28.4132 33.4154 28.1285 33.3568C25.8046 32.878 23.6878 31.9411 21.807 30.4864C20.7485 29.6678 19.8326 28.71 19.05 27.6263C17.6805 25.7298 16.7831 23.6266 16.3216 21.3353C16.185 20.6565 16.0819 19.9729 16.037 19.2815C16.0019 18.7405 15.9753 18.199 15.9592 17.91" fill="white"/> +</g> +<mask id="mask1" mask-type="alpha" maskUnits="userSpaceOnUse" x="0" y="39" width="10" height="10"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M0.784973 39.8586H9.01565V48.5607H0.784973V39.8586Z" fill="white"/> +</mask> +<g mask="url(#mask1)"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M2.16291 44.2098C2.16291 44.6126 2.22717 45.0032 2.35628 45.3819C2.485 45.7606 2.6683 46.095 2.90599 46.385C3.14368 46.6751 3.43193 46.907 3.77013 47.0802C4.10854 47.2532 4.48723 47.3398 4.90621 47.3398C5.3413 47.3398 5.72604 47.2494 6.06062 47.0679C6.39479 46.8866 6.67881 46.6471 6.91247 46.3488C7.14614 46.0511 7.3234 45.7163 7.44446 45.3457C7.56511 44.9752 7.62554 44.5965 7.62554 44.2098C7.62554 43.7987 7.56108 43.4061 7.43217 43.0312C7.30345 42.6565 7.11995 42.3262 6.88246 42.0402C6.64457 41.7545 6.35854 41.5247 6.02436 41.3513C5.68978 41.178 5.31713 41.0916 4.90621 41.0916C4.47132 41.0916 4.08457 41.1821 3.74596 41.3633C3.40776 41.5448 3.12152 41.7803 2.88806 42.0704C2.654 42.3604 2.47493 42.6928 2.35024 43.0675C2.22515 43.4421 2.16291 43.8228 2.16291 44.2098M4.89433 48.5607C4.28197 48.5607 3.72381 48.4378 3.22043 48.1921C2.71665 47.9463 2.28377 47.62 1.92119 47.2129C1.55861 46.8064 1.27842 46.3409 1.08122 45.817C0.883614 45.2933 0.784912 44.7577 0.784912 44.2098C0.784912 43.6377 0.889657 43.0896 1.09935 42.5661C1.30864 42.0424 1.59648 41.5789 1.96349 41.176C2.3299 40.7731 2.76499 40.4531 3.26857 40.2154C3.77215 39.9777 4.32206 39.8586 4.9185 39.8586C5.53065 39.8586 6.08862 39.9855 6.5922 40.2393C7.09578 40.4932 7.52684 40.8255 7.88539 41.2364C8.24374 41.6474 8.52192 42.1129 8.71952 42.6326C8.91672 43.1523 9.01563 43.682 9.01563 44.2217C9.01563 44.7939 8.9129 45.3416 8.70723 45.8653C8.50197 46.3893 8.21372 46.8503 7.84309 47.2494C7.47246 47.648 7.03515 47.9665 6.53177 48.204C6.02819 48.4419 5.48231 48.5607 4.89433 48.5607" fill="white"/> +</g> +<path fill-rule="evenodd" clip-rule="evenodd" d="M13.4028 47.485C13.6846 47.485 13.9406 47.4244 14.1702 47.3037C14.3999 47.1829 14.5973 47.0215 14.7624 46.8201C14.9274 46.6188 15.0543 46.3894 15.1432 46.1312C15.2316 45.8736 15.2761 45.6077 15.2761 45.3335C15.2761 45.0434 15.2257 44.7697 15.125 44.5119C15.0241 44.254 14.8871 44.0284 14.7141 43.8349C14.5407 43.6417 14.3334 43.4886 14.0917 43.3758C13.85 43.263 13.5881 43.2066 13.3061 43.2066C13.1369 43.2066 12.9596 43.2388 12.7743 43.3033C12.5888 43.3679 12.4158 43.4564 12.2546 43.5692C12.0933 43.682 11.9525 43.8129 11.8316 43.962C11.7107 44.111 11.6261 44.2744 11.5776 44.4512V46.1072C11.6582 46.3004 11.7629 46.4819 11.892 46.6509C12.021 46.8201 12.164 46.9653 12.3211 47.0862C12.4782 47.2068 12.6492 47.3037 12.8347 47.376C13.0201 47.4485 13.2094 47.485 13.4028 47.485M13.8379 48.6211C13.3303 48.6211 12.8831 48.5 12.4963 48.2585C12.1096 48.0168 11.8034 47.7026 11.5776 47.3158V51.0743H10.2484V42.1793H11.4207V43.3152C11.6624 42.9367 11.9744 42.6345 12.3573 42.4087C12.7399 42.1833 13.1731 42.0703 13.6566 42.0703C14.0917 42.0703 14.4903 42.1593 14.8531 42.3362C15.2157 42.5137 15.5299 42.7514 15.7958 43.0493C16.0617 43.3476 16.269 43.6941 16.4182 44.0889C16.5673 44.4837 16.6418 44.8986 16.6418 45.3335C16.6418 45.793 16.5731 46.2218 16.4363 46.6207C16.2992 47.0195 16.1058 47.3662 15.8562 47.6601C15.6062 47.9543 15.3103 48.188 14.9679 48.3612C14.6253 48.5343 14.2488 48.6211 13.8379 48.6211" fill="white"/> +<path fill-rule="evenodd" clip-rule="evenodd" d="M22.6242 44.8622C22.6 44.5965 22.5335 44.3505 22.425 44.1249C22.3162 43.8995 22.177 43.7082 22.0078 43.5508C21.8388 43.3937 21.6412 43.271 21.4156 43.1822C21.19 43.0936 20.9521 43.0493 20.7025 43.0493C20.4528 43.0493 20.2171 43.0936 19.9955 43.1822C19.7739 43.271 19.5785 43.3937 19.4093 43.5508C19.2401 43.7082 19.1032 43.8995 18.9984 44.1249C18.8935 44.3505 18.8292 44.5965 18.805 44.8622H22.6242ZM20.7025 48.6209C20.211 48.6209 19.7639 48.5341 19.361 48.361C18.9581 48.188 18.6137 47.9523 18.3276 47.654C18.0416 47.3561 17.82 47.0094 17.6629 46.6146C17.5058 46.22 17.4272 45.8008 17.4272 45.3577C17.4272 44.9147 17.5058 44.4935 17.6629 44.0947C17.82 43.6959 18.0416 43.3454 18.3276 43.0432C18.6137 42.7411 18.9581 42.5034 19.361 42.3304C19.7639 42.1569 20.2151 42.0703 20.7148 42.0703C21.2061 42.0703 21.6513 42.1591 22.0501 42.3362C22.4489 42.5137 22.7892 42.7493 23.0716 43.0432C23.3534 43.3375 23.5687 43.6798 23.7182 44.0703C23.867 44.4615 23.9416 44.8702 23.9416 45.2973C23.9416 45.3939 23.9375 45.4846 23.9295 45.5694C23.9214 45.654 23.9132 45.7243 23.9053 45.7807H18.8415C18.8655 46.0627 18.9319 46.3167 19.0407 46.5421C19.1495 46.7677 19.2903 46.9633 19.4639 47.1283C19.637 47.2934 19.8342 47.4203 20.0559 47.509C20.2775 47.5978 20.5092 47.6419 20.7509 47.6419C20.9281 47.6419 21.1032 47.6198 21.2768 47.5754C21.4498 47.5313 21.609 47.4669 21.7542 47.3823C21.899 47.2975 22.028 47.1947 22.141 47.0737C22.2536 46.953 22.3422 46.8201 22.4066 46.675L23.5429 47.0014C23.3252 47.4767 22.9644 47.8655 22.461 48.1677C21.9575 48.4698 21.3713 48.6209 20.7025 48.6209V48.6209Z" fill="white"/> +<path fill-rule="evenodd" clip-rule="evenodd" d="M30.6972 48.5H29.3678V44.9588C29.3678 44.3628 29.2731 43.9297 29.0838 43.6598C28.8944 43.3899 28.6144 43.2549 28.2438 43.2549C28.0504 43.2549 27.857 43.2912 27.6637 43.3635C27.4703 43.436 27.289 43.539 27.1198 43.6717C26.9506 43.8046 26.7995 43.962 26.6666 44.1432C26.5336 44.3245 26.4309 44.5238 26.3584 44.7413V48.5H25.0289V42.1793H26.2375V43.4481C26.4794 43.0213 26.8299 42.6849 27.289 42.4389C27.7483 42.1934 28.2561 42.0703 28.812 42.0703C29.1907 42.0703 29.5009 42.139 29.7426 42.276C29.9842 42.4129 30.1755 42.6003 30.3165 42.838C30.4575 43.0755 30.5562 43.3498 30.6126 43.6598C30.6688 43.97 30.6972 44.2984 30.6972 44.6446V48.5Z" fill="white"/> +<path fill-rule="evenodd" clip-rule="evenodd" d="M33.7669 44.3182H36.1359C36.3293 44.3182 36.5046 44.2759 36.6615 44.1913C36.8186 44.1067 36.9535 43.9901 37.0666 43.841C37.1792 43.692 37.2678 43.5205 37.3322 43.3272C37.3969 43.1338 37.4291 42.9283 37.4291 42.7108C37.4291 42.4932 37.3907 42.2878 37.3141 42.0946C37.2374 41.901 37.1368 41.7318 37.012 41.5868C36.8871 41.442 36.742 41.327 36.5769 41.2424C36.4117 41.158 36.2405 41.1155 36.0632 41.1155H33.7669V44.3182ZM32.4133 48.4999V39.9189H36.1478C36.5346 39.9189 36.8913 39.9997 37.2176 40.1607C37.5437 40.3218 37.8237 40.5335 38.0576 40.7952C38.2911 41.0572 38.4744 41.3554 38.6073 41.6895C38.7402 42.0239 38.8069 42.3645 38.8069 42.7108C38.8069 43.0011 38.7664 43.2788 38.6861 43.5447C38.6055 43.8106 38.4927 44.0566 38.3475 44.282C38.2026 44.5076 38.0254 44.703 37.8159 44.8681C37.6062 45.0335 37.3766 45.1562 37.127 45.237L39.1451 48.4999H37.6102L35.7492 45.5147H33.7669V48.4999H32.4133Z" fill="white"/> +<path fill-rule="evenodd" clip-rule="evenodd" d="M44.8376 44.8622C44.8135 44.5965 44.747 44.3505 44.6384 44.1249C44.5296 43.8995 44.3905 43.7082 44.2213 43.5508C44.0522 43.3937 43.8546 43.271 43.629 43.1822C43.4034 43.0936 43.1655 43.0493 42.916 43.0493C42.6662 43.0493 42.4305 43.0936 42.2089 43.1822C41.9874 43.271 41.792 43.3937 41.6228 43.5508C41.4536 43.7082 41.3166 43.8995 41.2119 44.1249C41.1069 44.3505 41.0427 44.5965 41.0185 44.8622H44.8376ZM42.916 48.6209C42.4245 48.6209 41.9773 48.5341 41.5744 48.361C41.1716 48.188 40.8271 47.9523 40.5411 47.654C40.2551 47.3561 40.0335 47.0094 39.8764 46.6146C39.7192 46.22 39.6407 45.8008 39.6407 45.3577C39.6407 44.9147 39.7192 44.4935 39.8764 44.0947C40.0335 43.6959 40.2551 43.3454 40.5411 43.0432C40.8271 42.7411 41.1716 42.5034 41.5744 42.3304C41.9773 42.1569 42.4285 42.0703 42.9283 42.0703C43.4196 42.0703 43.8647 42.1591 44.2636 42.3362C44.6624 42.5137 45.0026 42.7493 45.285 43.0432C45.5668 43.3375 45.7821 43.6798 45.9316 44.0703C46.0805 44.4615 46.155 44.8702 46.155 45.2973C46.155 45.3939 46.151 45.4846 46.1429 45.5694C46.1349 45.654 46.1266 45.7243 46.1187 45.7807H41.0549C41.0789 46.0627 41.1454 46.3167 41.2542 46.5421C41.3629 46.7677 41.5037 46.9633 41.6774 47.1283C41.8504 47.2934 42.0476 47.4203 42.2694 47.509C42.4909 47.5978 42.7226 47.6419 42.9643 47.6419C43.1416 47.6419 43.3166 47.6198 43.4903 47.5754C43.6633 47.5313 43.8224 47.4669 43.9676 47.3823C44.1125 47.2975 44.2414 47.1947 44.3544 47.0737C44.467 46.953 44.5556 46.8201 44.6201 46.675L45.7564 47.0014C45.5386 47.4767 45.1779 47.8655 44.6745 48.1677C44.1709 48.4698 43.5847 48.6209 42.916 48.6209V48.6209Z" fill="white"/> +<path fill-rule="evenodd" clip-rule="evenodd" d="M47.2546 39.6775H48.5842V46.675C48.5842 46.9089 48.6445 47.092 48.7653 47.2249C48.8864 47.3579 49.0554 47.4244 49.2731 47.4244C49.3616 47.4244 49.4643 47.4082 49.5813 47.376C49.6979 47.3442 49.8087 47.3077 49.9135 47.2674L50.1069 48.3068C49.9135 48.3953 49.684 48.4658 49.418 48.5181C49.1523 48.5703 48.9144 48.5967 48.7049 48.5967C48.2458 48.5967 47.8891 48.472 47.6355 48.2222C47.3817 47.9725 47.2546 47.6179 47.2546 47.1585V39.6775Z" fill="white"/> +<path fill-rule="evenodd" clip-rule="evenodd" d="M52.9228 47.6419C53.2451 47.6419 53.5493 47.5837 53.8353 47.4669C54.1213 47.35 54.3449 47.1867 54.5061 46.9772C54.6753 46.8322 54.7599 46.6793 54.7599 46.5179V45.684C54.5343 45.5954 54.2948 45.5269 54.041 45.4785C53.7869 45.4302 53.5394 45.406 53.2975 45.406C52.8221 45.406 52.4333 45.5088 52.1312 45.7142C51.829 45.9197 51.678 46.1918 51.678 46.53C51.678 46.8443 51.7946 47.1085 52.0286 47.3216C52.2621 47.5354 52.5602 47.6419 52.9228 47.6419M52.5602 48.6209C52.2541 48.6209 51.97 48.5703 51.7084 48.4698C51.4463 48.3691 51.2207 48.2301 51.0314 48.0528C50.842 47.8756 50.6932 47.6661 50.5844 47.4244C50.4756 47.1829 50.421 46.921 50.421 46.6388C50.421 46.3409 50.4855 46.0708 50.6144 45.829C50.7433 45.5875 50.9266 45.378 51.1645 45.2008C51.402 45.0235 51.6842 44.8863 52.0105 44.7896C52.3368 44.693 52.6972 44.6446 53.0922 44.6446C53.3899 44.6446 53.6842 44.6708 53.9745 44.7232C54.2643 44.7757 54.5262 44.8462 54.7599 44.9349V44.4996C54.7599 44.0325 54.6269 43.6679 54.3612 43.406C54.0951 43.1441 53.7124 43.013 53.2129 43.013C52.8747 43.013 52.5421 43.0755 52.2158 43.2003C51.8895 43.3252 51.5531 43.5047 51.2066 43.7382L50.7957 42.8922C51.6095 42.3445 52.4555 42.0703 53.3337 42.0703C54.2039 42.0703 54.8809 42.2921 55.3642 42.7352C55.8478 43.1782 56.0895 43.8149 56.0895 44.6446V46.9291C56.0895 47.2111 56.2061 47.3561 56.4398 47.3639V48.5C56.3109 48.5244 56.2001 48.5403 56.1076 48.5484C56.0148 48.5562 55.9241 48.5607 55.8355 48.5607C55.5777 48.5607 55.3781 48.496 55.2373 48.3671C55.0963 48.2384 55.0094 48.0732 54.9774 47.8718L54.9414 47.4727C54.6591 47.8434 54.3107 48.1274 53.8957 48.325C53.4808 48.5222 53.0358 48.6209 52.5602 48.6209" fill="white"/> +<path fill-rule="evenodd" clip-rule="evenodd" d="M57.7574 49.9867C57.8783 50.0107 57.9969 50.0308 58.1139 50.0471C58.2308 50.063 58.3254 50.0713 58.398 50.0713C58.5025 50.0713 58.5931 50.0489 58.6699 50.0048C58.7462 49.9603 58.825 49.8818 58.9056 49.7692C58.9861 49.6562 59.0687 49.4972 59.1533 49.2918C59.2379 49.0861 59.3364 48.8222 59.4494 48.4999L56.851 42.1792H58.2167L60.1746 47.3278L61.915 42.1792H63.1719L60.3075 49.9623C60.1786 50.3251 59.9548 50.6291 59.6368 50.875C59.3183 51.1206 58.9096 51.2436 58.41 51.2436C58.3133 51.2436 58.2126 51.2374 58.1079 51.2253C58.0031 51.2134 57.8863 51.187 57.7574 51.147V49.9867Z" fill="white"/> +</svg> diff --git a/packages/website/public/images/@next/clients/paradex.svg b/packages/website/public/images/@next/clients/paradex.svg new file mode 100644 index 000000000..e3bdf48b1 --- /dev/null +++ b/packages/website/public/images/@next/clients/paradex.svg @@ -0,0 +1,9 @@ +<svg width="82" height="47" viewBox="0 0 82 47" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M51.9065 2.40902L48.5125 19.4016C48.3937 19.9971 47.8718 20.4258 47.2653 20.4258H43.9271C42.6671 20.4258 41.4348 20.7925 40.379 21.4809L40.2783 21.5467L43.9832 2.99693C44.2283 1.76899 45.3053 0.885254 46.5559 0.885254H50.659C51.4619 0.885254 52.064 1.62077 51.9065 2.40902M29.1543 26.9147L32.5483 9.92205C32.6671 9.32634 33.1894 8.89757 33.7958 8.89757H37.134C38.3941 8.89757 39.6263 8.53122 40.6818 7.84283L40.7822 7.77698L37.0776 26.3265C36.8322 27.5547 35.7555 28.4384 34.5049 28.4384H30.4015C29.5989 28.4384 28.9965 27.7029 29.1543 26.9147" fill="white"/> +<mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="0" y="34" width="82" height="13"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M0.00012207 46.4356H81.0604V34.6733H0.00012207L0.00012207 46.4356Z" fill="white"/> +</mask> +<g mask="url(#mask0)"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M32.561 46.4356H30.7493L27.027 41.1475H28.3166C29.7831 41.1475 30.716 40.0956 30.716 38.8942C30.716 37.6095 29.8164 36.6252 28.3001 36.6252H25.3177V46.4356H23.2678V35.1377C23.2678 34.9274 23.4384 34.757 23.6486 34.757H28.4669C31.1494 34.757 32.7989 36.492 32.7989 38.7775C32.7989 40.5724 31.8089 41.9505 30.3627 42.5006L32.8148 45.9429C32.9613 46.1492 32.8141 46.4356 32.561 46.4356V46.4356ZM62.2248 41.4721H68.073V39.6369H62.2248V37.9942H60.1756V46.4356H62.2248H68.5118C68.6836 46.4356 68.8229 46.2958 68.8229 46.1239V44.6004H62.2248V41.4721ZM51.8391 34.757H48.3543C48.1445 34.757 47.9742 34.9274 47.9742 35.1377V36.6252H51.8391C54.2883 36.6252 55.8879 38.31 55.8879 40.613C55.8879 42.915 54.2883 44.5667 51.8391 44.5667H50.0231V37.9942H47.9742V46.4356H51.8391C55.5047 46.4356 58.0372 43.8827 58.0372 40.5796C58.0372 37.2759 55.5047 34.757 51.8391 34.757V34.757ZM60.1756 36.5919H68.8229V34.757H60.556C60.3458 34.757 60.1756 34.9274 60.1756 35.1377V36.5919ZM81.0605 34.757H78.7113L70.3137 46.4356H72.6628L75.6874 42.2297L78.7113 46.4356H80.4531C80.7066 46.4356 80.8537 46.1479 80.7056 45.9416L76.8617 40.5961L81.0605 34.757ZM74.7872 37.6934L72.6629 34.757H71.0583C70.7474 34.757 70.5678 35.109 70.7499 35.3608L73.6123 39.3273L74.7872 37.6934ZM39.2427 34.9015L34.2104 46.4356H36.3098L40.2585 37.1258L42.7826 43.0985H38.9758L38.267 44.9172H43.554L44.2076 46.4356H45.8979C46.1224 46.4356 46.273 46.205 46.1832 45.9991L41.3415 34.9015C41.281 34.7629 41.1441 34.6733 40.9929 34.6733H39.591C39.4401 34.6733 39.3032 34.7629 39.2427 34.9015V34.9015ZM14.5088 34.9015L9.47689 46.4356H11.576L15.525 37.1258L18.0488 43.0985H14.2423L13.5335 44.9172H18.8199L19.4738 46.4356H21.1641C21.3886 46.4356 21.5392 46.205 21.4494 45.9991L16.6079 34.9015C16.5471 34.7629 16.4102 34.6733 16.259 34.6733H14.8574C14.7062 34.6733 14.5693 34.7629 14.5088 34.9015V34.9015ZM4.84842 34.757H0.380527C0.170369 34.757 0.00012207 34.9274 0.00012207 35.1377V46.4356H1.73814C1.91026 46.4356 2.04932 46.2958 2.04932 46.1239V36.6252H4.6816C6.33948 36.6252 7.19758 37.8117 7.19758 39.2696C7.19758 40.8417 6.23129 42.1558 4.6816 42.1558H3.5064V44.0081H4.61488C7.53495 44.0081 9.28014 41.7804 9.28014 39.2197C9.28014 36.6593 7.56426 34.757 4.84842 34.757V34.757Z" fill="white"/> +</g> +</svg> diff --git a/packages/website/public/images/@next/clients/radar-relay.svg b/packages/website/public/images/@next/clients/radar-relay.svg new file mode 100644 index 000000000..ecc759fab --- /dev/null +++ b/packages/website/public/images/@next/clients/radar-relay.svg @@ -0,0 +1,13 @@ +<svg width="61" height="49" viewBox="0 0 61 49" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M16.3814 36.7544L12.573 48.1516H13.6538L17.3935 36.7544H16.3814Z" fill="white"/> +<path d="M17.1706 39.4236L18.7831 44.3179H15.5923L15.2664 45.2933H19.0919L20.0354 48.1512H21.1677L17.7024 37.8149L17.1706 39.4236Z" fill="white"/> +<path d="M43.9152 39.4236L45.5278 44.3179H42.3198L42.011 45.2933H45.8365L46.7801 48.1512H47.9123L44.447 37.8149L43.9152 39.4236Z" fill="white"/> +<path d="M43.1089 36.7544L39.3176 48.1516H40.3984L44.1382 36.7544H43.1089Z" fill="white"/> +<path d="M1.31935 38.3286H0.255737V48.1514H1.31935V38.3286Z" fill="white"/> +<path d="M7.40936 40.1086C7.40936 38.0892 5.86542 36.7373 3.54949 36.7373H0.255737V37.6956H3.51518C5.23068 37.6956 6.31145 38.6197 6.31145 40.1086C6.31145 41.6316 5.21353 42.6242 3.51518 42.6242H1.95408V43.5654H3.54949C3.7382 43.5654 3.9269 43.5483 4.11561 43.5311L6.22567 48.1516H7.39221L5.17922 43.2916C6.56877 42.7782 7.40936 41.5974 7.40936 40.1086Z" fill="white"/> +<path d="M54.6542 38.3286H53.5906V48.1514H54.6542V38.3286Z" fill="white"/> +<path d="M60.7442 40.1086C60.7442 38.0892 59.2003 36.7373 56.8843 36.7373H53.5906V37.6956H56.85C58.5655 37.6956 59.6463 38.6197 59.6463 40.1086C59.6463 41.6316 58.5484 42.6242 56.85 42.6242H55.2889V43.5654H56.8843C57.073 43.5654 57.2617 43.5483 57.4504 43.5311L59.5605 48.1516H60.727L58.5141 43.2916C59.9036 42.7782 60.7442 41.5974 60.7442 40.1086Z" fill="white"/> +<path d="M27.9267 36.7544H26.8631V48.1687H27.9267V36.7544Z" fill="white"/> +<path d="M30.3456 36.7544H28.5443V37.7298H30.3456C31.9753 37.7298 33.0218 38.7737 33.0218 40.3823V44.5408C33.0218 46.1494 31.9753 47.1933 30.3456 47.1933H28.5443V48.1687H30.3456C32.5757 48.1687 34.0854 46.6799 34.0854 44.4723V40.4337C34.0854 38.2261 32.5929 36.7544 30.3456 36.7544Z" fill="white"/> +<path d="M37.0055 22.2375C39.835 19.9572 41.6467 16.4218 41.6467 12.4471C41.6467 5.58552 36.2116 0 29.5348 0H19.4584V1.19241H29.5348C35.5805 1.19241 40.4864 6.23402 40.4864 12.4471C40.4864 16.0871 38.7968 19.3296 36.1709 21.4007L34.9292 20.1246C37.2498 18.4092 38.7561 15.606 38.7561 12.4471C38.7561 7.21724 34.6238 2.97057 29.5348 2.97057H19.4584V4.14207H29.5348C33.9928 4.14207 37.6162 7.86574 37.6162 12.4471C37.6162 15.2713 36.2319 17.7816 34.1149 19.2878L32.8732 18.0117C34.6849 16.8611 35.8859 14.811 35.8859 12.468C35.8859 8.86988 33.036 5.94115 29.5348 5.94115H19.4788L30.8579 17.6142C30.4304 17.7188 30.003 17.7816 29.5551 17.7816H19.4788V18.974H29.5551C30.349 18.974 31.0818 18.8276 31.7943 18.5556L33.1174 19.8945C32.0386 20.4384 30.8376 20.7313 29.5755 20.7313H19.4991V21.9237H29.5755C31.1633 21.9237 32.6696 21.5053 33.9724 20.7731L35.2345 22.0701C33.5856 23.0952 31.6314 23.7018 29.5755 23.7018H19.4991V24.8733H29.5755C31.9775 24.8733 34.1963 24.1621 36.0895 22.9278L39.7129 26.6515H19.4991V27.8439H42.5017L37.0055 22.2375ZM22.2676 7.11264H29.5348C32.405 7.11264 34.7256 9.49747 34.7256 12.4471C34.7256 14.4554 33.6264 16.2336 32.0182 17.1331L22.2676 7.11264Z" fill="white"/> +</svg> diff --git a/packages/website/public/images/@next/clients/sharkrelay.svg b/packages/website/public/images/@next/clients/sharkrelay.svg new file mode 100644 index 000000000..41d5376de --- /dev/null +++ b/packages/website/public/images/@next/clients/sharkrelay.svg @@ -0,0 +1,32 @@ +<svg width="69" height="49" viewBox="0 0 69 49" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g clip-path="url(#clip0)"> +<path d="M64.9397 26.25C64.9397 26.2761 64.9136 26.2761 64.9136 26.3023C64.9397 26.3023 64.9397 26.3023 64.9659 26.3023C64.9659 26.2761 64.9397 26.2761 64.9397 26.25Z" fill="white"/> +<path d="M68.0002 40.2872C67.8956 40.3918 67.8695 40.5225 67.791 40.6532C66.9541 42.3004 66.091 43.9476 65.2541 45.5947C65.2018 45.7255 65.1756 45.8301 65.1495 45.9608C65.1233 46.8759 65.1233 47.8171 65.0972 48.7322C65.0972 48.8106 65.0972 48.8891 65.0972 48.9675C64.9925 49.0198 64.9141 48.9937 64.8356 48.9937C64.5479 48.9937 64.2864 48.9937 63.9987 48.9675C63.8418 48.9675 63.8156 48.9675 63.8418 48.7845C63.8679 47.8433 63.8941 46.8759 63.8941 45.9346C63.8941 45.8039 63.8679 45.6732 63.8156 45.5425C63.1356 44.0522 62.4556 42.5619 61.7756 41.0716C61.6449 40.7578 61.4879 40.4441 61.3572 40.1303C61.4095 40.078 61.4618 40.1042 61.5141 40.1042C61.9064 40.1042 62.2987 40.1303 62.6649 40.1303C62.7956 40.1303 62.8479 40.1826 62.9002 40.2872C63.4233 41.5422 63.9726 42.7972 64.4956 44.0522C64.5218 44.0783 64.5218 44.1306 64.5741 44.1567C64.6264 44.1045 64.6525 44.0522 64.6787 43.9737C65.2541 42.7972 65.8556 41.5945 66.431 40.4179C66.5095 40.2349 66.6141 40.1826 66.7971 40.2088C67.1895 40.2349 67.5818 40.2349 67.9741 40.2349C68.0002 40.2611 68.0002 40.2872 68.0002 40.2872Z" fill="white"/> +<path d="M49.8744 0.0784365C49.8744 0.104582 49.8483 0.104582 49.8483 0.130728V0.156873C48.8806 0.130728 47.9129 0.104582 46.9452 0.0784365C46.9452 0.052291 46.9452 0.0261455 46.9452 -3.89598e-10C47.939 0.052291 48.9067 0.0784365 49.8744 0.0784365Z" fill="white"/> +<path d="M46.972 0.104492C47.9396 0.130638 48.9073 0.156783 49.875 0.182929C50.8427 0.209074 51.7842 0.339802 52.7258 0.496675C54.1642 0.731984 55.6027 1.07188 57.015 1.46406C57.0411 1.46406 57.0934 1.4902 57.1196 1.51635C57.0673 1.67322 56.9104 1.64708 56.8319 1.69937C55.1319 2.37915 53.4319 3.08508 51.8888 4.05246C51.3135 4.4185 50.7642 4.78454 50.3458 5.33359C50.2412 5.46432 50.1104 5.46432 49.9796 5.43818C49.1689 5.33359 48.3581 5.20287 47.5473 5.09828C46.9981 5.01985 46.4227 4.94141 45.795 4.86297C46.6843 5.67349 47.495 6.40556 48.3319 7.16378C47.9658 7.68669 47.5996 8.18345 47.2858 8.73251C46.1612 10.5888 45.3243 12.5236 44.9058 14.6414C44.3304 17.5958 44.6704 20.4195 46.1873 23.0602C46.2135 23.1125 46.2396 23.1648 46.2396 23.2171C46.2135 23.2433 46.1873 23.2694 46.1873 23.2956C45.2197 22.9034 44.252 22.485 43.2843 22.119C40.2766 20.9425 37.1905 20.0274 34.0259 19.3737C32.2213 19.0077 30.4167 18.7462 28.5859 18.6155C27.069 18.5109 25.5782 18.5371 24.0613 18.6417C23.0936 18.7201 22.1521 18.877 21.2105 19.0861C21.0798 19.1123 20.949 19.1646 20.8182 19.1123C20.8705 18.7462 21.0798 18.4586 21.2367 18.1449C22.7798 15.0597 24.7151 12.2622 27.0167 9.72604C28.8997 7.66054 30.9659 5.8565 33.3197 4.34006C36.1705 2.50988 39.2566 1.22875 42.5781 0.601257C44.0166 0.287511 45.4812 0.104492 46.972 0.104492Z" fill="white"/> +<path d="M8.78805 29.6229C8.70959 29.0739 8.84036 28.6294 9.12805 28.1849C10.6973 25.858 12.7373 24.1062 15.1696 22.7467C17.3926 21.5178 19.7726 20.7596 22.2834 20.3674C23.5649 20.1583 24.8726 20.0798 26.1803 20.0275C28.0372 19.9752 29.8941 20.1583 31.7249 20.3936C34.1833 20.7335 36.6156 21.3087 38.9956 22.0407C40.0679 22.3806 41.114 22.8251 42.1602 23.2434C44.8017 24.2631 47.4171 25.2828 50.0586 26.3025C51.0001 26.6685 51.9678 27.0345 52.9878 27.2176C55.3417 27.6359 57.5909 27.4267 59.657 26.041C59.8662 25.9103 60.0493 25.7796 60.2586 25.6227C60.2586 25.6227 60.2847 25.6227 60.3109 25.6227C60.4155 25.7011 60.3109 25.7795 60.2586 25.8318C59.5001 26.7992 58.4801 27.4267 57.3555 27.8973C56.0217 28.4202 54.6355 28.6294 53.2232 28.6556C50.8694 28.6817 48.594 28.2372 46.3709 27.5574C45.5863 27.3221 44.854 26.93 44.0956 26.6424C41.5587 25.7011 38.9956 24.969 36.3541 24.4461C34.8895 24.1585 33.451 23.9494 31.9602 23.7925C30.3126 23.6095 28.6649 23.531 26.991 23.5572C25.1864 23.5833 23.3818 23.7402 21.6034 24.0278C18.5695 24.5246 15.6403 25.4135 12.868 26.7731C11.7696 27.296 10.7234 27.8973 9.70343 28.551C9.41574 28.734 9.20651 28.9432 9.07574 29.2569C8.94497 29.3615 8.89266 29.4922 8.78805 29.6229Z" fill="white"/> +<path d="M47.4944 48.6012C45.8468 48.575 44.1991 48.5227 42.5514 48.4966C42.6037 45.5683 42.6822 42.64 42.7345 39.6855C44.3822 39.7117 46.0298 39.764 47.6775 39.7901C47.6775 40.2085 47.6514 40.6268 47.6514 41.0713C46.4221 41.0451 45.2191 41.019 43.9898 40.9928C43.9637 41.8033 43.9637 42.6138 43.9375 43.4244C44.9837 43.4505 46.0298 43.4766 47.076 43.5028C47.076 43.9473 47.0498 44.3656 47.0498 44.8101C46.0037 44.7839 44.9575 44.7578 43.9114 44.7316C43.8852 45.5683 43.8852 46.3527 43.8591 47.1893C45.0883 47.2155 46.3175 47.2416 47.5468 47.2677C47.4944 47.7384 47.4944 48.1567 47.4944 48.6012Z" fill="white"/> +<path d="M50.2149 47.3463C51.4702 47.3725 52.6733 47.3986 53.9025 47.4248C53.9548 47.5293 53.9287 47.6339 53.9287 47.7123C53.9287 47.9999 53.9025 48.3137 53.9025 48.6013C53.9025 48.7059 53.8764 48.732 53.7718 48.732C53.7456 48.732 53.7194 48.732 53.6933 48.732C52.1764 48.7059 50.6595 48.6536 49.1425 48.6274C49.0902 48.6274 49.0379 48.6274 48.9595 48.6013C49.0118 45.673 49.0902 42.7447 49.1425 39.8164C49.561 39.8164 49.9533 39.8426 50.3718 39.8426C50.3456 42.3525 50.2933 44.8363 50.2149 47.3463Z" fill="white"/> +<path d="M64.9129 26.3022C64.9129 26.5114 64.7299 26.616 64.6253 26.7729C63.1606 28.5246 61.3822 29.8842 59.3422 30.9039C57.2761 31.9235 55.1053 32.4987 52.8038 32.7079C50.9992 32.8648 49.2207 32.734 47.4684 32.3941C45.4546 32.002 43.4669 31.5313 41.5577 30.8254C40.0408 30.2764 38.6023 29.5966 37.3208 28.6031C36.9023 28.2893 36.5362 27.9494 36.2223 27.5572C36.17 27.4788 36.0916 27.4265 36.0916 27.3219C36.2223 27.2696 36.3008 27.3742 36.3792 27.4265C38.8377 28.6031 41.4008 29.3874 44.0684 29.9103C46.1869 30.3287 48.3576 30.564 50.5284 30.5378C53.9022 30.4855 57.1714 29.8842 60.336 28.6292C61.853 28.0278 63.2914 27.2958 64.6776 26.433C64.756 26.3545 64.8083 26.3022 64.9129 26.3022Z" fill="white"/> +<path d="M58.3758 40.6791C57.7481 42.2217 57.1204 43.7382 56.4665 45.2546C55.9958 46.3789 55.5512 47.5031 55.0804 48.6274C55.0281 48.7581 54.9758 48.8365 54.8189 48.7842C54.7404 48.7581 54.6881 48.7842 54.6096 48.7581C54.7142 48.4966 54.8188 48.2352 54.9235 47.9737C55.9958 45.3853 57.0681 42.7969 58.1404 40.2347C58.1665 40.1562 58.1665 40.0255 58.2973 39.9993C58.4281 39.9732 58.5588 39.9993 58.6111 40.1301C58.7419 40.4961 58.8727 40.836 59.0034 41.202C59.9188 43.6859 60.808 46.1958 61.7234 48.6797C61.7496 48.7581 61.7757 48.8365 61.8019 48.9411C61.6973 48.9934 61.5665 48.9673 61.4619 48.9411C61.3834 48.9411 61.3834 48.8365 61.3573 48.7842C61.1219 48.1567 60.9127 47.5293 60.6773 46.9279C59.945 44.8886 59.1865 42.8492 58.4542 40.8099C58.4542 40.7314 58.4542 40.7053 58.3758 40.6791Z" fill="white"/> +<path d="M27.1739 48.3659C26.9385 48.3659 26.86 48.1567 26.8077 48.0783L26.3108 46.8233C26.3108 46.8233 25.6046 45.0715 25.4216 44.6532C25.0554 44.6793 24.6631 44.6793 24.14 44.6793C23.9046 44.6793 23.6954 44.6793 23.46 44.6532C23.2246 44.6532 23.0154 44.6271 22.78 44.6271C22.6231 44.6271 22.4662 44.6271 22.3093 44.6271H22.2831C22.257 45.4114 22.257 46.1696 22.2308 46.954L22.2047 47.7645C22.2047 47.8429 22.2047 47.8952 22.2047 47.9475C22.1785 48.1306 22.0477 48.2351 21.8647 48.2351C21.6816 48.2351 21.5508 48.1044 21.5247 47.9475C21.5247 47.8952 21.5247 47.843 21.5247 47.8168L21.7077 39.4502C21.7077 39.4241 21.7077 39.398 21.7077 39.3718L21.7339 39.2411L21.8647 39.1626C21.9431 39.1104 22.0216 39.1104 22.1262 39.1104C22.1523 39.1104 22.2308 39.1104 22.2308 39.1104C22.2308 39.1104 23.4077 39.1365 23.8785 39.1365C24.2446 39.1365 24.6369 39.1626 25.0031 39.1626C25.4477 39.1626 25.84 39.2411 26.18 39.398C26.86 39.6856 27.2785 40.1562 27.4877 40.8621C27.7231 41.6465 27.6969 42.4308 27.4092 43.189C27.1739 43.8427 26.7031 44.3133 26.0493 44.5225L27.54 48.209L27.3308 48.3136C27.3308 48.3659 27.2523 48.3659 27.1739 48.3659ZM23.8 43.9996C24.1662 43.9996 24.5323 44.0257 24.8985 44.0257C25.0816 44.0257 25.2908 44.0257 25.5 43.9996C26.1539 43.8688 26.5723 43.5289 26.8077 42.9537C26.9646 42.5354 26.9908 42.1171 26.9646 41.6988C26.9646 41.3327 26.8862 41.0451 26.7292 40.7575C26.4416 40.2085 25.9446 39.9209 25.2908 39.8947C24.8985 39.8686 24.48 39.8686 23.957 39.8424C23.6693 39.8424 23.3816 39.8424 23.0939 39.8163C22.8585 39.8163 22.6493 39.8163 22.4139 39.8163L22.3093 43.9734L23.8 43.9996Z" fill="white"/> +<path d="M25.8133 44.3396C25.8657 44.3135 25.8918 44.3135 25.9441 44.2873C26.5718 44.0782 26.9903 43.686 27.1995 43.0847C27.461 42.3787 27.4872 41.6467 27.2518 40.9407C27.0687 40.3394 26.6764 39.8949 26.101 39.6596C25.761 39.5027 25.3949 39.4504 25.0026 39.4504C24.0872 39.4243 23.1718 39.3981 22.2564 39.3981C22.178 39.3981 22.1257 39.372 22.0472 39.4243C22.0472 39.4504 22.0472 39.4766 22.0472 39.5027C21.9949 42.3003 21.9164 45.0717 21.8641 47.8693C21.8641 47.8954 21.8641 47.9477 21.8641 47.9739C21.8641 48 21.8903 48.0262 21.9426 48.0262C21.9688 48.0262 22.0211 48 22.0211 47.9739C22.0211 47.9216 22.0211 47.8693 22.0211 47.817C22.0472 46.7712 22.0734 45.6992 22.0995 44.6534C22.0995 44.5749 22.0734 44.4965 22.1518 44.4181C22.2303 44.4181 22.3087 44.4181 22.3872 44.4181C23.4334 44.4181 24.4795 44.5227 25.5257 44.4442C25.6303 44.4442 25.6564 44.5227 25.6826 44.5749C25.9703 45.307 26.2841 46.0391 26.5718 46.7712C26.7287 47.1895 26.9118 47.6078 27.0687 48.0262C27.0949 48.1046 27.1472 48.183 27.278 48.1307C26.781 46.8758 26.258 45.6469 25.761 44.4181C25.7872 44.3396 25.8133 44.3396 25.8133 44.3396ZM25.578 44.2351C25.3687 44.2873 25.1334 44.2873 24.9241 44.2873C24.0349 44.2612 23.1195 44.2612 22.2303 44.2351C22.2041 44.2351 22.1518 44.2351 22.0995 44.2351L22.2041 39.5812C22.2303 39.5812 22.2564 39.555 22.2564 39.555C23.2764 39.5812 24.3226 39.5812 25.3426 39.6334C26.0487 39.6596 26.6503 39.9995 26.9903 40.6531C27.1733 40.9669 27.2518 41.3329 27.2518 41.6989C27.278 42.1696 27.2518 42.614 27.0687 43.0585C26.8072 43.7383 26.2841 44.1043 25.578 44.2351Z" fill="white"/> +<path d="M7.63696 47.9477C7.45389 47.9477 7.32312 47.817 7.32312 47.6601C7.32312 47.5817 7.32312 47.5032 7.32312 47.451L7.5062 39.2151C7.5062 39.1628 7.5062 39.1367 7.5062 39.0844C7.53235 38.9014 7.66312 38.7706 7.84619 38.7968C8.05542 38.8229 8.16004 38.9537 8.18619 39.1105C8.18619 39.1628 8.18619 39.2151 8.18619 39.2674L8.10773 43.0062L12.9462 43.1108C12.9723 42.0911 12.9985 41.0453 13.0246 40.0256L13.0508 39.2413C13.0508 39.0582 13.1816 38.9014 13.3646 38.9014C13.4692 38.9014 13.5477 38.9275 13.6262 39.006C13.6785 39.0844 13.7308 39.1628 13.7046 39.2674L13.5216 47.5817C13.5216 47.6601 13.5216 47.7124 13.5216 47.7647C13.4954 47.9477 13.3646 48.0523 13.1816 48.0523C12.9985 48.0523 12.8677 47.9216 12.8416 47.7386C12.8416 47.6863 12.8416 47.634 12.8416 47.5817L12.92 43.8167L8.08158 43.7121C8.05542 44.6795 8.02927 45.6469 8.00312 46.6143L7.97696 47.5032C7.97696 47.5555 7.97696 47.6078 7.97696 47.634C7.95081 47.817 7.82004 47.9477 7.63696 47.9477Z" fill="white"/> +<path d="M13.1557 43.5551C11.3772 43.5028 9.62495 43.4767 7.8465 43.4244C7.79419 43.5028 7.82034 43.5813 7.82034 43.6597C7.79419 44.9147 7.76804 46.1958 7.74188 47.4508C7.74188 47.5031 7.74188 47.5554 7.74188 47.6077C7.74188 47.66 7.71573 47.66 7.66342 47.66C7.63727 47.66 7.58496 47.6338 7.58496 47.6077C7.58496 47.5554 7.58496 47.477 7.58496 47.4247C7.63727 44.8363 7.68958 42.274 7.76804 39.6856C7.76804 39.5287 7.76804 39.3719 7.76804 39.215C7.76804 39.1888 7.76804 39.1365 7.76804 39.1104C7.76804 39.0581 7.82034 39.032 7.8465 39.0581C7.89881 39.0581 7.89881 39.0843 7.89881 39.1365C7.89881 39.1888 7.89881 39.2411 7.89881 39.2934C7.87265 40.5484 7.8465 41.8034 7.82034 43.0322C7.82034 43.1107 7.79419 43.1891 7.82034 43.2675C9.5988 43.3198 11.3511 43.346 13.1295 43.3983C13.1819 43.3198 13.1557 43.2414 13.1557 43.163C13.1819 41.908 13.208 40.6791 13.2342 39.4241C13.2342 39.3719 13.2342 39.3196 13.2342 39.2673C13.2342 39.215 13.2603 39.1888 13.3126 39.1888C13.3911 39.1888 13.3911 39.2411 13.3911 39.2934C13.3911 39.3457 13.3911 39.3719 13.3911 39.4241C13.3388 42.1433 13.2603 44.8886 13.208 47.6077C13.208 47.66 13.208 47.7123 13.208 47.7646C13.208 47.7907 13.1819 47.8169 13.1295 47.8169C13.1034 47.8169 13.0511 47.7907 13.0511 47.7646C13.0511 47.7123 13.0511 47.66 13.0511 47.6077C13.0772 46.3527 13.1034 45.0977 13.1295 43.8427C13.1557 43.7382 13.1819 43.6597 13.1557 43.5551Z" fill="white"/> +<path d="M3.00768 47.9475C2.90306 47.9475 2.79845 47.9475 2.69383 47.9214C2.27537 47.8952 1.93537 47.8168 1.62153 47.7122C0.758458 47.3723 0.20923 46.7187 0.0523074 45.7513C0 45.5422 0 45.333 0 45.1238C0.0261537 44.7839 0.287691 44.7839 0.339998 44.7839H0.366152C0.418459 44.7839 0.653843 44.8362 0.653843 45.1238C0.653843 45.3853 0.679996 45.5944 0.732304 45.8036C0.889226 46.5357 1.35999 47.0063 2.11845 47.1893C2.4323 47.2678 2.71999 47.32 3.03383 47.32C3.39998 47.32 3.79229 47.2678 4.15844 47.1632C5.28305 46.8494 5.46613 45.9343 5.41382 45.2284C5.38766 44.9147 5.3092 44.6532 5.15228 44.4179C4.9169 44.1042 4.60305 43.895 4.10613 43.7643C3.71383 43.6597 3.32152 43.5812 2.95537 43.4767C2.69383 43.4244 2.43229 43.3459 2.19691 43.2936C1.88307 43.2152 1.62153 43.1106 1.38615 42.9799C0.810765 42.6661 0.470767 42.1955 0.339998 41.568C0.235383 41.0451 0.261537 40.5745 0.418459 40.1039C0.627689 39.4764 1.0723 39.0058 1.7523 38.7705C2.22307 38.5874 2.69383 38.5613 3.26921 38.5352C3.68767 38.5613 4.13229 38.6136 4.55075 38.7705C5.38766 39.0842 5.88459 39.6856 6.06766 40.6007C6.09381 40.7575 6.11997 40.8883 6.11997 41.0451L6.14612 41.1759C6.14612 41.2281 6.14612 41.3066 6.14612 41.3589C6.14612 41.6988 5.85843 41.7249 5.80612 41.7249C5.67536 41.7249 5.59689 41.6726 5.54459 41.6203C5.43997 41.5157 5.46613 41.4112 5.46613 41.3589C5.46613 41.1497 5.43997 40.9144 5.41382 40.7052C5.28305 39.9993 4.89074 39.5548 4.2369 39.3718C3.8969 39.2672 3.5569 39.2149 3.24306 39.2149C2.79845 39.2149 2.37999 39.2934 1.96153 39.4503C1.43845 39.6594 1.12461 40.0516 1.04615 40.6529C0.993841 40.9667 1.01999 41.2543 1.0723 41.5419C1.20307 42.0387 1.54307 42.3785 2.0923 42.5877C2.30153 42.6661 2.53691 42.7184 2.79845 42.7707C2.90306 42.7969 3.00768 42.823 3.11229 42.8492C3.26921 42.8753 3.42614 42.9276 3.58306 42.9537C3.87075 43.0322 4.15844 43.0845 4.44613 43.1629C5.12613 43.3459 5.59689 43.712 5.91074 44.2349C6.06766 44.4963 6.14612 44.7839 6.17228 45.0715C6.19843 45.4376 6.22458 45.9605 6.01535 46.4834C5.75382 47.1109 5.3092 47.5292 4.62921 47.7645C4.02767 47.8952 3.5569 47.9737 3.00768 47.9475Z" fill="white"/> +<path d="M3.19118 38.8228C3.58348 38.8489 3.97579 38.875 4.3681 39.0319C5.12655 39.3195 5.54501 39.8686 5.70194 40.6529C5.72809 40.836 5.75424 41.019 5.75424 41.202C5.75424 41.2543 5.75424 41.3066 5.75424 41.3589C5.75424 41.4112 5.7804 41.4896 5.67578 41.4896C5.59732 41.4896 5.59732 41.4112 5.59732 41.3589C5.59732 41.1236 5.57117 40.8882 5.51886 40.6529C5.36194 39.8686 4.91732 39.3457 4.15887 39.1104C3.3481 38.875 2.51118 38.875 1.70042 39.1888C1.07273 39.4241 0.706576 39.9209 0.601961 40.5745C0.549654 40.9144 0.549654 41.2281 0.654269 41.568C0.811191 42.1955 1.22965 42.5877 1.83119 42.7969C2.17118 42.9276 2.51118 42.9799 2.87733 43.0583C3.32195 43.1629 3.76656 43.2675 4.21117 43.3721C4.7604 43.5289 5.23117 43.8165 5.51886 44.3133C5.64963 44.5486 5.72809 44.7839 5.75424 45.0454C5.7804 45.4899 5.7804 45.9082 5.62347 46.3265C5.38809 46.9017 4.96963 47.2678 4.39425 47.4769C3.84502 47.6599 3.29579 47.7122 2.72041 47.6599C2.38041 47.6338 2.04042 47.5815 1.70042 47.4508C0.889652 47.137 0.445039 46.5357 0.288117 45.699C0.261963 45.5421 0.261963 45.333 0.261963 45.1238C0.261963 45.0715 0.261963 45.0192 0.340424 45.0192C0.392731 45.0192 0.392731 45.0715 0.392731 45.1238C0.392731 45.3591 0.418885 45.5944 0.471193 45.8297C0.654269 46.6926 1.2035 47.2155 2.04042 47.4246C2.77272 47.6076 3.47887 47.6076 4.21117 47.3985C5.30963 47.0847 5.72809 46.2219 5.64963 45.2023C5.62347 44.8624 5.54501 44.5486 5.33578 44.261C5.04809 43.8427 4.62963 43.6335 4.13271 43.5028C3.50502 43.3459 2.85118 43.1891 2.19734 43.0322C1.9358 42.9799 1.67426 42.8753 1.43888 42.7446C0.941959 42.457 0.628115 42.0648 0.5235 41.5157C0.445039 41.0713 0.445039 40.6268 0.575807 40.1823C0.758883 39.6071 1.17734 39.2149 1.75272 39.0058C2.22349 38.875 2.69426 38.8228 3.19118 38.8228Z" fill="white"/> +<path d="M33.9471 48.5228C33.764 48.5228 33.6594 48.3659 33.6071 48.3137L33.1101 47.6077L30.4425 43.8166L30.2071 44.0519C29.9194 44.3395 29.6578 44.6533 29.3702 44.9409C29.344 44.967 29.344 44.9932 29.344 45.0455C29.3178 45.7775 29.3178 46.5358 29.2917 47.2678L29.2655 47.9476C29.2655 47.9999 29.2655 48.0522 29.2655 48.1045C29.2655 48.2875 29.1086 48.3921 28.9517 48.4182C28.7686 48.4182 28.6378 48.2875 28.6117 48.1045C28.6117 48.0522 28.6117 47.9999 28.6117 47.9738L28.7948 39.7641C28.7948 39.7118 28.7948 39.6334 28.7948 39.5811C28.8209 39.398 28.9517 39.2935 29.1348 39.2935C29.3178 39.2935 29.4486 39.4242 29.4486 39.6072C29.4486 39.6595 29.4486 39.7118 29.4486 39.7641L29.344 43.9996C30.1025 43.1891 30.8871 42.3525 31.6455 41.542L33.5024 39.5549C33.5547 39.5026 33.6594 39.3719 33.8424 39.3719C33.9209 39.3719 33.9994 39.398 34.0778 39.4503L34.3394 39.6333L30.8871 43.3199L34.3917 48.3137L34.1563 48.4705C34.104 48.4967 34.0255 48.5228 33.9471 48.5228Z" fill="white"/> +<path d="M33.9464 39.6856C32.8218 40.8883 31.6972 42.091 30.5726 43.2937C31.7233 44.9409 32.8741 46.5881 34.051 48.2352C33.9464 48.3137 33.8941 48.2352 33.8418 48.1829C33.6849 47.9476 33.5018 47.7123 33.3449 47.477C32.4295 46.1959 31.5141 44.8886 30.6249 43.6075C30.5987 43.5552 30.5464 43.5029 30.5203 43.4767C30.468 43.4767 30.4418 43.5029 30.4157 43.529C30.0234 43.9474 29.631 44.3918 29.2387 44.8102C29.1603 44.8886 29.1341 44.967 29.1341 45.0978C29.108 46.0651 29.0818 47.0064 29.0818 47.9738C29.0818 48.0261 29.0818 48.0783 29.0818 48.1306C29.0818 48.1829 29.0557 48.1829 29.0034 48.1829C28.9511 48.1829 28.951 48.1568 28.951 48.1306C28.951 48.0783 28.951 48.0261 28.951 47.9738C29.0034 45.2546 29.0818 42.5093 29.1341 39.7902C29.1341 39.7379 29.1341 39.6856 29.1341 39.6333C29.1341 39.6072 29.1603 39.5811 29.2126 39.5811C29.2649 39.5811 29.2649 39.6072 29.2649 39.6333C29.2649 39.6856 29.2649 39.7379 29.2649 39.7902C29.2387 41.3328 29.1864 42.8754 29.1603 44.418C29.1603 44.4964 29.1603 44.5748 29.1603 44.6794C29.3172 44.5748 29.4218 44.418 29.5264 44.3134C30.5987 43.1891 31.6449 42.0387 32.7172 40.9145C33.0833 40.5223 33.4233 40.1563 33.7895 39.7641C33.7633 39.6595 33.8156 39.5811 33.9464 39.6856Z" fill="white"/> +<path d="M14.2026 48.0786C14.1503 48.0786 14.098 48.0524 14.0457 48.0524L13.8364 47.974L13.8887 47.7387C13.941 47.5557 14.0195 47.3988 14.0718 47.2419C14.098 47.1896 14.1241 47.1373 14.1241 47.085C15.1964 44.4966 16.2687 41.9344 17.3149 39.3721C17.3933 39.0845 17.5764 39.0322 17.7072 39.0322C17.9164 39.0322 18.0472 39.163 18.0995 39.3721V39.3983C19.041 41.9605 19.9564 44.5489 20.8979 47.1112L21.081 47.5818C21.1072 47.6341 21.1333 47.7125 21.1595 47.7648L21.2641 48.0786L21.0549 48.1832C20.9764 48.2093 20.9241 48.2354 20.8456 48.2354C20.6887 48.2354 20.5841 48.1309 20.5056 47.9478C20.401 47.6864 20.3225 47.4249 20.2179 47.1635L20.061 46.6929L17.7072 40.1826L14.5687 47.791C14.4903 48.0001 14.3595 48.0786 14.2026 48.0786Z" fill="white"/> +<path d="M14.1241 47.7907C14.1765 47.5816 14.2811 47.3724 14.3595 47.1894C15.4318 44.601 16.5041 42.0387 17.5503 39.4765C17.5764 39.398 17.5764 39.2935 17.7072 39.2935C17.838 39.2935 17.8118 39.4242 17.8641 39.5026C18.858 42.2218 19.8518 44.967 20.8456 47.6862C20.8718 47.7646 20.898 47.8692 20.9503 47.9738C20.8195 48.0261 20.7933 47.9738 20.7672 47.8692C20.6103 47.4509 20.4533 47.0325 20.3226 46.6403C19.6949 44.8625 19.041 43.1107 18.4134 41.3328C18.2041 40.7576 17.9949 40.1824 17.7857 39.6072C17.7857 39.5811 17.7857 39.5549 17.7334 39.5288C17.6549 39.7118 17.5764 39.921 17.498 40.104C16.4518 42.6401 15.4057 45.1762 14.3595 47.6862C14.2811 47.7646 14.2811 47.8692 14.1241 47.7907Z" fill="white"/> +<path d="M46.214 23.2173C46.2401 23.2434 46.2663 23.2696 46.2401 23.2957C46.214 23.3219 46.1878 23.2957 46.1355 23.2696C46.1878 23.2434 46.214 23.2173 46.214 23.2173Z" fill="white"/> +<path d="M64.9136 26.3023C64.9136 26.2761 64.9397 26.2761 64.9397 26.25C64.9397 26.2761 64.9659 26.2761 64.9659 26.3023C64.9397 26.3023 64.9136 26.3023 64.9136 26.3023Z" fill="white"/> +<path d="M20.7912 19.1123C20.8174 19.1385 20.7912 19.1646 20.765 19.1646C20.765 19.1646 20.7389 19.1646 20.7389 19.1384C20.765 19.1384 20.7912 19.1123 20.7912 19.1123Z" fill="white"/> +<path d="M39.6746 45.0976C39.7269 45.0714 39.7531 45.0453 39.7792 45.0453C40.2761 44.81 40.6161 44.4178 40.7992 43.8949C41.113 43.0844 41.1392 42.2216 40.9561 41.3849C40.7207 40.2345 39.9884 39.6332 38.8115 39.5809C37.7654 39.5286 36.7454 39.5286 35.6992 39.5024C35.6731 39.5024 35.6469 39.5024 35.6208 39.5286C35.5946 39.5809 35.6208 39.6593 35.6208 39.7116C35.5685 42.483 35.49 45.2806 35.4377 48.052C35.4377 48.0782 35.4377 48.1043 35.4377 48.1305C35.4115 48.2612 35.4638 48.2873 35.5946 48.2873C35.9085 48.2873 36.2223 48.2873 36.5361 48.3135C36.5885 48.3135 36.6408 48.3396 36.7192 48.2612L36.7977 45.176C37.2684 45.176 37.7392 45.2022 38.1838 45.2022C38.3669 45.2022 38.3669 45.2022 38.4454 45.3852C38.8115 46.3264 39.1515 47.2677 39.5177 48.2089C39.5438 48.2873 39.57 48.3658 39.7007 48.3658C40.1454 48.3658 40.5638 48.3919 41.0346 48.3919C40.5638 47.3199 40.1192 46.2218 39.6746 45.0976ZM39.5961 43.2935C39.4392 43.7119 39.1254 43.9472 38.6546 43.9472C38.0531 43.9472 37.4254 43.921 36.7977 43.921L36.8761 40.8882C36.9285 40.8359 36.9808 40.862 37.0331 40.862C37.53 40.862 38.0269 40.8882 38.55 40.8882C38.6807 40.8882 38.8377 40.9143 38.9684 40.9404C39.3084 41.0189 39.5177 41.228 39.6484 41.5679C39.8054 42.1431 39.8054 42.7445 39.5961 43.2935Z" fill="white"/> +</g> +<defs> +<clipPath id="clip0"> +<rect width="69" height="49" fill="white"/> +</clipPath> +</defs> +</svg> diff --git a/packages/website/public/images/@next/clients/starbitex.svg b/packages/website/public/images/@next/clients/starbitex.svg new file mode 100644 index 000000000..eee21b3fc --- /dev/null +++ b/packages/website/public/images/@next/clients/starbitex.svg @@ -0,0 +1,22 @@ +<svg width="64" height="50" viewBox="0 0 64 50" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M28.6823 41.0316C28.7604 40.9785 28.8125 40.9785 28.8646 40.9785C29.7499 40.9785 30.6352 40.9785 31.5205 41.0051C32.0153 41.0316 32.51 41.1113 32.9526 41.3237C33.6557 41.6423 33.9682 42.2265 33.9161 42.9966C33.89 43.6338 33.6297 44.1649 33.0828 44.5101C33.0568 44.5366 33.0047 44.5632 32.9787 44.6163C33.0568 44.7225 33.161 44.7756 33.2651 44.8022C33.9421 45.0943 34.2806 45.5988 34.3327 46.3157C34.4369 47.6434 33.6557 48.3603 32.5621 48.679C32.1194 48.7852 31.6767 48.8383 31.2341 48.8117C30.479 48.8117 29.7499 48.8117 28.9948 48.8117C28.8906 48.8117 28.7864 48.8383 28.6563 48.7586C28.6823 46.2095 28.6823 43.6338 28.6823 41.0316ZM30.1665 46.4485C30.1665 46.714 30.1665 47.0061 30.1665 47.2716C30.1665 47.5637 30.1925 47.5903 30.505 47.5903C30.8175 47.5903 31.1039 47.5903 31.4164 47.5903C31.7028 47.5903 31.9632 47.5372 32.2236 47.431C32.6402 47.2451 32.8485 46.8733 32.8485 46.3954C32.8225 45.944 32.6141 45.6784 32.1975 45.5191C31.5986 45.2801 30.9737 45.4129 30.3748 45.3863C30.2446 45.3863 30.1925 45.466 30.1925 45.6253C30.1665 45.8909 30.1665 46.1564 30.1665 46.4485ZM31.0258 42.2C30.7654 42.2 30.5831 42.2 30.4008 42.2C30.2446 42.2 30.1665 42.2796 30.1925 42.4389C30.1925 42.9435 30.1925 43.4214 30.1925 43.9259C30.1925 44.1118 30.2707 44.1915 30.4529 44.1915C30.7914 44.1915 31.1039 44.1915 31.4164 44.1649C31.6507 44.1649 31.833 44.0852 32.0152 43.979C32.3798 43.7666 32.4839 43.448 32.4579 43.0497C32.4319 42.7045 32.2496 42.4655 31.9371 42.3327C31.5986 42.2 31.2862 42.2265 31.0258 42.2Z" fill="white"/> +<path d="M19.229 41.0315C19.3331 40.9518 19.4113 40.9784 19.4894 40.9784C20.2966 40.9784 21.0777 40.9784 21.8849 40.9784C22.5099 40.9784 23.1088 41.058 23.6816 41.3767C24.3326 41.7219 24.6711 42.306 24.7232 43.023C24.7752 43.5275 24.7492 44.0054 24.5149 44.4568C24.3065 44.8817 24.0201 45.2003 23.6035 45.4393C23.3171 45.5986 23.291 45.6252 23.4733 45.9438C23.968 46.8201 24.4367 47.6698 24.9315 48.546C24.9836 48.6257 25.0096 48.6788 25.0096 48.785C24.8534 48.8647 24.6971 48.8381 24.5409 48.8381C24.2545 48.8381 23.942 48.8381 23.6556 48.8381C23.4473 48.8381 23.3171 48.785 23.2129 48.5726C22.7963 47.7494 22.3536 46.9529 21.911 46.1297C21.8329 45.9704 21.7287 45.8907 21.5464 45.8907C21.3642 45.8907 21.1819 45.8907 20.9996 45.8907C20.7392 45.8907 20.7132 45.9438 20.7132 46.2094C20.7132 46.9263 20.7132 47.6698 20.7132 48.3867C20.7132 48.5195 20.7392 48.6523 20.6611 48.8116C20.1924 48.8116 19.7237 48.8116 19.229 48.8116C19.1769 48.5726 19.1509 41.4829 19.229 41.0315ZM20.6872 43.3947C20.6872 43.7133 20.6872 44.0054 20.6872 44.3241C20.6872 44.5365 20.7653 44.6162 20.9736 44.6162C21.4162 44.6162 21.8849 44.6162 22.3276 44.5365C22.588 44.4834 22.8223 44.3772 22.9786 44.1382C23.5514 43.4213 23.1869 42.4388 22.3016 42.2795C21.8589 42.1998 21.4423 42.1998 20.9996 42.1998C20.7913 42.1998 20.7132 42.2795 20.7132 42.4919C20.7132 42.8105 20.7132 43.1026 20.6872 43.3947Z" fill="white"/> +<path d="M51.1289 48.7853C51.1289 46.1831 51.1289 43.6074 51.1289 41.0583C51.2331 40.9787 51.3372 41.0052 51.4153 41.0052C52.7693 41.0052 54.0973 41.0052 55.4513 41.0052C55.8419 41.0052 55.8419 41.0052 55.8419 41.4035C55.8419 41.6159 55.8419 41.8284 55.8419 42.0143C55.8419 42.2798 55.8159 42.3063 55.5034 42.3063C54.8264 42.3063 54.1494 42.3063 53.4724 42.3063C53.2901 42.3063 53.0818 42.3063 52.8995 42.3063C52.7173 42.3063 52.6392 42.386 52.6392 42.5719C52.6392 42.9702 52.6392 43.3685 52.6392 43.7668C52.6392 44.0323 52.6912 44.0854 52.9777 44.0854C53.6547 44.0854 54.3317 44.0854 55.0087 44.0854C55.3472 44.0854 55.3472 44.0854 55.3472 44.4306C55.3472 44.643 55.3472 44.8554 55.3472 45.0944C55.3472 45.36 55.3211 45.3865 55.0608 45.3865C54.4098 45.3865 53.7849 45.3865 53.1339 45.3865C53.0558 45.3865 53.0037 45.3865 52.9256 45.3865C52.7433 45.3865 52.6392 45.4662 52.6392 45.652C52.6392 46.1565 52.6392 46.6876 52.6392 47.1921C52.6392 47.4046 52.6912 47.4577 52.9777 47.4577C53.7849 47.4577 54.566 47.4577 55.3732 47.4577C55.4513 47.4577 55.5295 47.4577 55.6076 47.4577C55.894 47.4577 55.92 47.5108 55.92 47.7763C55.92 48.0418 55.92 48.3074 55.92 48.5729C55.92 48.7057 55.868 48.7853 55.7117 48.7853C55.6596 48.7853 55.6076 48.7853 55.5555 48.7853C54.1754 48.7853 52.7954 48.7853 51.3893 48.7853C51.3372 48.8384 51.2331 48.8384 51.1289 48.7853Z" fill="white"/> +<path d="M11.5742 48.8383C11.7044 48.3869 11.8346 48.0151 11.9388 47.6168C12.2773 46.5281 12.6158 45.466 12.9543 44.3773C13.2928 43.3418 13.6052 42.2796 13.9437 41.244C13.9958 41.0847 14.1 40.9785 14.2822 40.9785C14.6989 40.9785 15.1415 40.9785 15.5581 40.9785C15.7404 40.9785 15.8446 41.0582 15.9227 41.2175C16.2352 42.2531 16.5737 43.2886 16.8861 44.3242C17.1726 45.2536 17.459 46.1829 17.7714 47.1123C17.9277 47.5903 18.0839 48.0682 18.2141 48.5462C18.2401 48.6259 18.2662 48.7055 18.2141 48.8117C17.7714 48.8117 17.3027 48.8117 16.834 48.8117C16.7039 48.8117 16.6518 48.7321 16.6257 48.6258C16.4955 48.1213 16.3393 47.6434 16.2352 47.1389C16.1831 46.9264 16.0789 46.8202 15.8706 46.8202C15.2196 46.8202 14.5947 46.8202 13.9437 46.8202C13.7354 46.8202 13.6573 46.8999 13.6052 47.1123C13.5011 47.5903 13.3449 48.0417 13.2407 48.4931C13.1626 48.7852 13.1365 48.8117 12.8241 48.8383C12.4335 48.8383 12.0429 48.8383 11.5742 48.8383ZM14.9332 42.2796C14.803 42.439 14.7509 42.5983 14.7249 42.731C14.6468 43.0762 14.5687 43.3949 14.4645 43.7401C14.3083 44.2446 14.1781 44.7756 14.0479 45.3067C13.9698 45.5722 14.0219 45.6519 14.3083 45.6519C14.6989 45.6519 15.0895 45.6519 15.48 45.6519C15.7925 45.6519 15.8185 45.5988 15.7144 45.3067C15.5581 44.696 15.4019 44.0852 15.2196 43.5011C15.1415 43.0762 15.0634 42.6779 14.9332 42.2796Z" fill="white"/> +<path d="M5.22159 41.8547C5.03932 42.1468 4.80497 42.3858 4.6227 42.6513C4.4925 42.8106 4.38835 42.7841 4.25816 42.6779C3.99777 42.4654 3.6853 42.3327 3.37284 42.253C2.98226 42.1468 2.59167 42.1468 2.22713 42.3327C1.70636 42.5716 1.6022 43.1293 2.01882 43.5276C2.25317 43.7665 2.56564 43.8462 2.85206 43.979C3.3468 44.1914 3.8155 44.3773 4.31023 44.6428C5.11743 45.0676 5.56009 45.7315 5.53405 46.6609C5.50802 47.6168 5.01328 48.2806 4.18004 48.6789C3.13849 49.1569 2.0709 49.0772 1.05539 48.5992C0.716884 48.4399 0.430457 48.254 0.144031 48.0151C-0.0382406 47.8557 -0.0382406 47.8026 0.0919532 47.6168C0.300263 47.3512 0.534612 47.0857 0.768961 46.7936C0.951232 46.7936 1.02935 46.9264 1.15954 47.006C1.75843 47.4309 2.38336 47.6699 3.11245 47.5637C3.6853 47.484 3.99777 47.1122 3.97173 46.6343C3.94569 46.2891 3.73738 46.0767 3.47699 45.9439C3.06037 45.7315 2.61771 45.5456 2.17505 45.3597C1.75843 45.1739 1.36785 44.9614 1.00331 44.6959C-0.0642794 43.9524 -0.0642794 42.1733 1.10746 41.3767C1.96674 40.7926 2.90414 40.7129 3.89361 41.0316C4.38835 41.1909 4.85705 41.4299 5.22159 41.8547Z" fill="white"/> +<path d="M63.0006 48.8115C62.584 48.8646 62.1934 48.8115 61.8289 48.8381C61.4383 48.8912 61.256 48.7319 61.0998 48.3867C60.7613 47.6432 60.3707 46.9262 60.0582 46.2093C60.0062 46.1031 59.9541 46.0234 59.876 45.8907C59.6416 46.1827 59.5635 46.5279 59.4073 46.8466C59.1208 47.4307 58.8344 48.0415 58.574 48.6522C58.5219 48.785 58.4438 48.8646 58.2876 48.8646C57.8449 48.8646 57.4023 48.8646 56.9596 48.8646C56.9336 48.8646 56.9075 48.8381 56.8555 48.8115C57.1159 48.2804 57.4023 47.7759 57.6627 47.2714C58.0272 46.5545 58.4178 45.8641 58.8084 45.1737C58.9386 44.9347 58.9386 44.7489 58.8084 44.5099C58.2616 43.5009 57.7147 42.4653 57.1679 41.4297C57.1159 41.3235 57.0638 41.2173 57.0638 41.1111C57.1159 41.0049 57.22 41.0314 57.2981 41.0314C57.6366 41.0314 58.0012 41.058 58.3397 41.0314C58.574 41.0049 58.7042 41.1111 58.8084 41.3235C59.1208 42.0404 59.4593 42.7308 59.7978 43.4212C59.8499 43.554 59.928 43.6602 59.9801 43.7929C60.1103 43.7133 60.1624 43.6071 60.2145 43.5009C60.5269 42.7574 60.8654 42.0139 61.1779 41.2704C61.256 41.1111 61.3602 41.0049 61.5685 41.0314C61.9851 41.058 62.4017 41.0314 62.8183 41.0314C62.8444 41.1907 62.7663 41.2969 62.7142 41.4031C62.1674 42.4653 61.6206 43.5009 61.0477 44.563C60.9175 44.802 60.8915 45.0144 61.0477 45.2534C61.6726 46.3421 62.2455 47.4573 62.8444 48.546C62.8965 48.5725 62.9225 48.6522 63.0006 48.8115Z" fill="white"/> +<path d="M40.6345 48.8381C40.5564 48.6522 40.5824 48.5195 40.5824 48.4132C40.5824 46.5545 40.5824 44.7223 40.5824 42.8636C40.5824 42.7839 40.5824 42.7043 40.5824 42.6246C40.6085 42.4122 40.5043 42.3325 40.3221 42.3325C39.8273 42.3325 39.3326 42.3325 38.8378 42.3325C38.4473 42.3325 38.4473 42.3325 38.4473 41.9342C38.4473 41.7218 38.4473 41.5094 38.4473 41.3235C38.4473 41.0314 38.4733 41.0314 38.7597 41.0049C38.916 41.0049 39.0982 41.0049 39.2545 41.0049C40.8168 41.0049 42.3791 41.0049 43.9414 41.0049C44.306 41.0049 44.332 41.0049 44.332 41.3766C44.332 41.5891 44.332 41.8015 44.332 42.0405C44.332 42.306 44.306 42.3325 44.0456 42.3325C43.5509 42.3325 43.0561 42.3325 42.5614 42.3325C42.1708 42.3325 42.1708 42.3325 42.1708 42.7308C42.1708 44.6161 42.1708 46.5014 42.1708 48.3867C42.1708 48.4664 42.1708 48.546 42.1708 48.6257C42.1708 48.7584 42.1187 48.8381 41.9885 48.8381C41.5198 48.8381 41.0772 48.8381 40.6345 48.8381Z" fill="white"/> +<path d="M8.16577 48.8381C8.08766 48.6522 8.11369 48.5195 8.11369 48.4132C8.11369 46.5545 8.11369 44.7223 8.11369 42.8636C8.11369 42.7839 8.11369 42.7043 8.11369 42.6246C8.13973 42.4122 8.03558 42.3325 7.85331 42.3325C7.35857 42.3325 6.86383 42.3325 6.3691 42.3325C5.97852 42.3325 5.97852 42.3325 5.97852 41.9342C5.97852 41.7218 5.97852 41.5094 5.97852 41.3235C5.97852 41.0314 6.00455 41.0314 6.29098 41.0049C6.44721 41.0049 6.62948 41.0049 6.78572 41.0049C8.34804 41.0049 9.91037 41.0049 11.4727 41.0049C11.8372 41.0049 11.8633 41.0049 11.8633 41.3766C11.8633 41.5891 11.8633 41.8015 11.8633 42.0405C11.8633 42.306 11.8372 42.3325 11.5768 42.3325C11.0821 42.3325 10.5874 42.3325 10.0926 42.3325C9.70206 42.3325 9.70206 42.3325 9.70206 42.7308C9.70206 44.6161 9.70206 46.5014 9.70206 48.3867C9.70206 48.4664 9.70206 48.546 9.70206 48.6257C9.70206 48.7584 9.64998 48.8381 9.51979 48.8381C9.05109 48.8381 8.60843 48.8381 8.16577 48.8381Z" fill="white"/> +<path d="M37.173 48.8115C36.7043 48.8115 36.2356 48.8115 35.7148 48.8115C35.7148 46.2093 35.7148 43.6336 35.7148 41.0049C36.1835 41.0049 36.6262 41.0049 37.0689 41.0049C37.173 41.0049 37.1991 41.0845 37.2251 41.1642C37.2251 41.2704 37.2251 41.3766 37.2251 41.4828C37.2251 43.793 37.2251 46.1297 37.2251 48.4398C37.2251 48.546 37.2511 48.6522 37.173 48.8115Z" fill="white"/> +<path d="M45.2448 42.5451C45.2708 41.1643 46.3905 40.1287 47.7705 40.2615C48.9162 40.3677 49.9057 41.3502 49.8276 42.7575C49.7495 44.3772 48.5257 45.1207 47.406 45.0676C46.1041 44.988 45.1667 43.8727 45.2448 42.5451ZM49.2027 42.2795C49.2547 42.0937 49.1506 41.9343 49.0725 41.8016C48.8381 41.2705 48.4475 40.9253 47.8747 40.8722C47.6664 40.8191 47.4841 40.8191 47.2758 40.8722C47.1977 40.8456 47.1196 40.8722 47.0415 40.8988C46.4165 41.1112 46.052 41.536 45.8957 42.1733C45.6874 43.1292 46.052 44.2976 47.2758 44.5366C48.083 44.6693 49.0985 44.1914 49.2027 43.0761C49.2287 42.784 49.2287 42.5185 49.2027 42.2795Z" fill="white"/> +<path d="M48.576 42.2C48.576 42.1204 48.576 42.0673 48.5499 41.9876C48.3676 41.6955 48.1593 41.5097 47.7948 41.4831C47.5084 41.4565 47.2219 41.4565 46.9095 41.4565C46.6491 41.4565 46.623 41.4831 46.623 41.7486C46.623 42.3328 46.623 42.9435 46.623 43.5277C46.623 43.7932 46.6491 43.8198 46.9095 43.8198C47.1699 43.8198 47.1959 43.7932 47.2219 43.5277C47.2219 43.448 47.2219 43.3684 47.2219 43.2887C47.2219 43.1825 47.248 43.0763 47.3782 43.0497C47.5084 43.0232 47.6125 43.0763 47.6646 43.1825C47.7427 43.2887 47.7688 43.3949 47.8469 43.5277C48.0291 43.8994 48.1593 43.926 48.5499 43.7667C48.5239 43.5277 48.3676 43.3684 48.2895 43.156C48.2374 43.0497 48.1333 42.917 48.3156 42.8108C48.3416 42.7577 48.3937 42.7046 48.4458 42.678H48.4718C48.4718 42.5983 48.5239 42.5452 48.576 42.5187C48.576 42.4656 48.576 42.439 48.602 42.3859C48.5499 42.3062 48.5499 42.2531 48.576 42.2ZM47.7948 42.4656C47.6646 42.6514 47.4563 42.6514 47.274 42.5718C47.3261 42.3859 47.3261 42.2 47.274 42.0142C47.3782 41.9345 47.4823 41.9611 47.5865 41.9876C47.6646 41.9611 47.6906 41.9876 47.7167 42.0407C47.8729 42.1469 47.925 42.3062 47.7948 42.4656Z" fill="white"/> +<path d="M48.4453 42.6513C48.4453 42.5716 48.4974 42.5185 48.5495 42.4919Z" fill="white"/> +<path d="M45.4291 23.2415H32.5582C31.196 21.8744 29.6928 20.6487 28.2836 19.3287C25.7 16.9244 23.1164 14.5672 20.4859 12.1629C20.251 11.9272 20.0161 11.6915 19.7813 11.4558H33.0749C33.4507 11.8329 33.8735 12.163 34.2023 12.493C37.6784 15.8401 41.1545 19.1401 44.6306 22.4872C44.9594 22.723 45.1943 23.0058 45.4291 23.2415Z" fill="white"/> +<path d="M46.0399 24.1843C45.9929 24.2786 45.9459 24.3729 45.852 24.5143C44.8655 25.74 43.926 26.9657 42.9396 28.1915C41.4364 30.0772 39.9332 31.9158 38.477 33.8015C38.0542 34.3672 37.5375 34.5558 36.8799 34.5558C32.981 34.5558 29.0352 34.5558 25.1364 34.5086C24.9015 34.5086 24.5727 34.5557 24.3848 34.4615L29.0822 28.8043L29.1761 28.6629C29.411 28.38 29.6459 28.0972 29.8807 27.8615C29.9747 27.7672 30.0217 27.6729 30.0686 27.5786L30.7732 26.73C30.9142 26.6829 31.0551 26.5886 31.196 26.4472C31.8537 25.6929 32.5113 25.0329 33.028 24.1843H46.0399Z" fill="white"/> +<path d="M40.1691 0.471334C40.1691 0.518477 40.1691 0.565614 40.1691 0.612757C40.1691 0.659899 40.1222 0.754197 40.1222 0.80134C40.1222 0.848482 40.0752 0.848488 40.0752 0.895631C40.0752 0.942774 40.0282 0.989894 40.0282 0.989894C39.9812 1.08418 39.8873 1.17848 39.8403 1.27277C39.6524 1.55563 33.4988 9.5699 32.7942 10.5128H19.2656C19.3596 10.3242 19.5005 10.1828 19.6414 10.0413C20.44 9.00419 21.2855 8.06134 22.0841 7.07134C23.7282 5.04419 25.4192 3.01704 27.0164 0.989894C27.4391 0.471322 27.9558 0.188488 28.6135 0.188488C32.1365 0.188488 35.6126 0.188488 39.1357 0.188488C39.5115 0.188488 39.8403 0.188477 40.1691 0.471334Z" fill="white"/> +<path d="M29.8352 26.3999L23.6816 33.8013C22.0375 32.1042 20.3934 30.4542 18.7493 28.7099C18.0447 27.9556 18.0447 27.9084 18.7024 27.1541C20.2525 25.3156 21.8496 23.4299 23.3998 21.5913C24.1514 20.6956 24.2453 20.6956 25.0439 21.497C26.688 23.147 28.2381 24.7499 29.8352 26.3999Z" fill="white"/> +<path d="M30.0683 27.5786C30.0213 27.6729 29.9743 27.7672 29.8804 27.8615C29.6455 28.1443 29.4107 28.38 29.1758 28.6629L30.0683 27.5786Z" fill="white"/> +<path d="M45.8993 6.93004C44.5841 8.67433 43.3158 10.3715 42.0944 12.1629C41.7656 12.6343 41.4838 12.6815 41.061 12.3043C39.4639 10.7486 37.7728 9.28719 36.2227 7.63719L41.2489 0.895763C42.7521 2.45148 44.2552 4.00719 45.7584 5.51576C46.2751 5.98719 46.3221 6.36433 45.8993 6.93004Z" fill="white"/> +<path d="M52.8997 5.98715C52.0072 5.84572 51.6784 4.99715 50.8798 5.04429C50.1752 5.09143 49.7994 5.89286 49.0479 5.98715C48.9539 5.46858 49.0479 5.0443 49.2358 4.66715C49.5646 4.00715 49.2827 3.58286 48.766 3.15858C48.4372 2.87572 47.8735 2.73429 47.9675 2.12143C48.2963 1.79143 48.719 1.93285 49.0948 1.93285C49.8464 1.97999 50.2692 1.65001 50.4101 0.895726C50.5041 0.518583 50.5041 0.0942857 51.0677 0C51.5845 0.471429 51.3496 1.41428 52.0072 1.79142C52.6179 2.16857 53.4164 1.69714 54.0271 2.12143C54.0271 2.78143 53.4634 2.87572 53.1346 3.15858C52.6179 3.58286 52.336 4.00715 52.6649 4.66715C52.8528 4.99716 52.9467 5.46858 52.8997 5.98715Z" fill="white"/> +<path d="M39.1818 2.1214L40.0274 1.03712C39.9804 1.1314 39.8865 1.22568 39.8395 1.31996C39.6046 1.64996 39.3697 1.93282 39.0879 2.26282L39.1818 2.1214Z" fill="white"/> +</svg> diff --git a/packages/website/public/images/@next/clients/tokenjar.svg b/packages/website/public/images/@next/clients/tokenjar.svg new file mode 100644 index 000000000..f36a6c6aa --- /dev/null +++ b/packages/website/public/images/@next/clients/tokenjar.svg @@ -0,0 +1,13 @@ +<svg width="65" height="54" viewBox="0 0 65 54" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M13.4087 47.2394C13.4087 48.5078 13.4276 49.7763 13.4087 51.0639C13.3898 52.1786 12.6333 52.9665 11.5554 52.9665C10.7043 52.9665 9.79657 53.2164 9.13465 52.3515C8.83206 51.9672 8.64294 51.6212 8.64294 51.1023C8.66186 48.5078 8.66186 45.9325 8.64294 43.338C8.64294 42.7615 8.86989 42.3771 9.26703 42.0312C10.137 41.2816 11.8769 41.2816 12.7657 41.9927C13.2196 42.3579 13.4466 42.7807 13.4276 43.4149C13.3709 44.6833 13.4087 45.971 13.4087 47.2394ZM10.137 47.2394C10.137 48.2964 10.1181 49.3534 10.137 50.4105C10.1559 51.2561 10.345 51.4291 11.0447 51.4291C11.7067 51.4291 11.8958 51.0831 11.8958 50.4681C11.8769 48.3156 11.8769 46.1439 11.8958 43.9915C11.8958 43.3765 11.7067 43.0305 11.0447 43.0305C10.345 43.0305 10.1559 43.2227 10.137 44.0491C10.1181 45.1254 10.137 46.1824 10.137 47.2394Z" fill="white"/> +<path d="M56.0165 52.7551H54.5414L54.4847 48.7L52.9906 48.6808V52.6975L51.4398 52.7359C51.4398 52.7359 51.4777 52.1593 51.4777 51.7942C51.4588 49.1228 51.5533 46.4514 51.4398 43.78C51.3642 41.935 52.4611 41.6083 53.766 41.5315C55.2979 41.4354 55.9787 42.2618 55.9787 43.8761C55.9787 46.4706 55.9787 49.0459 55.9787 51.6404C55.9976 52.044 56.0165 52.7551 56.0165 52.7551ZM54.4847 47.2586C54.4847 47.2586 54.4847 44.9331 54.4847 43.8185C54.4847 43.2996 54.2199 43.0497 53.7093 43.0497C53.1797 43.0689 52.9717 43.3572 52.9717 43.8569C52.9717 44.9716 52.9717 47.297 52.9717 47.297L54.4847 47.2586Z" fill="white"/> +<path d="M61.7656 52.8895C60.9713 52.928 60.4418 52.9087 60.4418 52.9087V41.5121H61.4063C61.4063 41.5121 63.0705 41.3391 63.8648 41.7812C64.4322 42.0887 64.7726 42.4922 64.7537 43.1649C64.7537 44.3949 64.7537 45.6249 64.7537 46.8549C64.7537 47.1047 64.6402 47.4891 64.4133 47.6428C64.1863 47.7966 63.9783 47.9503 63.9783 47.9503C63.9783 47.9503 64.262 49.2188 64.3376 49.7569C64.4889 50.737 64.9995 52.8895 64.9995 52.8895H63.6757C63.6757 52.8895 63.5811 52.4283 63.4866 52.0631C63.2218 51.0061 62.976 49.9491 62.749 48.8728C62.7112 48.6999 62.6355 48.3731 62.6355 48.3731L61.7278 48.3924C61.7278 48.3924 61.7278 48.7767 61.7278 48.9689C61.7656 50.2758 61.7656 51.5442 61.7656 52.8895ZM61.8223 46.951C63.1651 47.1816 63.4866 46.9317 63.5055 45.7018C63.5055 45.2789 63.5244 44.8561 63.5055 44.4333C63.4677 43.2226 63.1083 42.8766 61.8223 43.0688C61.8223 44.2988 61.8223 45.7018 61.8223 46.951Z" fill="white"/> +<path d="M35.459 45.2022C35.459 46.4514 35.3833 52.9089 35.3833 52.9089H34.2108L34.2865 41.5891L35.5536 41.6083L37.18 46.4514V41.6468L38.5038 41.5891V52.8897C38.5038 52.8897 37.7095 52.8897 37.2178 52.9089C37.2178 52.1401 37.2178 49.8916 37.2178 49.8916C37.2178 49.8916 35.5536 45.183 35.459 45.2022Z" fill="white"/> +<path d="M22.7515 52.7935L21.2196 52.755C21.2196 52.755 20.0471 49.6993 19.6877 48.5269C19.5932 48.2386 19.4419 47.7966 19.1771 47.1047C19.1771 48.8536 19.1771 52.755 19.1771 52.755H17.6831C17.6831 52.755 17.6831 52.2169 17.6831 51.7172C17.6831 48.7191 17.6642 45.7018 17.6831 42.7037C17.6831 42.1848 17.6831 41.6659 17.6831 41.6659L19.1204 41.6274C19.1204 41.6274 19.1204 45.0676 19.1204 46.9126C19.4419 46.3168 20.7846 41.6659 20.7846 41.6659H22.2598C22.2598 41.6659 21.0872 45.8555 20.7846 47.0471C21.0683 47.9696 22.7515 52.7935 22.7515 52.7935Z" fill="white"/> +<path d="M26.4768 52.8511C26.4768 49.065 26.4768 41.6274 26.4768 41.6274L29.9188 41.5505L29.8998 43.0112H27.9898V46.3168L29.5783 46.3552L29.6162 47.8542L27.9898 47.9119V51.2752H29.8998C29.8998 51.2752 29.8809 52.3898 29.8998 52.8703C28.7273 52.8511 27.6115 52.8511 26.4768 52.8511Z" fill="white"/> +<path d="M45.7101 41.5122H47.1664C47.1664 41.5122 47.2231 48.085 47.2042 50.7564C47.2042 52.217 46.4477 52.9857 45.105 52.9473C44.5944 52.9473 44.0648 52.8896 44.0648 52.8896C44.0648 52.8896 44.0648 52.1401 44.0648 51.3906C44.2161 51.3906 44.3107 51.4482 44.4241 51.429C45.5399 51.2368 45.6912 51.0831 45.7101 50.0068C45.7291 47.6429 45.7101 41.5122 45.7101 41.5122Z" fill="white"/> +<path d="M4.29299 41.8582V43.0305H2.78004V52.7167L1.4373 52.7551C1.4373 52.7551 1.47512 47.2586 1.47512 44.8947C1.47512 43.8185 1.47512 43.1074 1.47512 43.1074L0.0189118 43.0497L3.60715e-08 41.8966L4.29299 41.8582Z" fill="white"/> +<path d="M38.9414 6.9187V9.80149H35.594V30.9804L32.6059 31.0573C32.6059 31.0573 32.6815 18.8727 32.6815 13.6068C32.6815 11.2237 32.6815 9.78227 32.6815 9.78227H29.4665L29.4098 6.95714L38.9414 6.9187Z" fill="white"/> +<path d="M38.0325 36.3808C38.0325 36.3808 43.9141 33.671 43.9141 29.8657C43.9141 24.9842 43.9141 18.4691 43.9141 18.4691C43.9141 18.4691 43.9141 11.954 43.9141 7.07245C43.9141 2.19092 38.0325 0 38.0325 0C43.1008 2.97888 42.5713 8.68681 42.5713 8.68681V28.2321C42.5713 28.2321 43.1198 33.3827 38.0325 36.3808Z" fill="white"/> +<path d="M30.033 36.3808C30.033 36.3808 24.1514 33.671 24.1514 29.8657C24.1514 24.9842 24.1514 18.4691 24.1514 18.4691C24.1514 18.4691 24.1514 11.954 24.1514 7.07245C24.1514 2.19092 30.033 0 30.033 0C24.9646 2.97888 25.4941 8.68681 25.4941 8.68681V28.2321C25.4752 28.2321 24.9457 33.3827 30.033 36.3808Z" fill="white"/> +</svg> diff --git a/packages/website/public/images/@next/clients/veil.svg b/packages/website/public/images/@next/clients/veil.svg new file mode 100644 index 000000000..b4b36ce57 --- /dev/null +++ b/packages/website/public/images/@next/clients/veil.svg @@ -0,0 +1,4 @@ +<svg width="44" height="44" viewBox="0 0 44 44" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M43.9675 22.0108C43.9675 15.6664 43.9675 9.32189 43.9675 2.98825C43.9675 1.11523 42.8537 7.4544e-05 40.9722 7.4544e-05C28.3204 7.4544e-05 15.6687 7.4544e-05 3.01695 7.4544e-05C1.17867 -0.0107522 0.0108135 1.15854 0.0108135 3.00991C0.0108135 15.6555 0.0216269 28.312 0 40.9576C0 42.6899 1.27599 44.0108 3.03858 43.9999C15.6687 43.9566 28.2988 43.9566 40.9397 43.9999C42.6807 44.0108 44.0107 42.7116 43.9999 40.9251C43.9351 34.624 43.9675 28.312 43.9675 22.0108ZM18.4802 29.438C17.7557 31.2244 17.0312 33.0108 16.3067 34.7972C15.8525 35.9124 15.3875 37.0275 14.955 38.1535C14.7712 38.6299 14.4792 38.8139 13.971 38.8031C11.9489 38.749 12.3165 39.1062 11.5163 37.1358C10.4999 34.6132 9.4834 32.0905 8.46693 29.5679C8.1209 28.7126 8.23985 28.5285 9.14818 28.5394C10.9432 28.561 10.5756 28.2795 11.2352 29.9793C11.9597 31.8632 12.6626 33.747 13.4411 35.8041C14.1116 34.0285 14.7387 32.3937 15.3551 30.7697C15.5714 30.1958 15.7985 29.622 16.0039 29.0482C16.1337 28.7018 16.3499 28.5285 16.7392 28.5394C17.1177 28.561 17.4962 28.5394 17.8746 28.5394C18.5883 28.5502 18.7505 28.7667 18.4802 29.438ZM28.5583 34.4724C26.6984 34.4832 24.8385 34.4724 22.9894 34.4724H22.3622C22.2216 35.5659 22.7515 36.6269 23.5733 36.995C24.4276 37.374 25.4981 37.1358 26.1794 36.3563C26.4497 36.0423 26.7309 35.8799 27.1526 35.9124C27.5635 35.9448 27.9852 35.9124 28.3961 35.9232C29.0017 35.934 29.2288 36.248 28.8935 36.746C28.5475 37.2549 28.1366 37.7746 27.6176 38.1102C25.9523 39.1929 24.1248 39.312 22.2865 38.619C20.9673 38.121 20.1671 37.0816 19.7994 35.7283C19.4534 34.4724 19.4426 33.184 19.7345 31.9281C20.405 29.059 22.7948 28.063 25.1737 28.3878C27.6284 28.7234 29.0557 30.3366 29.2612 32.8267C29.2828 33.1191 29.3261 33.4006 29.3261 33.6929C29.3261 34.2992 29.1639 34.4616 28.5583 34.4724ZM33.9867 33.6929C33.9867 35.1004 33.9867 36.5078 33.9867 37.9153C33.9867 38.7165 33.9002 38.8031 33.0783 38.8031C32.6999 38.8031 32.3214 38.8031 31.9429 38.8031C31.5645 38.8031 31.3806 38.619 31.3806 38.2401C31.3806 35.2086 31.3806 32.1771 31.3806 29.1348C31.3806 28.7342 31.5753 28.5394 31.9754 28.5394C32.3863 28.5394 32.808 28.5394 33.2189 28.5394C33.8461 28.5394 33.9867 28.6801 33.9867 29.2972C33.9867 30.7697 33.9867 32.2313 33.9867 33.6929ZM34.0948 26.0925C34.084 26.6988 33.9434 26.8504 33.3811 26.8504C33.1324 26.8504 32.8729 26.8504 32.6242 26.8504C31.2833 26.8504 31.2617 26.9911 31.2725 25.497C31.2833 24.5335 31.359 24.4577 32.3214 24.4577H33.1324C33.2189 24.4577 33.3162 24.4577 33.4028 24.4577C34.0516 24.501 34.1273 24.685 34.0948 26.0925ZM39.2096 30.7047C39.2096 33.1191 39.2096 35.5443 39.2096 37.9586C39.2096 38.7057 39.1123 38.8031 38.3769 38.8031C38.0201 38.8031 37.6524 38.7923 37.2956 38.8031C36.7874 38.8248 36.5819 38.5974 36.5927 38.0885C36.6035 35.9773 36.5927 33.8661 36.5927 31.7549C36.5927 29.7303 36.5927 27.7165 36.5927 25.6919C36.5927 24.8799 36.7009 24.7716 37.5335 24.7716C37.8579 24.7716 38.1823 24.7825 38.5067 24.7716C39.0041 24.7608 39.2204 24.999 39.2204 25.497C39.1988 27.2401 39.2096 28.9724 39.2096 30.7047Z" fill="white"/> +<path d="M26.8125 33H22.7184C22.5194 31.2688 23.3047 29.7122 24.4147 29.5812C25.9015 29.3921 26.802 30.6432 26.8125 33Z" fill="white"/> +</svg> diff --git a/packages/website/public/images/@next/events/berlin.jpg b/packages/website/public/images/@next/events/berlin.jpg Binary files differnew file mode 100644 index 000000000..0bcc0fa63 --- /dev/null +++ b/packages/website/public/images/@next/events/berlin.jpg diff --git a/packages/website/public/images/@next/events/event-sample.jpg b/packages/website/public/images/@next/events/event-sample.jpg Binary files differnew file mode 100644 index 000000000..f7a832a5c --- /dev/null +++ b/packages/website/public/images/@next/events/event-sample.jpg diff --git a/packages/website/public/images/@next/events/london.jpg b/packages/website/public/images/@next/events/london.jpg Binary files differnew file mode 100644 index 000000000..4b6b7ef06 --- /dev/null +++ b/packages/website/public/images/@next/events/london.jpg diff --git a/packages/website/public/images/@next/events/sf.jpg b/packages/website/public/images/@next/events/sf.jpg Binary files differnew file mode 100644 index 000000000..efd7f7c29 --- /dev/null +++ b/packages/website/public/images/@next/events/sf.jpg diff --git a/packages/website/public/images/@next/jobs/map@2x.png b/packages/website/public/images/@next/jobs/map@2x.png Binary files differnew file mode 100644 index 000000000..08fa60ec0 --- /dev/null +++ b/packages/website/public/images/@next/jobs/map@2x.png diff --git a/packages/website/public/images/@next/press/logo-forbes.png b/packages/website/public/images/@next/press/logo-forbes.png Binary files differnew file mode 100644 index 000000000..6849c672b --- /dev/null +++ b/packages/website/public/images/@next/press/logo-forbes.png diff --git a/packages/website/public/images/@next/press/logo-fortune.png b/packages/website/public/images/@next/press/logo-fortune.png Binary files differnew file mode 100644 index 000000000..981f8c357 --- /dev/null +++ b/packages/website/public/images/@next/press/logo-fortune.png diff --git a/packages/website/public/images/@next/press/logo-techcrunch.png b/packages/website/public/images/@next/press/logo-techcrunch.png Binary files differnew file mode 100644 index 000000000..7f260d0ea --- /dev/null +++ b/packages/website/public/images/@next/press/logo-techcrunch.png diff --git a/packages/website/public/images/@next/press/logo-venturebeat.png b/packages/website/public/images/@next/press/logo-venturebeat.png Binary files differnew file mode 100644 index 000000000..2086bf0b7 --- /dev/null +++ b/packages/website/public/images/@next/press/logo-venturebeat.png diff --git a/packages/website/public/images/@next/relayer-logos/logo.png b/packages/website/public/images/@next/relayer-logos/logo.png Binary files differnew file mode 100755 index 000000000..d810cef4a --- /dev/null +++ b/packages/website/public/images/@next/relayer-logos/logo.png diff --git a/packages/website/public/images/@next/relayer-logos/logo_1.png b/packages/website/public/images/@next/relayer-logos/logo_1.png Binary files differnew file mode 100755 index 000000000..0068a7445 --- /dev/null +++ b/packages/website/public/images/@next/relayer-logos/logo_1.png diff --git a/packages/website/public/images/@next/relayer-logos/logo_2.1.png b/packages/website/public/images/@next/relayer-logos/logo_2.1.png Binary files differnew file mode 100755 index 000000000..f6cd92b0e --- /dev/null +++ b/packages/website/public/images/@next/relayer-logos/logo_2.1.png diff --git a/packages/website/public/images/@next/relayer-logos/logo_2.2.png b/packages/website/public/images/@next/relayer-logos/logo_2.2.png Binary files differnew file mode 100755 index 000000000..9461e91ee --- /dev/null +++ b/packages/website/public/images/@next/relayer-logos/logo_2.2.png diff --git a/packages/website/public/images/@next/relayer-logos/logo_2.3.png b/packages/website/public/images/@next/relayer-logos/logo_2.3.png Binary files differnew file mode 100755 index 000000000..fde896972 --- /dev/null +++ b/packages/website/public/images/@next/relayer-logos/logo_2.3.png diff --git a/packages/website/public/images/@next/relayer-logos/logo_2.png b/packages/website/public/images/@next/relayer-logos/logo_2.png Binary files differnew file mode 100755 index 000000000..e3015110c --- /dev/null +++ b/packages/website/public/images/@next/relayer-logos/logo_2.png diff --git a/packages/website/public/images/@next/relayer-logos/logo_3.png b/packages/website/public/images/@next/relayer-logos/logo_3.png Binary files differnew file mode 100755 index 000000000..b3d397fe1 --- /dev/null +++ b/packages/website/public/images/@next/relayer-logos/logo_3.png diff --git a/packages/website/public/images/@next/relayer-logos/logo_4.png b/packages/website/public/images/@next/relayer-logos/logo_4.png Binary files differnew file mode 100755 index 000000000..578be0af8 --- /dev/null +++ b/packages/website/public/images/@next/relayer-logos/logo_4.png diff --git a/packages/website/public/images/@next/relayer-logos/logo_5.png b/packages/website/public/images/@next/relayer-logos/logo_5.png Binary files differnew file mode 100755 index 000000000..baf3c4080 --- /dev/null +++ b/packages/website/public/images/@next/relayer-logos/logo_5.png diff --git a/packages/website/public/images/@next/team/advisors/davids.jpg b/packages/website/public/images/@next/team/advisors/davids.jpg Binary files differnew file mode 100755 index 000000000..904ebda01 --- /dev/null +++ b/packages/website/public/images/@next/team/advisors/davids.jpg diff --git a/packages/website/public/images/@next/team/advisors/frede.jpg b/packages/website/public/images/@next/team/advisors/frede.jpg Binary files differnew file mode 100755 index 000000000..cb882c53f --- /dev/null +++ b/packages/website/public/images/@next/team/advisors/frede.jpg diff --git a/packages/website/public/images/@next/team/advisors/joeyk.jpg b/packages/website/public/images/@next/team/advisors/joeyk.jpg Binary files differnew file mode 100755 index 000000000..c6050242f --- /dev/null +++ b/packages/website/public/images/@next/team/advisors/joeyk.jpg diff --git a/packages/website/public/images/@next/team/advisors/lindax.jpg b/packages/website/public/images/@next/team/advisors/lindax.jpg Binary files differnew file mode 100755 index 000000000..766532068 --- /dev/null +++ b/packages/website/public/images/@next/team/advisors/lindax.jpg diff --git a/packages/website/public/images/@next/team/advisors/olafc.jpg b/packages/website/public/images/@next/team/advisors/olafc.jpg Binary files differnew file mode 100755 index 000000000..bb0dc6cb5 --- /dev/null +++ b/packages/website/public/images/@next/team/advisors/olafc.jpg diff --git a/packages/website/public/images/@next/team/alexb.jpg b/packages/website/public/images/@next/team/alexb.jpg Binary files differnew file mode 100755 index 000000000..c076de14b --- /dev/null +++ b/packages/website/public/images/@next/team/alexb.jpg diff --git a/packages/website/public/images/@next/team/alexv.jpg b/packages/website/public/images/@next/team/alexv.jpg Binary files differnew file mode 100755 index 000000000..686f4a2e3 --- /dev/null +++ b/packages/website/public/images/@next/team/alexv.jpg diff --git a/packages/website/public/images/@next/team/amirb.jpg b/packages/website/public/images/@next/team/amirb.jpg Binary files differnew file mode 100755 index 000000000..19502735d --- /dev/null +++ b/packages/website/public/images/@next/team/amirb.jpg diff --git a/packages/website/public/images/@next/team/benb.jpg b/packages/website/public/images/@next/team/benb.jpg Binary files differnew file mode 100755 index 000000000..ef7fb69a9 --- /dev/null +++ b/packages/website/public/images/@next/team/benb.jpg diff --git a/packages/website/public/images/@next/team/blake.jpg b/packages/website/public/images/@next/team/blake.jpg Binary files differnew file mode 100755 index 000000000..0f5512af4 --- /dev/null +++ b/packages/website/public/images/@next/team/blake.jpg diff --git a/packages/website/public/images/@next/team/brandonm.jpg b/packages/website/public/images/@next/team/brandonm.jpg Binary files differnew file mode 100755 index 000000000..72368f994 --- /dev/null +++ b/packages/website/public/images/@next/team/brandonm.jpg diff --git a/packages/website/public/images/@next/team/chrisk.jpg b/packages/website/public/images/@next/team/chrisk.jpg Binary files differnew file mode 100755 index 000000000..cf900faea --- /dev/null +++ b/packages/website/public/images/@next/team/chrisk.jpg diff --git a/packages/website/public/images/@next/team/clayr.jpg b/packages/website/public/images/@next/team/clayr.jpg Binary files differnew file mode 100755 index 000000000..3fa550727 --- /dev/null +++ b/packages/website/public/images/@next/team/clayr.jpg diff --git a/packages/website/public/images/@next/team/eugenea.jpg b/packages/website/public/images/@next/team/eugenea.jpg Binary files differnew file mode 100755 index 000000000..dc9aecea1 --- /dev/null +++ b/packages/website/public/images/@next/team/eugenea.jpg diff --git a/packages/website/public/images/@next/team/fabiob.jpg b/packages/website/public/images/@next/team/fabiob.jpg Binary files differnew file mode 100755 index 000000000..c06a06c9f --- /dev/null +++ b/packages/website/public/images/@next/team/fabiob.jpg diff --git a/packages/website/public/images/@next/team/francesco.jpg b/packages/website/public/images/@next/team/francesco.jpg Binary files differnew file mode 100755 index 000000000..56ae0e870 --- /dev/null +++ b/packages/website/public/images/@next/team/francesco.jpg diff --git a/packages/website/public/images/@next/team/greg.jpg b/packages/website/public/images/@next/team/greg.jpg Binary files differnew file mode 100755 index 000000000..0b6df7083 --- /dev/null +++ b/packages/website/public/images/@next/team/greg.jpg diff --git a/packages/website/public/images/@next/team/jacobe.jpg b/packages/website/public/images/@next/team/jacobe.jpg Binary files differnew file mode 100755 index 000000000..29eed406d --- /dev/null +++ b/packages/website/public/images/@next/team/jacobe.jpg diff --git a/packages/website/public/images/@next/team/jasons.jpg b/packages/website/public/images/@next/team/jasons.jpg Binary files differnew file mode 100755 index 000000000..b0a40edba --- /dev/null +++ b/packages/website/public/images/@next/team/jasons.jpg diff --git a/packages/website/public/images/@next/team/leonidL.jpg b/packages/website/public/images/@next/team/leonidL.jpg Binary files differnew file mode 100755 index 000000000..e3dfd6a7d --- /dev/null +++ b/packages/website/public/images/@next/team/leonidL.jpg diff --git a/packages/website/public/images/@next/team/mattt.jpg b/packages/website/public/images/@next/team/mattt.jpg Binary files differnew file mode 100755 index 000000000..03f95a7c1 --- /dev/null +++ b/packages/website/public/images/@next/team/mattt.jpg diff --git a/packages/website/public/images/@next/team/melo.jpg b/packages/website/public/images/@next/team/melo.jpg Binary files differnew file mode 100755 index 000000000..2db8ec796 --- /dev/null +++ b/packages/website/public/images/@next/team/melo.jpg diff --git a/packages/website/public/images/@next/team/peterz.jpg b/packages/website/public/images/@next/team/peterz.jpg Binary files differnew file mode 100755 index 000000000..7708c75db --- /dev/null +++ b/packages/website/public/images/@next/team/peterz.jpg diff --git a/packages/website/public/images/@next/team/rahuls.jpg b/packages/website/public/images/@next/team/rahuls.jpg Binary files differnew file mode 100755 index 000000000..ef2f001dd --- /dev/null +++ b/packages/website/public/images/@next/team/rahuls.jpg diff --git a/packages/website/public/images/@next/team/remcoB.jpg b/packages/website/public/images/@next/team/remcoB.jpg Binary files differnew file mode 100755 index 000000000..bc997a18e --- /dev/null +++ b/packages/website/public/images/@next/team/remcoB.jpg diff --git a/packages/website/public/images/@next/team/steveK.jpg b/packages/website/public/images/@next/team/steveK.jpg Binary files differnew file mode 100755 index 000000000..aeede8bc5 --- /dev/null +++ b/packages/website/public/images/@next/team/steveK.jpg diff --git a/packages/website/public/images/@next/team/toms.jpg b/packages/website/public/images/@next/team/toms.jpg Binary files differnew file mode 100755 index 000000000..9d9dd2db8 --- /dev/null +++ b/packages/website/public/images/@next/team/toms.jpg diff --git a/packages/website/public/images/@next/team/weijew.jpg b/packages/website/public/images/@next/team/weijew.jpg Binary files differnew file mode 100755 index 000000000..0b2464e67 --- /dev/null +++ b/packages/website/public/images/@next/team/weijew.jpg diff --git a/packages/website/public/images/@next/team/willw.jpg b/packages/website/public/images/@next/team/willw.jpg Binary files differnew file mode 100755 index 000000000..c1bd8f406 --- /dev/null +++ b/packages/website/public/images/@next/team/willw.jpg diff --git a/packages/website/public/images/@next/team/xianny.jpg b/packages/website/public/images/@next/team/xianny.jpg Binary files differnew file mode 100755 index 000000000..4e6a3bb8c --- /dev/null +++ b/packages/website/public/images/@next/team/xianny.jpg diff --git a/packages/website/public/images/@next/team/zack.jpg b/packages/website/public/images/@next/team/zack.jpg Binary files differnew file mode 100755 index 000000000..9060d7592 --- /dev/null +++ b/packages/website/public/images/@next/team/zack.jpg diff --git a/packages/website/public/images/og_image.png b/packages/website/public/images/og_image.png Binary files differindex 74265bdf8..b9bafeb7e 100644 --- a/packages/website/public/images/og_image.png +++ b/packages/website/public/images/og_image.png diff --git a/packages/website/public/index.html b/packages/website/public/index.html index 538eca6d9..26ebcdec8 100644 --- a/packages/website/public/index.html +++ b/packages/website/public/index.html @@ -17,6 +17,7 @@ <link rel="stylesheet" href="/css/material-design-iconic-font.min.css" /> <link rel="stylesheet" href="/css/roboto.css" /> <link rel="stylesheet" href="/css/roboto_mono.css" /> + <link rel="stylesheet" href="/css/formular.css" /> <link rel="stylesheet" href="/css/basscss_responsive_custom.css" /> <link rel="stylesheet" href="/css/basscss_responsive_padding.css" /> <link rel="stylesheet" href="/css/basscss_responsive_margin.css" /> @@ -109,7 +110,7 @@ })(document, 'script', 'twitter-wjs'); </script> <!-- End Twitter SDK --> - <!-- Hotjar Tracking Code for https://0xproject.com/ --> + <!-- Hotjar Tracking Code for https://0x.org/ --> <script> (function(h, o, t, j, a, r) { h.hj = diff --git a/packages/website/ts/@next/components/aboutPageLayout.tsx b/packages/website/ts/@next/components/aboutPageLayout.tsx new file mode 100644 index 000000000..86a94ae2b --- /dev/null +++ b/packages/website/ts/@next/components/aboutPageLayout.tsx @@ -0,0 +1,71 @@ +import * as _ from 'lodash'; +import * as React from 'react'; +import styled from 'styled-components'; + +import { Button } from 'ts/@next/components/button'; +import { ChapterLink } from 'ts/@next/components/chapter_link'; +import { Column, Section } from 'ts/@next/components/newLayout'; +import { SiteWrap } from 'ts/@next/components/siteWrap'; +import { Heading, Paragraph } from 'ts/@next/components/text'; + +import { addFadeInAnimation } from 'ts/@next/constants/animations'; +import { WebsitePaths } from 'ts/types'; + +interface Props { + title: string; + description: React.ReactNode | string; + linkLabel?: string; + href?: string; + to?: string; + children?: React.ReactNode; +} + +export const AboutPageLayout = (props: Props) => ( + <SiteWrap theme="light"> + <Section isFlex={true} maxWidth="1170px" wrapWidth="100%"> + <Column> + <ChapterLink to={WebsitePaths.AboutMission}>Mission</ChapterLink> + <ChapterLink to={WebsitePaths.AboutTeam}>Team</ChapterLink> + <ChapterLink to={WebsitePaths.AboutPress}>Press</ChapterLink> + <ChapterLink to={WebsitePaths.AboutJobs}>Jobs</ChapterLink> + </Column> + + <Column width="70%" maxWidth="800px"> + <Column width="100%" maxWidth="680px"> + <AnimatedHeading size="medium">{props.title}</AnimatedHeading> + + <AnimatedParagraph size="medium" marginBottom="60px" isMuted={0.65}> + {props.description} + </AnimatedParagraph> + + {props.linkLabel && + (props.href || props.to) && ( + <AnimatedLink + to={props.to} + href={props.href} + target={!_.isUndefined(props.href) ? '_blank' : undefined} + isWithArrow={true} + isAccentColor={true} + > + {props.linkLabel} + </AnimatedLink> + )} + </Column> + </Column> + </Section> + + {props.children} + </SiteWrap> +); + +const AnimatedHeading = styled(Heading)` + ${addFadeInAnimation('0.5s')}; +`; + +const AnimatedParagraph = styled(Paragraph)` + ${addFadeInAnimation('0.5s', '0.15s')}; +`; + +const AnimatedLink = styled(Button)` + ${addFadeInAnimation('0.6s', '0.3s')}; +`; diff --git a/packages/website/ts/@next/components/animatedChatIcon.tsx b/packages/website/ts/@next/components/animatedChatIcon.tsx new file mode 100644 index 000000000..9a86e244c --- /dev/null +++ b/packages/website/ts/@next/components/animatedChatIcon.tsx @@ -0,0 +1,106 @@ +import * as React from 'react'; +import styled, { keyframes } from 'styled-components'; + +export const AnimatedChatIcon = () => ( + <svg width="150" height="150" viewBox="0 0 150 150" fill="none" xmlns="http://www.w3.org/2000/svg"> + <mask id="mask30" mask-type="alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="150" height="150"> + <circle cx="75" cy="75" r="73" fill="#00AE99" stroke="#00AE99" stroke-width="3" /> + </mask> + + <g mask="url(#mask30)"> + <circle cx="75" cy="75" r="73" stroke="#00AE99" stroke-width="3" /> + + <Rays> + <path vector-effect="non-scaling-stroke" d="M76 37H137.5" stroke="#00AE99" stroke-width="3" /> + <path + vector-effect="non-scaling-stroke" + d="M37 73.5L37 12M113 137.5L113 75" + stroke="#00AE99" + stroke-width="3" + /> + <path vector-effect="non-scaling-stroke" d="M13 113H71.5" stroke="#00AE99" stroke-width="3" /> + <path + vector-effect="non-scaling-stroke" + d="M49.087 47.5264L92.574 4.03932" + stroke="#00AE99" + stroke-width="3" + /> + <path + vector-effect="non-scaling-stroke" + d="M47.3192 100.913L3.8321 57.4259M146.314 92.4277L102.12 48.2335" + stroke="#00AE99" + stroke-width="3" + /> + <path + vector-effect="non-scaling-stroke" + d="M58.2793 145.814L101.766 102.327" + stroke="#00AE99" + stroke-width="3" + /> + </Rays> + + <Bubble> + <path + vector-effect="non-scaling-stroke" + d="M113 75C113 85.3064 108.897 94.6546 102.235 101.5C98.4048 105.436 71 132.5 71 132.5V112.792C51.8933 110.793 37 94.6359 37 75C37 54.0132 54.0132 37 75 37C95.9868 37 113 54.0132 113 75Z" + stroke="#00AE99" + strokeWidth="3" + /> + </Bubble> + + <Dot delay={0} vector-effect="non-scaling-stroke" cx="75" cy="75" r="4" stroke="#00AE99" strokeWidth="3" /> + <Dot + delay={4.4} + vector-effect="non-scaling-stroke" + cx="91" + cy="75" + r="4" + stroke="#00AE99" + strokeWidth="3" + /> + <Dot + delay={-4.6} + vector-effect="non-scaling-stroke" + cx="59" + cy="75" + r="4" + stroke="#00AE99" + strokeWidth="3" + /> + </g> + </svg> +); + +const scale = keyframes` + 0% { transform: scale(1.2) } + 15% { transform: scale(1) } + 85% { transform: scale(1) } + 100% { transform: scale(1.2) } +`; + +const fadeInOut = keyframes` + 0%, 30%, 50%, 100% { + transform: initial; + } + + 40% { + transform: translateY(-5px); + } +`; + +const Bubble = styled.g` + animation: ${scale} 4s infinite cubic-bezier(0.175, 0.885, 0.32, 1.275); + transform-origin: 50% 50%; +`; + +const Rays = styled.g` + animation: ${scale} 4s infinite cubic-bezier(0.175, 0.885, 0.32, 1.275); + transform-origin: 50% 50%; +`; + +const Dot = + styled.circle < + { delay: number } > + ` + animation: ${fadeInOut} 4s ${props => `${props.delay}s`} infinite; +`; diff --git a/packages/website/ts/@next/components/animatedCompassIcon.tsx b/packages/website/ts/@next/components/animatedCompassIcon.tsx new file mode 100644 index 000000000..5388f95ca --- /dev/null +++ b/packages/website/ts/@next/components/animatedCompassIcon.tsx @@ -0,0 +1,53 @@ +import * as React from 'react'; +import styled, { keyframes } from 'styled-components'; + +export const AnimatedCompassIcon = () => ( + <svg width="150" height="150" viewBox="0 0 150 150" fill="none" xmlns="http://www.w3.org/2000/svg"> + <g> + <circle cx="75" cy="75" r="73" stroke="#00AE99" stroke-width="3" /> + <circle cx="75" cy="75" r="58" stroke="#00AE99" stroke-width="3" /> + <Needle + d="M62.9792 62.9792L36.6447 113.355L87.0208 87.0208M62.9792 62.9792L113.355 36.6447L87.0208 87.0208M62.9792 62.9792L87.0208 87.0208" + stroke="#00AE99" + strokeWidth="3" + /> + + <Dial> + <path d="M75 2V17M75 133V148" stroke="#00AE99" stroke-width="3" /> + <path d="M2 75L17 75M133 75L148 75" stroke="#00AE99" stroke-width="3" /> + <path d="M11.7801 38.5L24.7705 46M125.229 104L138.22 111.5" stroke="#00AE99" stroke-width="3" /> + <path d="M38.5001 11.7801L46.0001 24.7705M104 125.229L111.5 138.22" stroke="#00AE99" stroke-width="3" /> + <path d="M111.5 11.7801L104 24.7705M46 125.229L38.5 138.22" stroke="#00AE99" stroke-width="3" /> + <path d="M138.22 38.5L125.229 46M24.7705 104L11.7801 111.5" stroke="#00AE99" stroke-width="3" /> + </Dial> + </g> + </svg> +); + +const point = keyframes` + 0% { transform: rotate(0deg) } + 20% { transform: rotate(10deg) } + 30% { transform: rotate(30deg) } + 60% { transform: rotate(-20deg) } + 80% { transform: rotate(-20deg) } + 100% { transform: rotate(0deg) } +`; + +const rotate = keyframes` + 0% { transform: rotate(0deg) } + 20% { transform: rotate(-10deg) } + 30% { transform: rotate(-30deg) } + 60% { transform: rotate(20deg) } + 80% { transform: rotate(20deg) } + 100% { transform: rotate(0deg) } +`; + +const Needle = styled.path` + animation: ${point} 5s infinite; + transform-origin: 50% 50%; +`; + +const Dial = styled.g` + animation: ${rotate} 5s infinite; + transform-origin: 50% 50%; +`; diff --git a/packages/website/ts/@next/components/banner.tsx b/packages/website/ts/@next/components/banner.tsx new file mode 100644 index 000000000..6c4d94dc5 --- /dev/null +++ b/packages/website/ts/@next/components/banner.tsx @@ -0,0 +1,147 @@ +import * as React from 'react'; +import styled from 'styled-components'; + +import { colors } from 'ts/style/colors'; + +import { Button } from 'ts/@next/components/button'; +import { ThemeInterface } from 'ts/@next/components/siteWrap'; +import { Paragraph } from 'ts/@next/components/text'; + +import { Column, Section } from 'ts/@next/components/newLayout'; + +interface Props { + heading?: string; + subline?: string; + mainCta?: CTAButton; + secondaryCta?: CTAButton; + theme?: ThemeInterface; +} + +interface CTAButton { + text: string; + href?: string; + onClick?: () => void; + shouldOpenInNewTab?: boolean; +} + +interface BorderProps { + isBottom?: boolean; +} + +export const Banner: React.StatelessComponent<Props> = (props: Props) => { + const { heading, subline, mainCta, secondaryCta } = props; + return ( + <CustomSection bgColor={colors.brandDark} isFlex={true} flexBreakpoint="900px" paddingMobile="120px 0"> + <Border /> + <Border isBottom={true} /> + + <Column> + <CustomHeading>{heading}</CustomHeading> + + {subline && ( + <Paragraph color={colors.white} isMuted={0.5} isNoMargin={true}> + {subline} + </Paragraph> + )} + </Column> + <Column> + <ButtonWrap> + {mainCta && ( + <Button + color={colors.white} + isTransparent={false} + href={mainCta.href} + target={mainCta.shouldOpenInNewTab ? '_blank' : ''} + > + {mainCta.text} + </Button> + )} + + {secondaryCta && ( + <Button + color={colors.white} + href={secondaryCta.href} + onClick={secondaryCta.onClick} + isTransparent={true} + > + {secondaryCta.text} + </Button> + )} + </ButtonWrap> + </Column> + </CustomSection> + ); +}; + +const CustomSection = styled(Section)` + color: ${colors.white}; + margin-top: 30px; + + @media (max-width: 900px) { + text-align: center; + + p { + margin-bottom: 30px; + } + + div:last-child { + margin-bottom: 0; + } + } +`; + +const CustomHeading = styled.h2` + font-size: 34px; + font-weight: 400; + margin-bottom: 10px @media (max-width: 768px) { + font-size: 30px; + } +`; + +const ButtonWrap = styled.div` + display: inline-block; + + @media (min-width: 768px) { + * + * { + margin-left: 15px; + } + } + + @media (max-width: 768px) { + a, + button { + display: block; + width: 220px; + } + + * + * { + margin-top: 15px; + } + } +`; + +// Note let's refactor this +// is it absolutely necessary to have a stateless component +// to pass props down into the styled icon? +const Border = + styled.div < + BorderProps > + ` + position: absolute; + background-image: ${props => + props.isBottom ? 'url(/images/@next/banner/bottomofcta.png);' : 'url(/images/@next/banner/topofcta.png);'}; + background-position: ${props => (props.isBottom ? 'left top' : 'left bottom')}; + left: 0; + width: calc(100% + 214px); + height: 40px; + top: ${props => !props.isBottom && 0}; + bottom: ${props => props.isBottom && 0}; + transform: translate(-112px); + + @media (max-width: 768px) { + width: calc(100% + 82px); + height: 40px; + transform: translate(-41px); + background-size: auto 80px; + } +`; diff --git a/packages/website/ts/@next/components/blockIconLink.tsx b/packages/website/ts/@next/components/blockIconLink.tsx new file mode 100644 index 000000000..8d66a4afa --- /dev/null +++ b/packages/website/ts/@next/components/blockIconLink.tsx @@ -0,0 +1,84 @@ +import { History, Location } from 'history'; +import * as React from 'react'; +import { match, withRouter } from 'react-router-dom'; +import styled from 'styled-components'; + +import { Button } from 'ts/@next/components/button'; +import { Icon } from 'ts/@next/components/icon'; + +interface BaseComponentProps { + icon?: string; + iconComponent?: React.ReactNode; + title: string; + linkLabel: string; + linkUrl?: string; + linkAction?: () => void; + history: History; + location: Location; + match: match<any>; +} + +class BaseComponent extends React.PureComponent<BaseComponentProps> { + public onClick = (): void => { + const { linkAction, linkUrl } = this.props; + + if (linkAction) { + linkAction(); + } else { + this.props.history.push(linkUrl); + } + }; + + public render(): React.ReactNode { + const { icon, iconComponent, linkUrl, linkAction, title, linkLabel } = this.props; + + return ( + <Wrap onClick={this.onClick}> + <div> + <Icon name={icon} component={iconComponent} size="large" margin={[0, 0, 'default', 0]} /> + + <Title>{title}</Title> + + <Button isWithArrow={true} isTransparent={true} href={linkUrl} onClick={linkAction}> + {linkLabel} + </Button> + </div> + </Wrap> + ); + } +} + +export const BlockIconLink = withRouter<BaseComponentProps>(BaseComponent); + +const Wrap = styled.div` + width: calc(50% - 15px); + height: 400px; + padding: 40px; + display: flex; + justify-content: center; + align-items: center; + text-align: center; + transition: background-color 0.25s; + background-color: ${props => props.theme.lightBgColor}; + cursor: pointer; + + a, + button { + pointer-events: none; + } + + @media (max-width: 900px) { + width: 100%; + margin-top: 30px; + } + + &:hover { + background-color: #002d28; + } +`; + +const Title = styled.h2` + font-size: 20px; + margin-bottom: 30px; + color: ${props => props.theme.linkColor}; +`; diff --git a/packages/website/ts/@next/components/button.tsx b/packages/website/ts/@next/components/button.tsx new file mode 100644 index 000000000..348f1b7b4 --- /dev/null +++ b/packages/website/ts/@next/components/button.tsx @@ -0,0 +1,102 @@ +import * as React from 'react'; +import { Link as ReactRouterLink } from 'react-router-dom'; +import styled from 'styled-components'; + +import { ThemeInterface } from 'ts/@next/components/siteWrap'; + +import { colors } from 'ts/style/colors'; + +interface ButtonInterface { + bgColor?: string; + color?: string; + children?: React.ReactNode | string; + isTransparent?: boolean; + isNoBorder?: boolean; + isNoPadding?: boolean; + isWithArrow?: boolean; + isAccentColor?: boolean; + hasIcon?: boolean | string; + isInline?: boolean; + href?: string; + type?: string; + target?: string; + to?: string; + onClick?: () => any; + theme?: ThemeInterface; + shouldUseAnchorTag?: boolean; +} + +export const Button = (props: ButtonInterface) => { + const { children, href, isWithArrow, to, shouldUseAnchorTag, target } = props; + let linkElem; + + if (href || shouldUseAnchorTag) { + linkElem = 'a'; + } + if (to) { + linkElem = ReactRouterLink; + } + + const Component = linkElem ? ButtonBase.withComponent<any>(linkElem) : ButtonBase; + const targetProp = href && target ? { target } : {}; + + return ( + <Component {...props} {...targetProp}> + {children} + + {isWithArrow && ( + <svg width="16" height="15" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path d="M4.484.246l.024 1.411 8.146.053L.817 13.547l.996.996L13.65 2.706l.052 8.146 1.412.024L15.045.315 4.484.246z" /> + </svg> + )} + </Component> + ); +}; + +const ButtonBase = + styled.button < + ButtonInterface > + ` + appearance: none; + border: 1px solid transparent; + display: inline-block; + background-color: ${props => props.bgColor || colors.brandLight}; + background-color: ${props => (props.isTransparent || props.isWithArrow) && 'transparent'}; + border-color: ${props => props.isTransparent && !props.isWithArrow && 'rgba(255, 255, 255, .4)'}; + color: ${props => (props.isAccentColor ? props.theme.linkColor : props.color || props.theme.textColor)}; + padding: ${props => !props.isNoPadding && !props.isWithArrow && '18px 30px'}; + white-space: ${props => props.isWithArrow && 'nowrap'}; + text-align: center; + font-size: ${props => (props.isWithArrow ? '20px' : '18px')}; + text-decoration: none; + cursor: pointer; + outline: none; + transition: background-color 0.35s, border-color 0.35s; + + // @todo Refactor to use theme props + ${props => + props.bgColor === 'dark' && + ` + background-color: ${colors.brandDark}; + color: ${colors.white}; + `} + + svg { + margin-left: 9px; + transition: transform 0.5s; + transform: translate3d(-2px, 2px, 0); + } + + path { + fill: ${props => (props.isAccentColor ? props.theme.linkColor : props.color || props.theme.textColor)}; + } + + &:hover { + background-color: ${props => !props.isTransparent && !props.isWithArrow && '#04BEA8'}; + border-color: ${props => props.isTransparent && !props.isNoBorder && !props.isWithArrow && '#00AE99'}; + + svg { + transform: translate3d(2px, -2px, 0); + } + } +`; diff --git a/packages/website/ts/@next/components/chapter_link.tsx b/packages/website/ts/@next/components/chapter_link.tsx new file mode 100644 index 000000000..fd974cec1 --- /dev/null +++ b/packages/website/ts/@next/components/chapter_link.tsx @@ -0,0 +1,15 @@ +import { NavLink as ReactRouterLink } from 'react-router-dom'; +import styled from 'styled-components'; + +export const ChapterLink = styled(ReactRouterLink).attrs({ + activeStyle: { opacity: 1 }, +})` + font-size: 1.222222222rem; + display: block; + opacity: 0.5; + margin-bottom: 1.666666667rem; + + &:hover { + opacity: 1; + } +`; diff --git a/packages/website/ts/@next/components/definition.tsx b/packages/website/ts/@next/components/definition.tsx new file mode 100644 index 000000000..8adef8d54 --- /dev/null +++ b/packages/website/ts/@next/components/definition.tsx @@ -0,0 +1,145 @@ +import * as React from 'react'; +import styled from 'styled-components'; + +import { Button } from 'ts/@next/components/button'; +import { Icon } from 'ts/@next/components/icon'; +import { Heading, Paragraph } from 'ts/@next/components/text'; + +interface Action { + label: string; + url?: string; + onClick?: () => void; + shouldUseAnchorTag?: boolean; +} + +interface Props { + isInline?: boolean; + isInlineIcon?: boolean; + isCentered?: boolean; + isWithMargin?: boolean; + icon: string; + iconSize?: 'medium' | 'large' | number; + fontSize?: 'default' | 'medium' | number; + title: string; + titleSize?: 'small' | 'default' | number; + description: React.ReactNode | string; + actions?: Action[]; +} + +export const Definition = (props: Props) => ( + <Wrap {...props}> + <Icon name={props.icon} size={props.iconSize || 'medium'} margin={[0, 0, 'default', 0]} /> + + <TextWrap {...props}> + <Heading + asElement="h2" + fontWeight="400" + marginBottom={props.titleSize === 'small' ? '7px' : '15px'} + size={props.titleSize || 'default'} + > + {props.title} + </Heading> + + {typeof props.description === 'string' ? ( + <Paragraph isMuted={true} size={props.fontSize || 'default'}> + {props.description} + </Paragraph> + ) : ( + <>{props.description}</> + )} + + {props.actions && ( + <LinkWrap> + {props.actions.map((item, index) => ( + <Button + key={`dlink-${index}`} + href={item.url} + onClick={item.onClick} + isWithArrow={true} + isAccentColor={true} + shouldUseAnchorTag={item.shouldUseAnchorTag} + target="_blank" + > + {item.label} + </Button> + ))} + </LinkWrap> + )} + </TextWrap> + </Wrap> +); + +const Wrap = + styled.div < + Props > + ` + max-width: ${props => props.isInline && '354px'}; + + & + & { + margin-top: ${props => props.isInlineIcon && '120px'}; + margin-top: ${props => props.isWithMargin && '60px'}; + } + + @media (min-width: 768px) { + width: ${props => (props.isInline ? 'calc(33.3333% - 30px)' : '100%')}; + display: ${props => props.isInlineIcon && 'flex'}; + justify-content: ${props => props.isInlineIcon && 'space-between'}; + align-items: ${props => props.isInlineIcon && 'center'}; + text-align: ${props => (props.isInlineIcon || !props.isCentered) && 'left'}; + } + + @media (max-width: 768px) { + margin: 0 auto; + + & + & { + margin-top: ${props => props.isInline && '60px'}; + } + } +`; + +const TextWrap = + styled.div < + Props > + ` + width: 100%; + max-width: 560px; + + ul { + padding-top: 10px; + padding-left: 1rem; + } + + li { + color: ${props => props.theme.paragraphColor}; + font-size: ${props => `var(--${props.fontSize || 'default'}Paragraph)`}; + font-weight: 300; + list-style: disc; + opacity: 0.75; + line-height: 1.444444444; + margin-bottom: 1rem; + } + + @media (min-width: 768px) { + margin-left: ${props => props.isInlineIcon && '60px'}; + } +`; + +const LinkWrap = styled.div` + margin-top: 60px; + + @media (min-width: 768px) { + display: inline-flex; + + a + a { + margin-left: 60px; + } + } + + @media (max-width: 768px) { + max-width: 250px; + + a + a { + margin-top: 15px; + } + } +`; diff --git a/packages/website/ts/@next/components/dropdowns/dropdown_developers.tsx b/packages/website/ts/@next/components/dropdowns/dropdown_developers.tsx new file mode 100644 index 000000000..96d88846b --- /dev/null +++ b/packages/website/ts/@next/components/dropdowns/dropdown_developers.tsx @@ -0,0 +1,180 @@ +import { Link } from '@0x/react-shared'; +import * as _ from 'lodash'; +import * as React from 'react'; +import styled, { withTheme } from 'styled-components'; + +import { Button } from 'ts/@next/components/button'; +import { Column, FlexWrap, WrapGrid } from 'ts/@next/components/newLayout'; +import { ThemeValuesInterface } from 'ts/@next/components/siteWrap'; +import { Heading } from 'ts/@next/components/text'; +import { WebsitePaths } from 'ts/types'; +import { constants } from 'ts/utils/constants'; + +interface Props { + theme: ThemeValuesInterface; +} + +interface LinkConfig { + label: string; + url: string; + shouldOpenInNewTab?: boolean; +} + +const introData: LinkConfig[] = [ + { + label: 'Build a relayer', + url: `${WebsitePaths.Wiki}#Build-A-Relayer`, + }, + { + label: 'Develop on Ethereum', + url: `${WebsitePaths.Wiki}#Ethereum-Development`, + }, + { + label: 'Make & take orders', + url: `${WebsitePaths.Wiki}#Create,-Validate,-Fill-Order`, + }, + { + label: 'Use networked liquidity', + url: `${WebsitePaths.Wiki}#Find,-Submit,-Fill-Order-From-Relayer`, + }, +]; + +const docsData: LinkConfig[] = [ + { + label: '0x.js', + url: WebsitePaths.ZeroExJs, + }, + { + label: '0x Connect', + url: WebsitePaths.Connect, + }, + { + label: 'Smart Contract', + url: WebsitePaths.SmartContracts, + }, +]; + +const linksData: LinkConfig[] = [ + { + label: 'Wiki', + url: WebsitePaths.Wiki, + }, + { + label: 'Github', + url: constants.URL_GITHUB_ORG, + shouldOpenInNewTab: true, + }, + { + label: 'Protocol specification', + url: constants.URL_PROTOCOL_SPECIFICATION, + shouldOpenInNewTab: true, + }, +]; + +export const DropdownDevelopers: React.FunctionComponent<Props> = withTheme((props: Props) => ( + <> + <DropdownWrap> + <div> + <Heading asElement="h4" size={14} color="inherit" marginBottom="15px" isMuted={0.35}> + Getting Started + </Heading> + + <StyledGrid isCentered={false} isWrapped={true}> + {_.map(introData, (item, index) => ( + <li> + <Link key={`introLink-${index}`} to={item.url}> + {item.label} + </Link> + </li> + ))} + </StyledGrid> + </div> + + <StyledWrap> + <Column width="calc(100% - 15px)"> + <Heading asElement="h4" size={14} color="inherit" marginBottom="15px" isMuted={0.35}> + Popular Docs + </Heading> + + <ul> + {_.map(docsData, (item, index) => ( + <li key={`docsLink-${index}`}> + <Link to={item.url} shouldOpenInNewTab={item.shouldOpenInNewTab}> + {item.label} + </Link> + </li> + ))} + </ul> + </Column> + + <Column width="calc(100% - 15px)"> + <Heading asElement="h4" size={14} color="inherit" marginBottom="15px" isMuted={0.35}> + Useful Links + </Heading> + + <ul> + {_.map(linksData, (item, index) => ( + <li key={`usefulLink-${index}`}> + <Link to={item.url} shouldOpenInNewTab={item.shouldOpenInNewTab}> + {item.label} + </Link> + </li> + ))} + </ul> + </Column> + </StyledWrap> + + <StyledLink + to={WebsitePaths.Docs} + bgColor={props.theme.dropdownButtonBg} + isAccentColor={true} + isNoBorder={true} + > + View All Documentation + </StyledLink> + </DropdownWrap> + </> +)); + +const DropdownWrap = styled.div` + padding: 15px 30px 75px 30px; + + a { + color: inherit; + } + + li { + margin: 8px 0; + } +`; + +const StyledGrid = styled(WrapGrid.withComponent('ul'))` + li { + width: 50%; + flex-shrink: 0; + } +`; + +const StyledWrap = styled(FlexWrap)` + padding-top: 20px; + margin-top: 30px; + position: relative; + + &:before { + content: ''; + width: 100%; + height: 1px; + background-color: ${props => props.theme.dropdownColor}; + opacity: 0.15; + position: absolute; + top: 0; + left: 0; + } +`; + +const StyledLink = styled(Button)` + width: 100%; + position: absolute; + bottom: 0; + left: 0; +`; diff --git a/packages/website/ts/@next/components/dropdowns/dropdown_products.tsx b/packages/website/ts/@next/components/dropdowns/dropdown_products.tsx new file mode 100644 index 000000000..886cee44a --- /dev/null +++ b/packages/website/ts/@next/components/dropdowns/dropdown_products.tsx @@ -0,0 +1,48 @@ +import * as _ from 'lodash'; +import * as React from 'react'; + +import { Link } from 'react-router-dom'; +import styled from 'styled-components'; +import { Heading, Paragraph } from 'ts/@next/components/text'; +import { WebsitePaths } from 'ts/types'; + +const navData = [ + { + title: '0x Instant', + description: 'Simple crypto purchasing', + url: WebsitePaths.Instant, + }, + { + title: '0x Launch Kit', + description: 'Build on the 0x protocol', + url: WebsitePaths.LaunchKit, + }, +]; + +export const DropdownProducts: React.FunctionComponent<{}> = () => ( + <List> + {_.map(navData, (item, index) => ( + <li key={`productLink-${index}`}> + <Link to={item.url}> + <Heading asElement="h3" color="inherit" isNoMargin={true} size="small"> + {item.title} + </Heading> + + {item.description && ( + <Paragraph color="inherit" isNoMargin={true} size="small" isMuted={0.5}> + {item.description} + </Paragraph> + )} + </Link> + </li> + ))} + </List> +); + +const List = styled.ul` + a { + padding: 15px 30px; + display: block; + color: inherit; + } +`; diff --git a/packages/website/ts/@next/components/footer.tsx b/packages/website/ts/@next/components/footer.tsx new file mode 100644 index 000000000..b30a0cc5e --- /dev/null +++ b/packages/website/ts/@next/components/footer.tsx @@ -0,0 +1,168 @@ +import { Link as SmartLink } from '@0x/react-shared'; +import * as _ from 'lodash'; +import * as React from 'react'; +import MediaQuery from 'react-responsive'; +import styled from 'styled-components'; + +import { Logo } from 'ts/@next/components/logo'; +import { Column, FlexWrap, WrapGrid } from 'ts/@next/components/newLayout'; +import { NewsletterForm } from 'ts/@next/components/newsletter_form'; +import { WebsitePaths } from 'ts/types'; +import { constants } from 'ts/utils/constants'; + +interface LinkInterface { + text: string; + url: string; + shouldOpenInNewTab?: boolean; +} + +interface LinkRows { + heading: string; + isOnMobile?: boolean; + links: LinkInterface[]; +} + +interface LinkListProps { + links: LinkInterface[]; +} + +const linkRows: LinkRows[] = [ + { + heading: 'Products', + isOnMobile: true, + links: [ + { url: WebsitePaths.Instant, text: '0x Instant' }, + { url: WebsitePaths.LaunchKit, text: '0x Launch Kit' }, + ], + }, + { + heading: 'Developers', + links: [ + { url: WebsitePaths.Docs, text: 'Documentation' }, + { url: constants.URL_GITHUB_ORG, text: 'GitHub', shouldOpenInNewTab: true }, + { url: constants.URL_PROTOCOL_SPECIFICATION, text: 'Protocol Spec', shouldOpenInNewTab: true }, + ], + }, + { + heading: 'About', + isOnMobile: true, + links: [ + { url: WebsitePaths.AboutMission, text: 'Mission' }, + { url: WebsitePaths.AboutTeam, text: 'Team' }, + { url: WebsitePaths.AboutJobs, text: 'Jobs' }, + { url: WebsitePaths.AboutPress, text: 'Press' }, + { url: WebsitePaths.Ecosystem, text: 'Grant Program' }, + ], + }, + { + heading: 'Community', + isOnMobile: true, + links: [ + { url: constants.URL_TWITTER, text: 'Twitter', shouldOpenInNewTab: true }, + { url: constants.URL_ZEROEX_CHAT, text: 'Discord Chat', shouldOpenInNewTab: true }, + { url: constants.URL_FACEBOOK, text: 'Facebook', shouldOpenInNewTab: true }, + { url: constants.URL_REDDIT, text: 'Reddit', shouldOpenInNewTab: true }, + ], + }, +]; + +export const Footer: React.StatelessComponent = () => ( + <FooterWrap> + <FlexWrap> + <FooterColumn width="35%"> + <Logo /> + <NewsletterForm /> + </FooterColumn> + + <FooterColumn width="55%"> + <WrapGrid isCentered={false} isWrapped={true}> + {_.map(linkRows, (row: LinkRows, index) => ( + <MediaQuery minWidth={row.isOnMobile ? 0 : 768} key={`fc-${index}`}> + <FooterSectionWrap> + <RowHeading>{row.heading}</RowHeading> + + <LinkList links={row.links} /> + </FooterSectionWrap> + </MediaQuery> + ))} + </WrapGrid> + </FooterColumn> + </FlexWrap> + </FooterWrap> +); + +const LinkList = (props: LinkListProps) => ( + <List> + {_.map(props.links, (link, index) => ( + <li key={`fl-${index}`}> + <Link to={link.url} shouldOpenInNewTab={link.shouldOpenInNewTab}> + {link.text} + </Link> + </li> + ))} + </List> +); + +const FooterWrap = styled.footer` + padding: 40px 30px 30px 30px; + margin-top: 30px; + background-color: ${props => props.theme.footerBg}; + color: ${props => props.theme.footerColor}; + + path { + fill: ${props => props.theme.footerColor}; + } + + @media (min-width: 768px) { + height: 350px; + } +`; + +const FooterColumn = styled(Column)` + @media (min-width: 768px) { + width: ${props => props.width}; + } + + @media (max-width: 768px) { + text-align: left; + } +`; + +const FooterSectionWrap = styled(FooterColumn)` + @media (max-width: 768px) { + width: 50%; + + & + & { + margin-top: 0; + margin-bottom: 30px; + } + } +`; + +const RowHeading = styled.h3` + color: inherit; + font-weight: 700; + font-size: 16px; + margin-bottom: 1.25em; + opacity: 0.75; +`; + +const List = styled.ul` + li + li { + margin-top: 8px; + } +`; + +const Link = styled(SmartLink)` + color: inherit; + opacity: 0.5; + display: block; + font-size: 16px; + line-height: 20px; + transition: opacity 0.25s; + text-decoration: none; + + &:hover { + opacity: 0.8; + } +`; diff --git a/packages/website/ts/@next/components/hamburger.tsx b/packages/website/ts/@next/components/hamburger.tsx new file mode 100644 index 000000000..435d206cd --- /dev/null +++ b/packages/website/ts/@next/components/hamburger.tsx @@ -0,0 +1,72 @@ +import * as React from 'react'; +import styled from 'styled-components'; + +interface Props { + isOpen: boolean; + onClick?: () => void; +} + +export const Hamburger: React.FunctionComponent<Props> = (props: Props) => { + return ( + <StyledHamburger isOpen={props.isOpen} onClick={props.onClick}> + <span /> + <span /> + <span /> + </StyledHamburger> + ); +}; + +const StyledHamburger = + styled.button < + Props > + ` + background: none; + border: 0; + width: 22px; + height: 16px; + position: relative; + z-index: 25; + padding: 0; + outline: none; + user-select: none; + + @media (min-width: 800px) { + display: none; + } + + span { + display: block; + background-color: ${props => props.theme.textColor}; + width: 100%; + height: 2px; + margin-bottom: 5px; + transform-origin: 4px 0px; + transition: transform 0.5s cubic-bezier(0.77,0.2,0.05,1.0), + background-color 0.5s cubic-bezier(0.77,0.2,0.05,1.0), + opacity 0.55s ease; + + &:first-child { + //transform-origin: 0% 0%; + } + + &:last-child { + //transform-origin: 0% 100%; + } + + ${props => + props.isOpen && + ` + opacity: 1; + transform: rotate(45deg) translate(0, 1px); + + &:nth-child(2) { + opacity: 0; + transform: rotate(0deg) scale(0.2, 0.2); + } + + &:last-child { + transform: rotate(-45deg) translate(1px, -4px); + } + `} + } +`; diff --git a/packages/website/ts/@next/components/header.tsx b/packages/website/ts/@next/components/header.tsx new file mode 100644 index 000000000..e886923df --- /dev/null +++ b/packages/website/ts/@next/components/header.tsx @@ -0,0 +1,252 @@ +import { Link } from '@0x/react-shared'; +import _ from 'lodash'; +import * as React from 'react'; +import MediaQuery from 'react-responsive'; +import styled, { css, withTheme } from 'styled-components'; + +import Headroom from 'react-headroom'; + +import { Button } from 'ts/@next/components/button'; +import { DropdownDevelopers } from 'ts/@next/components/dropdowns/dropdown_developers'; +import { DropdownProducts } from 'ts/@next/components/dropdowns/dropdown_products'; +import { Hamburger } from 'ts/@next/components/hamburger'; +import { Logo } from 'ts/@next/components/logo'; +import { MobileNav } from 'ts/@next/components/mobileNav'; +import { FlexWrap } from 'ts/@next/components/newLayout'; +import { ThemeValuesInterface } from 'ts/@next/components/siteWrap'; +import { WebsitePaths } from 'ts/types'; +import { constants } from 'ts/utils/constants'; + +interface HeaderProps { + location?: Location; + isNavToggled?: boolean; + toggleMobileNav?: () => void; + theme: ThemeValuesInterface; +} + +interface NavItemProps { + url?: string; + id?: string; + text?: string; + dropdownWidth?: number; + dropdownComponent?: React.FunctionComponent<any>; + shouldOpenInNewTab?: boolean; +} + +interface DropdownWrapInterface { + width?: number; +} + +const navItems: NavItemProps[] = [ + { + id: 'why', + url: WebsitePaths.Why, + text: 'Why 0x', + }, + { + id: 'products', + text: 'Products', + dropdownComponent: DropdownProducts, + dropdownWidth: 280, + }, + { + id: 'developers', + text: 'Developers', + dropdownComponent: DropdownDevelopers, + dropdownWidth: 480, + }, + { + id: 'about', + url: WebsitePaths.AboutMission, + text: 'About', + }, + { + id: 'blog', + url: constants.URL_BLOG, + shouldOpenInNewTab: true, + text: 'Blog', + }, +]; + +class HeaderBase extends React.Component<HeaderProps> { + public onUnpin = () => { + if (this.props.isNavToggled) { + this.props.toggleMobileNav(); + } + }; + + public render(): React.ReactNode { + const { isNavToggled, toggleMobileNav, theme } = this.props; + + return ( + <Headroom onUnpin={this.onUnpin} downTolerance={4} upTolerance={10}> + <StyledHeader isNavToggled={isNavToggled}> + <HeaderWrap> + <Link to={WebsitePaths.Home}> + <Logo /> + </Link> + + <NavLinks> + {_.map(navItems, (link, index) => <NavItem key={`navlink-${index}`} link={link} />)} + </NavLinks> + + <MediaQuery minWidth={990}> + <TradeButton bgColor={theme.headerButtonBg} color="#ffffff" href="/portal"> + Trade on 0x + </TradeButton> + </MediaQuery> + + <Hamburger isOpen={isNavToggled} onClick={toggleMobileNav} /> + <MobileNav isToggled={isNavToggled} toggleMobileNav={toggleMobileNav} /> + </HeaderWrap> + </StyledHeader> + </Headroom> + ); + } +} + +export const Header = withTheme(HeaderBase); + +const NavItem = (props: { link: NavItemProps; key: string }) => { + const { link } = props; + const Subnav = link.dropdownComponent; + const linkElement = _.isUndefined(link.url) ? ( + <StyledAnchor href="#">{link.text}</StyledAnchor> + ) : ( + <StyledNavLink to={link.url} shouldOpenInNewTab={link.shouldOpenInNewTab}> + {link.text} + </StyledNavLink> + ); + return ( + <LinkWrap> + {linkElement} + + {link.dropdownComponent && ( + <DropdownWrap width={link.dropdownWidth}> + <Subnav /> + </DropdownWrap> + )} + </LinkWrap> + ); +}; + +const StyledHeader = + styled.header < + HeaderProps > + ` + padding: 30px; + background-color: ${props => props.theme.bgColor}; +`; + +const LinkWrap = styled.li` + position: relative; + + a { + display: block; + } + + @media (min-width: 800px) { + &:hover > div { + display: block; + visibility: visible; + opacity: 1; + transform: translate3d(0, 0, 0); + transition: opacity 0.35s, transform 0.35s, visibility 0s; + } + } +`; + +const linkStyles = css` + color: ${props => props.theme.textColor}; + opacity: 0.5; + transition: opacity 0.35s; + padding: 15px 0; + margin: 0 30px; + + &:hover { + opacity: 1; + } +`; + +const StyledNavLink = styled(Link).attrs({ + activeStyle: { opacity: 1 }, +})` + ${linkStyles}; +`; + +const StyledAnchor = styled.a` + ${linkStyles}; + cursor: default; +`; + +const HeaderWrap = styled(FlexWrap)` + justify-content: space-between; + align-items: center; + + @media (max-width: 800px) { + padding-top: 0; + display: flex; + padding-bottom: 0; + } +`; + +const NavLinks = styled.ul` + display: flex; + align-items: center; + justify-content: space-between; + + @media (max-width: 800px) { + display: none; + } +`; + +const DropdownWrap = + styled.div < + DropdownWrapInterface > + ` + width: ${props => props.width || 280}px; + padding: 15px 0; + border: 1px solid transparent; + border-color: ${props => props.theme.dropdownBorderColor}; + background-color: ${props => props.theme.dropdownBg}; + color: ${props => props.theme.dropdownColor}; + position: absolute; + top: 100%; + left: calc(50% - ${props => (props.width || 280) / 2}px); + visibility: hidden; + opacity: 0; + transform: translate3d(0, -10px, 0); + transition: opacity 0.35s, transform 0.35s, visibility 0s 0.35s; + z-index: 20; + + &:after, &:before { + bottom: 100%; + left: 50%; + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; + pointer-events: none; + } + &:after { + border-color: rgba(255, 255, 255, 0); + border-bottom-color: ${props => props.theme.dropdownBg}; + border-width: 10px; + margin-left: -10px; + } + &:before { + border-color: rgba(255, 0, 0, 0); + border-bottom-color: ${props => props.theme.dropdownBorderColor}; + border-width: 11px; + margin-left: -11px; + } + + @media (max-width: 768px) { + display: none; + } +`; + +const TradeButton = styled(Button)` + padding: 14px 22px !important; +`; diff --git a/packages/website/ts/@next/components/hero.tsx b/packages/website/ts/@next/components/hero.tsx new file mode 100644 index 000000000..4c8874d3e --- /dev/null +++ b/packages/website/ts/@next/components/hero.tsx @@ -0,0 +1,152 @@ +import * as React from 'react'; +import styled from 'styled-components'; + +import { addFadeInAnimation } from 'ts/@next/constants/animations'; + +interface Props { + title: string; + maxWidth?: string; + maxWidthHeading?: string; + isLargeTitle?: boolean; + isFullWidth?: boolean; + isCenteredMobile?: boolean; + description: string; + figure?: React.ReactNode; + actions?: React.ReactNode; +} + +const Section = styled.section` + padding: 120px 0; + + @media (max-width: 768px) { + padding: 60px 0; + } +`; + +interface WrapProps { + isCentered?: boolean; + isFullWidth?: boolean; + isCenteredMobile?: boolean; +} +const Wrap = + styled.div < + WrapProps > + ` + width: calc(100% - 60px); + margin: 0 auto; + + @media (min-width: 768px) { + max-width: ${props => (!props.isFullWidth ? '895px' : '1136px')}; + flex-direction: row-reverse; + display: flex; + align-items: center; + text-align: ${props => props.isCentered && 'center'}; + justify-content: ${props => (props.isCentered ? 'center' : 'space-between')}; + } + + @media (max-width: 768px) { + text-align: ${props => (props.isCenteredMobile ? `center` : 'left')}; + } +`; + +interface TitleProps { + isLarge?: any; + maxWidth?: string; +} +const Title = + styled.h1 < + TitleProps > + ` + font-size: ${props => (props.isLarge ? '80px' : '50px')}; + font-weight: 300; + line-height: 1.1; + margin-left: auto; + margin-right: auto; + margin-bottom: 30px; + max-width: ${props => props.maxWidth}; + ${addFadeInAnimation('0.5s')} + + @media (max-width: 1024px) { + font-size: 60px; + } + + @media (max-width: 768px) { + font-size: 46px; + } +`; + +const Description = styled.p` + font-size: 22px; + line-height: 31px; + font-weight: 300; + padding: 0; + margin-bottom: 50px; + color: ${props => props.theme.introTextColor}; + ${addFadeInAnimation('0.5s', '0.15s')} @media (max-width: 1024px) { + margin-bottom: 30px; + } +`; + +const Content = + styled.div < + { width: string } > + ` + width: 100%; + + @media (min-width: 768px) { + max-width: ${props => props.width}; + } +`; + +const ButtonWrap = styled.div` + display: inline-flex; + align-items: center; + + * + * { + margin-left: 12px; + } + + > *:nth-child(1) { + ${addFadeInAnimation('0.6s', '0.3s')}; + } + > *:nth-child(2) { + ${addFadeInAnimation('0.6s', '0.4s')}; + } + + @media (max-width: 500px) { + flex-direction: column; + justify-content: center; + + * { + padding-left: 20px; + padding-right: 20px; + } + + * + * { + margin-left: 0; + margin-top: 12px; + } + } +`; + +export const Hero: React.StatelessComponent<Props> = (props: Props) => ( + <Section> + <Wrap isCentered={!props.figure} isFullWidth={props.isFullWidth} isCenteredMobile={props.isCenteredMobile}> + {props.figure && <Content width="400px">{props.figure}</Content>} + + <Content width={props.maxWidth ? props.maxWidth : props.figure ? '546px' : '678px'}> + <Title isLarge={props.isLargeTitle} maxWidth={props.maxWidthHeading}> + {props.title} + </Title> + + <Description>{props.description}</Description> + + {props.actions && <ButtonWrap>{props.actions}</ButtonWrap>} + </Content> + </Wrap> + </Section> +); + +Hero.defaultProps = { + isCenteredMobile: true, +}; diff --git a/packages/website/ts/@next/components/heroAnimation.tsx b/packages/website/ts/@next/components/heroAnimation.tsx new file mode 100644 index 000000000..42956fb6a --- /dev/null +++ b/packages/website/ts/@next/components/heroAnimation.tsx @@ -0,0 +1,123 @@ +import * as React from 'react'; +import styled, { keyframes } from 'styled-components'; + +export const HeroAnimation = () => ( + <Image width="404" height="404" viewBox="0 0 404 404" fill="none" xmlns="http://www.w3.org/2000/svg"> + <mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="404" height="404"> + <circle cx="202" cy="202" r="200" fill="#00AE99" stroke="#00AE99" stroke-width="3" /> + </mask> + <g mask="url(#mask0)"> + <circle cx="202" cy="202" r="200" stroke="#00AE99" strokeWidth="3" /> + <TopCircle + vector-effect="non-scaling-stroke" + cx="201.667" + cy="68.6667" + r="66.6667" + stroke="#00AE99" + strokeWidth="3" + /> + <LeftCircle + vector-effect="non-scaling-stroke" + cx="68.6667" + cy="202.667" + r="66.6667" + stroke="#00AE99" + strokeWidth="3" + /> + <Logo + vector-effect="non-scaling-stroke" + d="M168.17 260.29L167.271 259.089L165.46 260.444L167.413 261.585L168.17 260.29ZM197.32 269.2L197.219 270.696L197.226 270.697L197.32 269.2ZM237.414 258.856L238.22 260.12L238.225 260.117L237.414 258.856ZM252.653 245.439L253.801 246.405L254.55 245.515L253.874 244.568L252.653 245.439ZM241.096 229.872L242.285 228.958L242.281 228.952L242.276 228.946L241.096 229.872ZM237.72 225.571L238.901 224.645L237.582 222.965L236.449 224.775L237.72 225.571ZM219.719 241.445L218.672 242.519L219.418 243.246L220.36 242.801L219.719 241.445ZM208.264 230.282L209.311 229.207L208.392 228.312L207.365 229.081L208.264 230.282ZM143.827 169.549L145.02 168.64L143.647 166.838L142.524 168.806L143.827 169.549ZM135.133 198.43L133.637 198.329L133.636 198.337L135.133 198.43ZM145.464 238.577L144.201 239.388L145.464 238.577ZM158.862 253.837L157.895 254.984L158.786 255.736L159.735 255.057L158.862 253.837ZM174.409 242.264L175.324 243.453L175.33 243.448L175.336 243.443L174.409 242.264ZM178.705 238.885L179.632 240.064L181.287 238.761L179.516 237.623L178.705 238.885ZM162.851 220.757L161.78 219.707L161.049 220.452L161.495 221.397L162.851 220.757ZM174.102 209.286L175.173 210.337L176.082 209.41L175.295 208.377L174.102 209.286ZM235.163 145.072L236.036 146.292L237.92 144.945L235.92 143.777L235.163 145.072ZM206.014 136.162L205.91 137.658L205.913 137.658L206.014 136.162ZM165.817 146.506L166.629 147.767L166.632 147.765L165.817 146.506ZM150.578 159.922L149.43 158.956L148.681 159.846L149.357 160.793L150.578 159.922ZM162.135 175.489L160.946 176.403L160.951 176.409L160.955 176.415L162.135 175.489ZM165.511 179.791L164.331 180.717L165.634 182.378L166.773 180.6L165.511 179.791ZM183.614 163.916L184.655 162.836L183.913 162.122L182.98 162.557L183.614 163.916ZM194.354 174.26L193.313 175.341L194.212 176.206L195.226 175.48L194.354 174.26ZM259.608 235.505L258.411 236.409L259.789 238.233L260.914 236.243L259.608 235.505ZM268.2 206.931L269.696 207.033L269.697 207.024L268.2 206.931ZM257.87 166.784L259.135 165.979L259.132 165.974L257.87 166.784ZM244.471 151.524L245.439 150.378L244.547 149.625L243.598 150.304L244.471 151.524ZM228.924 163.097L228.009 161.909L228.003 161.913L227.997 161.918L228.924 163.097ZM224.629 166.477L223.701 165.298L222.034 166.609L223.826 167.744L224.629 166.477ZM240.584 184.604L239.228 185.244L239.235 185.259L239.242 185.274L240.584 184.604ZM240.687 184.809L241.767 185.849L242.502 185.086L242.029 184.139L240.687 184.809ZM229.845 196.075L228.764 195.035L227.877 195.957L228.648 196.979L229.845 196.075ZM167.413 261.585C176.201 266.718 186.346 269.964 197.219 270.696L197.421 267.703C187.019 267.002 177.321 263.898 168.926 258.994L167.413 261.585ZM197.226 270.697C212.283 271.639 226.405 267.659 238.22 260.12L236.607 257.591C225.307 264.8 211.813 268.604 197.413 267.703L197.226 270.697ZM238.225 260.117C244.08 256.348 249.307 251.742 253.801 246.405L251.506 244.473C247.204 249.583 242.203 253.989 236.602 257.594L238.225 260.117ZM253.874 244.568C250.283 239.533 246.385 234.295 242.285 228.958L239.906 230.786C243.989 236.1 247.864 241.309 251.432 246.31L253.874 244.568ZM242.276 228.946C241.713 228.229 241.151 227.512 240.588 226.795C240.026 226.078 239.463 225.362 238.901 224.645L236.54 226.497C237.103 227.213 237.665 227.93 238.228 228.647C238.791 229.364 239.353 230.081 239.916 230.798L242.276 228.946ZM236.449 224.775C232.311 231.384 226.193 236.725 219.078 240.089L220.36 242.801C227.974 239.201 234.538 233.481 238.992 226.367L236.449 224.775ZM220.766 240.371L209.311 229.207L207.217 231.356L218.672 242.519L220.766 240.371ZM207.365 229.081L167.271 259.089L169.069 261.49L209.163 231.483L207.365 229.081ZM142.524 168.806C137.505 177.601 134.368 187.549 133.637 198.329L136.63 198.532C137.33 188.214 140.33 178.703 145.13 170.293L142.524 168.806ZM133.636 198.337C132.696 213.409 136.668 227.654 144.201 239.388L146.726 237.767C139.531 226.56 135.73 212.947 136.63 198.524L133.636 198.337ZM144.201 239.388C147.965 245.25 152.565 250.484 157.895 254.984L159.83 252.691C154.727 248.383 150.327 243.376 146.726 237.767L144.201 239.388ZM159.735 255.057C164.764 251.461 169.994 247.558 175.324 243.453L173.494 241.076C168.187 245.164 162.985 249.045 157.99 252.617L159.735 255.057ZM175.336 243.443C176.768 242.317 178.2 241.19 179.632 240.064L177.777 237.706C176.345 238.832 174.913 239.959 173.481 241.086L175.336 243.443ZM179.516 237.623C172.904 233.374 167.568 227.241 164.208 220.117L161.495 221.397C165.09 229.021 170.8 235.588 177.894 240.147L179.516 237.623ZM163.922 221.807L175.173 210.337L173.031 208.236L161.78 219.707L163.922 221.807ZM175.295 208.377L145.02 168.64L142.634 170.458L172.909 210.196L175.295 208.377ZM235.92 143.777C227.132 138.643 216.987 135.398 206.114 134.665L205.913 137.658C216.315 138.359 226.012 141.463 234.407 146.367L235.92 143.777ZM206.118 134.665C191.055 133.618 176.824 137.599 165.003 145.246L166.632 147.765C177.926 140.459 191.515 136.657 205.91 137.658L206.118 134.665ZM165.006 145.244C159.151 149.013 153.924 153.619 149.43 158.956L151.725 160.888C156.027 155.779 161.028 151.372 166.629 147.767L165.006 145.244ZM149.357 160.793C152.948 165.828 156.846 171.066 160.946 176.403L163.325 174.575C159.242 169.261 155.367 164.052 151.799 159.051L149.357 160.793ZM160.955 176.415C161.518 177.132 162.08 177.849 162.643 178.566C163.205 179.283 163.768 180 164.331 180.717L166.691 178.865C166.128 178.148 165.566 177.431 165.003 176.714C164.441 175.997 163.878 175.28 163.315 174.563L160.955 176.415ZM166.773 180.6C171.021 173.973 177.044 168.635 184.248 165.276L182.98 162.557C175.251 166.161 168.796 171.885 164.248 178.981L166.773 180.6ZM182.574 164.997L193.313 175.341L195.394 173.18L184.655 162.836L182.574 164.997ZM195.226 175.48L236.036 146.292L234.291 143.852L193.481 173.04L195.226 175.48ZM260.914 236.243C265.827 227.556 268.964 217.713 269.696 207.033L266.703 206.828C266.003 217.042 263.004 226.453 258.303 234.767L260.914 236.243ZM269.697 207.024C270.638 191.949 266.663 177.81 259.135 165.979L256.604 167.589C263.804 178.904 267.603 192.417 266.703 206.837L269.697 207.024ZM259.132 165.974C255.368 160.111 250.769 154.878 245.439 150.378L243.503 152.67C248.606 156.978 253.007 161.986 256.607 167.594L259.132 165.974ZM243.598 150.304C238.57 153.901 233.339 157.803 228.009 161.909L229.84 164.285C235.147 160.197 240.349 156.316 245.344 152.744L243.598 150.304ZM227.997 161.918C227.281 162.481 226.565 163.045 225.849 163.608C225.133 164.171 224.417 164.734 223.701 165.298L225.556 167.656C226.272 167.092 226.988 166.529 227.704 165.966C228.42 165.402 229.136 164.839 229.852 164.276L227.997 161.918ZM223.826 167.744C230.535 171.992 235.869 178.121 239.228 185.244L241.941 183.964C238.345 176.339 232.632 169.769 225.431 165.209L223.826 167.744ZM239.242 185.274L239.345 185.479L242.029 184.139L241.926 183.934L239.242 185.274ZM239.606 183.769L228.764 195.035L230.926 197.115L241.767 185.849L239.606 183.769ZM228.648 196.979L258.411 236.409L260.806 234.601L231.042 195.171L228.648 196.979Z" + fill="#00AE99" + /> + <Rectangle + vector-effect="non-scaling-stroke" + d="M269 135V268.333H442V135H269Z" + stroke="#00AE99" + strokeWidth="3" + /> + <Square + vector-effect="non-scaling-stroke" + d="M339.64 269.64L270 339.281L343.913 413.194L413.554 343.554L339.64 269.64Z" + stroke="#00AE99" + strokeWidth="3" + /> + <Oblong + vector-effect="non-scaling-stroke" + d="M202.5 269C202.5 269 269 269 269 335.5C269 402 202.5 402 202.5 402H-6.5C-6.5 402 -77 402 -77 335.5C-77 269 -6.5 269 -6.5 269H202.5Z" + stroke="#00AE99" + strokeWidth="3" + /> + </g> + </Image> +); + +const moveUp = keyframes` + 0% { transform: translate3d(0, 0, 0) } + 45% { transform: translate3d(0, 0, 0) } + 55% { transform: translate3d(0, -7%, 0) } + 85% { transform: translate3d(0, -7%, 0) } + 100% { transform: translate3d(0, 0, 0) } +`; + +const moveLeft = keyframes` + 0% { transform: translate3d(0, 0, 0) } + 45% { transform: translate3d(0, 0, 0) } + 55% { transform: translate3d(-7%, 0, 0) } + 85% { transform: translate3d(-7%, 0, 0) } + 100% { transform: translate3d(0, 0, 0) } +`; + +const moveDiag = keyframes` + 0% { transform: translate3d(0, 0, 0) } + 45% { transform: translate3d(0, 0, 0) } + 55% { transform: translate3d(5%, 5%, 0) } + 85% { transform: translate3d(5%, 5%, 0) } + 100% { transform: translate3d(0, 0, 0) } +`; + +const moveRight = keyframes` + 0% { transform: translate3d(0, 0, 0) } + 45% { transform: translate3d(0, 0, 0) } + 55% { transform: translate3d(7%, 0, 0) } + 85% { transform: translate3d(7%, 0, 0) } + 100% { transform: translate3d(0, 0, 0) } +`; + +const spin = keyframes` + 0% { transform: rotate(0deg) } + 65% { transform: rotate(0deg) } + 85% { transform: rotate(90deg) } + 100% { transform: rotate(90deg) } +`; + +const moveIn = keyframes` + 0% { opacity: 0; transform: scale(1.7) rotate(-30deg) } + 100% { opacity: 1; transform: scale(1) rotate(0deg) } +`; + +const Image = styled.svg` + opacity: 0; + transform: scale(1.5) rotate(-30deg); + animation: ${moveIn} 2s forwards; +`; + +const TopCircle = styled.circle` + animation: ${moveUp} 4s -2.85s infinite; +`; +const LeftCircle = styled.circle` + animation: ${moveLeft} 4s -2.85s infinite; +`; +const Oblong = styled.path` + animation: ${moveLeft} 4s -2.85s infinite; +`; +const Square = styled.path` + animation: ${moveDiag} 4s -2.85s infinite; +`; +const Rectangle = styled.path` + animation: ${moveRight} 4s -2.85s infinite; +`; + +const Logo = styled.path` + animation: ${spin} 4s -2.8s infinite; + transform-origin: 202px 202.7px; +`; diff --git a/packages/website/ts/@next/components/heroImage.tsx b/packages/website/ts/@next/components/heroImage.tsx new file mode 100644 index 000000000..af7c055ac --- /dev/null +++ b/packages/website/ts/@next/components/heroImage.tsx @@ -0,0 +1,27 @@ +import * as React from 'react'; +import styled from 'styled-components'; + +interface Props { + image: React.ReactNode; +} + +export const LandingAnimation = (props: Props) => <Wrap>{props.image}</Wrap>; + +const Wrap = styled.figure` + display: inline-block; + + svg { + width: 100%; + height: auto; + } + + @media (min-width: 768px) { + width: 100%; + max-width: 400px; + } + + @media (max-width: 768px) { + width: 180px; + margin-bottom: 40px; + } +`; diff --git a/packages/website/ts/@next/components/icon.tsx b/packages/website/ts/@next/components/icon.tsx new file mode 100644 index 000000000..fc9d488f9 --- /dev/null +++ b/packages/website/ts/@next/components/icon.tsx @@ -0,0 +1,72 @@ +import * as React from 'react'; +import Loadable from 'react-loadable'; +import styled from 'styled-components'; + +import { Paragraph } from 'ts/@next/components/text'; +import { getCSSPadding, PaddingInterface } from 'ts/@next/constants/utilities'; + +interface IconProps extends PaddingInterface { + name?: string; + component?: React.ReactNode; + size?: 'small' | 'medium' | 'large' | 'hero' | number; +} + +export const Icon: React.FunctionComponent<IconProps> = (props: IconProps) => { + if (props.name && !props.component) { + const IconSVG = Loadable({ + loader: async () => import(/* webpackChunkName: "icon" */ `ts/@next/icons/illustrations/${props.name}.svg`), + loading: () => <Paragraph>Loading</Paragraph>, + }); + + return ( + <StyledIcon {...props}> + <IconSVG /> + </StyledIcon> + ); + } + + if (props.component) { + return <StyledIcon {...props}>{props.component}</StyledIcon>; + } + + return null; +}; + +export const InlineIconWrap = + styled.div < + PaddingInterface > + ` + margin: ${props => getCSSPadding(props.margin)}; + display: flex; + align-items: center; + justify-content: center; + + > figure { + margin: 0 5px; + } +`; + +const _getSize = (size: string | number = 'small'): string => { + if (typeof size === 'string') { + return `var(--${size}Icon)`; + } + + return `${size}px`; +}; + +const StyledIcon = + styled.figure < + IconProps > + ` + width: ${props => _getSize(props.size)}; + height: ${props => _getSize(props.size)}; + margin: ${props => getCSSPadding(props.margin)}; + display: inline-block; + flex-shrink: 0; + + svg { + width: 100%; + height: 100%; + object-fit: cover; + } +`; diff --git a/packages/website/ts/@next/components/image.tsx b/packages/website/ts/@next/components/image.tsx new file mode 100644 index 000000000..65b2a9705 --- /dev/null +++ b/packages/website/ts/@next/components/image.tsx @@ -0,0 +1,20 @@ +import * as React from 'react'; +import styled from 'styled-components'; + +interface Props { + alt?: string; + src?: any; + srcset?: any; + isCentered?: boolean; +} + +const ImageClass: React.FunctionComponent<Props> = (props: Props) => { + return <img {...props} />; +}; + +export const Image = + styled(ImageClass) < + Props > + ` + margin: ${props => props.isCentered && `0 auto`}; +`; diff --git a/packages/website/ts/@next/components/layout.tsx b/packages/website/ts/@next/components/layout.tsx new file mode 100644 index 000000000..770ee159c --- /dev/null +++ b/packages/website/ts/@next/components/layout.tsx @@ -0,0 +1,177 @@ +import styled from 'styled-components'; +import { getCSSPadding, PADDING_SIZES, PaddingInterface } from 'ts/@next/constants/utilities'; + +interface WrapWidths { + default: string; + full: string; + medium: string; + narrow: string; + [key: string]: string; +} + +interface ColumnWidths { + [key: string]: string; +} + +interface SectionProps { + isNoPadding?: boolean; + isPadLarge?: boolean; + isNoMargin?: boolean; + bgColor?: string; + isFullWidth?: boolean; + isRelative?: boolean; +} + +interface WrapProps extends PaddingInterface { + width?: 'default' | 'full' | 'medium' | 'narrow'; + bgColor?: string; + isWrapped?: boolean; + isCentered?: boolean; + isReversed?: boolean; +} + +interface ColumnProps { + colWidth?: '1/4' | '1/3' | '1/2' | '2/3'; + isNoPadding?: boolean; + isNoMargin?: boolean; + isPadLarge?: boolean; + isFlexGrow?: boolean; + isMobileCentered?: boolean; + bgColor?: string; +} + +interface GetColWidthArgs { + span?: number; + columns: number; +} + +export interface WrapStickyInterface { + offsetTop?: string; +} + +const _getColumnWidth = (args: GetColWidthArgs): string => { + const { span = 1, columns } = args; + const percentWidth = span / columns * 100; + const gutterDiff = GUTTER * (columns - 1) / columns; + return `calc(${percentWidth}% - ${gutterDiff}px)`; +}; + +const GUTTER = 30 as number; +const MAX_WIDTH = 1500; +export const BREAKPOINTS = { + mobile: '768px', +}; +const WRAPPER_WIDTHS: WrapWidths = { + default: `${MAX_WIDTH}px`, // tbd + full: '100%', + medium: '1136px', + narrow: '930px', +}; +const COLUMN_WIDTHS: ColumnWidths = { + '1/4': _getColumnWidth({ columns: 4 }), + '1/3': _getColumnWidth({ columns: 3 }), + '1/2': _getColumnWidth({ columns: 2 }), + '2/3': _getColumnWidth({ span: 2, columns: 3 }), +}; + +export const Main = styled.main` + max-width: ${MAX_WIDTH}px; + margin: 0 auto; + + @media (min-width: ${BREAKPOINTS.mobile}) { + width: calc(100% - 60px); + } +`; + +// We can also turn Section into a stateless comp, +// passing a asElement (same patter nas Heading) so we dont have to +// make a const on every route to withComponent-size it. +// just <Section asElement?="div/section/footer/header/whatever" /> ? +export const Section = + styled.section < + SectionProps > + ` + width: ${props => (props.isFullWidth ? `calc(100% + ${GUTTER * 2}px)` : '100%')}; + padding: ${props => !props.isNoPadding && (props.isPadLarge ? `${PADDING_SIZES.large}` : PADDING_SIZES.default)}; + background-color: ${props => props.bgColor}; + position: ${props => props.isRelative && 'relative'}; + overflow: ${props => props.isRelative && 'hidden'}; + margin-bottom: ${props => !props.isNoMargin && `${GUTTER}px`}; + + @media (min-width: 1560px) { + width: ${props => props.isFullWidth && '100vw'}; + margin-left: ${props => props.isFullWidth && `calc(750px - 50vw)`}; + } + + @media (max-width: ${BREAKPOINTS.mobile}) { + margin-bottom: ${props => !props.isNoMargin && `${GUTTER / 2}px`}; + padding: ${props => + props.isPadLarge ? `${PADDING_SIZES.large} ${PADDING_SIZES.default}` : PADDING_SIZES.default}; + } +`; + +const WrapBase = + styled.div < + WrapProps > + ` + max-width: ${props => WRAPPER_WIDTHS[props.width || 'default']}; + padding: ${props => props.padding && getCSSPadding(props.padding)}; + background-color: ${props => props.bgColor}; + margin: 0 auto; +`; + +export const Wrap = styled(WrapBase)` + @media (min-width: ${BREAKPOINTS.mobile}) { + display: flex; + justify-content: space-between; + flex-wrap: wrap; + flex-direction: ${props => props.isReversed && 'row-reverse'}; + } +`; + +export const WrapCentered = styled(WrapBase)` + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + text-align: center; +`; + +export const WrapSticky = + styled.div < + WrapStickyInterface > + ` + position: sticky; + top: ${props => props.offsetTop || '60px'}; +`; + +export const WrapGrid = styled(WrapBase)` + display: flex; + flex-wrap: ${props => props.isWrapped && `wrap`}; + justify-content: ${props => (props.isCentered ? `center` : 'space-between')}; +`; + +export const Column = + styled.div < + ColumnProps > + ` + background-color: ${props => props.bgColor}; + flex-grow: ${props => props.isFlexGrow && 1}; + + @media (min-width: ${BREAKPOINTS.mobile}) { + padding: ${props => + !props.isNoPadding && + (props.isPadLarge ? `${PADDING_SIZES.large} ${PADDING_SIZES.default}` : PADDING_SIZES.default)}; + width: ${props => (props.colWidth ? COLUMN_WIDTHS[props.colWidth] : '100%')}; + } + + @media (max-width: ${BREAKPOINTS.mobile}) { + padding: ${props => !props.isNoPadding && (props.isPadLarge ? '40px 30px' : 0)}; + margin-bottom: 20px; + text-align: ${props => props.isMobileCentered && 'center'}; + } +`; + +WrapGrid.defaultProps = { + isCentered: true, +}; diff --git a/packages/website/ts/@next/components/link.tsx b/packages/website/ts/@next/components/link.tsx new file mode 100644 index 000000000..080a0abcc --- /dev/null +++ b/packages/website/ts/@next/components/link.tsx @@ -0,0 +1,64 @@ +import { Link as SmartLink } from '@0x/react-shared'; +import * as React from 'react'; +import styled from 'styled-components'; + +interface LinkInterface { + color?: string; + children?: React.ReactNode | string; + isNoArrow?: boolean; + hasIcon?: boolean | string; + isBlock?: boolean; + isCentered?: boolean; + href?: string; + theme?: { + textColor: string; + }; + shouldOpenInNewTab?: boolean; + target?: string; +} + +export const Link = (props: LinkInterface) => { + const { children, isNoArrow, href } = props; + + return ( + <StyledLink to={href} {...props}> + {children} + {!isNoArrow && ( + <svg width="25" height="25" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path + d="M8.484 5.246l.023 1.411 8.147.053L4.817 18.547l.996.996L17.65 7.706l.052 8.146 1.411.024-.068-10.561-10.561-.069z" + fill="currentColor" + /> + </svg> + )} + </StyledLink> + ); +}; + +// Added this, & + & doesnt really work since we switch with element types... +export const LinkWrap = styled.div` + a + a, + a + button, + button + a { + margin-left: 20px; + } +`; + +const StyledLink = + styled(SmartLink) < + LinkInterface > + ` + display: ${props => !props.isBlock && 'inline-flex'}; + color: ${props => props.color || props.theme.linkColor}; + text-align: center; + font-size: 18px; + text-decoration: none; + align-items: center; + + @media (max-width: 768px) { + } + + svg { + margin-left: 3px; + } +`; diff --git a/packages/website/ts/@next/components/logo.tsx b/packages/website/ts/@next/components/logo.tsx new file mode 100644 index 000000000..227d48ee0 --- /dev/null +++ b/packages/website/ts/@next/components/logo.tsx @@ -0,0 +1,41 @@ +import * as React from 'react'; +import styled from 'styled-components'; + +import { ThemeInterface } from 'ts/@next/components/siteWrap'; +import LogoIcon from 'ts/@next/icons/logo-with-type.svg'; + +interface LogoInterface { + theme?: ThemeInterface; +} + +// Note let's refactor this +// is it absolutely necessary to have a stateless component +// to pass props down into the styled icon? +const StyledLogo = styled.div` + text-align: left; + position: relative; + z-index: 25; + + @media (max-width: 800px) { + svg { + width: 60px; + } + } +`; + +const Icon = + styled(LogoIcon) < + LogoInterface > + ` + flex-shrink: 0; + + path { + fill: ${props => props.theme.textColor}; + } +`; + +export const Logo: React.StatelessComponent<LogoInterface> = (props: LogoInterface) => ( + <StyledLogo> + <Icon {...props} /> + </StyledLogo> +); diff --git a/packages/website/ts/@next/components/mobileNav.tsx b/packages/website/ts/@next/components/mobileNav.tsx new file mode 100644 index 000000000..13cf46fca --- /dev/null +++ b/packages/website/ts/@next/components/mobileNav.tsx @@ -0,0 +1,121 @@ +import * as React from 'react'; +import MediaQuery from 'react-responsive'; +import styled from 'styled-components'; + +import { Link } from 'react-router-dom'; + +import { WrapGrid, WrapProps } from 'ts/@next/components/newLayout'; +import { WebsitePaths } from 'ts/types'; + +interface Props { + isToggled: boolean; + toggleMobileNav: () => void; +} + +export class MobileNav extends React.PureComponent<Props> { + public render(): React.ReactNode { + const { isToggled, toggleMobileNav } = this.props; + + return ( + <MediaQuery maxWidth={800}> + <Wrap isToggled={isToggled}> + <Section> + <h4>Products</h4> + + <ul> + <li> + <Link to={WebsitePaths.Instant}>0x Instant</Link> + </li> + <li> + <Link to={WebsitePaths.LaunchKit}>0x Launch Kit</Link> + </li> + </ul> + </Section> + + <Section isDark={true}> + <Grid as="ul" isFullWidth={true} isWrapped={true}> + <li> + <Link to={WebsitePaths.Why}>Why 0x</Link> + </li> + <li> + <Link to={WebsitePaths.AboutMission}>About</Link> + </li> + <li> + <a href="https://blog.0xproject.com/latest" target="_blank"> + Blog + </a> + </li> + </Grid> + </Section> + + {isToggled && <Overlay onClick={toggleMobileNav} />} + </Wrap> + </MediaQuery> + ); + } +} + +const Wrap = + styled.nav < + { isToggled: boolean } > + ` + width: 100%; + height: 357px; + background-color: ${props => props.theme.mobileNavBgUpper}; + color: ${props => props.theme.mobileNavColor}; + transition: ${props => (props.isToggled ? 'visibility 0s, transform 0.5s' : 'visibility 0s 0.5s, transform 0.5s')}; + transform: translate3d(0, ${props => (props.isToggled ? 0 : '-100%')}, 0); + visibility: ${props => !props.isToggled && 'hidden'}; + position: fixed; + display: flex; + flex-direction: column; + justify-content: flex-end; + z-index: 20; + top: 0; + left: 0; + font-size: 20px; + + a { + padding: 15px 0; + display: block; + color: inherit; + } + + h4 { + font-size: 14px; + opacity: 0.5; + } +`; + +const Overlay = styled.div` + position: absolute; + width: 100vw; + height: 100vh; + top: 100%; + background: transparent; + cursor: pointer; +`; + +interface SectionProps { + isDark?: boolean; +} +const Section = + styled.div < + SectionProps > + ` + width: 100%; + padding: 15px 30px; + background-color: ${props => (props.isDark ? props.theme.mobileNavBgLower : 'transparent')}; +`; + +const Grid = + styled(WrapGrid) < + WrapProps > + ` + justify-content: flex-start; + + li { + width: 50%; + flex-shrink: 0; + } +`; diff --git a/packages/website/ts/@next/components/modals/input.tsx b/packages/website/ts/@next/components/modals/input.tsx new file mode 100644 index 000000000..8cfcc9763 --- /dev/null +++ b/packages/website/ts/@next/components/modals/input.tsx @@ -0,0 +1,95 @@ +import * as React from 'react'; +import styled from 'styled-components'; + +export enum InputWidth { + Half, + Full, +} + +interface InputProps { + name: string; + width?: InputWidth; + label: string; + type?: string; + errors?: ErrorProps; + isErrors?: boolean; + required?: boolean; +} + +interface ErrorProps { + [key: string]: string; +} + +export const Input = React.forwardRef((props: InputProps, ref?: React.Ref<HTMLInputElement>) => { + const { name, label, type, errors } = props; + const id = `input-${name}`; + const componentType = type === 'textarea' ? 'textarea' : 'input'; + const isErrors = errors.hasOwnProperty(name) && errors[name] !== null; + const errorMessage = isErrors ? errors[name] : null; + + return ( + <InputWrapper {...props}> + <Label htmlFor={id}>{label}</Label> + <StyledInput as={componentType} ref={ref} id={id} isErrors={isErrors} {...props} /> + {isErrors && <Error>{errorMessage}</Error>} + </InputWrapper> + ); +}); + +Input.defaultProps = { + width: InputWidth.Full, + errors: {}, +}; + +const StyledInput = styled.input` + appearance: none; + background-color: #fff; + border: 1px solid #d5d5d5; + color: #000; + font-size: 1.294117647rem; + padding: 16px 15px 14px; + outline: none; + width: 100%; + min-height: ${props => props.type === 'textarea' && `120px`}; + + background-color: ${(props: InputProps) => props.isErrors && `#FDEDED`}; + border-color: ${(props: InputProps) => props.isErrors && `#FD0000`}; + + &::placeholder { + color: #c3c3c3; + } +`; + +const InputWrapper = + styled.div < + InputProps > + ` + position: relative; + flex-grow: ${props => props.width === InputWidth.Full && 1}; + width: ${props => props.width === InputWidth.Half && `calc(50% - 15px)`}; + + @media (max-width: 768px) { + width: 100%; + margin-bottom: 30px; + } +`; + +const Label = styled.label` + color: #000; + font-size: 1.111111111rem; + line-height: 1.4em; + margin-bottom: 10px; + display: inline-block; +`; + +const Error = styled.span` + color: #fd0000; + font-size: 0.833333333rem; + line-height: 1em; + display: inline-block; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + transform: translateY(24px); +`; diff --git a/packages/website/ts/@next/components/modals/modal_contact.tsx b/packages/website/ts/@next/components/modals/modal_contact.tsx new file mode 100644 index 000000000..b97baf5e7 --- /dev/null +++ b/packages/website/ts/@next/components/modals/modal_contact.tsx @@ -0,0 +1,278 @@ +import * as _ from 'lodash'; +import * as React from 'react'; +import styled from 'styled-components'; + +import { colors } from 'ts/style/colors'; + +import { DialogContent, DialogOverlay } from '@reach/dialog'; +import '@reach/dialog/styles.css'; + +import { Button } from 'ts/@next/components/button'; +import { Icon } from 'ts/@next/components/icon'; +import { Input, InputWidth } from 'ts/@next/components/modals/input'; +import { Heading, Paragraph } from 'ts/@next/components/text'; +import { GlobalStyle } from 'ts/@next/constants/globalStyle'; + +interface Props { + theme?: GlobalStyle; + isOpen?: boolean; + onDismiss?: () => void; +} + +interface FormProps { + isSuccessful?: boolean; + isSubmitting?: boolean; +} + +interface ErrorResponseProps { + param: string; + location: string; + msg: string; +} + +interface ErrorResponse { + errors: ErrorResponseProps[]; +} + +interface ErrorProps { + [key: string]: string; +} + +export class ModalContact extends React.Component<Props> { + public state = { + isSubmitting: false, + isSuccessful: false, + errors: {}, + }; + public nameRef: React.RefObject<HTMLInputElement> = React.createRef(); + public emailRef: React.RefObject<HTMLInputElement> = React.createRef(); + public companyProjectRef: React.RefObject<HTMLInputElement> = React.createRef(); + public linkRef: React.RefObject<HTMLInputElement> = React.createRef(); + public commentsRef: React.RefObject<HTMLInputElement> = React.createRef(); + public constructor(props: Props) { + super(props); + } + public render(): React.ReactNode { + const { isOpen, onDismiss } = this.props; + const { isSuccessful, errors } = this.state; + + return ( + <> + <DialogOverlay + style={{ background: 'rgba(0, 0, 0, 0.75)', zIndex: 30 }} + isOpen={isOpen} + onDismiss={onDismiss} + > + <StyledDialogContent> + <Form onSubmit={this._onSubmitAsync.bind(this)} isSuccessful={isSuccessful}> + <Heading color={colors.textDarkPrimary} size={34} asElement="h2"> + Contact the 0x Core Team + </Heading> + <Paragraph isMuted={true} color={colors.textDarkPrimary}> + If you're considering building on 0x, we're happy to answer your questions. Fill out the + form so we can connect you with the right person to help you get started. + </Paragraph> + <InputRow> + <Input + name="name" + label="Your name" + type="text" + width={InputWidth.Half} + ref={this.nameRef} + required={true} + errors={errors} + /> + <Input + name="email" + label="Your email" + type="email" + ref={this.emailRef} + required={true} + errors={errors} + width={InputWidth.Half} + /> + </InputRow> + <InputRow> + <Input + name="companyOrProject" + label="Name of your project / company" + type="text" + ref={this.companyProjectRef} + required={true} + errors={errors} + /> + </InputRow> + <InputRow> + <Input + name="link" + label="Do you have any documentation or a website?" + type="text" + ref={this.linkRef} + errors={errors} + /> + </InputRow> + <InputRow> + <Input + name="comments" + label="Anything else?" + type="textarea" + ref={this.commentsRef} + errors={errors} + /> + </InputRow> + <ButtonRow> + <Button + color="#5C5C5C" + isNoBorder={true} + isTransparent={true} + type="button" + onClick={this.props.onDismiss} + > + Back + </Button> + <Button>Submit</Button> + </ButtonRow> + </Form> + <Confirmation isSuccessful={isSuccessful}> + <Icon name="rocketship" size="large" margin={[0, 0, 'default', 0]} /> + <Heading color={colors.textDarkPrimary} size={34} asElement="h2"> + Thanks for contacting us. + </Heading> + <Paragraph isMuted={true} color={colors.textDarkPrimary}> + We'll get back to you soon. If you need quick support in the meantime, reach out to the + 0x team on Discord. + </Paragraph> + <Button onClick={this.props.onDismiss}>Done</Button> + </Confirmation> + </StyledDialogContent> + </DialogOverlay> + </> + ); + } + private async _onSubmitAsync(e: Event): Promise<void> { + e.preventDefault(); + + const name = this.nameRef.current.value; + const email = this.emailRef.current.value; + const projectOrCompany = this.companyProjectRef.current.value; + const link = this.linkRef.current.value; + const comments = this.commentsRef.current.value; + + this.setState({ ...this.state, errors: [], isSubmitting: true }); + + try { + // Disabling no-unbound method b/c no reason for _.isEmpty to be bound + // tslint:disable:no-unbound-method + const response = await fetch('https://website-api.0xproject.com/leads', { + method: 'post', + mode: 'cors', + credentials: 'same-origin', + headers: { + 'content-type': 'application/json; charset=utf-8', + }, + body: JSON.stringify(_.omitBy({ name, email, projectOrCompany, link, comments }, _.isEmpty)), + }); + + if (!response.ok) { + const errorResponse: ErrorResponse = await response.json(); + const errors = this._parseErrors(errorResponse.errors); + this.setState({ ...this.state, isSubmitting: false, errors }); + + throw new Error('Request failed'); + } + + this.setState({ ...this.state, isSuccessful: true }); + } catch (e) { + // Empty block + } + } + private _parseErrors(errors: ErrorResponseProps[]): ErrorProps { + const initialValue: {} = {}; + return _.reduce( + errors, + (hash: ErrorProps, error: ErrorResponseProps) => { + const { param, msg } = error; + const key = param; + hash[key] = msg; + + return hash; + }, + initialValue, + ); + } +} +// Handle errors: {"errors":[{"location":"body","param":"name","msg":"Invalid value"},{"location":"body","param":"email","msg":"Invalid value"}]} + +const InputRow = styled.div` + width: 100%; + flex: 0 0 auto; + + @media (min-width: 768px) { + display: flex; + justify-content: space-between; + margin-bottom: 30px; + } +`; + +const ButtonRow = styled(InputRow)` + @media (max-width: 768px) { + display: flex; + flex-direction: column; + + button:nth-child(1) { + order: 2; + } + + button:nth-child(2) { + order: 1; + margin-bottom: 10px; + } + } +`; + +const StyledDialogContent = styled(DialogContent)` + position: relative; + max-width: 800px; + background-color: #f6f6f6 !important; + padding: 60px 60px !important; + + @media (max-width: 768px) { + width: calc(100vw - 40px) !important; + margin: 40px auto !important; + padding: 30px 30px !important; + } +`; + +const Form = + styled.form < + FormProps > + ` + position: relative; + transition: opacity 0.30s ease-in-out, visibility 0.30s ease-in-out; + + opacity: ${props => props.isSuccessful && `0`}; + visibility: ${props => props.isSuccessful && `hidden`}; +`; + +const Confirmation = + styled.div < + FormProps > + ` + position: absolute; + top: 50%; + text-align: center; + width: 100%; + left: 0; + transition: opacity 0.30s ease-in-out, visibility 0.30s ease-in-out; + transition-delay: 0.40s; + padding: 60px 60px; + transform: translateY(-50%); + opacity: ${props => (props.isSuccessful ? `1` : `0`)}; + visibility: ${props => (props.isSuccessful ? 'visible' : `hidden`)}; + + p { + max-width: 492px; + margin-left: auto; + margin-right: auto; + } +`; diff --git a/packages/website/ts/@next/components/newLayout.tsx b/packages/website/ts/@next/components/newLayout.tsx new file mode 100644 index 000000000..28e7653c5 --- /dev/null +++ b/packages/website/ts/@next/components/newLayout.tsx @@ -0,0 +1,152 @@ +import * as React from 'react'; +import styled from 'styled-components'; + +export interface WrapProps { + bgColor?: string; + id?: string; + offsetTop?: string; + maxWidth?: string; + wrapWidth?: string; + isFullWidth?: boolean; + isTextCentered?: boolean; + isCentered?: boolean; + isWrapped?: boolean; +} + +export interface WrapGridProps { + isWrapped?: boolean; + isCentered?: boolean; +} + +export interface WrapStickyProps { + offsetTop?: string; +} + +export interface SectionProps extends WrapProps { + isPadded?: boolean; + isFullWidth?: boolean; + isFlex?: boolean; + padding?: string; + paddingMobile?: string; + flexBreakpoint?: string; + maxWidth?: string; + bgColor?: 'dark' | 'light' | string; + children: any; +} + +export interface FlexProps { + padding?: string; + isFlex?: boolean; + flexBreakpoint?: string; +} + +export interface ColumnProps { + padding?: string; + width?: string; + maxWidth?: string; +} + +export const Section: React.FunctionComponent<SectionProps> = (props: SectionProps) => { + return ( + <SectionBase {...props}> + <Wrap {...props}>{props.children}</Wrap> + </SectionBase> + ); +}; + +export const Column = + styled.div < + ColumnProps > + ` + width: ${props => props.width}; + max-width: ${props => props.maxWidth}; + padding: ${props => props.padding}; + + @media (max-width: 768px) { + width: 100%; + + & + & { + margin-top: 60px; + } + } +`; + +export const FlexWrap = + styled.div < + FlexProps > + ` + max-width: 1500px; + margin: 0 auto; + padding: ${props => props.padding}; + + @media (min-width: ${props => props.flexBreakpoint || '768px'}) { + display: ${props => props.isFlex && 'flex'}; + justify-content: ${props => props.isFlex && 'space-between'}; + } +`; + +export const WrapSticky = + styled.div < + WrapProps > + ` + position: sticky; + top: ${props => props.offsetTop || '60px'}; +`; + +const SectionBase = + styled.section < + SectionProps > + ` + width: ${props => !props.isFullWidth && 'calc(100% - 60px)'}; + max-width: 1500px; + margin: 0 auto; + padding: ${props => props.isPadded && '120px 0'}; + background-color: ${props => props.theme[`${props.bgColor}BgColor`] || props.bgColor}; + position: relative; + overflow: ${props => !props.isFullWidth && 'hidden'}; + + @media (max-width: 768px) { + padding: ${props => props.isPadded && (props.paddingMobile || '40px 0')}; + } +`; + +const Wrap = + styled(FlexWrap) < + WrapProps > + ` + width: ${props => props.wrapWidth || 'calc(100% - 60px)'}; + width: ${props => props.bgColor && 'calc(100% - 60px)'}; + max-width: ${props => !props.isFullWidth && (props.maxWidth || '895px')}; + text-align: ${props => props.isTextCentered && 'center'}; + margin: 0 auto; +`; + +export const WrapGrid = + styled(Wrap) < + WrapProps > + ` + display: flex; + flex-wrap: ${props => props.isWrapped && `wrap`}; + justify-content: ${props => (props.isCentered ? `center` : 'space-between')}; + + @media (max-width: 768px) { + width: 100%; + } +`; + +Section.defaultProps = { + isPadded: true, +}; + +FlexWrap.defaultProps = { + isFlex: true, +}; + +WrapGrid.defaultProps = { + isCentered: true, + isFullWidth: true, +}; + +Wrap.defaultProps = { + isFlex: false, +}; diff --git a/packages/website/ts/@next/components/newsletter_form.tsx b/packages/website/ts/@next/components/newsletter_form.tsx new file mode 100644 index 000000000..8572ccc5f --- /dev/null +++ b/packages/website/ts/@next/components/newsletter_form.tsx @@ -0,0 +1,202 @@ +import * as React from 'react'; +import styled, { withTheme } from 'styled-components'; + +import { ThemeValuesInterface } from 'ts/@next/components/siteWrap'; +import { colors } from 'ts/style/colors'; +import { errorReporter } from 'ts/utils/error_reporter'; + +interface FormProps { + theme: ThemeValuesInterface; +} + +interface InputProps { + isSubmitted: boolean; + name: string; + type: string; + label: string; + textColor: string; + required?: boolean; +} + +interface ArrowProps { + isSubmitted: boolean; +} + +const Input = React.forwardRef((props: InputProps, ref: React.Ref<HTMLInputElement>) => { + const { name, label, type } = props; + const id = `input-${name}`; + + return ( + <InnerInputWrapper {...props}> + <label className="visuallyHidden" htmlFor={id}> + {label} + </label> + <StyledInput ref={ref} id={id} placeholder={label} type={type || 'text'} {...props} /> + </InnerInputWrapper> + ); +}); + +class Form extends React.Component<FormProps> { + public emailInput = React.createRef<HTMLInputElement>(); + public state = { + isSubmitted: false, + }; + public render(): React.ReactNode { + const { isSubmitted } = this.state; + const { theme } = this.props; + + return ( + <StyledForm onSubmit={this._onSubmitAsync.bind(this)}> + <InputWrapper> + <Input + isSubmitted={isSubmitted} + name="email" + type="email" + label="Email Address" + ref={this.emailInput} + required={true} + textColor={theme.textColor} + /> + + <SubmitButton> + <Arrow + isSubmitted={isSubmitted} + width="22" + height="17" + fill="none" + xmlns="http://www.w3.org/2000/svg" + > + <path + d="M13.066 0l-1.068 1.147 6.232 6.557H0v1.592h18.23l-6.232 6.557L13.066 17l8.08-8.5-8.08-8.5z" + fill="#CBCBCB" + /> + </Arrow> + </SubmitButton> + <SuccessText isSubmitted={isSubmitted}>🎉 Thank you for signing up!</SuccessText> + </InputWrapper> + <Text>Subscribe to our newsletter for updates in the 0x ecosystem</Text> + </StyledForm> + ); + } + + private async _onSubmitAsync(e: React.FormEvent<HTMLFormElement>): Promise<void> { + e.preventDefault(); + + const email = this.emailInput.current.value; + const referrer = 'https://0x.org/'; + + this.setState({ isSubmitted: true }); + + if (email === 'triggererror@0xproject.org') { + throw new Error('Manually triggered error'); + } + + try { + await fetch('https://website-api.0x.org/newsletter_subscriber/substack', { + method: 'post', + mode: 'cors', + headers: { + 'content-type': 'application/json; charset=utf-8', + }, + body: JSON.stringify({ email, referrer }), + }); + } catch (e) { + errorReporter.report(e); + } + } +} + +export const NewsletterForm = withTheme(Form); + +const StyledForm = styled.form` + appearance: none; + border: 0; + color: ${colors.white}; + padding: 13px 0 14px; + margin-top: 27px; +`; + +const StyledInput = + styled.input < + InputProps > + ` + appearance: none; + background-color: transparent; + border: 0; + border-bottom: 1px solid #393939; + color: ${props => props.textColor || '#fff'}; + font-size: 1.294117647rem; + padding: 15px 0; + outline: none; + width: 100%; + + &::placeholder { + color: #B1B1B1; // #9D9D9D on light theme + } +`; + +const InputWrapper = styled.div` + position: relative; +`; + +const InnerInputWrapper = + styled.div < + ArrowProps > + ` + opacity: ${props => props.isSubmitted && 0}; + visibility: ${props => props.isSubmitted && 'hidden'}; + transition: opacity 0.25s ease-in-out, visibility 0.25s ease-in-out; + transition-delay: 0.30s; +`; + +const SubmitButton = styled.button` + width: 44px; + height: 44px; + background-color: transparent; + border: 0; + position: absolute; + right: 0; + top: calc(50% - 22px); + overflow: hidden; + outline: 0; + + &:focus-within { + //background-color: #eee; + } +`; + +const Text = styled.p` + color: #656565; + font-size: 0.833333333rem; + font-weight: 300; + line-height: 1.2em; + margin-top: 15px; +`; + +const SuccessText = + styled.p < + ArrowProps > + ` + color: #B1B1B1; + font-size: 1rem; + font-weight: 300; + line-height: 1.2em; + padding-top: 25px; + position: absolute; + left: 0; + top: 0; + text-align: left; + right: 50px; + opacity: ${props => (props.isSubmitted ? 1 : 0)}; + visibility: ${props => (props.isSubmitted ? 'visible' : 'hidden')}; + transition: opacity 0.25s ease-in-out, visibility 0.25s ease-in-out; + transition-delay: 0.55s; +`; + +const Arrow = + styled.svg < + ArrowProps > + ` + transform: ${props => props.isSubmitted && `translateX(44px)`}; + transition: transform 0.25s ease-in-out; +`; diff --git a/packages/website/ts/@next/components/sections/landing/about.tsx b/packages/website/ts/@next/components/sections/landing/about.tsx new file mode 100644 index 000000000..7b51b0d13 --- /dev/null +++ b/packages/website/ts/@next/components/sections/landing/about.tsx @@ -0,0 +1,81 @@ +import * as React from 'react'; +import styled from 'styled-components'; + +import { Button } from 'ts/@next/components/button'; +import { Icon, InlineIconWrap } from 'ts/@next/components/icon'; +import { Column, FlexWrap, Section } from 'ts/@next/components/newLayout'; +import { Paragraph } from 'ts/@next/components/text'; +import { WebsitePaths } from 'ts/types'; + +interface FigureProps { + value: string; + description: string; +} + +export const SectionLandingAbout = () => ( + <Section bgColor="dark" isTextCentered={true}> + <InlineIconWrap> + <Icon name="descriptionCoin" size="small" /> + <Icon name="descriptionCopy" size="small" /> + <Icon name="descriptionFlask" size="small" /> + <Icon name="descriptionBolt" size="small" /> + </InlineIconWrap> + + <Paragraph size="large" isCentered={true} isMuted={1} padding={['large', 0, 'default', 0]}> + Anyone in the world can use 0x to service a wide variety of markets ranging from gaming items to financial + instruments to assets that could have never existed before. + </Paragraph> + + <DeveloperLink href={`${WebsitePaths.Why}#cases`} isWithArrow={true} isAccentColor={true}> + Discover how developers use 0x + </DeveloperLink> + + <hr + style={{ + width: '100%', + maxWidth: '340px', + borderColor: '#3C4746', + margin: '60px auto', + }} + /> + + <FlexWrap as="dl"> + <Figure value="353K" description="Total Transactions" /> + + <Figure value="$447M" description="Total Volume" /> + + <Figure value="30+" description="Total Projects" /> + </FlexWrap> + </Section> +); + +const Figure = (props: FigureProps) => ( + <Column padding="0 30px"> + <FigureValue>{props.value}</FigureValue> + <FigureDescription>{props.description}</FigureDescription> + </Column> +); + +const DeveloperLink = styled(Button)` + @media (max-width: 500px) { + && { + white-space: pre-wrap; + line-height: 1.3; + } + } +`; + +const FigureValue = styled.dt` + font-size: 50px; + font-weight: 300; + margin-bottom: 15px; + + @media (max-width: 768px) { + font-size: 40px; + } +`; + +const FigureDescription = styled.dd` + font-size: 18px; + color: #999999; +`; diff --git a/packages/website/ts/@next/components/sections/landing/clients.tsx b/packages/website/ts/@next/components/sections/landing/clients.tsx new file mode 100644 index 000000000..4170fde46 --- /dev/null +++ b/packages/website/ts/@next/components/sections/landing/clients.tsx @@ -0,0 +1,113 @@ +import * as _ from 'lodash'; +import * as React from 'react'; +import styled from 'styled-components'; +import { Heading } from 'ts/@next/components/text'; + +import { Section, WrapGrid } from 'ts/@next/components/newLayout'; + +interface ProjectLogo { + name: string; + imageUrl?: string; + persistOnMobile?: boolean; +} + +interface StyledProjectInterface { + isOnMobile?: boolean; +} + +const projects: ProjectLogo[] = [ + { + name: 'Radar Relay', + imageUrl: 'images/@next/clients/radar-relay.svg', + persistOnMobile: true, + }, + { + name: 'Paradex', + imageUrl: 'images/@next/clients/paradex.svg', + persistOnMobile: true, + }, + { + name: 'Star Bit Ex', + imageUrl: 'images/@next/clients/starbitex.svg', + }, + { + name: 'LedgerDex', + imageUrl: 'images/@next/clients/ledgerdex.svg', + }, + { + name: 'OpenRelay', + imageUrl: 'images/@next/clients/openrelay.svg', + persistOnMobile: true, + }, + { + name: 'Bamboo Relay', + imageUrl: 'images/@next/clients/bamboo.svg', + persistOnMobile: true, + }, + { + name: 'dEX', + imageUrl: 'images/@next/clients/ercdex.svg', + persistOnMobile: true, + }, + { + name: 'emoon', + imageUrl: 'images/@next/clients/emoon.svg', + persistOnMobile: true, + }, + { + name: 'Gods Unchained', + imageUrl: 'images/@next/clients/godsUnchained.svg', + }, + { + name: 'Instex', + imageUrl: 'images/@next/clients/instex.svg', + }, + { + name: 'Lake Trade', + imageUrl: 'images/@next/clients/laketrade.svg', + }, + { + name: 'Veil', + imageUrl: 'images/@next/clients/veil.svg', + }, +]; + +export const SectionLandingClients = () => ( + <Section isTextCentered={true}> + <Heading size="small">Join the growing number of projects developing on 0x</Heading> + + <WrapGrid isWrapped={true}> + {_.map(projects, (item: ProjectLogo, index) => ( + <StyledProject key={`client-${index}`} isOnMobile={item.persistOnMobile}> + <img src={item.imageUrl} alt={item.name} /> + </StyledProject> + ))} + </WrapGrid> + </Section> +); + +const StyledProject = + styled.div < + StyledProjectInterface > + ` + flex-shrink: 0; + + img { + object-fit: contain; + width: 100%; + height: 100%; + } + + @media (min-width: 768px) { + width: auto; + height: 50px; + margin: 30px; + } + + @media (max-width: 768px) { + width: auto; + height: 42px; + margin: 15px; + display: ${props => !props.isOnMobile && 'none'}; + } +`; diff --git a/packages/website/ts/@next/components/sections/landing/cta.tsx b/packages/website/ts/@next/components/sections/landing/cta.tsx new file mode 100644 index 000000000..ec7f5d961 --- /dev/null +++ b/packages/website/ts/@next/components/sections/landing/cta.tsx @@ -0,0 +1,29 @@ +import * as React from 'react'; + +import { BlockIconLink } from 'ts/@next/components/blockIconLink'; +import { Section } from 'ts/@next/components/newLayout'; + +import { AnimatedChatIcon } from 'ts/@next/components/animatedChatIcon'; +import { AnimatedCompassIcon } from 'ts/@next/components/animatedCompassIcon'; +import { WebsitePaths } from 'ts/types'; + +interface Props { + onContactClick?: () => void; +} + +export const SectionLandingCta = (props: Props) => ( + <Section isPadded={false} isFlex={true} maxWidth="auto" wrapWidth="100%" flexBreakpoint="900px"> + <BlockIconLink + iconComponent={<AnimatedCompassIcon />} + title="Ready to build on 0x?" + linkLabel="Get Started" + linkUrl={WebsitePaths.Docs} + /> + <BlockIconLink + iconComponent={<AnimatedChatIcon />} + title="Want help from the 0x team?" + linkLabel="Get in Touch" + linkAction={props.onContactClick} + /> + </Section> +); diff --git a/packages/website/ts/@next/components/sections/landing/hero.tsx b/packages/website/ts/@next/components/sections/landing/hero.tsx new file mode 100644 index 000000000..cf67ad66d --- /dev/null +++ b/packages/website/ts/@next/components/sections/landing/hero.tsx @@ -0,0 +1,31 @@ +import * as React from 'react'; + +import { Button } from 'ts/@next/components/button'; +import { Hero } from 'ts/@next/components/hero'; +import { LandingAnimation } from 'ts/@next/components/heroImage'; + +import { HeroAnimation } from 'ts/@next/components/heroAnimation'; +import { WebsitePaths } from 'ts/types'; + +export const SectionLandingHero = () => ( + <Hero + title="Powering Decentralized Exchange" + isLargeTitle={true} + isFullWidth={true} + description="0x is an open protocol that enables the peer-to-peer exchange of assets on the Ethereum blockchain." + figure={<LandingAnimation image={<HeroAnimation />} />} + actions={<HeroActions />} + /> +); + +const HeroActions = () => ( + <> + <Button href="https://0x.org/docs" isInline={true}> + Get Started + </Button> + + <Button to={WebsitePaths.Why} isTransparent={true} isInline={true}> + Learn More + </Button> + </> +); diff --git a/packages/website/ts/@next/components/separator.tsx b/packages/website/ts/@next/components/separator.tsx new file mode 100644 index 000000000..0b8b8d766 --- /dev/null +++ b/packages/website/ts/@next/components/separator.tsx @@ -0,0 +1,7 @@ +import styled from 'styled-components'; + +export const Separator = styled.hr` + background: #eaeaea; + height: 1px; + border: 0; +`; diff --git a/packages/website/ts/@next/components/siteWrap.tsx b/packages/website/ts/@next/components/siteWrap.tsx new file mode 100644 index 000000000..75cb9a268 --- /dev/null +++ b/packages/website/ts/@next/components/siteWrap.tsx @@ -0,0 +1,149 @@ +import * as React from 'react'; +import styled, { ThemeProvider } from 'styled-components'; + +import { colors } from 'ts/style/colors'; + +import { Footer } from 'ts/@next/components/footer'; +import { Header } from 'ts/@next/components/header'; +import { GlobalStyles } from 'ts/@next/constants/globalStyle'; + +interface Props { + theme?: 'dark' | 'light' | 'gray'; + children: any; +} + +interface State { + isMobileNavOpen: boolean; +} + +interface MainProps { + isNavToggled: boolean; +} + +export interface ThemeValuesInterface { + bgColor: string; + darkBgColor?: string; + lightBgColor: string; + introTextColor: string; + textColor: string; + paragraphColor: string; + linkColor: string; + mobileNavBgUpper: string; + mobileNavBgLower: string; + mobileNavColor: string; + dropdownBg: string; + dropdownButtonBg: string; + dropdownBorderColor?: string; + dropdownColor: string; + headerButtonBg: string; + footerBg: string; + footerColor: string; +} + +export interface ThemeInterface { + [key: string]: ThemeValuesInterface; +} + +const GLOBAL_THEMES: ThemeInterface = { + dark: { + bgColor: '#000000', + darkBgColor: '#111A19', + lightBgColor: '#003831', + introTextColor: 'rgba(255, 255, 255, 0.75)', + textColor: '#FFFFFF', + paragraphColor: '#FFFFFF', + linkColor: colors.brandLight, + mobileNavBgUpper: '#003831', + mobileNavBgLower: '#022924', + mobileNavColor: '#FFFFFF', + dropdownBg: '#111A19', + dropdownButtonBg: '#003831', + dropdownColor: '#FFFFFF', + headerButtonBg: '#00AE99', + footerBg: '#181818', + footerColor: '#FFFFFF', + }, + light: { + bgColor: '#FFFFFF', + lightBgColor: '#F3F6F4', + darkBgColor: '#003831', + introTextColor: 'rgba(92, 92, 92, 0.87)', + textColor: '#000000', + paragraphColor: '#474747', + linkColor: colors.brandDark, + mobileNavBgUpper: '#FFFFFF', + mobileNavBgLower: '#F3F6F4', + mobileNavColor: '#000000', + dropdownBg: '#FBFBFB', + dropdownButtonBg: '#F3F6F4', + dropdownColor: '#003831', + dropdownBorderColor: '#E4E4E4', + headerButtonBg: '#003831', + footerBg: '#F2F2F2', + footerColor: '#000000', + }, + gray: { + bgColor: '#e0e0e0', + lightBgColor: '#003831', + introTextColor: 'rgba(92, 92, 92, 0.87)', + textColor: '#000000', + paragraphColor: '#777777', + linkColor: colors.brandDark, + mobileNavBgUpper: '#FFFFFF', + mobileNavBgLower: '#F3F6F4', + mobileNavColor: '#000000', + dropdownBg: '#FFFFFF', + dropdownButtonBg: '#F3F6F4', + dropdownColor: '#003831', + headerButtonBg: '#003831', + footerBg: '#181818', + footerColor: '#FFFFFF', + }, +}; + +export class SiteWrap extends React.Component<Props, State> { + public state = { + isMobileNavOpen: false, + }; + + public componentDidMount(): void { + document.documentElement.style.overflowY = 'auto'; + window.scrollTo(0, 0); + } + + public toggleMobileNav = () => { + this.setState({ + isMobileNavOpen: !this.state.isMobileNavOpen, + }); + }; + + public render(): React.ReactNode { + const { children, theme = 'dark' } = this.props; + const { isMobileNavOpen } = this.state; + const currentTheme = GLOBAL_THEMES[theme]; + + return ( + <> + <ThemeProvider theme={currentTheme}> + <> + <GlobalStyles /> + + <Header isNavToggled={isMobileNavOpen} toggleMobileNav={this.toggleMobileNav} /> + + <Main isNavToggled={isMobileNavOpen}>{children}</Main> + + <Footer /> + </> + </ThemeProvider> + </> + ); + } +} + +const Main = + styled.main < + MainProps > + ` + transition: transform 0.5s, opacity 0.5s; + opacity: ${props => props.isNavToggled && '0.5'}; +`; diff --git a/packages/website/ts/@next/components/slider/slider.tsx b/packages/website/ts/@next/components/slider/slider.tsx new file mode 100644 index 000000000..33a352b9f --- /dev/null +++ b/packages/website/ts/@next/components/slider/slider.tsx @@ -0,0 +1,177 @@ +import * as React from 'react'; +import Flickity from 'react-flickity-component'; +import styled from 'styled-components'; + +import { colors } from 'ts/style/colors'; + +import { Icon } from 'ts/@next/components/icon'; +import { Heading, Paragraph } from 'ts/@next/components/text'; + +interface SliderProps {} + +interface SlideProps { + icon: string; + heading: string; + text: string; + href?: string; +} + +const flickityOptions = { + initialIndex: 0, + cellAlign: 'left', + arrowShape: + 'M0 50.766L42.467 93.58l5.791-5.839-32.346-32.61H100V46.84H15.48L50.2 11.838 44.409 6 5.794 44.93l-.003-.003z', + prevNextButtons: true, +}; + +export const Slide: React.StatelessComponent<SlideProps> = (props: SlideProps) => { + const { heading, text, icon } = props; + + return ( + <StyledSlide> + <SlideHead> + <Icon name={icon} size="large" /> + </SlideHead> + <SlideContent> + <Heading asElement="h4" size="small" marginBottom="15px"> + {heading} + </Heading> + <Paragraph isMuted={true}>{text}</Paragraph> + </SlideContent> + </StyledSlide> + ); +}; + +export const Slider: React.StatelessComponent<SliderProps> = props => { + return ( + <StyledSlider> + <Flickity + className={'carousel'} // default '' + elementType={'div'} // default 'div' + options={flickityOptions} // takes flickity options {} + disableImagesLoaded={false} // default false + > + {props.children} + </Flickity> + </StyledSlider> + ); +}; + +const StyledSlider = styled.div` + //overflow: hidden; + width: 100%; + height: 520px; + + @media (max-width: 500px) { + height: 450px; + } + + .carousel { + display: block; + user-select: none; + touch-action: pan-y; + -webkit-tap-highlight-color: transparent; + outline: none; + + @media (max-width: 500px) { + overflow: hidden; + margin-left: -20px; + width: calc(100vw - 20px); + } + } + + .flickity-viewport { + outline: none; + } + + .flickity-button { + cursor: pointer; + position: absolute; + width: 74px; + height: 74px; + background-color: #000; + display: flex; + outline: 0; + top: calc(50% - 37px); + border: 0; + padding: 0; + transition: background-color 0.4s ease-in-out, visibility 0.4s ease-in-out, opacity 0.4s ease-in-out; + + &:disabled { + opacity: 0; + visibility: hidden; + } + + &:hover { + background-color: hsla(0, 0%, 10%, 1); + } + + &.previous { + left: 0; + } + + &.next { + right: 0; + } + + svg { + margin: auto; + width: 28px; + height: auto; + } + + path { + fill: #fff; + } + } +`; + +const StyledSlide = styled.div` + background-color: ${colors.backgroundDark}; + width: 560px; + height: 520px; + flex: 0 0 auto; + opacity: 0.3; + transition: opacity 0.4s ease-in-out; + + & + & { + margin-left: 30px; + } + + @media (max-width: 1200px) { + width: 100%; + } + + @media (max-width: 500px) { + width: calc(100vw - 10px - 30px); + height: 450px; + + & + & { + margin-left: 10px; + } + } + + &.is-selected { + opacity: 1; + } +`; + +const SlideHead = styled.div` + background-color: ${colors.brandDark}; + height: 300px; + display: flex; + justify-content: center; + align-items: center; + + @media (max-width: 500px) { + height: 240px; + } +`; + +const SlideContent = styled.div` + padding: 30px; + + @media (max-width: 500px) { + padding: 20px; + } +`; diff --git a/packages/website/ts/@next/components/text.tsx b/packages/website/ts/@next/components/text.tsx new file mode 100644 index 000000000..9f6ed9e7a --- /dev/null +++ b/packages/website/ts/@next/components/text.tsx @@ -0,0 +1,83 @@ +import * as React from 'react'; +import styled from 'styled-components'; +import { getCSSPadding, PaddingInterface } from 'ts/@next/constants/utilities'; + +interface BaseTextInterface extends PaddingInterface { + size?: 'default' | 'medium' | 'large' | 'small' | number; + isCentered?: boolean; + textAlign?: string; +} + +interface HeadingProps extends BaseTextInterface { + asElement?: 'h1' | 'h2' | 'h3' | 'h4'; + maxWidth?: string; + fontWeight?: string; + isCentered?: boolean; + isFlex?: boolean; + isNoMargin?: boolean; + isMuted?: boolean | number; + marginBottom?: string; + color?: string; +} + +interface ParagraphProps extends BaseTextInterface { + isNoMargin?: boolean; + marginBottom?: string; // maybe we should remove isNoMargin + isMuted?: boolean | number; + fontWeight?: string | number; +} + +const StyledHeading = + styled.h1 < + HeadingProps > + ` + max-width: ${props => props.maxWidth}; + color: ${props => props.color || props.theme.textColor}; + display: ${props => props.isFlex && `inline-flex`}; + align-items: center; + justify-content: ${props => props.isFlex && `space-between`}; + font-size: ${props => + typeof props.size === 'string' ? `var(--${props.size || 'default'}Heading)` : `${props.size}px`}; + line-height: ${props => `var(--${props.size || 'default'}HeadingHeight)`}; + text-align: ${props => props.isCentered && 'center'}; + padding: ${props => props.padding && getCSSPadding(props.padding)}; + margin-left: ${props => props.isCentered && 'auto'}; + margin-right: ${props => props.isCentered && 'auto'}; + margin-bottom: ${props => !props.isNoMargin && (props.marginBottom || '30px')}; + opacity: ${props => (typeof props.isMuted === 'boolean' ? 0.75 : props.isMuted)}; + font-weight: ${props => (props.fontWeight ? props.fontWeight : ['h4'].includes(props.asElement) ? 400 : 300)}; + width: ${props => props.isFlex && `100%`}; +`; + +export const Heading: React.StatelessComponent<HeadingProps> = props => { + const { asElement = 'h1', children } = props; + const Component = StyledHeading.withComponent(asElement); + + return <Component {...props}>{children}</Component>; +}; + +Heading.defaultProps = { + size: 'default', +}; + +// No need to declare it twice as Styled then rewrap as a stateless comp +// Note: this would be useful to be implemented the same way was "Heading" +// and be more generic. e.g. <Text /> with a props asElement so we can use it +// for literally anything = +export const Paragraph = + styled.p < + ParagraphProps > + ` + font-size: ${props => `var(--${props.size || 'default'}Paragraph)`}; + font-weight: ${props => props.fontWeight || 300}; + margin-bottom: ${props => !props.isNoMargin && (props.marginBottom || '30px')}; + padding: ${props => props.padding && getCSSPadding(props.padding)}; + color: ${props => props.color || props.theme.paragraphColor}; + opacity: ${props => (typeof props.isMuted === 'boolean' ? 0.75 : props.isMuted)}; + text-align: ${props => (props.textAlign ? props.textAlign : props.isCentered && 'center')}; + line-height: 1.4; +`; + +Paragraph.defaultProps = { + isMuted: true, +}; diff --git a/packages/website/ts/@next/constants/.gitkeep b/packages/website/ts/@next/constants/.gitkeep new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/packages/website/ts/@next/constants/.gitkeep diff --git a/packages/website/ts/@next/constants/animations.tsx b/packages/website/ts/@next/constants/animations.tsx new file mode 100644 index 000000000..6a58c4b40 --- /dev/null +++ b/packages/website/ts/@next/constants/animations.tsx @@ -0,0 +1,18 @@ +import { css, keyframes } from 'styled-components'; + +export const fadeIn = keyframes` + 0% { + transform: translateY(10px); + opacity: 0; + } + 100% { + transform: translateY(0); + opacity: 1; + } +`; + +export const addFadeInAnimation = (duration: string = '0.5s', delay: string = '0s') => css` + opacity: 0; + transform: translateY(10px); + animation: ${fadeIn} ${duration} ${delay} forwards; +`; diff --git a/packages/website/ts/@next/constants/cssReset.js b/packages/website/ts/@next/constants/cssReset.js new file mode 100644 index 000000000..4c5105b50 --- /dev/null +++ b/packages/website/ts/@next/constants/cssReset.js @@ -0,0 +1,50 @@ +export const cssReset = ` + *, + *:before, + *:after { + box-sizing: border-box; + } + html, body, div, span, applet, object, iframe, + h1, h2, h3, h4, h5, h6, p, blockquote, pre, + a, abbr, acronym, address, big, cite, code, + del, dfn, em, img, ins, kbd, q, s, samp, + small, strike, strong, sub, sup, tt, var, + b, u, i, center, + dl, dt, dd, ol, ul, li, + fieldset, form, label, legend, + table, caption, tbody, tfoot, thead, tr, th, td, + article, aside, canvas, details, embed, + figure, figcaption, footer, header, hgroup, + menu, nav, output, ruby, section, summary, + time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; + } + /* HTML5 display-role reset for older browsers */ + article, aside, details, figcaption, figure, + footer, header, hgroup, menu, nav, section { + display: block; + } + body { + line-height: 1; + } + ol, ul { + list-style: none; + } + blockquote, q { + quotes: none; + } + blockquote:before, blockquote:after, + q:before, q:after { + content: ''; + content: none; + } + table { + border-collapse: collapse; + border-spacing: 0; + } +`; diff --git a/packages/website/ts/@next/constants/globalStyle.tsx b/packages/website/ts/@next/constants/globalStyle.tsx new file mode 100644 index 000000000..b095fafb5 --- /dev/null +++ b/packages/website/ts/@next/constants/globalStyle.tsx @@ -0,0 +1,109 @@ +import { createGlobalStyle, withTheme } from 'styled-components'; +import { cssReset } from 'ts/@next/constants/cssReset'; + +export interface GlobalStyle { + theme: { + bgColor: string; + textColor: string; + linkColor: string; + dropdownButtonBg: string; + }; +} + +const GlobalStyles = withTheme( + createGlobalStyle < + GlobalStyle > + ` + ${cssReset}; + + html { + font-size: 18px; + background-color: ${props => props.theme.bgColor}; + overflow-x: hidden; + } + + @media (min-width: 768px) { + :root { + --smallHeading: 20px; + --defaultHeading: 28px; + --mediumHeading: 50px; + --largeHeading: 80px; + --smallHeadingHeight: 1.4em; + --defaultHeadingHeight: 1.357142857em; + --mediumHeadingHeight: 1.16em; + --largeHeadingHeight: 1em; + --smallParagraph: 14px; + --defaultParagraph: 18px; + --mediumParagraph: 22px; + --largeParagraph: 28px; + --smallIcon: 75px; + --mediumIcon: 85px; + --largeIcon: 145px; + --heroIcon: 282px; + } + } + + @media (max-width: 1170px) { + :root { + --largeHeading: 60px; + } + } + + @media (max-width: 768px) { + :root { + --smallHeading: 18px; + --defaultHeading: 18px; + --mediumHeading: 40px; + --largeHeading: 46px; + --smallHeadingHeight: 1.4em; // TO DO + --defaultHeadingHeight: 1.357142857em; // TO DO + --mediumHeadingHeight: 1.16em; // TO DO + --largeHeadingHeight: 1.108695652em; // TO DO + --smallParagraph: 14px; // TO DO + --defaultParagraph: 16px; // TO DO + --mediumParagraph: 20px; // TO DO + --largeParagraph: 20px; // TO DO + --smallIcon: 55px; + --mediumIcon: 85px; + --largeIcon: 115px; + } + } + + body { + font-family: 'Formular', sans-serif !important; + -webkit-font-smoothing: antialiased; + color: ${props => props.theme.textColor}; + font-feature-settings: "zero"; + scroll-behavior: smooth; + } + + .visuallyHidden { + position: absolute !important; + clip: rect(1px 1px 1px 1px); /* IE6, IE7 */ + clip: rect(1px, 1px, 1px, 1px); + padding:0 !important; + border:0 !important; + height: 1px !important; + width: 1px !important; + overflow: hidden; + } + + img, svg { + max-width: 100%; + object-fit: contain; + } + + a, button { + text-decoration: none; + font-family: inherit; + outline: none; + } + + svg + p, + img + p { + padding-top: 30px; + } +`, +); + +export { GlobalStyles }; diff --git a/packages/website/ts/@next/constants/utilities.tsx b/packages/website/ts/@next/constants/utilities.tsx new file mode 100644 index 000000000..ee5c5b4ce --- /dev/null +++ b/packages/website/ts/@next/constants/utilities.tsx @@ -0,0 +1,22 @@ +export interface PaddingInterface { + padding?: number | Array<'large' | 'default' | 'small' | number>; + margin?: number | Array<'large' | 'default' | 'small' | number>; +} + +interface PaddingSizes { + [key: string]: string; +} + +export const PADDING_SIZES: PaddingSizes = { + default: '30px', + large: '60px', + small: '15px', +}; + +export const getCSSPadding = (value: number | Array<string | number> = 0): string => { + if (Array.isArray(value)) { + return value.map(val => PADDING_SIZES[val] || `${val}px`).join(' '); + } else { + return `${value}px`; + } +}; diff --git a/packages/website/ts/@next/icons/form-arrow.svg b/packages/website/ts/@next/icons/form-arrow.svg new file mode 100644 index 000000000..2070a6d48 --- /dev/null +++ b/packages/website/ts/@next/icons/form-arrow.svg @@ -0,0 +1 @@ +<svg width="22" height="17" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M13.066 0l-1.068 1.147 6.232 6.557H0v1.592h18.23l-6.232 6.557L13.066 17l8.08-8.5-8.08-8.5z" fill="#CBCBCB"/></svg>
\ No newline at end of file diff --git a/packages/website/ts/@next/icons/illustrations/0x.svg b/packages/website/ts/@next/icons/illustrations/0x.svg new file mode 100755 index 000000000..b0810f751 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/0x.svg @@ -0,0 +1,14 @@ +<svg width="404" height="404" viewBox="0 0 404 404" fill="none" xmlns="http://www.w3.org/2000/svg"> +<mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="404" height="404"> +<circle cx="202" cy="202" r="200" fill="#00AE99" stroke="#00AE99" stroke-width="3"/> +</mask> +<g mask="url(#mask0)"> +<circle cx="202" cy="202" r="200" stroke="#00AE99" stroke-width="3"/> +<circle cx="201.667" cy="68.6667" r="66.6667" stroke="#00AE99" stroke-width="3"/> +<circle cx="68.6667" cy="202.667" r="66.6667" stroke="#00AE99" stroke-width="3"/> +<path d="M168.17 260.29L167.271 259.089L165.46 260.444L167.413 261.585L168.17 260.29ZM197.32 269.2L197.219 270.696L197.226 270.697L197.32 269.2ZM237.414 258.856L238.22 260.12L238.225 260.117L237.414 258.856ZM252.653 245.439L253.801 246.405L254.55 245.515L253.874 244.568L252.653 245.439ZM241.096 229.872L242.285 228.958L242.281 228.952L242.276 228.946L241.096 229.872ZM237.72 225.571L238.901 224.645L237.582 222.965L236.449 224.775L237.72 225.571ZM219.719 241.445L218.672 242.519L219.418 243.246L220.36 242.801L219.719 241.445ZM208.264 230.282L209.311 229.207L208.392 228.312L207.365 229.081L208.264 230.282ZM143.827 169.549L145.02 168.64L143.647 166.838L142.524 168.806L143.827 169.549ZM135.133 198.43L133.637 198.329L133.636 198.337L135.133 198.43ZM145.464 238.577L144.201 239.388L145.464 238.577ZM158.862 253.837L157.895 254.984L158.786 255.736L159.735 255.057L158.862 253.837ZM174.409 242.264L175.324 243.453L175.33 243.448L175.336 243.443L174.409 242.264ZM178.705 238.885L179.632 240.064L181.287 238.761L179.516 237.623L178.705 238.885ZM162.851 220.757L161.78 219.707L161.049 220.452L161.495 221.397L162.851 220.757ZM174.102 209.286L175.173 210.337L176.082 209.41L175.295 208.377L174.102 209.286ZM235.163 145.072L236.036 146.292L237.92 144.945L235.92 143.777L235.163 145.072ZM206.014 136.162L205.91 137.658L205.913 137.658L206.014 136.162ZM165.817 146.506L166.629 147.767L166.632 147.765L165.817 146.506ZM150.578 159.922L149.43 158.956L148.681 159.846L149.357 160.793L150.578 159.922ZM162.135 175.489L160.946 176.403L160.951 176.409L160.955 176.415L162.135 175.489ZM165.511 179.791L164.331 180.717L165.634 182.378L166.773 180.6L165.511 179.791ZM183.614 163.916L184.655 162.836L183.913 162.122L182.98 162.557L183.614 163.916ZM194.354 174.26L193.313 175.341L194.212 176.206L195.226 175.48L194.354 174.26ZM259.608 235.505L258.411 236.409L259.789 238.233L260.914 236.243L259.608 235.505ZM268.2 206.931L269.696 207.033L269.697 207.024L268.2 206.931ZM257.87 166.784L259.135 165.979L259.132 165.974L257.87 166.784ZM244.471 151.524L245.439 150.378L244.547 149.625L243.598 150.304L244.471 151.524ZM228.924 163.097L228.009 161.909L228.003 161.913L227.997 161.918L228.924 163.097ZM224.629 166.477L223.701 165.298L222.034 166.609L223.826 167.744L224.629 166.477ZM240.584 184.604L239.228 185.244L239.235 185.259L239.242 185.274L240.584 184.604ZM240.687 184.809L241.767 185.849L242.502 185.086L242.029 184.139L240.687 184.809ZM229.845 196.075L228.764 195.035L227.877 195.957L228.648 196.979L229.845 196.075ZM167.413 261.585C176.201 266.718 186.346 269.964 197.219 270.696L197.421 267.703C187.019 267.002 177.321 263.898 168.926 258.994L167.413 261.585ZM197.226 270.697C212.283 271.639 226.405 267.659 238.22 260.12L236.607 257.591C225.307 264.8 211.813 268.604 197.413 267.703L197.226 270.697ZM238.225 260.117C244.08 256.348 249.307 251.742 253.801 246.405L251.506 244.473C247.204 249.583 242.203 253.989 236.602 257.594L238.225 260.117ZM253.874 244.568C250.283 239.533 246.385 234.295 242.285 228.958L239.906 230.786C243.989 236.1 247.864 241.309 251.432 246.31L253.874 244.568ZM242.276 228.946C241.713 228.229 241.151 227.512 240.588 226.795C240.026 226.078 239.463 225.362 238.901 224.645L236.54 226.497C237.103 227.213 237.665 227.93 238.228 228.647C238.791 229.364 239.353 230.081 239.916 230.798L242.276 228.946ZM236.449 224.775C232.311 231.384 226.193 236.725 219.078 240.089L220.36 242.801C227.974 239.201 234.538 233.481 238.992 226.367L236.449 224.775ZM220.766 240.371L209.311 229.207L207.217 231.356L218.672 242.519L220.766 240.371ZM207.365 229.081L167.271 259.089L169.069 261.49L209.163 231.483L207.365 229.081ZM142.524 168.806C137.505 177.601 134.368 187.549 133.637 198.329L136.63 198.532C137.33 188.214 140.33 178.703 145.13 170.293L142.524 168.806ZM133.636 198.337C132.696 213.409 136.668 227.654 144.201 239.388L146.726 237.767C139.531 226.56 135.73 212.947 136.63 198.524L133.636 198.337ZM144.201 239.388C147.965 245.25 152.565 250.484 157.895 254.984L159.83 252.691C154.727 248.383 150.327 243.376 146.726 237.767L144.201 239.388ZM159.735 255.057C164.764 251.461 169.994 247.558 175.324 243.453L173.494 241.076C168.187 245.164 162.985 249.045 157.99 252.617L159.735 255.057ZM175.336 243.443C176.768 242.317 178.2 241.19 179.632 240.064L177.777 237.706C176.345 238.832 174.913 239.959 173.481 241.086L175.336 243.443ZM179.516 237.623C172.904 233.374 167.568 227.241 164.208 220.117L161.495 221.397C165.09 229.021 170.8 235.588 177.894 240.147L179.516 237.623ZM163.922 221.807L175.173 210.337L173.031 208.236L161.78 219.707L163.922 221.807ZM175.295 208.377L145.02 168.64L142.634 170.458L172.909 210.196L175.295 208.377ZM235.92 143.777C227.132 138.643 216.987 135.398 206.114 134.665L205.913 137.658C216.315 138.359 226.012 141.463 234.407 146.367L235.92 143.777ZM206.118 134.665C191.055 133.618 176.824 137.599 165.003 145.246L166.632 147.765C177.926 140.459 191.515 136.657 205.91 137.658L206.118 134.665ZM165.006 145.244C159.151 149.013 153.924 153.619 149.43 158.956L151.725 160.888C156.027 155.779 161.028 151.372 166.629 147.767L165.006 145.244ZM149.357 160.793C152.948 165.828 156.846 171.066 160.946 176.403L163.325 174.575C159.242 169.261 155.367 164.052 151.799 159.051L149.357 160.793ZM160.955 176.415C161.518 177.132 162.08 177.849 162.643 178.566C163.205 179.283 163.768 180 164.331 180.717L166.691 178.865C166.128 178.148 165.566 177.431 165.003 176.714C164.441 175.997 163.878 175.28 163.315 174.563L160.955 176.415ZM166.773 180.6C171.021 173.973 177.044 168.635 184.248 165.276L182.98 162.557C175.251 166.161 168.796 171.885 164.248 178.981L166.773 180.6ZM182.574 164.997L193.313 175.341L195.394 173.18L184.655 162.836L182.574 164.997ZM195.226 175.48L236.036 146.292L234.291 143.852L193.481 173.04L195.226 175.48ZM260.914 236.243C265.827 227.556 268.964 217.713 269.696 207.033L266.703 206.828C266.003 217.042 263.004 226.453 258.303 234.767L260.914 236.243ZM269.697 207.024C270.638 191.949 266.663 177.81 259.135 165.979L256.604 167.589C263.804 178.904 267.603 192.417 266.703 206.837L269.697 207.024ZM259.132 165.974C255.368 160.111 250.769 154.878 245.439 150.378L243.503 152.67C248.606 156.978 253.007 161.986 256.607 167.594L259.132 165.974ZM243.598 150.304C238.57 153.901 233.339 157.803 228.009 161.909L229.84 164.285C235.147 160.197 240.349 156.316 245.344 152.744L243.598 150.304ZM227.997 161.918C227.281 162.481 226.565 163.045 225.849 163.608C225.133 164.171 224.417 164.734 223.701 165.298L225.556 167.656C226.272 167.092 226.988 166.529 227.704 165.966C228.42 165.402 229.136 164.839 229.852 164.276L227.997 161.918ZM223.826 167.744C230.535 171.992 235.869 178.121 239.228 185.244L241.941 183.964C238.345 176.339 232.632 169.769 225.431 165.209L223.826 167.744ZM239.242 185.274L239.345 185.479L242.029 184.139L241.926 183.934L239.242 185.274ZM239.606 183.769L228.764 195.035L230.926 197.115L241.767 185.849L239.606 183.769ZM228.648 196.979L258.411 236.409L260.806 234.601L231.042 195.171L228.648 196.979Z" fill="#00AE99"/> +<path d="M269 135V268.333H442V135H269Z" stroke="#00AE99" stroke-width="3"/> +<path d="M339.64 269.64L270 339.281L343.913 413.194L413.554 343.554L339.64 269.64Z" stroke="#00AE99" stroke-width="3"/> +<path d="M202.5 269C202.5 269 269 269 269 335.5C269 402 202.5 402 202.5 402H-6.5C-6.5 402 -77 402 -77 335.5C-77 269 -6.5 269 -6.5 269H202.5Z" stroke="#00AE99" stroke-width="3"/> +</g> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/buildBusiness.svg b/packages/website/ts/@next/icons/illustrations/buildBusiness.svg new file mode 100755 index 000000000..48e5b3b1c --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/buildBusiness.svg @@ -0,0 +1,6 @@ +<svg width="90" height="90" viewBox="0 0 90 90" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M2 45C2 68.7579 21.2421 88 45 88C68.7579 88 88 68.7579 88 45C88 21.6448 69.3906 2.63278 46.1793 2.02876C45.7478 2.02876 45.3452 2 44.9137 2C21.2134 2.02876 2 21.2709 2 45Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/> +<path d="M78.8765 52.5843V69.7753H12.1349V52.5843M78.8765 52.5843V21.236H12.1349V52.5843M78.8765 52.5843H51.5731H39.4383H12.1349" stroke="#00AE99" stroke-width="3"/> +<path d="M56.6293 11.1236H34.3821V21.236H56.6293V11.1236Z" stroke="#00AE99" stroke-width="3"/> +<rect width="22.2472" height="6.06742" transform="matrix(1 0 0 -1 34.3821 58.6517)" stroke="#00AE99" stroke-width="3"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/checkmark.svg b/packages/website/ts/@next/icons/illustrations/checkmark.svg new file mode 100644 index 000000000..e17a7ab8b --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/checkmark.svg @@ -0,0 +1 @@ +<svg width="124" height="124" viewBox="0 0 124 124" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M61.878.5h.002c.327 0 .64.01.924.02l.01.001a23.966 23.966 0 0 0 .87.02C96.885 1.405 123.5 28.597 123.5 62c0 33.979-27.521 61.5-61.5 61.5S.5 95.979.5 62C.5 28.063 27.979.541 61.878.5zm.002 3C29.64 3.54 3.5 29.717 3.5 62c0 32.322 26.178 58.5 58.5 58.5s58.5-26.178 58.5-58.5c0-31.768-25.308-57.628-56.875-58.46-.32 0-.625-.01-.904-.02h-.01c-.294-.011-.56-.02-.83-.02z" fill="#00AE99"/><path fill-rule="evenodd" clip-rule="evenodd" d="M47.502 98.561l55.419-55.419L88.779 29 47.495 70.284 34.142 56.932 20 71.074l16.573 16.573.008-.007L47.502 98.56zM36.573 83.405l.008-.008 10.921 10.921L98.68 43.142l-9.9-9.9-41.284 41.285-13.353-13.352-9.9 9.9 12.331 12.33z" fill="#00AE99"/></svg>
\ No newline at end of file diff --git a/packages/website/ts/@next/icons/illustrations/code-repo.svg b/packages/website/ts/@next/icons/illustrations/code-repo.svg new file mode 100644 index 000000000..43e412198 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/code-repo.svg @@ -0,0 +1,7 @@ +<svg width="82" height="82" viewBox="0 0 82 82" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M40.9185 1.43051e-06L40.9197 0C41.1377 7.15256e-07 41.3462 0.00719154 41.5359 0.0137337L41.5428 0.0139726C41.7392 0.0207458 41.9163 0.0267566 42.097 0.0267566C42.1057 0.0267566 42.1143 0.0268694 42.123 0.027095C64.2563 0.603056 82 18.7315 82 41C82 63.6526 63.6526 82 41 82C18.3474 82 0 63.6526 0 41C0 18.3752 18.3193 0.0274277 40.9185 1.43051e-06ZM40.9203 2C19.4262 2.02641 2 19.4778 2 41C2 62.548 19.452 80 41 80C62.548 80 80 62.548 80 41C80 19.8212 63.1283 2.58105 42.0835 2.02675C41.8704 2.02646 41.6666 2.01943 41.4808 2.01302L41.4739 2.01278C41.2777 2.00602 41.1008 2.00001 40.9203 2Z" fill="#00AE99"/> +<path fill-rule="evenodd" clip-rule="evenodd" d="M10.7026 14.378C10.7026 13.8257 11.1504 13.378 11.7026 13.378H33.7762C34.3284 13.378 34.7762 13.8257 34.7762 14.378V36.4516C34.7762 37.0039 34.3284 37.4516 33.7762 37.4516H11.7026C11.1504 37.4516 10.7026 37.0039 10.7026 36.4516V14.378ZM12.7026 15.378V35.4516H32.7762V15.378H12.7026Z" fill="#00AE99"/> +<path fill-rule="evenodd" clip-rule="evenodd" d="M38.6621 20.6785L33.0687 15.0851L34.4829 13.6709L40.3692 19.5572C40.5567 19.7447 40.6621 19.9991 40.6621 20.2643V42.3379C40.6621 42.8902 40.2143 43.3379 39.6621 43.3379H17.5885C17.3233 43.3379 17.0689 43.2325 16.8814 43.045L10.9951 37.1587L12.4093 35.7445L18.0027 41.3379H38.6621V20.6785Z" fill="#00AE99"/> +<path fill-rule="evenodd" clip-rule="evenodd" d="M38.6621 42.338C38.6621 41.7857 39.1098 41.338 39.6621 41.338H61.7357C62.288 41.338 62.7357 41.7857 62.7357 42.338V64.4116C62.7357 64.9638 62.288 65.4116 61.7357 65.4116H39.6621C39.1098 65.4116 38.6621 64.9638 38.6621 64.4116V42.338ZM40.6621 43.338V63.4116H60.7357V43.338H40.6621Z" fill="#00AE99"/> +<path fill-rule="evenodd" clip-rule="evenodd" d="M66.622 48.6385L61.0286 43.0451L62.4429 41.6309L68.3291 47.5172C68.5167 47.7047 68.622 47.9591 68.622 48.2243V70.2979C68.622 70.8501 68.1743 71.2979 67.622 71.2979H45.5485C45.2833 71.2979 45.0289 71.1925 44.8414 71.005L38.9551 65.1187L40.3693 63.7045L45.9627 69.2979H66.622V48.6385Z" fill="#00AE99"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/coin.svg b/packages/website/ts/@next/icons/illustrations/coin.svg new file mode 100644 index 000000000..a1fb123a4 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/coin.svg @@ -0,0 +1 @@ +<svg width="88" height="88" viewBox="0 0 88 88" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M44 87c23.748 0 43-19.252 43-43S67.748 1 44 1 1 20.252 1 44s19.252 43 43 43z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/><path d="M43.999 78.4c18.998 0 34.4-15.401 34.4-34.4 0-18.998-15.401-34.4-34.4-34.4S9.599 25.002 9.599 44C9.599 63 25 78.4 43.999 78.4z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/><path d="M35.1 57.76v1h20.529v-7.395h-6.098V26.738H42.36l-.254.173-6.568 4.456-.438.298v8.906l1.561-1.06 5.006-3.397v15.251H35.1v6.395z" stroke="#00AE99" stroke-width="2"/><path d="M9.597 43.766c7.115-1.173 12.588-7.271 12.588-14.777 0-3.362-1.095-6.41-2.971-8.913-5.864 6.177-9.538 14.542-9.617 23.69zM9.597 44.234c.079 9.226 3.753 17.513 9.617 23.69a14.719 14.719 0 0 0 2.97-8.913c0-7.506-5.472-13.682-12.587-14.777zM78.399 43.766c-7.115-1.173-12.587-7.271-12.587-14.777 0-3.362 1.094-6.41 2.97-8.913 5.864 6.177 9.539 14.542 9.617 23.69zM78.399 44.235c-.079 9.225-3.753 17.512-9.617 23.689a14.718 14.718 0 0 1-2.97-8.913c0-7.506 5.472-13.682 12.587-14.776z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/></svg> diff --git a/packages/website/ts/@next/icons/illustrations/consistently-ship.svg b/packages/website/ts/@next/icons/illustrations/consistently-ship.svg new file mode 100644 index 000000000..733655a3f --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/consistently-ship.svg @@ -0,0 +1,6 @@ +<svg width="104" height="104" viewBox="0 0 104 104" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M37.5485 62.3767L10.6742 80.0615M16.1162 86.694L39.2493 63.9073" stroke="#00AE99" stroke-width="2.5"/> +<path d="M43.1605 67.4788L29.2115 96.3881M21.8987 91.9664L41.2898 65.7782" stroke="#00AE99" stroke-width="2.5"/> +<path d="M64.6767 66.0071L63.4346 66.1475L63.4346 66.1475L64.6767 66.0071ZM65.0025 50.4035L66.2054 50.7435L65.0025 50.4035ZM71.1301 36.7515L70.153 35.9719L70.1082 36.0281L70.0701 36.0891L71.1301 36.7515ZM61.2375 73.5299L60.4186 74.4743L61.3787 75.3068L62.1953 74.3331L61.2375 73.5299ZM47.4561 66.4802L48.3306 67.3734L48.3678 67.337L48.4018 67.2977L47.4561 66.4802ZM45.1781 66.5118L45.9955 65.5661L45.9955 65.5661L45.1781 66.5118ZM44.504 67.2916L45.2499 68.2947L45.36 68.2128L45.4497 68.109L44.504 67.2916ZM43.2195 67.2024L44.037 66.2568L44.037 66.2568L43.2195 67.2024ZM51.486 57.3064L50.6457 58.2318L50.657 58.2421L50.6685 58.2521L51.486 57.3064ZM62.7637 71.4218L63.819 72.0917L63.819 72.0917L62.7637 71.4218ZM76.5283 23.4963L77.6859 23.0248L77.5727 22.7469L77.3457 22.5507L76.5283 23.4963ZM35.9701 41.1929L36.0109 42.4422L36.0109 42.4422L35.9701 41.1929ZM51.3624 38.6129L50.8519 37.4718L51.3624 38.6129ZM63.9842 30.5744L64.793 31.5275L64.8478 31.481L64.8969 31.4285L63.9842 30.5744ZM29.0241 45.6843L28.0908 44.8528L27.2455 45.8017L28.2082 46.6313L29.0241 45.6843ZM37.9936 58.3007L37.0479 57.4833L37.0139 57.5226L36.9833 57.5647L37.9936 58.3007ZM38.2919 60.5593L39.1094 59.6137L39.1094 59.6137L38.2919 60.5593ZM37.6179 61.3391L36.6722 60.5217L36.5825 60.6255L36.5174 60.7463L37.6179 61.3391ZM37.8919 62.5972L38.7094 61.6516L38.7094 61.6515L37.8919 62.5972ZM46.4878 52.9859L45.6704 53.9316L45.6819 53.9416L45.6937 53.9513L46.4878 52.9859ZM30.8892 43.8692L30.0736 42.9219L30.0736 42.9219L30.8892 43.8692ZM76.3188 23.3153L77.1362 22.3696L76.9092 22.1734L76.6179 22.1016L76.3188 23.3153ZM70.1348 36.0655L51.3508 57.796L53.2421 59.4309L72.0261 37.7004L70.1348 36.0655ZM65.9188 65.8667C65.5634 62.7233 64.3047 57.4681 66.2054 50.7435L63.7996 50.0635C61.7311 57.3817 63.1075 63.2547 63.4346 66.1475L65.9188 65.8667ZM66.2054 50.7435C67.7494 45.2809 70.8444 39.5677 72.1902 37.4138L70.0701 36.0891C68.6538 38.3557 65.431 44.2919 63.7996 50.0635L66.2054 50.7435ZM72.1073 37.531C72.8165 36.642 73.9266 35.0937 74.9321 33.5888C75.9127 32.1211 76.8909 30.5525 77.2543 29.671L74.943 28.7181C74.6915 29.3283 73.864 30.6874 72.8534 32.1999C71.8677 33.6752 70.801 35.1596 70.153 35.9719L72.1073 37.531ZM62.0564 72.5855L50.6963 62.7347L49.0585 64.6235L60.4186 74.4743L62.0564 72.5855ZM48.9317 62.8617L46.5104 65.6628L48.4018 67.2977L50.823 64.4966L48.9317 62.8617ZM46.5816 65.5871C46.6163 65.5531 46.6022 65.5735 46.5354 65.6101C46.4766 65.6423 46.4098 65.6684 46.3459 65.6814C46.2855 65.6937 46.2383 65.6924 46.1986 65.6831C46.1638 65.6751 46.0953 65.6523 45.9955 65.5661L44.3607 67.4575C45.1854 68.1704 46.1014 68.2823 46.8439 68.1313C47.5166 67.9946 48.0515 67.6467 48.3306 67.3734L46.5816 65.5871ZM44.2324 65.6944L43.5584 66.4741L45.4497 68.109L46.1238 67.3293L44.2324 65.6944ZM43.7582 66.2885C43.804 66.2544 43.8326 66.2427 43.8431 66.2387C43.857 66.2334 43.8754 66.2284 43.9003 66.2268C43.9278 66.2251 43.9618 66.228 43.9962 66.2392C44.0323 66.251 44.0456 66.2643 44.037 66.2568L42.4021 68.1481C43.5138 69.1091 44.7467 68.6688 45.2499 68.2947L43.7582 66.2885ZM50.6685 58.2521C51.1247 58.6464 51.5236 59.8632 50.612 60.9178L52.5033 62.5527C54.3763 60.3859 53.7352 57.5984 52.3034 56.3607L50.6685 58.2521ZM50.612 60.9178L48.9317 62.8617L50.823 64.4966L52.5033 62.5527L50.612 60.9178ZM62.1953 74.3331C62.6486 73.7926 63.2417 73.0013 63.819 72.0917L61.7083 70.7519C61.1892 71.5698 60.6611 72.2719 60.2798 72.7266L62.1953 74.3331ZM63.819 72.0917C64.381 71.2063 64.9483 70.1773 65.3541 69.1342C65.7512 68.1137 66.0422 66.9586 65.9188 65.8667L63.4346 66.1475C63.4916 66.6522 63.3613 67.3615 63.0243 68.2277C62.6961 69.0712 62.2166 69.9513 61.7083 70.7519L63.819 72.0917ZM50.6948 62.7335L45.811 58.5118L44.1761 60.4032L49.0599 64.6248L50.6948 62.7335ZM48.0426 55.9286C49.1315 56.8715 50.1183 57.753 50.6457 58.2318L52.3263 56.381C51.7849 55.8894 50.7834 54.9948 49.679 54.0386L48.0426 55.9286ZM40.7648 64.3497L44.3607 67.4575L45.9955 65.5661L42.3996 62.4582L40.7648 64.3497ZM39.6096 65.7343L42.4021 68.1481L44.037 66.2568L41.2445 63.8429L39.6096 65.7343ZM77.2543 29.671C77.6017 28.8283 77.9174 27.7261 78.0507 26.5812C78.1821 25.4521 78.1499 24.1638 77.6859 23.0248L75.3706 23.9679C75.6133 24.5637 75.6738 25.3787 75.5675 26.2921C75.463 27.1897 75.2106 28.0692 74.943 28.7181L77.2543 29.671ZM62.9156 29.8252L44.1315 51.5557L46.0229 53.1906L64.8069 31.4601L62.9156 29.8252ZM36.0109 42.4422C38.9206 42.3473 44.9309 42.8595 51.8728 39.7539L50.8519 37.4718C44.4731 40.3255 39.0911 39.8404 35.9294 39.9436L36.0109 42.4422ZM51.8728 39.7539C57.3477 37.3047 62.7552 33.2568 64.793 31.5275L63.1754 29.6213C61.2389 31.2646 56.0337 35.1537 50.8519 37.4718L51.8728 39.7539ZM64.8969 31.4285C65.6069 30.6698 66.9213 29.3996 68.2385 28.2108C69.5889 26.992 70.814 25.9765 71.3813 25.6394L70.1041 23.4903C69.2845 23.9774 67.8738 25.1723 66.5635 26.3549C65.2199 27.5676 63.8485 28.89 63.0715 29.7203L64.8969 31.4285ZM28.2082 46.6313L39.5989 56.4466L41.2308 54.5527L29.8401 44.7374L28.2082 46.6313ZM39.4692 54.6822L37.0479 57.4833L38.9392 59.1182L41.3605 56.3171L39.4692 54.6822ZM36.9833 57.5647C36.7532 57.8804 36.4864 58.46 36.4484 59.1453C36.4065 59.9019 36.6497 60.7921 37.4745 61.505L39.1094 59.6137C39.0096 59.5275 38.9772 59.4629 38.9642 59.4297C38.9494 59.3918 38.9412 59.3452 38.9446 59.2836C38.9482 59.2185 38.9644 59.1487 38.9878 59.0859C39.0143 59.0144 39.0324 58.9976 39.0039 59.0368L36.9833 57.5647ZM37.3462 59.7419L36.6722 60.5217L38.5635 62.1566L39.2376 61.3768L37.3462 59.7419ZM36.5174 60.7463C36.22 61.2983 35.9627 62.5819 37.0745 63.5429L38.7094 61.6515C38.7007 61.6441 38.7158 61.6554 38.7326 61.6893C38.7487 61.7218 38.7565 61.755 38.7588 61.7825C38.7609 61.8074 38.7585 61.8263 38.7553 61.8408C38.7529 61.8517 38.7454 61.8817 38.7183 61.9319L36.5174 60.7463ZM47.3052 52.0403C45.8734 50.8026 43.0225 50.5715 41.1495 52.7383L43.0408 54.3732C43.9524 53.3186 45.2142 53.5373 45.6704 53.9316L47.3052 52.0403ZM41.1495 52.7383L39.4692 54.6822L41.3605 56.3171L43.0408 54.3732L41.1495 52.7383ZM29.9575 46.5158C30.3523 46.0726 30.9705 45.4485 31.7047 44.8165L30.0736 42.9219C29.2572 43.6247 28.56 44.3261 28.0908 44.8528L29.9575 46.5158ZM31.7047 44.8165C32.4234 44.1978 33.2248 43.596 34.012 43.1492C34.8203 42.6904 35.5033 42.4588 36.0109 42.4422L35.9294 39.9436C34.8311 39.9794 33.7302 40.4345 32.7779 40.975C31.8045 41.5275 30.8684 42.2377 30.0736 42.9219L31.7047 44.8165ZM39.5974 56.4453L44.4813 60.667L46.1161 58.7756L41.2323 54.554L39.5974 56.4453ZM49.9826 54.3011C48.8767 53.3467 47.8466 52.4851 47.2819 52.0206L45.6937 53.9513C46.2438 54.4038 47.2588 55.2527 48.3493 56.1937L49.9826 54.3011ZM42.7049 62.7221L39.1094 59.6137L37.4744 61.5049L41.0699 64.6133L42.7049 62.7221ZM41.5018 64.0654L38.7094 61.6516L37.0745 63.5429L39.8669 65.9567L41.5018 64.0654ZM71.3813 25.6394C71.9847 25.2807 72.8184 24.9037 73.6914 24.6705C74.5799 24.4331 75.395 24.375 76.0197 24.529L76.6179 22.1016C75.4237 21.8073 74.1443 21.9618 73.0462 22.2552C71.9326 22.5527 70.8876 23.0246 70.1041 23.4903L71.3813 25.6394ZM77.3457 22.5507L77.1362 22.3696L75.5013 24.2609L75.7108 24.442L77.3457 22.5507Z" fill="#00AE99"/> +<path d="M52 102C79.6142 102 102 79.6142 102 52C102 24.3858 79.6142 2 52 2C24.3858 2 2 24.3858 2 52C2 79.6142 24.3858 102 52 102Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/customize.svg b/packages/website/ts/@next/icons/illustrations/customize.svg new file mode 100644 index 000000000..1f018ee7a --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/customize.svg @@ -0,0 +1 @@ +<svg width="152" height="152" viewBox="0 0 152 152" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M76 151c41.421 0 75-33.579 75-75S117.421 1 76 1 1 34.579 1 76s33.579 75 75 75z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/><path d="M120.5 122.906H31.503c-12.943 0-23.478-10.485-23.478-23.478 0-12.993 10.485-23.478 23.478-23.478H120.5" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/><path d="M120.499 122.906c12.967 0 23.478-10.511 23.478-23.478 0-12.967-10.511-23.478-23.478-23.478-12.967 0-23.478 10.511-23.478 23.478 0 12.967 10.511 23.478 23.478 23.478z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/><path d="M120.5 122.906H31.503c-12.943 0-23.478-10.485-23.478-23.478 0-12.993 10.485-23.478 23.478-23.478H120.5" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/><path d="M120.499 122.906c12.967 0 23.478-10.511 23.478-23.478 0-12.967-10.511-23.478-23.478-23.478-12.967 0-23.478 10.511-23.478 23.478 0 12.967 10.511 23.478 23.478 23.478z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/><path d="M31.5 29.093h88.996c12.943 0 23.478 10.485 23.478 23.478 0 12.993-10.485 23.478-23.478 23.478H31.499" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/><path d="M31.503 76.052c12.967 0 23.478-10.512 23.478-23.478 0-12.967-10.511-23.479-23.478-23.479-12.966 0-23.478 10.512-23.478 23.479 0 12.966 10.512 23.478 23.478 23.478z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/></svg>
\ No newline at end of file diff --git a/packages/website/ts/@next/icons/illustrations/decentralisedLoans.svg b/packages/website/ts/@next/icons/illustrations/decentralisedLoans.svg new file mode 100755 index 000000000..72d0de7fc --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/decentralisedLoans.svg @@ -0,0 +1,13 @@ +<svg width="151" height="150" viewBox="0 0 151 150" fill="none" xmlns="http://www.w3.org/2000/svg"> +<circle cx="76" cy="75" r="73" stroke="#00AE99" stroke-width="3"/> +<rect x="3" y="75" width="45.9619" height="45.9619" transform="rotate(-45 3 75)" stroke="#00AE99" stroke-width="3"/> +<rect x="85" y="75" width="45" height="45" transform="rotate(-45 85 75)" stroke="#00AE99" stroke-width="3"/> +<path d="M89 79L76 92M100 115L85 100L71.5 113.5L63 105L76 92M100 115L113 102M100 115L106 121C97.6605 129.494 89.3395 138.006 81 146.5L38.5 104M76 92L63 79" stroke="#00AE99" stroke-width="3"/> +<path d="M63.5 71.5L76.5 58.5M52.5 35.5L67.5 50.5L81 37L89.5 45.5L76.5 58.5M52.5 35.5L39.5 48.5M52.5 35.5L46.5 29.5C54.8395 21.0061 63.1605 12.4939 71.5 4L114 46.5M76.5 58.5L89.5 71.5" stroke="#00AE99" stroke-width="3"/> +<path d="M93 134.5L87 128.5" stroke="#00AE99" stroke-width="3"/> +<path d="M99 128L93.5 122.5" stroke="#00AE99" stroke-width="3"/> +<path d="M87 140L81.5 134.5" stroke="#00AE99" stroke-width="3"/> +<path d="M60.5 16.5L66.5 22.5" stroke="#00AE99" stroke-width="3"/> +<path d="M54.5 23L60 28.5" stroke="#00AE99" stroke-width="3"/> +<path d="M66.5 11L72 16.5" stroke="#00AE99" stroke-width="3"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/description.svg b/packages/website/ts/@next/icons/illustrations/description.svg new file mode 100755 index 000000000..1887b182e --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/description.svg @@ -0,0 +1,21 @@ +<svg width="353" height="80" viewBox="0 0 353 80" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M130.818 77C151.253 77 167.818 60.4345 167.818 40C167.818 19.5655 151.253 3 130.818 3C110.384 3 93.8181 19.5655 93.8181 40C93.8181 60.4345 110.384 77 130.818 77Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M140.505 11.9474V21.0965H149.654" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M149.655 21.0964V49.351H124.562V11.9473H140.506L149.655 21.0964Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M121.131 68.0529V58.9038H111.982" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M111.982 58.9039V30.6494H137.075V68.053H121.131L111.982 58.9039Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M40 77C60.4345 77 77 60.4345 77 40C77 19.5655 60.4345 3 40 3C19.5655 3 3.00001 19.5655 3.00001 40C3.00001 60.4345 19.5655 77 40 77Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M40.0037 76.9359C60.4007 76.9359 76.9357 60.4009 76.9357 40.0038C76.9357 19.6068 60.4007 3.07178 40.0037 3.07178C19.6066 3.07178 3.07159 19.6068 3.07159 40.0038C3.07159 60.4009 19.6066 76.9359 40.0037 76.9359Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M30.0225 54.7728V56.2728H31.5225H51.4155H52.9155V54.7728V48.9811V47.4811H51.4155H46.3684V22.5411V21.0411H44.8684H38.5732H38.1123L37.7309 21.2999L30.6803 26.0843L30.0225 26.5306V27.3255V34.2922V37.1228L32.3648 35.5335L37.0732 32.3385V47.4811H31.5225H30.0225V48.9811V54.7728Z" stroke="#00AE99" stroke-width="3"/> +<path d="M3.06793 39.7483C10.7062 38.4893 16.5817 31.9422 16.5817 23.8843C16.5817 20.275 15.4066 17.0015 13.3921 14.3156C7.09688 20.9465 3.15187 29.9277 3.06793 39.7483Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M3.06793 40.2518C3.15187 50.1563 7.09688 59.0535 13.3921 65.6845C15.4066 62.9986 16.5817 59.725 16.5817 56.1158C16.5817 48.0579 10.7062 41.4269 3.06793 40.2518Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M76.9322 39.7483C69.294 38.4893 63.4184 31.9422 63.4184 23.8843C63.4184 20.275 64.5936 17.0015 66.608 14.3156C72.9033 20.9465 76.8483 29.9277 76.9322 39.7483Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M76.9321 40.2518C76.8482 50.1563 72.9031 59.0536 66.6079 65.6846C64.5934 62.9986 63.4183 59.7251 63.4183 56.1158C63.4183 48.0579 69.2939 41.4269 76.9321 40.2518Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M221.987 77C242.421 77 258.987 60.4345 258.987 40C258.987 19.5655 242.421 3 221.987 3C201.552 3 184.987 19.5655 184.987 40C184.987 60.4345 201.552 77 221.987 77Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M221.987 77C242.421 77 258.987 60.4345 258.987 40C258.987 19.5655 242.421 3 221.987 3C201.552 3 184.987 19.5655 184.987 40C184.987 60.4345 201.552 77 221.987 77Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M225.754 38.1178V16.3887H228.848V10.2668H215.125V16.3887H218.219V38.1178C211.156 39.7996 205.908 46.1905 205.908 53.725C205.908 62.605 213.106 69.8032 221.986 69.8032C230.866 69.8032 238.065 62.605 238.065 53.725C238.065 46.1232 232.817 39.7996 225.754 38.1178Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M228.848 10.1979H215.124V16.3197H228.848V10.1979Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M208.6 44.7092H235.307" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M312.805 77C333.239 77 349.805 60.4345 349.805 40C349.805 19.5655 333.239 3 312.805 3C292.37 3 275.805 19.5655 275.805 40C275.805 60.4345 292.37 77 312.805 77Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M312.607 15.2613L290.287 45.3102H312.607L312.668 64.4778L334.926 34.3678H312.607V15.2613Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/descriptionBolt.svg b/packages/website/ts/@next/icons/illustrations/descriptionBolt.svg new file mode 100755 index 000000000..45e51240f --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/descriptionBolt.svg @@ -0,0 +1,4 @@ +<svg width="78" height="78" viewBox="0 0 78 78" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M38.8049 76C59.2395 76 75.8049 59.4345 75.8049 39C75.8049 18.5655 59.2395 2 38.8049 2C18.3704 2 1.80493 18.5655 1.80493 39C1.80493 59.4345 18.3704 76 38.8049 76Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M38.6065 14.2613L16.2874 44.3102H38.6065L38.6679 63.4778L60.9257 33.3678H38.6065V14.2613Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/descriptionCoin.svg b/packages/website/ts/@next/icons/illustrations/descriptionCoin.svg new file mode 100755 index 000000000..d1015b98d --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/descriptionCoin.svg @@ -0,0 +1,9 @@ +<svg width="78" height="78" viewBox="0 0 78 78" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M39 76C59.4345 76 76 59.4345 76 39C76 18.5655 59.4345 2 39 2C18.5655 2 2.00001 18.5655 2.00001 39C2.00001 59.4345 18.5655 76 39 76Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M39.0037 75.9359C59.4007 75.9359 75.9357 59.4009 75.9357 39.0038C75.9357 18.6068 59.4007 2.07178 39.0037 2.07178C18.6066 2.07178 2.07159 18.6068 2.07159 39.0038C2.07159 59.4009 18.6066 75.9359 39.0037 75.9359Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M29.0225 53.7728V55.2728H30.5225H50.4155H51.9155V53.7728V47.9811V46.4811H50.4155H45.3684V21.5411V20.0411H43.8684H37.5732H37.1123L36.7309 20.2999L29.6803 25.0843L29.0225 25.5306V26.3255V33.2922V36.1228L31.3648 34.5335L36.0732 31.3385V46.4811H30.5225H29.0225V47.9811V53.7728Z" stroke="#00AE99" stroke-width="3"/> +<path d="M2.06793 38.7483C9.70615 37.4893 15.5817 30.9422 15.5817 22.8843C15.5817 19.275 14.4066 16.0015 12.3921 13.3156C6.09688 19.9465 2.15187 28.9277 2.06793 38.7483Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M2.06793 39.2518C2.15187 49.1563 6.09688 58.0535 12.3921 64.6845C14.4066 61.9986 15.5817 58.725 15.5817 55.1158C15.5817 47.0579 9.70615 40.4269 2.06793 39.2518Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M75.9322 38.7483C68.294 37.4893 62.4184 30.9422 62.4184 22.8843C62.4184 19.275 63.5936 16.0015 65.608 13.3156C71.9033 19.9465 75.8483 28.9277 75.9322 38.7483Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M75.9321 39.2518C75.8482 49.1563 71.9031 58.0536 65.6079 64.6846C63.5934 61.9986 62.4183 58.7251 62.4183 55.1158C62.4183 47.0579 68.2939 40.4269 75.9321 39.2518Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/descriptionCopy.svg b/packages/website/ts/@next/icons/illustrations/descriptionCopy.svg new file mode 100755 index 000000000..6c9b5f0fc --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/descriptionCopy.svg @@ -0,0 +1,7 @@ +<svg width="78" height="78" viewBox="0 0 78 78" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M38.8181 3.5C19.212 3.5 3.31812 19.3939 3.31812 39C3.31812 58.6061 19.212 74.5 38.8181 74.5C58.4242 74.5 74.3181 58.6061 74.3181 39C74.3181 19.3939 58.4242 3.5 38.8181 3.5ZM0.318115 39C0.318115 17.737 17.5552 0.5 38.8181 0.5C60.0811 0.5 77.3181 17.737 77.3181 39C77.3181 60.263 60.0811 77.5 38.8181 77.5C17.5552 77.5 0.318115 60.263 0.318115 39Z" fill="#00AE99"/> +<path fill-rule="evenodd" clip-rule="evenodd" d="M47.0054 10.9473H50.0054V18.5964H57.6545V21.5964H47.0054V10.9473Z" fill="#00AE99"/> +<path fill-rule="evenodd" clip-rule="evenodd" d="M31.0619 9.44727H49.1268L59.1546 19.475V49.8509H31.0619V9.44727ZM34.0619 12.4473V46.8509H56.1546V20.7177L47.8842 12.4473H34.0619Z" fill="#00AE99"/> +<path fill-rule="evenodd" clip-rule="evenodd" d="M19.9818 56.4038H30.6309V67.0529H27.6309V59.4038H19.9818V56.4038Z" fill="#00AE99"/> +<path fill-rule="evenodd" clip-rule="evenodd" d="M18.4818 28.1494H46.5745V68.553H28.5096L18.4818 58.5253V28.1494ZM21.4818 31.1494V57.2826L29.7522 65.553H43.5745V31.1494H21.4818Z" fill="#00AE99"/> +</svg>
\ No newline at end of file diff --git a/packages/website/ts/@next/icons/illustrations/descriptionFlask.svg b/packages/website/ts/@next/icons/illustrations/descriptionFlask.svg new file mode 100755 index 000000000..703b069d5 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/descriptionFlask.svg @@ -0,0 +1,7 @@ +<svg width="78" height="78" viewBox="0 0 78 78" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M38.9868 76C59.4213 76 75.9868 59.4345 75.9868 39C75.9868 18.5655 59.4213 2 38.9868 2C18.5523 2 1.9868 18.5655 1.9868 39C1.9868 59.4345 18.5523 76 38.9868 76Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M38.9868 76C59.4213 76 75.9868 59.4345 75.9868 39C75.9868 18.5655 59.4213 2 38.9868 2C18.5523 2 1.9868 18.5655 1.9868 39C1.9868 59.4345 18.5523 76 38.9868 76Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M42.7537 37.1178V15.3887H45.8483V9.26685H32.1246V15.3887H35.2192V37.1178C28.1555 38.7996 22.9083 45.1905 22.9083 52.725C22.9083 61.605 30.1064 68.8032 38.9864 68.8032C47.8664 68.8032 55.0646 61.605 55.0646 52.725C55.0646 45.1232 49.8174 38.7996 42.7537 37.1178Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M45.848 9.19794H32.1243V15.3197H45.848V9.19794Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M25.5996 43.7092H52.3069" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/eficientDesign.svg b/packages/website/ts/@next/icons/illustrations/eficientDesign.svg new file mode 100755 index 000000000..6b8f852c3 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/eficientDesign.svg @@ -0,0 +1,11 @@ +<svg width="90" height="90" viewBox="0 0 90 90" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M45 88C68.7482 88 88 68.7482 88 45C88 21.2518 68.7482 2 45 2C21.2518 2 2 21.2518 2 45C2 68.7482 21.2518 88 45 88Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> +<path d="M70.2962 31.8956L57.4584 19.3542L44.833 32.1067L57.6708 44.6481L70.2962 31.8956Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> +<path d="M74.8267 14.5717L57.4829 19.3431L70.311 31.8859L74.8267 14.5717Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> +<path d="M32.184 19.5506L19.5587 32.3031L32.3965 44.8445L45.0218 32.092L32.184 19.5506Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> +<path d="M14.7418 15.0572L19.5451 32.2857L32.1719 19.5429L14.7418 15.0572Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> +<path d="M19.698 57.5441L32.5358 70.0856L45.1612 57.3331L32.3234 44.7916L19.698 57.5441Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> +<path d="M15.1732 74.8574L32.517 70.086L19.6889 57.5432L15.1732 74.8574Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> +<path d="M57.8244 69.8803L70.4497 57.1278L57.6119 44.5863L44.9865 57.3389L57.8244 69.8803Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> +<path d="M75.2582 74.3715L70.4548 57.1429L57.8281 69.8858L75.2582 74.3715Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/eth-based-tokens.svg b/packages/website/ts/@next/icons/illustrations/eth-based-tokens.svg new file mode 100644 index 000000000..b0370d234 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/eth-based-tokens.svg @@ -0,0 +1,6 @@ +<svg width="84" height="84" viewBox="0 0 84 84" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M42.1187 1.19995L42.1199 1.19995C42.3379 1.19995 42.5464 1.20714 42.7361 1.21368L42.743 1.21392C42.9394 1.2207 43.1165 1.22671 43.2972 1.22671C43.3058 1.22671 43.3145 1.22682 43.3232 1.22705C65.4565 1.80301 83.2002 19.9314 83.2002 42.1999C83.2002 64.8526 64.8528 83.1999 42.2002 83.1999C19.5476 83.1999 1.2002 64.8526 1.2002 42.1999C1.2002 19.5752 19.5195 1.22738 42.1187 1.19995ZM42.1205 3.19995C20.6264 3.22636 3.2002 20.6778 3.2002 42.1999C3.2002 63.748 20.6521 81.1999 42.2002 81.1999C63.7482 81.1999 81.2002 63.748 81.2002 42.1999C81.2002 21.0212 64.3285 3.781 43.2837 3.2267C43.0706 3.22641 42.8668 3.21938 42.681 3.21297L42.6741 3.21274C42.4779 3.20597 42.301 3.19997 42.1205 3.19995Z" fill="#00AE99"/> +<path fill-rule="evenodd" clip-rule="evenodd" d="M68.0979 42.2001C68.0979 42.5434 67.9218 42.8627 67.6314 43.0459L42.7337 58.7489C42.4077 58.9544 41.9927 58.9544 41.6667 58.7489L16.769 43.0459C16.4786 42.8628 16.3025 42.5434 16.3025 42.2001C16.3025 41.8567 16.4786 41.5374 16.769 41.3543L41.6667 25.6513C41.9927 25.4457 42.4077 25.4457 42.7337 25.6513L67.6314 41.3543C67.9218 41.5374 68.0979 41.8567 68.0979 42.2001ZM42.2002 27.6794L19.177 42.2001L42.2002 56.7208L65.2234 42.2001L42.2002 27.6794Z" fill="#00AE99"/> +<path fill-rule="evenodd" clip-rule="evenodd" d="M66.1803 49.8738C66.5224 50.2245 66.5601 50.7714 66.2693 51.1656L43.005 82.7131C42.8165 82.9687 42.5178 83.1196 42.2002 83.1196C41.8826 83.1196 41.5838 82.9687 41.3953 82.7131L18.1311 51.1656C17.8403 50.7714 17.878 50.2245 18.2201 49.8739C18.5621 49.5232 19.1079 49.4719 19.5092 49.7528L42.2002 65.6307L64.8912 49.7528C65.2925 49.4719 65.8383 49.5232 66.1803 49.8738ZM61.0375 54.8904L42.7735 67.6705C42.4292 67.9114 41.9711 67.9114 41.6268 67.6705L23.3628 54.8904L42.2002 80.4347L61.0375 54.8904Z" fill="#00AE99"/> +<path fill-rule="evenodd" clip-rule="evenodd" d="M42.2002 1.28039C42.5439 1.28039 42.8635 1.45687 43.0465 1.74773L68.1713 41.6673L66.4786 42.7326L42.2002 4.15775L17.9218 42.7327L16.2291 41.6673L41.3539 1.74773C41.5369 1.45687 41.8565 1.28039 42.2002 1.28039Z" fill="#00AE99"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/extensibleArchitecture.svg b/packages/website/ts/@next/icons/illustrations/extensibleArchitecture.svg new file mode 100755 index 000000000..7674b3289 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/extensibleArchitecture.svg @@ -0,0 +1,11 @@ +<svg width="90" height="90" viewBox="0 0 90 90" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M45.0089 45.022L80.128 45.022L80.128 68.6648L68.5 68.6648" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M44.9968 45.0043L69.8295 69.837L53.1116 86.5548L44.9968 78.4399" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M45 44.9999V80.119H21.3572V69" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M44.9932 44.9767L20.1605 69.8094L3.44264 53.0916L11.5575 44.9767" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M45.0066 44.9802L9.88753 44.9802L9.88753 21.3373L21 21.3373" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M45.0057 44.9928L20.173 20.1601L36.8908 3.44228L45.0057 11.5571" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M45.0133 44.9977L45.0133 9.87867L68.6561 9.87867L68.6561 21" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M45.0249 45.006H62H78.4605L86.5754 36.8911L69.8575 20.1733L45.0249 45.006Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M45 88C68.7482 88 88 68.7482 88 45C88 21.2518 68.7482 2 45 2C21.2518 2 2 21.2518 2 45C2 68.7482 21.2518 88 45 88Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/flexibleIntegration.svg b/packages/website/ts/@next/icons/illustrations/flexibleIntegration.svg new file mode 100755 index 000000000..dee44d4c0 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/flexibleIntegration.svg @@ -0,0 +1,12 @@ +<svg width="150" height="150" viewBox="0 0 150 150" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M75 148C115.317 148 148 115.317 148 75C148 34.6832 115.317 2 75 2C34.6832 2 2 34.6832 2 75C2 115.317 34.6832 148 75 148Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<rect x="45" y="4" width="30" height="71" rx="15" stroke="#00AE99" stroke-width="3"/> +<rect x="45" y="4" width="30" height="30" rx="15" stroke="#00AE99" stroke-width="3"/> +<rect x="116" y="45" width="30" height="30" rx="15" stroke="#00AE99" stroke-width="3"/> +<rect x="75" y="116" width="30" height="30" rx="15" stroke="#00AE99" stroke-width="3"/> +<rect x="4" y="75" width="30" height="30" rx="15" stroke="#00AE99" stroke-width="3"/> +<rect x="75" y="75" width="30" height="71" rx="15" stroke="#00AE99" stroke-width="3"/> +<rect x="75" y="45" width="71" height="30" rx="15" stroke="#00AE99" stroke-width="3"/> +<rect x="4" y="75" width="71" height="30" rx="15" stroke="#00AE99" stroke-width="3"/> +<path d="M43.5 19V60H46.5V19H43.5ZM30 73.5C22.5442 73.5 16.5 67.4558 16.5 60H13.5C13.5 69.1127 20.8873 76.5 30 76.5V73.5ZM43.5 60C43.5 67.4558 37.4558 73.5 30 73.5V76.5C39.1127 76.5 46.5 69.1127 46.5 60H43.5ZM106.5 131V90H103.5V131H106.5ZM120 76.5C127.456 76.5 133.5 82.5442 133.5 90H136.5C136.5 80.8873 129.113 73.5 120 73.5V76.5ZM120 73.5C110.887 73.5 103.5 80.8873 103.5 90H106.5C106.5 82.5442 112.544 76.5 120 76.5V73.5ZM131 43.5H90V46.5H131V43.5ZM90 43.5C82.5442 43.5 76.5 37.4558 76.5 30H73.5C73.5 39.1127 80.8873 46.5 90 46.5V43.5ZM90 13.5C80.8873 13.5 73.5 20.8873 73.5 30H76.5C76.5 22.5442 82.5442 16.5 90 16.5V13.5ZM19 106.5H60V103.5H19V106.5ZM73.5 120C73.5 127.456 67.4558 133.5 60 133.5V136.5C69.1127 136.5 76.5 129.113 76.5 120H73.5ZM60 106.5C67.4558 106.5 73.5 112.544 73.5 120H76.5C76.5 110.887 69.1127 103.5 60 103.5V106.5ZM139.099 40.8017C136.843 42.4964 134.041 43.5 131 43.5V46.5C134.713 46.5 138.143 45.2719 140.901 43.2004L139.099 40.8017ZM90 16.5H116.5V13.5H90V16.5ZM16.5 60V33H13.5V60H16.5ZM40.8008 10.8995C42.496 13.1559 43.5 15.9585 43.5 19H46.5C46.5 15.2865 45.2714 11.8556 43.1992 9.09752L40.8008 10.8995ZM19 103.5C15.2865 103.5 11.8556 104.729 9.09752 106.801L10.8995 109.199C13.1559 107.504 15.9585 106.5 19 106.5V103.5ZM60 133.5H33V136.5H60V133.5ZM109.199 139.1C107.504 136.844 106.5 134.041 106.5 131H103.5C103.5 134.714 104.729 138.144 106.801 140.902L109.199 139.1ZM133.5 90V116.5H136.5V90H133.5Z" fill="#00AE99"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/flexibleIntegration0xInstant.svg b/packages/website/ts/@next/icons/illustrations/flexibleIntegration0xInstant.svg new file mode 100755 index 000000000..bb5116b8b --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/flexibleIntegration0xInstant.svg @@ -0,0 +1,17 @@ +<svg width="250" height="250" viewBox="0 0 250 250" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M125 247C192.379 247 247 192.379 247 125C247 57.6213 192.379 3 125 3C57.6213 3 3 57.6213 3 125C3 192.379 57.6213 247 125 247Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M125 2V49.5839C125 63.4281 113.777 74.651 99.9329 74.651V74.651C86.0887 74.651 74.8658 63.4281 74.8658 49.5839V13" stroke="#00AE99" stroke-width="3"/> +<rect x="25" y="75" width="50.1342" height="50.1342" rx="25.0671" stroke="#00AE99" stroke-width="3"/> +<rect x="125" y="25" width="50.1342" height="50.1342" rx="25.0671" stroke="#00AE99" stroke-width="3"/> +<rect x="108" y="88" width="34" height="34" rx="17" stroke="#00AE99" stroke-width="3"/> +<rect x="175" y="125" width="50.1342" height="50.1342" rx="25.0671" stroke="#00AE99" stroke-width="3"/> +<rect x="75" y="175" width="50.1342" height="50.1342" rx="25.0671" stroke="#00AE99" stroke-width="3"/> +<path d="M125 248V200.067C125 186.223 136.223 175 150.067 175V175C163.911 175 175.134 186.223 175.134 200.067V236.5" stroke="#00AE99" stroke-width="3"/> +<path d="M246.5 125H200.067C186.223 125 175 113.777 175 99.9328V99.9328C175 86.0886 186.223 74.8657 200.067 74.8657H235.5" stroke="#00AE99" stroke-width="3"/> +<path d="M200 73.5001H150V76.5001H200V73.5001ZM150 73.5001C137.021 73.5001 126.5 62.9788 126.5 50.0001H123.5C123.5 64.6356 135.364 76.5001 150 76.5001V73.5001ZM150 23.5001C135.364 23.5001 123.5 35.3645 123.5 50.0001H126.5C126.5 37.0214 137.021 26.5001 150 26.5001V23.5001ZM223.12 54.2318C221.128 65.1907 211.533 73.5001 200 73.5001V76.5001C213.009 76.5001 223.825 67.1282 226.072 54.7682L223.12 54.2318ZM150 26.5001H195V23.5001H150V26.5001Z" fill="#00AE99"/> +<path d="M3 125H49.5839C63.4281 125 74.651 136.223 74.651 150.067V150.067C74.651 163.911 63.4281 175.134 49.5839 175.134H14" stroke="#00AE99" stroke-width="3"/> +<path d="M73.5 50V100H76.5V50H73.5ZM50 123.5C37.0213 123.5 26.5 112.979 26.5 100H23.5C23.5 114.636 35.3645 126.5 50 126.5V123.5ZM73.5 100C73.5 112.979 62.9787 123.5 50 123.5V126.5C64.6355 126.5 76.5 114.636 76.5 100H73.5ZM223.5 150V194H226.5V150H223.5ZM176.5 200V150H173.5V200H176.5ZM200 126.5C212.979 126.5 223.5 137.021 223.5 150H226.5C226.5 135.364 214.636 123.5 200 123.5V126.5ZM200 123.5C185.364 123.5 173.5 135.364 173.5 150H176.5C176.5 137.021 187.021 126.5 200 126.5V123.5ZM50 176.5H100V173.5H50V176.5ZM123.5 200C123.5 212.979 112.979 223.5 100 223.5V226.5C114.636 226.5 126.5 214.636 126.5 200H123.5ZM100 176.5C112.979 176.5 123.5 187.021 123.5 200H126.5C126.5 185.364 114.636 173.5 100 173.5V176.5ZM54.7016 26.9701C65.4275 29.1474 73.5 38.6326 73.5 50H76.5C76.5 37.1778 67.3949 26.4855 55.2984 24.0301L54.7016 26.9701ZM26.5 100V55H23.5V100H26.5ZM100 223.5H55V226.5H100V223.5ZM50 173.5C37.1778 173.5 26.4855 182.605 24.0301 194.702L26.9701 195.298C29.1474 184.572 38.6326 176.5 50 176.5V173.5ZM195.768 223.12C184.809 221.128 176.5 211.533 176.5 200H173.5C173.5 213.009 182.872 223.825 195.232 226.072L195.768 223.12Z" fill="#00AE99"/> +<rect x="75" y="75" width="100" height="100" stroke="#00AE99" stroke-width="3"/> +<rect x="86" y="144" width="78" height="19" stroke="#00AE99" stroke-width="3"/> +<path d="M88 134H162" stroke="#00AE99" stroke-width="3"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/flexibleOrders.svg b/packages/website/ts/@next/icons/illustrations/flexibleOrders.svg new file mode 100755 index 000000000..f4545ae38 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/flexibleOrders.svg @@ -0,0 +1,4 @@ +<svg width="91" height="90" viewBox="0 0 91 90" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M2 45C2 68.7579 21.2421 88 45 88C68.7579 88 88 68.7579 88 45C88 21.6448 69.3906 2.63278 46.1793 2.02876C45.7478 2.02876 45.3452 2 44.9137 2C21.2134 2.02876 2 21.2709 2 45Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/> +<path d="M67.7548 20.2253V59.6647C67.7548 65.8083 62.7745 70.7886 56.6309 70.7886V70.7886C50.4873 70.7886 45.507 65.8083 45.507 59.6647V31.3492C45.507 25.2057 40.5266 20.2253 34.383 20.2253V20.2253C28.2395 20.2253 23.2591 25.2057 23.2591 31.3492V70.7886M67.7548 20.2253L60.676 27.3042M67.7548 20.2253L74.8337 27.3042M23.2591 70.7886L15.6746 63.2041M23.2591 70.7886L30.8436 63.2041" stroke="#00AE99" stroke-width="3"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/gamingAndCollectibles.svg b/packages/website/ts/@next/icons/illustrations/gamingAndCollectibles.svg new file mode 100755 index 000000000..c66af5088 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/gamingAndCollectibles.svg @@ -0,0 +1,18 @@ +<svg width="150" height="150" viewBox="0 0 150 150" fill="none" xmlns="http://www.w3.org/2000/svg"> +<circle cx="116" cy="34" r="32" stroke="#00AE99" stroke-width="3"/> +<circle cx="116" cy="34" r="14" stroke="#00AE99" stroke-width="3"/> +<path d="M116 5L121.216 17.9481L133.046 10.5385L129.655 24.0794L143.581 25.0385L132.878 34L143.581 42.9615L129.655 43.9206L133.046 57.4615L121.216 50.0519L116 63L110.784 50.0519L98.9542 57.4615L102.345 43.9206L88.4194 42.9615L99.122 34L88.4194 25.0385L102.345 24.0794L98.9542 10.5385L110.784 17.9481L116 5Z" stroke="#00AE99" stroke-width="3"/> +<circle cx="34" cy="34" r="32" stroke="#00AE99" stroke-width="3"/> +<path d="M66 34H45M2 34H23" stroke="#00AE99" stroke-width="3"/> +<circle cx="34" cy="34" r="11" stroke="#00AE99" stroke-width="3"/> +<circle cx="34" cy="34" r="4" stroke="#00AE99" stroke-width="3"/> +<circle cx="116" cy="116" r="32" stroke="#00AE99" stroke-width="3"/> +<circle cx="116" cy="116" r="6" stroke="#00AE99" stroke-width="3"/> +<path d="M103 114C103 110.686 100.314 108 97 108C93.6863 108 91 110.686 91 114" stroke="#00AE99" stroke-width="3"/> +<path d="M141 114C141 110.686 138.314 108 135 108C131.686 108 129 110.686 129 114" stroke="#00AE99" stroke-width="3"/> +<path d="M116 122V125C116 128.866 112.866 132 109 132V132C105.134 132 102 128.866 102 125V124" stroke="#00AE99" stroke-width="3"/> +<path d="M123 133V134C123 137.866 119.866 141 116 141V141C112.134 141 109 137.866 109 134V133" stroke="#00AE99" stroke-width="3"/> +<path d="M116 122V125C116 128.866 119.134 132 123 132V132C126.866 132 130 128.866 130 125V124" stroke="#00AE99" stroke-width="3"/> +<circle cx="34" cy="116" r="32" stroke="#00AE99" stroke-width="3"/> +<path d="M33.5556 142L7 113.1M33.5556 142L61 113.1M33.5556 142L22 113.1M33.5556 142L46.4444 113.1M7 113.1L16.8889 98H33.5556M7 113.1H22M61 113.1L51.1111 98H33.5556M61 113.1H46.4444M22 113.1H46.4444M22 113.1L33.5556 98M46.4444 113.1L33.5556 98" stroke="#00AE99" stroke-width="3"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/generateRevenueForYourBusiness-large.svg b/packages/website/ts/@next/icons/illustrations/generateRevenueForYourBusiness-large.svg new file mode 100755 index 000000000..681b8c41e --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/generateRevenueForYourBusiness-large.svg @@ -0,0 +1,28 @@ +<svg width="250" height="250" viewBox="0 0 250 250" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M177.423 216C176.501 218.606 176 221.411 176 224.333C176 227.953 176.769 231.394 178.154 234.5" stroke="#00AE99" stroke-width="3"/> +<path d="M177.423 199.333C176.501 201.94 176 204.745 176 207.667C176 216.712 180.804 224.636 188 229.025" stroke="#00AE99" stroke-width="3"/> +<path d="M224.577 182.667C225.499 185.273 226 188.078 226 191C226 191.504 225.985 192.004 225.956 192.5M177.423 182.667C176.501 185.273 176 188.078 176 191C176 204.807 187.193 216 201 216C202.712 216 204.384 215.828 206 215.5" stroke="#00AE99" stroke-width="3"/> +<path d="M224.577 166C225.499 168.606 226 171.411 226 174.333C226 188.14 214.807 199.333 201 199.333C187.193 199.333 176 188.14 176 174.333C176 171.411 176.501 168.606 177.423 166" stroke="#00AE99" stroke-width="3"/> +<path d="M224.577 149.333C225.499 151.94 226 154.745 226 157.667C226 171.474 214.807 182.667 201 182.667C187.193 182.667 176 171.474 176 157.667C176 154.745 176.501 151.94 177.423 149.333" stroke="#00AE99" stroke-width="3"/> +<path d="M224.577 132.667C225.499 135.273 226 138.078 226 141C226 154.807 214.807 166 201 166C187.193 166 176 154.807 176 141C176 138.078 176.501 135.273 177.423 132.667" stroke="#00AE99" stroke-width="3"/> +<path d="M224.577 116C225.499 118.606 226 121.411 226 124.333C226 138.14 214.807 149.333 201 149.333C187.193 149.333 176 138.14 176 124.333C176 121.411 176.501 118.606 177.423 116" stroke="#00AE99" stroke-width="3"/> +<path d="M224.577 99.3333C225.499 101.94 226 104.745 226 107.667C226 121.474 214.807 132.667 201 132.667C187.193 132.667 176 121.474 176 107.667C176 104.745 176.501 101.94 177.423 99.3333" stroke="#00AE99" stroke-width="3"/> +<ellipse cx="201" cy="91" rx="25" ry="25" stroke="#00AE99" stroke-width="3"/> +<path d="M193.5 101V102.5H195H207H208.5V101V97.2266V95.7266H207H204.551V80V78.5H203.051H199.253H198.762L198.366 78.7901L194.113 81.9073L193.5 82.3568V83.1172V87.6563V90.6153L195.887 88.8661L197.753 87.4982V95.7266H195H193.5V97.2266V101Z" stroke="#00AE99" stroke-width="3"/> +<path d="M148.577 216.667C149.499 219.273 150 222.078 150 225C150 233.805 145.449 241.546 138.57 246M101.423 216.667C100.501 219.273 100 222.078 100 225C100 233.805 104.551 241.546 111.43 246" stroke="#00AE99" stroke-width="3"/> +<path d="M148.577 234.667C149.499 237.273 150 240.078 150 243C150 243.335 149.993 243.668 149.98 244M101.423 234.667C100.501 237.273 100 240.078 100 243C100 243.335 100.007 243.668 100.02 244" stroke="#00AE99" stroke-width="3"/> +<path d="M148.577 200C149.499 202.606 150 205.411 150 208.333C150 222.14 138.807 233.333 125 233.333C111.193 233.333 100 222.14 100 208.333C100 205.411 100.501 202.606 101.423 200" stroke="#00AE99" stroke-width="3"/> +<path d="M148.577 183.333C149.499 185.94 150 188.745 150 191.667C150 205.474 138.807 216.667 125 216.667C111.193 216.667 100 205.474 100 191.667C100 188.745 100.501 185.94 101.423 183.333" stroke="#00AE99" stroke-width="3"/> +<path d="M148.577 166.667C149.499 169.273 150 172.078 150 175C150 188.807 138.807 200 125 200C111.193 200 100 188.807 100 175C100 172.078 100.501 169.273 101.423 166.667" stroke="#00AE99" stroke-width="3"/> +<path d="M148.577 150C149.499 152.606 150 155.411 150 158.333C150 172.14 138.807 183.333 125 183.333C111.193 183.333 100 172.14 100 158.333C100 155.411 100.501 152.606 101.423 150" stroke="#00AE99" stroke-width="3"/> +<path d="M148.577 133.333C149.499 135.94 150 138.745 150 141.667C150 155.474 138.807 166.667 125 166.667C111.193 166.667 100 155.474 100 141.667C100 138.745 100.501 135.94 101.423 133.333" stroke="#00AE99" stroke-width="3"/> +<circle cx="125" cy="125" r="25" stroke="#00AE99" stroke-width="3"/> +<path d="M117.5 135V136.5H119H131H132.5V135V131.227V129.727H131H128.551V114V112.5H127.051H123.253H122.762L122.366 112.79L118.113 115.907L117.5 116.357V117.117V121.656V124.615L119.887 122.866L121.753 121.498V129.727H119H117.5V131.227V135Z" stroke="#00AE99" stroke-width="3"/> +<path d="M71.5775 216.333C72.4987 218.94 73 221.745 73 224.667C73 227.966 72.3608 231.116 71.1996 234" stroke="#00AE99" stroke-width="3"/> +<path d="M71.5774 199.667C72.4987 202.273 73 205.078 73 208C73 216.834 68.4176 224.599 61.5 229.045" stroke="#00AE99" stroke-width="3"/> +<path d="M23 191.333C23 188.411 23.5013 185.606 24.4225 183M71.5774 183C72.4987 185.606 73 188.411 73 191.333C73 205.14 61.8071 216.333 48 216.333C46.8122 216.333 45.6437 216.25 44.5 216.09" stroke="#00AE99" stroke-width="3"/> +<path d="M71.5774 166.333C72.4987 168.94 73 171.745 73 174.667C73 188.474 61.8071 199.667 48 199.667C34.1929 199.667 23 188.474 23 174.667C23 171.745 23.5013 168.94 24.4225 166.333" stroke="#00AE99" stroke-width="3"/> +<ellipse cx="48" cy="158" rx="25" ry="25" stroke="#00AE99" stroke-width="3"/> +<path d="M40.5 168V169.5H42H54H55.5V168V164.227V162.727H54H51.5506V147V145.5H50.0506H46.2532H45.7623L45.3665 145.79L41.1133 148.907L40.5 149.357V150.117V154.656V157.615L42.8867 155.866L44.7532 154.498V162.727H42H40.5V164.227V168Z" stroke="#00AE99" stroke-width="3"/> +<circle cx="125" cy="125" r="121.667" stroke="#00AE99" stroke-width="3"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/getInTouch.svg b/packages/website/ts/@next/icons/illustrations/getInTouch.svg new file mode 100755 index 000000000..f44365351 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/getInTouch.svg @@ -0,0 +1,13 @@ +<svg width="150" height="150" viewBox="0 0 150 150" fill="none" xmlns="http://www.w3.org/2000/svg"> +<circle cx="75" cy="75" r="73" stroke="#00AE99" stroke-width="3"/> +<path d="M113 75C113 85.3064 108.897 94.6546 102.235 101.5C98.4048 105.436 71 132.5 71 132.5V112.792C51.8933 110.793 37 94.6359 37 75C37 54.0132 54.0132 37 75 37C95.9868 37 113 54.0132 113 75Z" stroke="#00AE99" stroke-width="3"/> +<circle cx="75" cy="75" r="4" stroke="#00AE99" stroke-width="3"/> +<circle cx="91" cy="75" r="4" stroke="#00AE99" stroke-width="3"/> +<circle cx="59" cy="75" r="4" stroke="#00AE99" stroke-width="3"/> +<path d="M76 37H137.5" stroke="#00AE99" stroke-width="3"/> +<path d="M37 73.5L37 12M113 137.5L113 75" stroke="#00AE99" stroke-width="3"/> +<path d="M13 113H71.5" stroke="#00AE99" stroke-width="3"/> +<path d="M49.087 47.5264L92.574 4.03932" stroke="#00AE99" stroke-width="3"/> +<path d="M47.3192 100.913L3.8321 57.4259M146.314 92.4277L102.12 48.2335" stroke="#00AE99" stroke-width="3"/> +<path d="M58.2793 145.814L101.766 102.327" stroke="#00AE99" stroke-width="3"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/getStarted.svg b/packages/website/ts/@next/icons/illustrations/getStarted.svg new file mode 100644 index 000000000..627e1810b --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/getStarted.svg @@ -0,0 +1,13 @@ +<svg width="150" height="150" viewBox="0 0 150 150" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g> +<circle cx="75" cy="75" r="73" stroke="#00AE99" stroke-width="3"/> +<circle cx="75" cy="75" r="58" stroke="#00AE99" stroke-width="3"/> +<path d="M62.9792 62.9792L36.6447 113.355L87.0208 87.0208M62.9792 62.9792L113.355 36.6447L87.0208 87.0208M62.9792 62.9792L87.0208 87.0208" stroke="#00AE99" stroke-width="3"/> +<path d="M75 2V17M75 133V148" stroke="#00AE99" stroke-width="3"/> +<path d="M2 75L17 75M133 75L148 75" stroke="#00AE99" stroke-width="3"/> +<path d="M11.7801 38.5L24.7705 46M125.229 104L138.22 111.5" stroke="#00AE99" stroke-width="3"/> +<path d="M38.5001 11.7801L46.0001 24.7705M104 125.229L111.5 138.22" stroke="#00AE99" stroke-width="3"/> +<path d="M111.5 11.7801L104 24.7705M46 125.229L38.5 138.22" stroke="#00AE99" stroke-width="3"/> +<path d="M138.22 38.5L125.229 46M24.7705 104L11.7801 111.5" stroke="#00AE99" stroke-width="3"/> +</g> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/launchKit.svg b/packages/website/ts/@next/icons/illustrations/launchKit.svg new file mode 100644 index 000000000..fa11584af --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/launchKit.svg @@ -0,0 +1,18 @@ +<svg width="404" height="404" viewBox="0 0 404 404" fill="none" xmlns="http://www.w3.org/2000/svg"> +<circle cx="202" cy="202" r="200" stroke="#00AE99" stroke-width="3"/> +<rect x="61" y="251" width="39" height="92" rx="19.5" stroke="#00AE99" stroke-width="3"/> +<rect x="100" y="251" width="39" height="92" rx="19.5" stroke="#00AE99" stroke-width="3"/> +<rect x="139" y="251" width="39" height="92" rx="19.5" stroke="#00AE99" stroke-width="3"/> +<rect x="61" y="251" width="39" height="39" rx="19.5" stroke="#00AE99" stroke-width="3"/> +<rect x="100" y="251" width="39" height="39" rx="19.5" stroke="#00AE99" stroke-width="3"/> +<rect x="139" y="304" width="39" height="39" rx="19.5" stroke="#00AE99" stroke-width="3"/> +<rect x="178" y="304" width="39" height="39" rx="19.5" stroke="#00AE99" stroke-width="3"/> +<rect x="178" y="251" width="39" height="92" rx="19.5" stroke="#00AE99" stroke-width="3"/> +<circle cx="100" cy="212" r="39" stroke="#00AE99" stroke-width="3"/> +<circle cx="178" cy="212" r="39" stroke="#00AE99" stroke-width="3"/> +<rect x="61" y="79" width="156" height="94" stroke="#00AE99" stroke-width="3"/> +<rect width="39" height="18" transform="matrix(1 0 0 -1 84 79)" stroke="#00AE99" stroke-width="3"/> +<rect width="39" height="18" transform="matrix(1 0 0 -1 155 79)" stroke="#00AE99" stroke-width="3"/> +<path d="M217 94V61H250M217 94L250 61M217 94H250V61M217 94V241.125M250 61H333M333 61H343V251H217V241.125M333 61V241.125H217" stroke="#00AE99" stroke-width="3"/> +<path d="M275.825 252L218 343H341L275.825 252Z" stroke="#00AE99" stroke-width="3"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/launchKit_versionB.svg b/packages/website/ts/@next/icons/illustrations/launchKit_versionB.svg new file mode 100755 index 000000000..45f9ecc75 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/launchKit_versionB.svg @@ -0,0 +1,7 @@ +<svg width="404" height="404" viewBox="0 0 404 404" fill="none" xmlns="http://www.w3.org/2000/svg"> +<circle cx="202" cy="202" r="200" stroke="#00AE99" stroke-width="3"/> +<path d="M111.093 201.667L201.622 292.195M111.093 201.667L24.7433 115.316L115.098 24.6137L188.958 98.4738M111.093 201.667L24.7432 288.017L114.053 379.764L201.622 292.195M111.093 201.667L167.107 145.653M292.151 201.667L201.622 292.195M292.151 201.667L379.546 289.062L289.191 379.764L201.622 292.195M292.151 201.667L380.59 113.227L290.236 22.5243L214.983 97.7774M292.151 201.667L236.137 145.653M201.622 292.195L201.622 400.137M201.622 400.137L254.81 346.95M201.622 400.137L148.435 346.95" stroke="#00AE99" stroke-width="3"/> +<path d="M202 85L262 145H142L202 85Z" stroke="#00AE99" stroke-width="3"/> +<path d="M202 146L262 205H142L202 146Z" stroke="#00AE99" stroke-width="3"/> +<path d="M245 249L202 206L159 249" stroke="#00AE99" stroke-width="3"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/legalResources.svg b/packages/website/ts/@next/icons/illustrations/legalResources.svg new file mode 100755 index 000000000..a8ba7fceb --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/legalResources.svg @@ -0,0 +1,4 @@ +<svg width="90" height="90" viewBox="0 0 90 90" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M2.00001 45C2.00001 68.7578 21.2421 88 45 88C68.7579 88 88 68.7578 88 45C88 21.6448 69.3906 2.63278 46.1793 2.02876C45.7478 2.02876 45.3452 2 44.9137 2C21.2134 2.02876 2.00001 21.2709 2.00001 45Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/> +<path d="M45 76V11M45 76H15H75H45ZM45 11H24M45 11H66M24 11L4 47M24 11L44 47M66 11L46 47M66 11L86 47M4 47H44M4 47C4 47 4 65 24 65C44 65 44 47 44 47M46 47H86M46 47C46 47 46 65 66 65C85.25 65 86 47 86 47" stroke="#00AE99" stroke-width="3"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/logo-mark.svg b/packages/website/ts/@next/icons/illustrations/logo-mark.svg new file mode 100644 index 000000000..4e9c9d2cb --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/logo-mark.svg @@ -0,0 +1,6 @@ +<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M6.30134 18.9605L8.63004 16.5511L5.73498 12.6444L2.04888 7.4287C0.746637 9.65112 0 12.2381 0 15C0 19.5753 2.04888 23.6718 5.28027 26.4229L9.95919 23.1161C8.36771 22.1247 7.08565 20.6812 6.30134 18.9605Z" fill="white"/> +<path d="M11.0395 6.30134L13.4489 8.63004L17.3556 5.73498L22.5713 2.04888C20.3489 0.746637 17.7619 0 15 0C10.4247 0 6.32825 2.04888 3.57713 5.28027L6.88386 9.95919C7.87534 8.36771 9.31883 7.08565 11.0395 6.30134Z" fill="white"/> +<path d="M21.37 13.4489L24.265 17.3556L27.9511 22.5713C29.2534 20.3489 30 17.7619 30 15C30 10.4247 27.9511 6.32825 24.7197 3.57713L20.0408 6.88386C21.6323 7.87534 22.9144 9.31883 23.6987 11.0395L21.37 13.4489Z" fill="white"/> +<path d="M26.4229 24.7197L23.1161 20.0408C22.1247 21.6323 20.6812 22.9144 18.9605 23.6987L16.5511 21.37L12.6444 24.265L7.4287 27.9511C9.65112 29.2534 12.2381 30 15 30C19.5753 30 23.6718 27.9511 26.4229 24.7197Z" fill="white"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/logo-outlined.svg b/packages/website/ts/@next/icons/illustrations/logo-outlined.svg new file mode 100644 index 000000000..a09d2355f --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/logo-outlined.svg @@ -0,0 +1,14 @@ +<svg width="400" height="406" viewBox="0 0 400 406" fill="none" xmlns="http://www.w3.org/2000/svg"> +<mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="400" height="406"> +<ellipse cx="200" cy="202.967" rx="200" ry="202.744" fill="#C4C4C4"/> +</mask> +<g mask="url(#mask0)"> +<path d="M162.629 260.116L161.587 258.71L159.447 260.297L161.753 261.631L162.629 260.116ZM193.062 269.329L192.945 271.075L192.953 271.076L193.062 269.329ZM234.92 258.634L235.854 260.113L235.86 260.109L234.92 258.634ZM250.83 244.761L252.163 245.895L253.051 244.85L252.25 243.738L250.83 244.761ZM238.764 228.665L240.146 227.592L240.141 227.585L240.135 227.578L238.764 228.665ZM235.24 224.217L236.612 223.13L235.079 221.196L233.761 223.282L235.24 224.217ZM216.446 240.631L215.231 241.89L216.098 242.727L217.189 242.216L216.446 240.631ZM204.487 229.088L205.702 227.829L204.636 226.8L203.445 227.682L204.487 229.088ZM137.215 166.291L138.602 165.224L137.006 163.149L135.699 165.418L137.215 166.291ZM128.139 196.154L126.393 196.035L126.392 196.044L128.139 196.154ZM138.924 237.666L137.455 238.618H137.455L138.924 237.666ZM152.912 253.445L151.79 254.787L152.824 255.652L153.924 254.873L152.912 253.445ZM169.143 241.478L170.204 242.87L170.211 242.864L170.218 242.859L169.143 241.478ZM173.628 237.984L174.703 239.364L176.66 237.839L174.567 236.507L173.628 237.984ZM157.077 219.24L155.833 218.008L154.968 218.882L155.497 219.992L157.077 219.24ZM168.822 207.379L170.066 208.611L171.142 207.524L170.209 206.312L168.822 207.379ZM232.57 140.982L233.582 142.41L235.808 140.833L233.447 139.467L232.57 140.982ZM202.138 131.769L202.018 133.515L202.021 133.515L202.138 131.769ZM160.173 142.464L161.114 143.94L161.117 143.938L160.173 142.464ZM144.263 156.337L142.93 155.203L142.042 156.248L142.843 157.36L144.263 156.337ZM156.329 172.433L154.946 173.506L154.952 173.513L154.957 173.52L156.329 172.433ZM159.853 176.881L158.481 177.968L159.996 179.88L161.322 177.832L159.853 176.881ZM178.753 160.467L179.961 159.201L179.1 158.379L178.019 158.878L178.753 160.467ZM189.965 171.163L188.757 172.429L189.8 173.424L190.976 172.591L189.965 171.163ZM258.091 234.489L256.699 235.55L258.301 237.651L259.611 235.357L258.091 234.489ZM267.06 204.944L268.806 205.065L268.807 205.054L267.06 204.944ZM256.276 163.432L257.748 162.486L257.744 162.48L256.276 163.432ZM242.287 147.653L243.41 146.311L242.376 145.446L241.276 146.225L242.287 147.653ZM226.057 159.62L224.995 158.228L224.988 158.234L224.981 158.239L226.057 159.62ZM221.572 163.114L220.496 161.734L218.526 163.27L220.642 164.597L221.572 163.114ZM238.23 181.858L236.65 182.61L236.658 182.628L236.667 182.646L238.23 181.858ZM238.336 182.07L239.592 183.289L240.46 182.395L239.899 181.282L238.336 182.07ZM227.018 193.719L225.763 192.499L224.712 193.58L225.626 194.779L227.018 193.719ZM161.753 261.631C170.951 266.952 181.568 270.316 192.945 271.075L193.178 267.583C182.345 266.86 172.246 263.658 163.505 258.601L161.753 261.631ZM192.953 271.076C208.709 272.053 223.488 267.928 235.854 260.113L233.985 257.154C222.219 264.589 208.167 268.512 193.17 267.583L192.953 271.076ZM235.86 260.109C241.988 256.203 247.459 251.428 252.163 245.895L249.497 243.628C245.018 248.896 239.811 253.44 233.979 257.158L235.86 260.109ZM252.25 243.738C248.498 238.53 244.428 233.112 240.146 227.592L237.381 229.737C241.642 235.231 245.687 240.615 249.41 245.784L252.25 243.738ZM240.135 227.578C239.548 226.837 238.961 226.095 238.373 225.354C237.786 224.613 237.199 223.872 236.612 223.13L233.868 225.304C234.455 226.045 235.043 226.786 235.63 227.528C236.217 228.269 236.805 229.01 237.392 229.751L240.135 227.578ZM233.761 223.282C229.462 230.082 223.103 235.581 215.704 239.046L217.189 242.216C225.166 238.48 232.048 232.542 236.719 225.152L233.761 223.282ZM217.662 239.372L205.702 227.829L203.272 230.347L215.231 241.89L217.662 239.372ZM203.445 227.682L161.587 258.71L163.671 261.522L205.529 230.494L203.445 227.682ZM135.699 165.418C130.444 174.538 127.159 184.855 126.393 196.035L129.885 196.274C130.614 185.639 133.736 175.836 138.732 167.165L135.699 165.418ZM126.392 196.044C125.407 211.676 129.568 226.449 137.455 238.618L140.392 236.714C132.904 225.162 128.949 211.131 129.886 196.264L126.392 196.044ZM137.455 238.618C141.395 244.696 146.211 250.122 151.79 254.787L154.035 252.102C148.722 247.66 144.14 242.496 140.392 236.714L137.455 238.618ZM153.924 254.873C159.176 251.152 164.638 247.116 170.204 242.87L168.081 240.087C162.542 244.313 157.113 248.324 151.901 252.017L153.924 254.873ZM170.218 242.859C171.713 241.694 173.208 240.529 174.703 239.364L172.552 236.603C171.057 237.768 169.562 238.933 168.067 240.098L170.218 242.859ZM174.567 236.507C167.693 232.132 162.147 225.819 158.657 218.488L155.497 219.992C159.267 227.91 165.253 234.728 172.688 239.46L174.567 236.507ZM158.32 220.471L170.066 208.611L167.579 206.148L155.833 218.008L158.32 220.471ZM170.209 206.312L138.602 165.224L135.828 167.358L167.435 208.446L170.209 206.312ZM233.447 139.467C224.248 134.146 213.631 130.782 202.254 130.023L202.021 133.515C212.855 134.238 222.953 137.44 231.694 142.497L233.447 139.467ZM202.258 130.023C186.496 128.937 171.602 133.064 159.229 140.991L161.117 143.938C172.876 136.404 187.027 132.482 202.018 133.515L202.258 130.023ZM159.232 140.989C153.105 144.895 147.634 149.67 142.93 155.203L145.596 157.47C150.075 152.202 155.282 147.658 161.114 143.94L159.232 140.989ZM142.843 157.36C146.594 162.568 150.665 167.986 154.946 173.506L157.712 171.361C153.451 165.867 149.406 160.483 145.683 155.314L142.843 157.36ZM154.957 173.52C155.545 174.261 156.132 175.003 156.719 175.744C157.307 176.485 157.894 177.226 158.481 177.968L161.225 175.794C160.637 175.053 160.05 174.312 159.463 173.57C158.875 172.829 158.288 172.088 157.701 171.347L154.957 173.52ZM161.322 177.832C165.736 171.011 171.997 165.515 179.487 162.056L178.019 158.878C169.919 162.619 163.152 168.561 158.384 175.93L161.322 177.832ZM177.545 161.733L188.757 172.429L191.173 169.896L179.961 159.201L177.545 161.733ZM190.976 172.591L233.582 142.41L231.559 139.554L188.953 169.735L190.976 172.591ZM259.611 235.357C264.754 226.349 268.04 216.141 268.806 205.065L265.315 204.823C264.586 215.35 261.465 225.05 256.571 233.621L259.611 235.357ZM268.807 205.054C269.792 189.418 265.63 174.754 257.748 162.486L254.803 164.378C262.298 176.043 266.251 189.971 265.314 204.834L268.807 205.054ZM257.744 162.48C253.804 156.402 248.989 150.976 243.41 146.311L241.165 148.996C246.478 153.438 251.059 158.602 254.807 164.384L257.744 162.48ZM241.276 146.225C236.024 149.946 230.561 153.982 224.995 158.228L227.118 161.011C232.657 156.785 238.086 152.774 243.299 149.081L241.276 146.225ZM224.981 158.239C224.234 158.822 223.486 159.404 222.739 159.987C221.991 160.569 221.244 161.151 220.496 161.734L222.648 164.495C223.395 163.912 224.143 163.33 224.89 162.747C225.637 162.165 226.385 161.583 227.132 161L224.981 158.239ZM220.642 164.597C227.616 168.971 233.159 175.281 236.65 182.61L239.81 181.106C236.039 173.186 230.05 166.365 222.502 161.632L220.642 164.597ZM236.667 182.646L236.774 182.858L239.899 181.282L239.792 181.07L236.667 182.646ZM237.081 180.85L225.763 192.499L228.273 194.938L239.592 183.289L237.081 180.85ZM225.626 194.779L256.699 235.55L259.483 233.428L228.41 192.658L225.626 194.779Z" fill="#00AE99"/> +<ellipse cx="60.0003" cy="200.535" rx="68" ry="68.9328" stroke="#00AE99" stroke-width="3.5"/> +<ellipse cx="201.6" cy="61.8583" rx="68.8" ry="69.7438" stroke="#00AE99" stroke-width="3.5"/> +<rect x="267.2" y="133.224" width="137.6" height="137.866" stroke="#00AE99" stroke-width="3.5"/> +<rect width="99.6242" height="99.6242" transform="matrix(0.702274 -0.711907 0.702274 0.711907 271.273 342.124)" stroke="#00AE99" stroke-width="3.5"/> +<path d="M267.2 340.833C267.2 301.418 235.248 269.467 195.834 269.467H-11.2003V412.198H195.834C235.248 412.198 267.2 380.247 267.2 340.833V340.833Z" stroke="#00AE99" stroke-width="3.5"/> +</g> +<path d="M398.25 202.967C398.25 313.996 309.468 403.961 200 403.961C90.532 403.961 1.75 313.996 1.75 202.967C1.75 91.939 90.532 1.97368 200 1.97368C309.468 1.97368 398.25 91.939 398.25 202.967Z" stroke="#00AE99" stroke-width="3.5"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/long-term-impact.svg b/packages/website/ts/@next/icons/illustrations/long-term-impact.svg new file mode 100644 index 000000000..dbd051598 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/long-term-impact.svg @@ -0,0 +1,9 @@ +<svg width="104" height="104" viewBox="0 0 104 104" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M52 102C79.6142 102 102 79.6142 102 52C102 24.3858 79.6142 2 52 2C24.3858 2 2 24.3858 2 52C2 79.6142 24.3858 102 52 102Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +<path d="M51.8639 91.7959C73.9553 91.7959 91.8639 73.8873 91.8639 51.7959C91.8639 29.7045 73.9553 11.7959 51.8639 11.7959C29.7726 11.7959 11.864 29.7045 11.864 51.7959C11.864 73.8873 29.7726 91.7959 51.8639 91.7959Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +<path d="M51.8636 91.7959C65.0741 91.7959 75.7833 73.8873 75.7833 51.7959C75.7833 29.7045 65.0741 11.7959 51.8636 11.7959C38.6531 11.7959 27.9438 29.7045 27.9438 51.7959C27.9438 73.8873 38.6531 91.7959 51.8636 91.7959Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +<path d="M51.864 11.7959V91.7959" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +<path d="M91.8639 51.796H11.864" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +<path d="M86.6201 71.7827H17.1084" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +<path d="M86.6201 31.7823H17.1084" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +</svg>
\ No newline at end of file diff --git a/packages/website/ts/@next/icons/illustrations/low-cost.svg b/packages/website/ts/@next/icons/illustrations/low-cost.svg new file mode 100644 index 000000000..530cbdd79 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/low-cost.svg @@ -0,0 +1,30 @@ +<svg width="82" height="82" viewBox="0 0 82 82" fill="none" xmlns="http://www.w3.org/2000/svg"> +<mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="82" height="82"> +<path d="M41 79.9333C62.5023 79.9333 79.9333 62.5023 79.9333 41C79.9333 19.4977 62.5023 2.06665 41 2.06665C19.4977 2.06665 2.06665 19.4977 2.06665 41C2.06665 62.5023 19.4977 79.9333 41 79.9333Z" fill="#00AE99" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +</mask> +<g mask="url(#mask0)"> +<ellipse cx="41" cy="76" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="3"/> +<ellipse cx="41" cy="71" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="3"/> +<ellipse cx="41" cy="66" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="3"/> +<ellipse cx="41" cy="61" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="3"/> +<ellipse cx="41" cy="56" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="3"/> +<circle cx="41" cy="50" r="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="3"/> +<circle cx="41" cy="44" r="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="3"/> +<ellipse cx="18" cy="89" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="3"/> +<ellipse cx="18" cy="84" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="3"/> +<ellipse cx="18" cy="79" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="3"/> +<ellipse cx="18" cy="74" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="3"/> +<ellipse cx="18" cy="69" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="3"/> +<circle cx="18" cy="63" r="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="3"/> +<circle cx="18" cy="57" r="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="3"/> +<ellipse cx="64" cy="70" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="3"/> +<ellipse cx="64" cy="64" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="3"/> +<ellipse cx="64" cy="59" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="3"/> +<ellipse cx="64" cy="54" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="3"/> +<ellipse cx="64" cy="49" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="3"/> +<ellipse cx="64" cy="44" rx="8" ry="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="3"/> +<circle cx="64" cy="38" r="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="3"/> +<circle cx="64" cy="32" r="8" fill="#F3F6F4" stroke="#00AE99" stroke-width="3"/> +<circle cx="41" cy="41" r="38.9333" stroke="#00AE99" stroke-width="3"/> +</g> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/marketingDesignHelp.svg b/packages/website/ts/@next/icons/illustrations/marketingDesignHelp.svg new file mode 100755 index 000000000..1e65bd54f --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/marketingDesignHelp.svg @@ -0,0 +1,11 @@ +<svg width="90" height="90" viewBox="0 0 90 90" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M45 88C68.7482 88 88 68.7482 88 45C88 21.2518 68.7482 2 45 2C21.2518 2 2 21.2518 2 45C2 68.7482 21.2518 88 45 88Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> +<path d="M70.2962 31.8956L57.4583 19.3541L44.833 32.1066L57.6708 44.6481L70.2962 31.8956Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> +<path d="M74.8267 14.5717L57.4829 19.3431L70.311 31.8859L74.8267 14.5717Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> +<path d="M32.184 19.5506L19.5587 32.3031L32.3965 44.8446L45.0218 32.092L32.184 19.5506Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> +<path d="M14.7418 15.0572L19.5451 32.2858L32.1719 19.5429L14.7418 15.0572Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> +<path d="M19.698 57.5441L32.5358 70.0856L45.1612 57.3331L32.3234 44.7916L19.698 57.5441Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> +<path d="M15.1732 74.8574L32.517 70.086L19.6889 57.5432L15.1732 74.8574Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> +<path d="M57.8243 69.8803L70.4497 57.1277L57.6119 44.5863L44.9865 57.3388L57.8243 69.8803Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> +<path d="M75.2581 74.3715L70.4548 57.1429L57.828 69.8857L75.2581 74.3715Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="bevel"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/milestoneGrants.svg b/packages/website/ts/@next/icons/illustrations/milestoneGrants.svg new file mode 100755 index 000000000..2c581864f --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/milestoneGrants.svg @@ -0,0 +1,7 @@ +<svg width="90" height="90" viewBox="0 0 90 90" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M2 45C2 68.7578 21.2421 88 45 88C68.7579 88 88 68.7578 88 45C88 21.6448 69.3906 2.63278 46.1793 2.02876C45.7478 2.02876 45.3452 2 44.9137 2C21.2134 2.02876 2 21.2709 2 45Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/> +<path d="M86.5 55.5L45 14L3.5 55.5" stroke="#00AE99" stroke-width="3"/> +<path d="M45 14C41.1667 18.8333 35.8 30.8 45 40C56.5 51.5 52 59.5 45 67C38.5223 73.9404 40.1798 83.4498 44.0292 88" stroke="#00AE99" stroke-width="3"/> +<path d="M78 73L45 40L12 73" stroke="#00AE99" stroke-width="3"/> +<path d="M62.5 84.5L45 67L27.5 84.5" stroke="#00AE99" stroke-width="3"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/networkedLiquidity-small.svg b/packages/website/ts/@next/icons/illustrations/networkedLiquidity-small.svg new file mode 100755 index 000000000..4b65a5353 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/networkedLiquidity-small.svg @@ -0,0 +1,20 @@ +<svg width="90" height="90" viewBox="0 0 90 90" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M39 8.48029C33.2192 9.42014 27.8875 11.702 23.335 14.9961M50.9349 8.48029C56.7423 9.41185 62.0964 11.6963 66.6651 15M75 23.3344C78.2924 27.8864 80.574 33.2182 81.5163 39M81.5163 51.0017C80.574 56.7845 78.2925 62.1161 75 66.6678M66.6651 75.002C62.0964 78.306 56.7423 80.5917 50.9349 81.5271M39 81.5165C33.2177 80.5746 27.8865 78.2936 23.335 75.002M15 66.6678C11.7076 62.1161 9.42602 56.7845 8.48376 51.0017M8.48376 39.0004C9.42608 33.2186 11.7078 27.8868 14.9996 23.3344" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/> +<path d="M42.163 47.837C40.6123 46.2863 40.6123 43.7489 42.163 42.163C43.7137 40.6123 46.2511 40.6123 47.837 42.163C49.3877 43.7137 49.3877 46.2511 47.837 47.837C46.2511 49.3877 43.7137 49.3877 42.163 47.837Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M42.163 30.837C40.6123 29.2863 40.6123 26.7489 42.163 25.163C43.7137 23.6123 46.2511 23.6123 47.837 25.163C49.3877 26.7137 49.3877 29.2511 47.837 30.837C46.2511 32.3877 43.7137 32.3877 42.163 30.837Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M42.163 64.837C40.6123 63.2863 40.6123 60.7489 42.163 59.163C43.7137 57.6123 46.2511 57.6123 47.837 59.163C49.3877 60.7137 49.3877 63.2511 47.837 64.837C46.2511 66.3877 43.7137 66.3877 42.163 64.837Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M40.7445 12.2555C38.4185 9.92952 38.4185 6.12335 40.7445 3.74449C43.0705 1.4185 46.8766 1.4185 49.2555 3.74449C51.5815 6.07048 51.5815 9.87665 49.2555 12.2555C46.8766 14.5815 43.0705 14.5815 40.7445 12.2555Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M40.7445 86.2555C38.4185 83.9295 38.4185 80.1233 40.7445 77.7445C43.0705 75.4185 46.8766 75.4185 49.2555 77.7445C51.5815 80.0705 51.5815 83.8767 49.2555 86.2555C46.8766 88.5815 43.0705 88.5815 40.7445 86.2555Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M30.837 47.837C29.2863 49.3877 26.7489 49.3877 25.163 47.837C23.6123 46.2863 23.6123 43.7489 25.163 42.163C26.7137 40.6123 29.2511 40.6123 30.837 42.163C32.3877 43.7489 32.3877 46.2863 30.837 47.837Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M64.837 47.837C63.2863 49.3877 60.7489 49.3877 59.163 47.837C57.6123 46.2863 57.6123 43.7489 59.163 42.163C60.7137 40.6123 63.2511 40.6123 64.837 42.163C66.3877 43.7489 66.3877 46.2863 64.837 47.837Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M12.2555 49.2555C9.92952 51.5815 6.12335 51.5815 3.74449 49.2555C1.4185 46.9295 1.4185 43.1234 3.74449 40.7445C6.07048 38.4185 9.87665 38.4185 12.2555 40.7445C14.5815 43.1233 14.5815 46.9295 12.2555 49.2555Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M86.2555 49.2555C83.9295 51.5815 80.1233 51.5815 77.7445 49.2555C75.4185 46.9295 75.4185 43.1234 77.7445 40.7445C80.0705 38.4185 83.8767 38.4185 86.2555 40.7445C88.5815 43.1233 88.5815 46.9295 86.2555 49.2555Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M32.9792 36.9913C30.7863 36.9913 28.992 35.1971 28.9671 32.9792C28.9671 30.7862 30.7614 28.992 32.9792 28.9671C35.1722 28.9671 36.9665 30.7613 36.9914 32.9792C36.9665 35.1971 35.1722 36.9913 32.9792 36.9913Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M57.0209 61.0329C54.8279 61.0329 53.0337 59.2387 53.0087 57.0208C53.0087 54.8278 54.803 53.0336 57.0209 53.0087C59.2138 53.0087 61.0081 54.8029 61.033 57.0208C61.0081 59.2387 59.2138 61.0329 57.0209 61.0329Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M18.8371 24.8552C15.5476 24.8552 12.8563 22.1639 12.8189 18.837C12.8189 15.5476 15.5103 12.8562 18.8371 12.8188C22.1265 12.8188 24.8179 15.5102 24.8553 18.837C24.8179 22.1639 22.1265 24.8552 18.8371 24.8552Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M71.163 77.1812C67.8736 77.1812 65.1822 74.4898 65.1448 71.163C65.1448 67.8735 67.8362 65.1822 71.163 65.1448C74.4525 65.1448 77.1438 67.8361 77.1812 71.163C77.1438 74.4898 74.4525 77.1812 71.163 77.1812Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M36.9913 57.0209C36.9913 59.2138 35.197 61.0081 32.9791 61.033C30.7862 61.033 28.9919 59.2388 28.967 57.0209C28.967 54.8279 30.7612 53.0337 32.9791 53.0088C35.197 53.0337 36.9913 54.8279 36.9913 57.0209Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M61.0329 32.9793C61.0329 35.1722 59.2386 36.9665 57.0208 36.9914C54.8278 36.9914 53.0335 35.1971 53.0086 32.9793C53.0086 30.7863 54.8029 28.992 57.0208 28.9671C59.2386 28.992 61.0329 30.7863 61.0329 32.9793Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M24.8552 71.163C24.8552 74.4525 22.1639 77.1438 18.837 77.1812C15.5476 77.1812 12.8562 74.4899 12.8188 71.163C12.8188 67.8736 15.5102 65.1822 18.837 65.1448C22.1639 65.1822 24.8552 67.8736 24.8552 71.163Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M77.1812 18.8371C77.1812 22.1266 74.4898 24.8179 71.163 24.8553C67.8735 24.8553 65.1822 22.1639 65.1448 18.8371C65.1448 15.5477 67.8361 12.8563 71.163 12.8189C74.4898 12.8563 77.1812 15.5477 77.1812 18.8371Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/networkedLiquidity.svg b/packages/website/ts/@next/icons/illustrations/networkedLiquidity.svg new file mode 100755 index 000000000..c50ba7e7c --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/networkedLiquidity.svg @@ -0,0 +1,28 @@ +<svg width="151" height="150" viewBox="0 0 151 150" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M138.211 65C136.62 55.0255 132.688 45.8318 126.996 38M138.211 85C136.62 94.9746 132.688 104.168 126.996 112M112.994 126C105.164 131.69 95.972 135.62 86 137.211M66 137.211C56.0279 135.62 46.8364 131.69 39.0059 126M25.0043 112C19.3121 104.168 15.3801 94.9746 13.7892 85M13.7892 65C15.3801 55.0255 19.3121 45.8318 25.0043 38M39.0059 24C46.8364 18.3101 56.0279 14.3797 66 12.7893M86 12.7893C95.9721 14.3797 105.164 18.3101 112.994 24" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M75.9998 21.882C81.4901 21.882 85.9408 17.4313 85.9408 11.941C85.9408 6.45074 81.4901 2 75.9998 2C70.5096 2 66.0588 6.45074 66.0588 11.941C66.0588 17.4313 70.5096 21.882 75.9998 21.882Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M75.9998 148C81.4901 148 85.9408 143.549 85.9408 138.059C85.9408 132.569 81.4901 128.118 75.9998 128.118C70.5096 128.118 66.0588 132.569 66.0588 138.059C66.0588 143.549 70.5096 148 75.9998 148Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M129.118 75.0001C129.118 80.4903 133.569 84.9411 139.059 84.9411C144.549 84.9411 149 80.4903 149 75.0001C149 69.5098 144.549 65.0591 139.059 65.0591C133.569 65.0591 129.118 69.5098 129.118 75.0001Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M2.99982 75.0001C2.99982 80.4903 7.45056 84.9411 12.9408 84.9411C18.4311 84.9411 22.8818 80.4903 22.8818 75.0001C22.8818 69.5098 18.4311 65.0591 12.9408 65.0591C7.45056 65.0591 2.99982 69.5098 2.99982 75.0001Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M113.56 37.4399C117.442 41.3221 123.737 41.3221 127.619 37.4399C131.501 33.5577 131.501 27.2634 127.619 23.3812C123.737 19.499 117.442 19.499 113.56 23.3812C109.678 27.2634 109.678 33.5577 113.56 37.4399Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M24.381 126.619C28.2632 130.501 34.5575 130.501 38.4397 126.619C42.322 122.737 42.322 116.442 38.4398 112.56C34.5576 108.678 28.2632 108.678 24.381 112.56C20.4988 116.442 20.4988 122.737 24.381 126.619Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M38.4397 37.4399C42.3219 33.5577 42.3219 27.2634 38.4397 23.3812C34.5575 19.499 28.2632 19.499 24.381 23.3812C20.4988 27.2634 20.4988 33.5577 24.381 37.4399C28.2632 41.3221 34.5575 41.3221 38.4397 37.4399Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M127.619 126.619C131.501 122.737 131.501 116.442 127.619 112.56C123.736 108.678 117.442 108.678 113.56 112.56C109.678 116.442 109.678 122.737 113.56 126.619C117.442 130.501 123.737 130.501 127.619 126.619Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M71.8365 79.1636C69.5464 76.8735 69.5464 73.1261 71.8365 70.784C74.1265 68.4939 77.8739 68.4939 80.216 70.784C82.5061 73.074 82.5061 76.8214 80.216 79.1636C77.8739 81.4537 74.1265 81.4537 71.8365 79.1636Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M51.7456 79.1636C49.4556 76.8735 49.4556 73.1261 51.7456 70.784C54.0357 68.4939 57.7831 68.4939 60.1252 70.784C62.4153 73.074 62.4153 76.8214 60.1252 79.1636C57.7831 81.4537 54.0878 81.4537 51.7456 79.1636Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M31.7071 79.1636C29.417 76.8735 29.417 73.1261 31.7071 70.784C33.9971 68.4939 37.7445 68.4939 40.0867 70.784C42.3767 73.074 42.3767 76.8214 40.0867 79.1636C37.7445 81.4537 33.9971 81.4537 31.7071 79.1636Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M91.8748 79.1636C89.5847 76.8736 89.5847 73.1262 91.8748 70.784C94.1649 68.4939 97.9123 68.4939 100.254 70.784C102.544 73.0741 102.544 76.8215 100.254 79.1636C97.9123 81.4537 94.1649 81.4537 91.8748 79.1636Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M111.912 79.1636C109.622 76.8736 109.622 73.1262 111.912 70.784C114.202 68.4939 117.95 68.4939 120.292 70.784C122.582 73.0741 122.582 76.8215 120.292 79.1636C117.95 81.4537 114.202 81.4537 111.912 79.1636Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M55.9113 60.7908C55.9113 57.5118 58.5657 54.9094 61.7926 54.9094C65.0716 54.9094 67.6739 57.5638 67.6739 60.7908C67.6739 64.0697 65.0195 66.6721 61.7926 66.6721C58.5657 66.7241 55.9113 64.0697 55.9113 60.7908Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M41.7526 46.6344C41.7526 43.3554 44.407 40.7531 47.6339 40.7531C50.9129 40.7531 53.5152 43.4075 53.5152 46.6344C53.5152 49.9134 50.8608 52.5157 47.6339 52.5157C44.3549 52.5157 41.7526 49.9134 41.7526 46.6344Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M84.2758 89.1566C84.2758 85.8776 86.9302 83.2753 90.1571 83.2753C93.4361 83.2753 96.0384 85.9297 96.0384 89.1566C96.0384 92.4356 93.384 95.0379 90.1571 95.0379C86.8781 95.09 84.2758 92.4356 84.2758 89.1566Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M98.4327 103.365C98.4327 100.086 101.087 97.4841 104.314 97.4841C107.593 97.4841 110.195 100.139 110.195 103.365C110.195 106.644 107.541 109.247 104.314 109.247C101.087 109.247 98.4327 106.592 98.4327 103.365Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M90.1579 54.9094C93.4369 54.9094 96.0392 57.5638 96.0392 60.7907C96.0392 64.0697 93.3848 66.672 90.1579 66.672C86.8789 66.672 84.2766 64.0176 84.2766 60.7907C84.2766 57.5638 86.8789 54.9094 90.1579 54.9094Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M104.366 40.7531C107.645 40.7531 110.248 43.4075 110.248 46.6344C110.248 49.9134 107.593 52.5157 104.366 52.5157C101.087 52.5157 98.4851 49.8613 98.4851 46.6344C98.4331 43.3554 101.087 40.7531 104.366 40.7531Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M61.7933 83.2753C65.0722 83.2753 67.6746 85.9297 67.6746 89.1566C67.6746 92.4356 65.0202 95.0379 61.7933 95.0379C58.5143 95.0379 55.9119 92.3835 55.9119 89.1566C55.9119 85.8776 58.5663 83.2753 61.7933 83.2753Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M47.6344 97.4323C50.9134 97.4323 53.5158 100.087 53.5158 103.314C53.5158 106.593 50.8614 109.195 47.6344 109.195C44.3555 109.195 41.7531 106.541 41.7531 103.314C41.7531 100.087 44.3555 97.4323 47.6344 97.4323Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M71.836 50.7461C74.1261 48.456 77.8735 48.456 80.2156 50.7461C82.5057 53.0362 82.5057 56.7836 80.2156 59.1257C77.9255 61.4158 74.1781 61.4158 71.836 59.1257C69.4939 56.7836 69.4939 53.0882 71.836 50.7461Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M71.836 30.7078C74.1261 28.4177 77.8735 28.4177 80.2156 30.7078C82.5057 32.9979 82.5057 36.7453 80.2156 39.0874C77.9255 41.3775 74.1781 41.3775 71.836 39.0874C69.4939 36.7453 69.4939 32.9979 71.836 30.7078Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M71.836 90.8745C74.1261 88.5844 77.8735 88.5844 80.2156 90.8745C82.5057 93.1646 82.5057 96.912 80.2156 99.2541C77.9255 101.544 74.1781 101.544 71.836 99.2541C69.4939 96.912 69.4939 93.1646 71.836 90.8745Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M71.836 110.913C74.1261 108.622 77.8735 108.622 80.2156 110.913C82.5057 113.203 82.5057 116.95 80.2156 119.292C77.9255 121.582 74.1781 121.582 71.836 119.292C69.4939 116.95 69.4939 113.203 71.836 110.913Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/orderBooks.svg b/packages/website/ts/@next/icons/illustrations/orderBooks.svg new file mode 100755 index 000000000..44e001ff0 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/orderBooks.svg @@ -0,0 +1,8 @@ +<svg width="150" height="150" viewBox="0 0 150 150" fill="none" xmlns="http://www.w3.org/2000/svg"> +<circle cx="75" cy="75" r="73" stroke="#00AE99" stroke-width="3"/> +<path d="M75 64V75M75 75H69V128H75M75 75H81V128H75M75 128V139" stroke="#00AE99" stroke-width="3"/> +<path d="M98 16V27M98 27H92V75H98M98 27H104V75H98M98 75V86" stroke="#00AE99" stroke-width="3"/> +<path d="M52 16V27M52 27H46V75H52M52 27H58V75H52M52 75V86" stroke="#00AE99" stroke-width="3"/> +<path d="M29 64V75M29 75H23V100H29M29 75H35V100H29M29 100V111" stroke="#00AE99" stroke-width="3"/> +<path d="M121 64V75M121 75H115V100H121M121 75H127V100H121M121 100V111" stroke="#00AE99" stroke-width="3"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/predictionMarkets.svg b/packages/website/ts/@next/icons/illustrations/predictionMarkets.svg new file mode 100755 index 000000000..820b79416 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/predictionMarkets.svg @@ -0,0 +1,7 @@ +<svg width="150" height="150" viewBox="0 0 150 150" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M126.5 126.737C139.78 113.518 148 95.2188 148 75C148 34.6832 115.317 2 75 2C34.6832 2 2 34.6832 2 75C2 94.9638 10.0138 113.056 23 126.235" stroke="#00AE99" stroke-width="3"/> +<path d="M127 4V22M127 40V22M127 22H109H145" stroke="#00AE99" stroke-width="3"/> +<path d="M104 37V45M104 53V45M104 45H96H112" stroke="#00AE99" stroke-width="3"/> +<rect x="19" y="137" width="112" height="11" stroke="#00AE99" stroke-width="3"/> +<rect x="23" y="126" width="104" height="11" stroke="#00AE99" stroke-width="3"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/protocol.svg b/packages/website/ts/@next/icons/illustrations/protocol.svg new file mode 100644 index 000000000..5c9c1531a --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/protocol.svg @@ -0,0 +1 @@ +<svg width="144" height="144" viewBox="0 0 144 144" fill="none" xmlns="http://www.w3.org/2000/svg"><g style="mix-blend-mode:screen" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"><path d="M72 132.722c33.536 0 60.722-27.186 60.722-60.722S105.536 11.278 72 11.278 11.278 38.464 11.278 72 38.464 132.722 72 132.722z"/><path d="M72 20.557A9.278 9.278 0 1 0 72 2a9.278 9.278 0 0 0 0 18.557zM114.942 38.336a9.278 9.278 0 1 0-9.278-9.278 9.278 9.278 0 0 0 9.278 9.278zM132.722 81.278A9.278 9.278 0 0 0 142 72a9.278 9.278 0 0 0-9.278-9.278 9.278 9.278 0 1 0 0 18.556zM114.942 124.221a9.279 9.279 0 1 0 0-18.557 9.279 9.279 0 0 0 0 18.557zM72 142a9.278 9.278 0 0 0 9.278-9.278 9.278 9.278 0 1 0-18.556 0A9.278 9.278 0 0 0 72 142zM29.058 124.221a9.278 9.278 0 0 0 9.278-9.279 9.278 9.278 0 0 0-9.278-9.278 9.278 9.278 0 0 0-9.279 9.278 9.278 9.278 0 0 0 9.279 9.279zM11.278 81.278a9.278 9.278 0 1 0 0-18.556 9.278 9.278 0 0 0 0 18.556zM29.058 38.336a9.278 9.278 0 1 0 0-18.557 9.278 9.278 0 0 0 0 18.557zM68.114 75.886c-2.138-2.137-2.138-5.635 0-7.82 2.137-2.138 5.635-2.138 7.82 0 2.138 2.137 2.138 5.634 0 7.82-2.185 2.138-5.683 2.138-7.82 0zM49.363 75.886c-2.137-2.137-2.137-5.635 0-7.82 2.137-2.138 5.635-2.138 7.821 0 2.137 2.137 2.137 5.634 0 7.82a5.571 5.571 0 0 1-7.821 0zM30.66 75.886c-2.137-2.137-2.137-5.635 0-7.82 2.138-2.138 5.636-2.138 7.822 0 2.137 2.137 2.137 5.634 0 7.82-2.186 2.138-5.684 2.138-7.821 0zM86.816 75.886c-2.137-2.137-2.137-5.635 0-7.82 2.138-2.138 5.635-2.138 7.821 0 2.138 2.137 2.138 5.634 0 7.82-2.186 2.138-5.683 2.138-7.82 0zM105.518 75.886c-2.137-2.137-2.137-5.635 0-7.82 2.138-2.138 5.635-2.138 7.821 0 2.138 2.137 2.138 5.634 0 7.82-2.186 2.138-5.683 2.138-7.821 0zM53.25 58.738c0-3.06 2.477-5.489 5.489-5.489 3.06 0 5.489 2.477 5.489 5.49 0 3.06-2.478 5.489-5.49 5.489-3.011.048-5.489-2.43-5.489-5.49zM40.036 45.525c0-3.06 2.478-5.489 5.49-5.489 3.06 0 5.489 2.477 5.489 5.49 0 3.06-2.478 5.489-5.49 5.489a5.453 5.453 0 0 1-5.489-5.49zM79.724 85.213c0-3.06 2.477-5.49 5.49-5.49 3.06 0 5.488 2.478 5.488 5.49 0 3.06-2.477 5.49-5.489 5.49-3.06.048-5.49-2.43-5.49-5.49zM92.937 98.475c0-3.06 2.477-5.49 5.49-5.49a5.483 5.483 0 0 1 5.488 5.49c0 3.06-2.477 5.489-5.489 5.489s-5.49-2.478-5.49-5.49zM85.213 53.25c3.06 0 5.49 2.477 5.49 5.488 0 3.06-2.478 5.49-5.49 5.49a5.483 5.483 0 0 1-5.49-5.49 5.483 5.483 0 0 1 5.49-5.489zM98.475 40.036c3.06 0 5.489 2.477 5.489 5.49 0 3.06-2.477 5.489-5.49 5.489a5.484 5.484 0 0 1-5.489-5.49c-.048-3.06 2.43-5.489 5.49-5.489zM58.739 79.724c3.06 0 5.489 2.477 5.489 5.489 0 3.06-2.478 5.49-5.49 5.49a5.483 5.483 0 0 1-5.489-5.49c0-3.06 2.478-5.49 5.49-5.49zM45.525 92.937c3.06 0 5.49 2.477 5.49 5.49a5.483 5.483 0 0 1-5.49 5.488 5.483 5.483 0 0 1-5.489-5.489 5.484 5.484 0 0 1 5.49-5.49zM68.114 49.363c2.137-2.138 5.635-2.138 7.82 0 2.138 2.137 2.138 5.635 0 7.82-2.137 2.138-5.634 2.138-7.82 0a5.483 5.483 0 0 1 0-7.82zM68.114 30.66c2.137-2.137 5.635-2.137 7.82 0 2.138 2.138 2.138 5.636 0 7.822-2.137 2.137-5.634 2.137-7.82 0-2.186-2.186-2.186-5.684 0-7.821zM68.114 86.816c2.137-2.137 5.635-2.137 7.82 0 2.138 2.138 2.138 5.635 0 7.821-2.137 2.137-5.634 2.137-7.82 0-2.186-2.186-2.186-5.683 0-7.82zM68.114 105.518c2.137-2.137 5.635-2.137 7.82 0 2.138 2.138 2.138 5.635 0 7.821-2.137 2.138-5.634 2.138-7.82 0-2.186-2.186-2.186-5.683 0-7.821z"/></g></svg>
\ No newline at end of file diff --git a/packages/website/ts/@next/icons/illustrations/ready-to-build.svg b/packages/website/ts/@next/icons/illustrations/ready-to-build.svg new file mode 100644 index 000000000..a26a4e236 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/ready-to-build.svg @@ -0,0 +1 @@ +<svg width="152" height="152" viewBox="0 0 152 152" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M76 151c41.421 0 75-33.579 75-75S117.421 1 76 1 1 34.579 1 76s33.579 75 75 75z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/><path d="M76 1.502l-30.852 44.8H76L76.05 76l30.803-44.9H76.001V1.502zM76 75.997l-30.853 44.799H76l.05 29.699 30.803-44.899H76V75.997z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10" stroke-linejoin="round"/><path d="M1.502 75.998l44.8 30.852V75.998L76 75.948 31.1 45.144v30.853H1.503zM76 76l45.101 31.522V76L151 75.95l-45.202-31.47V76H76z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10" stroke-linejoin="round"/></svg>
\ No newline at end of file diff --git a/packages/website/ts/@next/icons/illustrations/recruitingSupport.svg b/packages/website/ts/@next/icons/illustrations/recruitingSupport.svg new file mode 100755 index 000000000..d630b23d7 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/recruitingSupport.svg @@ -0,0 +1,7 @@ +<svg width="90" height="90" viewBox="0 0 90 90" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M2 45C2 68.7578 21.2421 88 45 88C68.7579 88 88 68.7578 88 45C88 21.6448 69.3906 2.63278 46.1793 2.02876C45.7478 2.02876 45.3452 2 44.9137 2C21.2134 2.02876 2 21.2709 2 45Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/> +<path d="M30 45C30 53.2876 36.7124 60 45 60C53.2876 60 60 53.2876 60 45C60 36.8528 53.5084 30.2207 45.4114 30.01C45.2609 30.01 45.1204 30 44.9699 30C36.7023 30.01 30 36.7224 30 45Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/> +<path d="M21 45C21 58.2602 31.7398 69 45 69C58.2602 69 69 58.2602 69 45C69 31.9645 58.6134 21.3532 45.6582 21.0161C45.4174 21.0161 45.1926 21 44.9518 21C31.7237 21.0161 21 31.7559 21 45Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/> +<path d="M56.5 56L76 75.5" stroke="#00AE99" stroke-width="3"/> +<path d="M45 70.5C54.0057 70.5 62.1515 74.8777 67.8311 81.94L70.1689 80.06C63.9926 72.3798 55.0243 67.5 45 67.5V70.5ZM45 67.5C34.9757 67.5 26.0074 72.3798 19.8311 80.06L22.1689 81.94C27.8485 74.8777 35.9943 70.5 45 70.5V67.5Z" fill="#00AE99"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/right-thing.svg b/packages/website/ts/@next/icons/illustrations/right-thing.svg new file mode 100644 index 000000000..eba2bbc36 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/right-thing.svg @@ -0,0 +1,6 @@ +<svg width="104" height="104" viewBox="0 0 104 104" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M52 102C79.6142 102 102 79.6142 102 52C102 24.3858 79.6142 2 52 2C24.3858 2 2 24.3858 2 52C2 79.6142 24.3858 102 52 102Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +<path d="M92.0611 24.6135C81.9235 14.476 65.4872 14.476 55.3496 24.6135L51.6804 28.286L48.008 24.6135C37.8704 14.476 21.4341 14.476 11.2965 24.6135C1.15897 34.7511 1.15897 51.1874 11.2965 61.325L14.969 64.9974L51.6804 101.706L88.3918 64.9942L92.0643 61.3218C102.199 51.1874 102.199 34.7511 92.0611 24.6135Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +<path d="M81.2925 45.1702C73.8581 37.7358 61.8044 37.7358 54.3731 45.1702L51.6796 47.8637L48.9861 45.1702C41.5517 37.7358 29.4979 37.7358 22.0635 45.1702C14.6291 52.6046 14.6291 64.6583 22.0635 72.0928L24.757 74.7863L51.6764 101.709L78.599 74.7863L81.2925 72.0928C88.7269 64.6583 88.7269 52.6046 81.2925 45.1702Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +<path d="M70.5248 65.73C65.7935 60.9987 58.1223 60.9987 53.3942 65.73L51.6796 67.4446L49.9649 65.73C45.2336 60.9987 37.5625 60.9987 32.8344 65.73C28.1031 70.4613 28.1031 78.1324 32.8344 82.8605L34.5491 84.5752L51.6796 101.706L68.8101 84.5752L70.5248 82.8605C75.256 78.1292 75.256 70.4613 70.5248 65.73Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/robustSmartContracts.svg b/packages/website/ts/@next/icons/illustrations/robustSmartContracts.svg new file mode 100755 index 000000000..060f2d00c --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/robustSmartContracts.svg @@ -0,0 +1,6 @@ +<svg width="90" height="90" viewBox="0 0 90 90" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M45 88C68.7482 88 88 68.7482 88 45C88 21.2518 68.7482 2 45 2C21.2518 2 2 21.2518 2 45C2 68.7482 21.2518 88 45 88Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M70 29V79H20V11H52M70 29L52 11M70 29V11H52" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M30 45H60M30 55H60M30 65H60" stroke="#00AE99" stroke-width="3"/> +<path d="M52 11V29H70" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/rocketship.svg b/packages/website/ts/@next/icons/illustrations/rocketship.svg new file mode 100644 index 000000000..e9b4b83ab --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/rocketship.svg @@ -0,0 +1,9 @@ +<svg width="124" height="124" viewBox="0 0 124 124" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M44.6582 74.4521L12.4089 95.6738M18.9394 103.633L46.699 76.2888" stroke="#00AE99" stroke-width="2.5"/> +<path d="M51.3926 80.5745L34.6538 115.266M25.8784 109.96L49.1477 78.5338" stroke="#00AE99" stroke-width="2.5"/> +<path d="M77.212 78.8086L75.9699 78.949L75.9699 78.949L77.212 78.8086ZM77.603 60.0842L76.4001 59.7443L77.603 60.0842ZM84.9562 43.7018L83.979 42.9223L83.9342 42.9785L83.8961 43.0394L84.9562 43.7018ZM73.085 87.8359L72.2661 88.7803L73.2262 89.6128L74.0428 88.6391L73.085 87.8359ZM56.5473 79.3763L57.4218 80.2694L57.459 80.2331L57.493 80.1937L56.5473 79.3763ZM53.8137 79.4142L54.6312 78.4685L54.6311 78.4685L53.8137 79.4142ZM53.0049 80.3499L53.7507 81.3531L53.8608 81.2712L53.9505 81.1674L53.0049 80.3499ZM51.4635 80.243L52.2809 79.2973L52.2809 79.2973L51.4635 80.243ZM61.3832 68.3677L60.5429 69.2931L60.5542 69.3034L60.5658 69.3134L61.3832 68.3677ZM74.9165 85.3062L75.9718 85.9761L75.9718 85.9761L74.9165 85.3062ZM91.434 27.7957L92.5916 27.3241L92.4784 27.0462L92.2514 26.85L91.434 27.7957ZM42.7642 49.0315L42.8049 50.2809L42.8049 50.2809L42.7642 49.0315ZM61.2349 45.9355L61.7453 47.0765L61.2349 45.9355ZM76.3811 36.2894L77.1898 37.2424L77.2446 37.1959L77.2937 37.1435L76.3811 36.2894ZM34.429 54.4212L33.4956 53.5898L32.6503 54.5386L33.613 55.3682L34.429 54.4212ZM45.1923 69.5609L44.2467 68.7435L44.2127 68.7828L44.182 68.8248L45.1923 69.5609ZM45.5503 72.2712L46.3678 71.3256L46.3678 71.3256L45.5503 72.2712ZM44.7415 73.207L43.7958 72.3895L43.7061 72.4933L43.641 72.6141L44.7415 73.207ZM45.0703 74.7167L45.8878 73.771L45.8878 73.771L45.0703 74.7167ZM55.3854 63.1831L54.5679 64.1288L54.5795 64.1388L54.5913 64.1485L55.3854 63.1831ZM36.667 52.2431L35.8515 51.2958L35.8515 51.2958L36.667 52.2431ZM91.1826 27.5784L92 26.6327L91.773 26.4365L91.4817 26.3647L91.1826 27.5784ZM83.9509 43.0422L61.4101 69.1188L63.3014 70.7536L85.8422 44.6771L83.9509 43.0422ZM78.4541 78.6681C78.0305 74.9211 76.5083 68.5531 78.8059 60.4242L76.4001 59.7443C73.9348 68.4667 75.5746 75.4525 75.9699 78.949L78.4541 78.6681ZM78.8059 60.4242C80.6674 53.8382 84.3943 46.96 86.0163 44.3642L83.8961 43.0394C82.2037 45.748 78.349 52.8492 76.4001 59.7443L78.8059 60.4242ZM85.9334 44.4813C86.7782 43.4222 88.106 41.5706 89.3107 39.7677C90.4904 38.002 91.6492 36.1406 92.0741 35.11L89.7628 34.1571C89.4497 34.9164 88.4417 36.5683 87.232 38.3788C86.0471 40.1522 84.7628 41.9398 83.979 42.9223L85.9334 44.4813ZM73.904 86.8915L60.2718 75.0706L58.634 76.9594L72.2661 88.7803L73.904 86.8915ZM58.5072 75.1976L55.6017 78.5589L57.493 80.1937L60.3985 76.8324L58.5072 75.1976ZM55.6728 78.4831C55.6952 78.4612 55.6589 78.4988 55.5624 78.5515C55.474 78.5998 55.3704 78.6413 55.265 78.6627C55.163 78.6835 55.0696 78.6837 54.9818 78.6633C54.8989 78.6441 54.7803 78.5974 54.6312 78.4685L52.9963 80.3599C53.9198 81.1581 54.9373 81.2805 55.7629 81.1126C56.5187 80.959 57.1181 80.5669 57.4218 80.2694L55.6728 78.4831ZM52.8681 78.5968L52.0592 79.5325L53.9505 81.1674L54.7594 80.2317L52.8681 78.5968ZM52.2591 79.3468C52.279 79.332 52.2917 79.3249 52.2958 79.3226C52.3006 79.32 52.302 79.3197 52.3006 79.3202C52.2965 79.3217 52.2938 79.3219 52.2957 79.3217C52.2974 79.3216 52.3007 79.3216 52.3054 79.3221C52.3102 79.3227 52.3147 79.3237 52.3182 79.3249C52.3218 79.326 52.3213 79.3263 52.3164 79.3236C52.3115 79.3208 52.2994 79.3133 52.2809 79.2973L50.646 81.1886C51.8617 82.2394 53.2052 81.7587 53.7507 81.3531L52.2591 79.3468ZM60.5658 69.3134C61.2107 69.8709 61.7136 71.4882 60.5236 72.8649L62.4149 74.4998C64.5664 72.0109 63.8212 68.8229 62.2006 67.422L60.5658 69.3134ZM60.5236 72.8649L58.5072 75.1976L60.3985 76.8324L62.4149 74.4998L60.5236 72.8649ZM74.0428 88.6391C74.5796 87.999 75.2848 87.0584 75.9718 85.9761L73.8611 84.6363C73.2323 85.627 72.5921 86.4784 72.1273 87.0326L74.0428 88.6391ZM75.9718 85.9761C76.6408 84.9221 77.3127 83.7022 77.792 82.4704C78.2624 81.2613 78.5956 79.9197 78.4541 78.6681L75.9699 78.949C76.045 79.6133 75.8726 80.509 75.4621 81.5639C75.0605 82.5961 74.4763 83.6671 73.8611 84.6363L75.9718 85.9761ZM75.7339 84.3606L62.2867 72.7367L60.6518 74.628L74.099 86.2519L75.7339 84.3606ZM60.2703 75.0693L54.4097 70.0034L52.7748 71.8947L58.6354 76.9607L60.2703 75.0693ZM57.4148 66.5254C58.723 67.6581 59.9087 68.7173 60.5429 69.2931L62.2235 67.4423C61.5753 66.8537 60.3749 65.7815 59.0512 64.6354L57.4148 66.5254ZM48.6813 76.6305L52.9964 80.3599L54.6311 78.4685L50.316 74.739L48.6813 76.6305ZM47.2951 78.2921L50.646 81.1886L52.2809 79.2973L48.9299 76.4007L47.2951 78.2921ZM92.0741 35.11C92.483 34.1181 92.8555 32.8177 93.0125 31.4685C93.1677 30.1352 93.1262 28.6366 92.5916 27.3241L90.2763 28.2672C90.5897 29.0365 90.6594 30.0618 90.5293 31.1795C90.4011 32.2814 90.0918 33.359 89.7628 34.1571L92.0741 35.11ZM75.2878 35.5538L52.747 61.6303L54.6383 63.2652L77.1792 37.1886L75.2878 35.5538ZM42.8049 50.2809C46.3218 50.1661 53.4713 50.778 61.7453 47.0765L60.7244 44.7945C53.0135 48.244 46.4923 47.6592 42.7234 47.7822L42.8049 50.2809ZM61.7453 47.0765C68.2859 44.1505 74.7546 39.309 77.1898 37.2424L75.5723 35.3363C73.2384 37.3168 66.9718 41.9996 60.7244 44.7945L61.7453 47.0765ZM77.2937 37.1435C78.1525 36.2258 79.7355 34.6963 81.3187 33.2674C82.9352 31.8084 84.4239 30.572 85.1299 30.1523L83.8526 28.0033C82.8943 28.5728 81.2201 29.9887 79.6437 31.4115C78.034 32.8643 76.3941 34.446 75.4684 35.4352L77.2937 37.1435ZM33.613 55.3682L47.2819 67.1466L48.9138 65.2527L35.2449 53.4743L33.613 55.3682ZM47.1522 65.3822L44.2467 68.7435L46.138 70.3784L49.0435 67.0171L47.1522 65.3822ZM44.182 68.8248C43.9317 69.1684 43.6304 69.8183 43.5877 70.5883C43.5411 71.4295 43.8094 72.4187 44.7329 73.2169L46.3678 71.3256C46.2187 71.1967 46.1553 71.0861 46.1243 71.0068C46.0914 70.9229 46.0781 70.8305 46.0839 70.7266C46.0899 70.6192 46.1159 70.5106 46.1509 70.4161C46.1892 70.3131 46.221 70.2717 46.2026 70.297L44.182 68.8248ZM44.6047 71.4538L43.7958 72.3895L45.6871 74.0244L46.496 73.0887L44.6047 71.4538ZM43.641 72.6141C43.3186 73.2126 43.0373 74.6115 44.2529 75.6624L45.8878 73.771C45.8693 73.755 45.8601 73.7441 45.8566 73.7397C45.8532 73.7353 45.8534 73.7348 45.8551 73.7381C45.8567 73.7414 45.8584 73.7457 45.8597 73.7504C45.8609 73.7549 45.8613 73.7583 45.8614 73.7599C45.8616 73.7618 45.8613 73.7592 45.8623 73.7549C45.8626 73.7534 45.8624 73.7548 45.8606 73.76C45.8589 73.7644 45.8537 73.7779 45.8419 73.7998L43.641 72.6141ZM56.2028 62.2375C54.5822 60.8366 51.32 60.5606 49.1686 63.0495L51.0599 64.6844C52.25 63.3077 53.9229 63.5713 54.5679 64.1288L56.2028 62.2375ZM49.1686 63.0495L47.1522 65.3822L49.0435 67.0171L51.0599 64.6844L49.1686 63.0495ZM35.3623 55.2527C35.8435 54.7125 36.5933 53.9559 37.4825 53.1904L35.8515 51.2958C34.88 52.1321 34.0513 52.966 33.4956 53.5898L35.3623 55.2527ZM37.4825 53.1904C38.3526 52.4414 39.3278 51.7084 40.291 51.1617C41.2754 50.6029 42.1367 50.3027 42.8049 50.2809L42.7234 47.7822C41.4645 47.8233 40.1853 48.347 39.057 48.9875C37.9074 49.6399 36.7976 50.4813 35.8515 51.2958L37.4825 53.1904ZM35.8496 53.1887L49.2968 64.8126L50.9317 62.9213L37.4845 51.2974L35.8496 53.1887ZM47.2804 67.1453L53.141 72.2113L54.7759 70.3199L48.9153 65.254L47.2804 67.1453ZM59.4158 64.9506C58.0903 63.8066 56.8557 62.774 56.1795 62.2178L54.5913 64.1485C55.2529 64.6927 56.4724 65.7127 57.7825 66.8433L59.4158 64.9506ZM50.6824 75.0557L46.3678 71.3256L44.7328 73.2168L49.0474 76.9469L50.6824 75.0557ZM49.2387 76.6676L45.8878 73.771L44.2529 75.6624L47.6038 78.559L49.2387 76.6676ZM85.1299 30.1523C85.872 29.7113 86.8935 29.2494 87.9652 28.9631C89.0523 28.6726 90.0769 28.5933 90.8835 28.792L91.4817 26.3647C90.1056 26.0255 88.6168 26.2013 87.3199 26.5478C86.0077 26.8984 84.7749 27.4551 83.8526 28.0033L85.1299 30.1523ZM92.2514 26.85L92 26.6327L90.3651 28.524L90.6165 28.7413L92.2514 26.85Z" fill="#00AE99"/> +<path d="M66.0818 13.4286V16.2857M66.0818 19.1428V16.2857M66.0818 16.2857H63.2246H68.9389" stroke="#00AE99" stroke-width="2.5"/> +<path d="M108.122 62V64.8571M108.122 67.7143V64.8571M108.122 64.8571H105.265H110.979" stroke="#00AE99" stroke-width="2.5"/> +<path d="M37.9182 25.6735V28.5307M37.9182 31.3878V28.5307M37.9182 28.5307H35.061H40.7753" stroke="#00AE99" stroke-width="2.5"/> +<path d="M62 122C95.1371 122 122 95.1371 122 62C122 28.8629 95.1371 2 62 2C28.8629 2 2 28.8629 2 62C2 95.1371 28.8629 122 62 122Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/secureTrading.svg b/packages/website/ts/@next/icons/illustrations/secureTrading.svg new file mode 100755 index 000000000..21912961d --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/secureTrading.svg @@ -0,0 +1,15 @@ +<svg width="91" height="90" viewBox="0 0 91 90" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M2 45C2 68.7579 21.2421 88 45 88C68.7579 88 88 68.7579 88 45C88 21.6448 69.3906 2.63278 46.1793 2.02876C45.7478 2.02876 45.3452 2 44.9137 2C21.2134 2.02876 2 21.2709 2 45Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/> +<path d="M15 15H75V75H62.8125H26.25H15V15Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M68.2435 21.7253H21.7253V68.2436H30.4475H58.7945H68.2435V21.7253Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M14.6464 44.9844H21.7253" stroke="#00AE99" stroke-width="3"/> +<path d="M14.6464 34.8718H21.7253" stroke="#00AE99" stroke-width="3"/> +<path d="M14.6464 55.0971H21.7253" stroke="#00AE99" stroke-width="3"/> +<circle cx="44.9844" cy="44.9844" r="14.1577" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M44.9844 30.8267V38.9168" stroke="#00AE99" stroke-width="3"/> +<path d="M32.1647 38.9766L39.4902 42.4097" stroke="#00AE99" stroke-width="3"/> +<path d="M35.2801 55.2932L40.8255 49.4026" stroke="#00AE99" stroke-width="3"/> +<path d="M54.7349 55.2497L49.1632 49.3839" stroke="#00AE99" stroke-width="3"/> +<path d="M57.8132 38.996L50.4825 42.4181" stroke="#00AE99" stroke-width="3"/> +<ellipse cx="44.9844" cy="44.9844" rx="5.05633" ry="5.05633" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/social-discord.svg b/packages/website/ts/@next/icons/illustrations/social-discord.svg new file mode 100644 index 000000000..144f6e061 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/social-discord.svg @@ -0,0 +1,3 @@ +<svg width="40" height="44" viewBox="0 0 40 44" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M34.8156 0C37.3489 0 39.3921 2.04861 39.5129 4.45939V43.2425L34.6895 39.1471L32.0409 36.7363L29.1509 34.2175L30.3581 38.1904H5.06478C2.5387 38.1904 0.488281 36.2715 0.488281 33.7292V4.46839C0.488281 2.05762 2.5423 0.00540532 5.07379 0.00540532H34.803L34.8156 0ZM23.7924 10.2395H23.7383L23.3744 10.5998C27.1095 11.6809 28.9166 13.3691 28.9166 13.3691C26.5095 12.1656 24.3401 11.5638 22.1708 11.3205C20.6033 11.0773 19.0357 11.2052 17.7114 11.3205H17.3511C16.5042 11.3205 14.7025 11.6809 12.2881 12.6448C11.4467 13.0106 10.9638 13.2502 10.9638 13.2502C10.9638 13.2502 12.7692 11.4449 16.7475 10.4809L16.5042 10.2377C16.5042 10.2377 13.4917 10.1224 10.2395 12.5259C10.2395 12.5259 6.98727 18.1907 6.98727 25.1744C6.98727 25.1744 8.78905 28.3094 13.7313 28.4284C13.7313 28.4284 14.452 27.468 15.1817 26.623C12.407 25.7798 11.3259 24.0933 11.3259 24.0933C11.3259 24.0933 11.5674 24.2122 11.9295 24.4536H12.0376C12.0917 24.4536 12.1169 24.4807 12.1457 24.5077V24.5185C12.1746 24.5473 12.1998 24.5726 12.2539 24.5726C12.8484 24.8176 13.443 25.059 13.9295 25.2933C14.7691 25.6572 15.8484 26.0194 17.1727 26.259C18.8483 26.5023 20.769 26.6194 22.9564 26.259C24.0374 26.0158 25.1185 25.778 26.1996 25.2951C26.9023 24.9347 27.7671 24.5744 28.7166 23.9672C28.7166 23.9672 27.6356 25.6536 24.7437 26.4969C25.3383 27.3365 26.1761 28.2986 26.1761 28.2986C31.1202 28.1905 33.0409 25.0554 33.149 25.1888C33.149 18.2159 29.8788 12.5403 29.8788 12.5403C26.9329 10.353 24.1762 10.2701 23.6897 10.2701L23.7906 10.2341L23.7924 10.2395ZM24.0951 18.1907C25.3617 18.1907 26.3834 19.2718 26.3834 20.5961C26.3834 21.9294 25.3563 23.0104 24.0951 23.0104C22.8339 23.0104 21.8068 21.9294 21.8068 20.6069C21.8105 19.2736 22.8393 18.1961 24.0951 18.1961V18.1907ZM15.9096 18.1907C17.1709 18.1907 18.1907 19.2718 18.1907 20.5961C18.1907 21.9294 17.1637 23.0104 15.9024 23.0104C14.6412 23.0104 13.6142 21.9294 13.6142 20.6069C13.6142 19.2736 14.6412 18.1961 15.9024 18.1961L15.9096 18.1907Z" fill="white"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/social-fb.svg b/packages/website/ts/@next/icons/illustrations/social-fb.svg new file mode 100644 index 000000000..e50cf107a --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/social-fb.svg @@ -0,0 +1,3 @@ +<svg width="38" height="38" viewBox="0 0 38 38" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M35.9037 0H2.09633C0.938917 0 0 0.938917 0 2.09633V35.9037C0 37.0627 0.938917 38 2.09633 38H20.2952V23.2845H15.3409V17.5513H20.2952V13.3158C20.2952 8.40908 23.294 5.73958 27.6719 5.73958C29.7698 5.73958 31.5733 5.89317 32.0989 5.96283V11.0928H29.0573C26.6823 11.0928 26.22 12.2344 26.22 13.8969V17.556H31.8947L31.1584 23.3035H26.22V38H35.9021C37.0627 38 38 37.0627 38 35.9037V2.09633C38 0.938917 37.0627 0 35.9037 0Z" fill="white"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/social-github.svg b/packages/website/ts/@next/icons/illustrations/social-github.svg new file mode 100644 index 000000000..ef0025582 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/social-github.svg @@ -0,0 +1,3 @@ +<svg width="38" height="38" viewBox="0 0 38 38" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M19 0.17334C8.5025 0.17334 0 8.68059 0 19.1733C0 27.5698 5.4435 34.69 12.9913 37.1996C13.9412 37.3785 14.2896 36.7911 14.2896 36.286C14.2896 35.8348 14.2738 34.6393 14.2658 33.056C8.98067 34.2023 7.866 30.5068 7.866 30.5068C7.0015 28.3139 5.75225 27.7281 5.75225 27.7281C4.03117 26.5501 5.88525 26.5738 5.88525 26.5738C7.79317 26.7068 8.79542 28.5308 8.79542 28.5308C10.4896 31.4363 13.243 30.5971 14.3292 30.111C14.5002 28.8823 14.9894 28.0448 15.5325 27.5698C11.3129 27.0948 6.878 25.4608 6.878 18.1806C6.878 16.1064 7.61425 14.4123 8.83342 13.0823C8.61967 12.6025 7.97842 10.6708 8.99967 8.05359C8.99967 8.05359 10.5909 7.54376 14.2247 10.0011C15.7447 9.57834 17.3597 9.36934 18.9747 9.35984C20.5897 9.36934 22.2047 9.57834 23.7247 10.0011C27.3347 7.54376 28.9259 8.05359 28.9259 8.05359C29.9472 10.6708 29.3059 12.6025 29.1159 13.0823C30.3272 14.4123 31.0634 16.1064 31.0634 18.1806C31.0634 25.4798 26.6222 27.0868 22.3947 27.5539C23.0597 28.1239 23.6772 29.2893 23.6772 31.0689C23.6772 33.6118 23.6534 35.6543 23.6534 36.2718C23.6534 36.7705 23.9859 37.3643 24.9597 37.1743C32.5613 34.6821 38 27.5571 38 19.1733C38 8.68059 29.4928 0.17334 19 0.17334Z" fill="white"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/social-newsletter.svg b/packages/website/ts/@next/icons/illustrations/social-newsletter.svg new file mode 100644 index 000000000..572cb8ed9 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/social-newsletter.svg @@ -0,0 +1,3 @@ +<svg width="38" height="30" viewBox="0 0 38 30" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M38 3.125V26.875C38 28.2208 36.9708 29.25 35.625 29.25H33.25V7.69608L19 17.9292L4.75 7.69608V29.25H2.375C1.02758 29.25 0 28.2208 0 26.875V3.125C0 2.45208 0.2565 1.85833 0.682417 1.434C1.10833 1.00333 1.70367 0.75 2.375 0.75H3.16667L19 12.2292L34.8333 0.75H35.625C36.2979 0.75 36.8917 1.0065 37.3176 1.434C37.7451 1.85833 38 2.45208 38 3.125Z" fill="white"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/social-reddit.svg b/packages/website/ts/@next/icons/illustrations/social-reddit.svg new file mode 100644 index 000000000..b93510b36 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/social-reddit.svg @@ -0,0 +1,3 @@ +<svg width="50" height="41" viewBox="0 0 50 41" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M4.49975 24.6813C4.37725 25.2447 4.31396 25.8246 4.31396 26.4105C4.31396 33.4398 13.3012 39.1687 24.3505 39.1687C35.3957 39.1687 44.383 33.4439 44.383 26.4105C44.383 25.8511 44.3238 25.2958 44.2156 24.7588L44.1849 24.6935C44.1421 24.5812 44.1257 24.4689 44.1257 24.3566C43.5092 21.9577 41.8452 19.7813 39.4382 18.0215C39.3463 17.9888 39.2585 17.9418 39.1809 17.8785C39.1278 17.8377 39.089 17.7928 39.0441 17.7479C35.3855 15.2285 30.1508 13.6483 24.3526 13.6483C18.6054 13.6483 13.4217 15.1979 9.76307 17.6723C9.73449 17.7091 9.70386 17.7397 9.66303 17.7724C9.58341 17.8398 9.49154 17.8949 9.39762 17.9255C6.93542 19.6854 5.22861 21.8801 4.59162 24.3015C4.59162 24.4199 4.56304 24.5343 4.51608 24.6506L4.49975 24.6813ZM24.4526 35.7898C20.7899 35.7898 18.2113 34.9956 16.5658 33.3459C16.2126 32.9907 16.2126 32.4129 16.5658 32.0556C16.9251 31.7188 17.5049 31.7188 17.8622 32.0556C19.1484 33.3398 21.3024 33.9809 24.4526 33.9809C27.6008 33.9809 29.7425 33.3684 31.0246 32.0842C31.3615 31.7494 31.9433 31.7494 32.3088 32.0842C32.6457 32.4517 32.6457 33.0336 32.3088 33.4011C30.6571 35.0507 28.0928 35.8469 24.424 35.8469L24.4526 35.7898ZM17.0905 20.3285C15.2244 20.3285 13.6667 21.8903 13.6667 23.7523C13.6667 25.6102 15.2244 27.121 17.0905 27.121C18.9565 27.121 20.4612 25.6102 20.4612 23.7523C20.4612 21.8903 18.9524 20.3285 17.0905 20.3285ZM31.8576 20.3285C29.9915 20.3285 28.4317 21.8903 28.4317 23.7523C28.4317 25.6102 29.9915 27.121 31.8576 27.121C33.7236 27.121 35.2283 25.6102 35.2283 23.7523C35.2283 21.8903 33.7196 20.3285 31.8576 20.3285ZM41.1429 17.0721C43.2601 18.7728 44.8178 20.7899 45.612 23.001C46.5308 22.315 47.08 21.237 47.08 20.0427C47.08 17.997 45.416 16.3351 43.3683 16.3351C42.5537 16.3351 41.7799 16.5984 41.1429 17.0762V17.0721ZM5.53486 16.3392C3.4871 16.3392 1.82522 18.0051 1.82522 20.0508C1.82522 21.1594 2.31317 22.1905 3.14003 22.8867C3.95872 20.6837 5.53282 18.6952 7.65815 17.0149C7.04158 16.5862 6.30455 16.3432 5.5369 16.3432V16.3392H5.53486ZM24.3526 41C12.2947 41 2.48875 34.4566 2.48875 26.4187C2.48875 25.8572 2.5357 25.308 2.62758 24.767C1.00856 23.7605 0 21.9863 0 20.0427C0 16.9884 2.50508 14.5037 5.56344 14.5037C6.9395 14.5037 8.22368 15.006 9.23225 15.8961C13.0215 13.4645 18.1276 11.9333 23.7523 11.8292L27.4517 0.55124L28.2766 0.745195C28.2766 0.745195 28.3092 0.745194 28.3092 0.749278L36.931 2.77662C37.6334 1.1474 39.2544 0 41.147 0C43.6562 0 45.7019 2.0498 45.7019 4.561C45.7019 7.07629 43.6541 9.122 41.147 9.122C38.6399 9.122 36.5942 7.0722 36.5942 4.56917L28.7318 2.7072L25.7368 11.8476C31.1471 12.0619 36.0409 13.5911 39.7097 15.9737C40.7183 15.0264 42.0453 14.5058 43.452 14.5058C46.5104 14.5058 49.0011 16.9823 49.0011 20.0406C49.0011 22.0557 47.8987 23.8911 46.1878 24.8691C46.247 25.3897 46.3082 25.8777 46.3082 26.3983C46.2776 34.4382 36.4962 40.9816 24.422 40.9816L24.3526 41ZM41.051 1.82726C39.5402 1.82726 38.3153 3.05019 38.3153 4.55896C38.3153 6.06568 39.5402 7.29474 41.051 7.29474C42.5455 7.29474 43.7664 6.06976 43.7664 4.57121C43.7664 3.07469 42.5455 1.85176 41.0163 1.85176L41.051 1.82726Z" fill="white"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/social-twitter.svg b/packages/website/ts/@next/icons/illustrations/social-twitter.svg new file mode 100644 index 000000000..bc8e2f7d7 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/social-twitter.svg @@ -0,0 +1,3 @@ +<svg width="45" height="36" viewBox="0 0 45 36" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M44.8202 4.28708C43.1869 5.00497 41.4429 5.49403 39.6067 5.71733C41.478 4.58974 42.9175 2.81253 43.5985 0.692059C41.8434 1.71631 39.8983 2.46189 37.8276 2.87712C36.1741 1.10729 33.8174 0 31.2005 0C26.1863 0 22.1206 4.06562 22.1206 9.07428C22.1206 9.79402 22.2037 10.4861 22.355 11.1486C14.807 10.7924 8.11705 7.16789 3.63989 1.68862C2.85186 3.02107 2.41079 4.56944 2.41079 6.25622C2.41079 9.41201 4.01637 12.1858 6.44872 13.8153C4.95941 13.7674 3.55869 13.3577 2.33697 12.6785V12.7911C2.33697 17.1926 5.46139 20.8633 9.61928 21.6993C8.85709 21.9041 8.05246 22.0149 7.22752 22.0149C6.64804 22.0149 6.09255 21.9595 5.53705 21.8562C6.70156 25.4604 10.0493 28.0884 14.0337 28.1622C10.9333 30.5964 7.00422 32.047 2.77251 32.047C2.05276 32.047 1.33487 32.0045 0.613281 31.9233C4.65306 34.4959 9.41258 36 14.5597 36C31.2687 36 40.3947 22.1662 40.3947 10.189C40.3947 9.80325 40.3947 9.41385 40.367 9.0263C42.1405 7.75475 43.6889 6.14733 44.9069 4.32399L44.8202 4.28708Z" fill="white"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/stableTokens.svg b/packages/website/ts/@next/icons/illustrations/stableTokens.svg new file mode 100755 index 000000000..9e854b0e6 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/stableTokens.svg @@ -0,0 +1,10 @@ +<svg width="150" height="150" viewBox="0 0 150 150" fill="none" xmlns="http://www.w3.org/2000/svg"> +<circle cx="75" cy="75" r="73" stroke="#00AE99" stroke-width="3"/> +<path d="M32 96H119M32 96V85H119V96M32 96H36V106.5H48M103 142V106.5M48 142V106.5M119 96H115V106.5H103M103 106.5H92.25M48 106.5H58.75M75.5 106.5V148M75.5 106.5H58.75M75.5 106.5H92.25M58.75 106.5V146M92.25 106.5V146" stroke="#00AE99" stroke-width="3"/> +<path d="M75.3265 76.5343C93.1472 76.5343 107.594 62.0878 107.594 44.2672C107.594 26.4465 93.1472 12 75.3265 12C57.5058 12 43.0593 26.4465 43.0593 44.2672C43.0593 62.0878 57.5058 76.5343 75.3265 76.5343Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M66.4197 57.1739V58.6739H67.9197H85.2999H86.7999V57.1739V52.1138V50.6138H85.2999H81.0799V29.0134V27.5134H79.5799H74.0798H73.6189L73.2375 27.7722L67.0774 31.9523L66.4197 32.3986V33.1935V39.2803V42.1109L68.7619 40.5215L72.5798 37.9308V50.6138H67.9197H66.4197V52.1138V57.1739Z" stroke="#00AE99" stroke-width="3"/> +<path d="M43.0593 44.0473C49.7328 42.9472 54.8662 37.2271 54.8662 30.187C54.8662 27.0337 53.8395 24.1736 52.0795 21.8269C46.5794 27.6203 43.1327 35.4671 43.0593 44.0473Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M43.0593 44.4871C43.1327 53.1405 46.5794 60.914 52.0795 66.7074C53.8395 64.3607 54.8662 61.5007 54.8662 58.3473C54.8662 51.3072 49.7328 45.5137 43.0593 44.4871Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M107.594 44.0473C100.92 42.9472 95.7869 37.2271 95.7869 30.187C95.7869 27.0337 96.8135 24.1736 98.5736 21.8269C104.074 27.6203 107.52 35.4671 107.594 44.0473Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M107.594 44.4871C107.52 53.1405 104.074 60.914 98.5736 66.7074C96.8135 64.3607 95.7869 61.5007 95.7869 58.3473C95.7869 51.3072 100.92 45.5137 107.594 44.4871Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/standardForExchange.svg b/packages/website/ts/@next/icons/illustrations/standardForExchange.svg new file mode 100755 index 000000000..f8075ed6d --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/standardForExchange.svg @@ -0,0 +1,12 @@ +<svg width="90" height="90" viewBox="0 0 90 90" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g clip-path="url(#clip0)"> +<path d="M2 45C2 68.7579 21.2421 88 45 88C68.7579 88 88 68.7579 88 45C88 21.6448 69.3906 2.63278 46.1793 2.02876C45.7478 2.02876 45.3452 2 44.9137 2C21.2134 2.02876 2 21.2709 2 45Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/> +<path d="M30 21L2 45L30 69V56.5H59.5V69L88 45L59.5 21V34H30V21Z" stroke="#00AE99" stroke-width="3"/> +<path d="M45 1V89" stroke="#00AE99" stroke-width="3"/> +</g> +<defs> +<clipPath id="clip0"> +<rect width="90" height="90" fill="white"/> +</clipPath> +</defs> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/support.svg b/packages/website/ts/@next/icons/illustrations/support.svg new file mode 100644 index 000000000..368e7cc02 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/support.svg @@ -0,0 +1 @@ +<svg width="152" height="152" viewBox="0 0 152 152" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M76 151c41.421 0 75-33.579 75-75S117.421 1 76 1 1 34.579 1 76s33.579 75 75 75z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/><path d="M114.869 14.138H38.226v124.818h76.643V14.138z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/><path d="M101.73 26.189H51.365v100.73h50.365V26.189z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/><path d="M76.547 76.554c13.908 0 25.183-11.275 25.183-25.183 0-13.907-11.275-25.182-25.183-25.182-13.907 0-25.182 11.275-25.182 25.182 0 13.908 11.275 25.183 25.182 25.183zM76.547 126.919c13.908 0 25.183-11.274 25.183-25.182S90.455 76.554 76.547 76.554c-13.907 0-25.182 11.275-25.182 25.183s11.275 25.182 25.182 25.182z" stroke="#00AE99" stroke-width="2" stroke-miterlimit="10"/></svg>
\ No newline at end of file diff --git a/packages/website/ts/@next/icons/illustrations/supportForAllEthereumStandards-large.svg b/packages/website/ts/@next/icons/illustrations/supportForAllEthereumStandards-large.svg new file mode 100755 index 000000000..1f840204a --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/supportForAllEthereumStandards-large.svg @@ -0,0 +1,28 @@ +<svg width="250" height="250" viewBox="0 0 250 250" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g clip-path="url(#clip0)"> +<path d="M192.122 112.755C221.878 112.755 246 88.6333 246 58.8776C246 29.1218 221.878 5 192.122 5C162.367 5 138.245 29.1218 138.245 58.8776C138.245 88.6333 162.367 112.755 192.122 112.755Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M206.229 18.0288V31.3513H219.551" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M219.551 31.3511V72.494H183.012V18.0287H206.229L219.551 31.3511Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M178.016 99.7268V86.4043H164.694" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M164.694 86.4045V45.2616H201.233V99.7269H178.016L164.694 86.4045Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M59.8776 114.323C89.6333 114.323 113.755 90.2008 113.755 60.445C113.755 30.6893 89.6333 6.56747 59.8776 6.56747C30.1218 6.56747 6 30.6893 6 60.445C6 90.2008 30.1218 114.323 59.8776 114.323Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M59.8775 114.224C89.5786 114.224 113.656 90.1464 113.656 60.4453C113.656 30.7442 89.5786 6.66666 59.8775 6.66666C30.1764 6.66666 6.09888 30.7442 6.09888 60.4453C6.09888 90.1464 30.1764 114.224 59.8775 114.224Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M46.0329 81.9563V83.4563H47.5329H76.5H78V81.9563V73.5229V72.0229H76.5H68.4665V35.0223V33.5223H66.9665H57.7997H57.3388L56.9574 33.7811L46.6906 40.7478L46.0329 41.1942V41.9891V52.1337V54.9643L48.3751 53.3749L56.2997 47.9975V72.0229H47.5329H46.0329V73.5229V81.9563Z" stroke="#00AE99" stroke-width="3"/> +<path d="M6.09889 60.0786C17.2213 58.2452 25.777 48.7118 25.777 36.9782C25.777 31.7226 24.0658 26.9559 21.1325 23.0447C11.9656 32.7004 6.22112 45.7784 6.09889 60.0786Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M6.09889 60.8116C6.22112 75.2341 11.9656 88.1898 21.1325 97.8456C24.0658 93.9344 25.777 89.1676 25.777 83.912C25.777 72.1785 17.2213 62.5228 6.09889 60.8116Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M113.656 60.0786C102.534 58.2452 93.9781 48.7118 93.9781 36.9782C93.9781 31.7226 95.6892 26.9559 98.6226 23.0447C107.789 32.7004 113.534 45.7784 113.656 60.0786Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M113.656 60.8117C113.534 75.2342 107.789 88.1899 98.6226 97.8456C95.6892 93.9345 93.9781 89.1677 93.9781 83.9121C93.9781 72.1786 102.534 62.5229 113.656 60.8117Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M59.8776 246.567C89.6333 246.567 113.755 222.446 113.755 192.69C113.755 162.934 89.6333 138.812 59.8776 138.812C30.1218 138.812 6 162.934 6 192.69C6 222.446 30.1218 246.567 59.8776 246.567Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M59.8776 246.567C89.6333 246.567 113.755 222.446 113.755 192.69C113.755 162.934 89.6333 138.812 59.8776 138.812C30.1218 138.812 6 162.934 6 192.69C6 222.446 30.1218 246.567 59.8776 246.567Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M65.3633 189.944V158.303H69.8695V149.389H49.8858V158.303H54.3919V189.944C44.1062 192.393 36.4654 201.699 36.4654 212.67C36.4654 225.601 46.947 236.083 59.8776 236.083C72.8082 236.083 83.2899 225.601 83.2899 212.67C83.2899 201.601 75.6491 192.393 65.3633 189.944Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M69.8694 149.294H49.8857V158.208H69.8694V149.294Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M40.3837 199.547H79.2735" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M192.122 246.567C221.878 246.567 246 222.446 246 192.69C246 162.934 221.878 138.812 192.122 138.812C162.367 138.812 138.245 162.934 138.245 192.69C138.245 222.446 162.367 246.567 192.122 246.567Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M191.833 156.667L159.333 200.422H191.833L191.923 228.333L224.333 184.489H191.833V156.667Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +</g> +<defs> +<clipPath id="clip0"> +<rect width="250" height="250" fill="white"/> +</clipPath> +</defs> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/supportForAllEthereumStandards.svg b/packages/website/ts/@next/icons/illustrations/supportForAllEthereumStandards.svg new file mode 100755 index 000000000..32a4d8602 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/supportForAllEthereumStandards.svg @@ -0,0 +1,21 @@ +<svg width="200" height="200" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M152.898 90.2041C176.703 90.2041 196 70.9066 196 47.102C196 23.2974 176.703 4 152.898 4C129.093 4 109.796 23.2974 109.796 47.102C109.796 70.9066 129.093 90.2041 152.898 90.2041Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +<path d="M164.183 14.423V25.081H174.841" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +<path d="M174.841 25.0809V57.9952H145.61V14.4229H164.183L174.841 25.0809Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +<path d="M141.613 79.7814V69.1234H130.955" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +<path d="M130.955 69.1236V36.2093H160.186V79.7815H141.613L130.955 69.1236Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +<path d="M47.102 91.4581C70.9066 91.4581 90.2041 72.1606 90.2041 48.356C90.2041 24.5514 70.9066 5.25398 47.102 5.25398C23.2974 5.25398 4 24.5514 4 48.356C4 72.1606 23.2974 91.4581 47.102 91.4581Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +<path d="M47.102 91.3791C70.8629 91.3791 90.1249 72.1171 90.1249 48.3562C90.1249 24.5953 70.8629 5.33333 47.102 5.33333C23.3411 5.33333 4.0791 24.5953 4.0791 48.3562C4.0791 72.1171 23.3411 91.3791 47.102 91.3791Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +<path d="M35.9761 65.5651V66.8151H37.2261H60.3998H61.6498V65.5651V58.8183V57.5683H60.3998H54.023V28.0178V26.7678H52.773H45.4395H45.0555L44.7377 26.9835L36.5242 32.5569L35.9761 32.9289V33.5913V41.7069V44.0658L37.928 42.7413L44.1895 38.4924V57.5683H37.2261H35.9761V58.8183V65.5651Z" stroke="#00AE99" stroke-width="2.5"/> +<path d="M4.0791 48.0629C12.977 46.5962 19.8216 38.9694 19.8216 29.5826C19.8216 25.3781 18.4527 21.5647 16.106 18.4357C8.77251 26.1603 4.17688 36.6227 4.0791 48.0629Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +<path d="M4.0791 48.6493C4.17688 60.1873 8.77251 70.5519 16.106 78.2765C18.4527 75.1475 19.8216 71.3341 19.8216 67.1296C19.8216 57.7428 12.977 50.0182 4.0791 48.6493Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +<path d="M90.1248 48.0629C81.2269 46.5962 74.3823 38.9694 74.3823 29.5826C74.3823 25.3781 75.7512 21.5647 78.0979 18.4357C85.4314 26.1603 90.027 36.6227 90.1248 48.0629Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +<path d="M90.1248 48.6494C90.027 60.1874 85.4314 70.552 78.0979 78.2765C75.7512 75.1476 74.3823 71.3342 74.3823 67.1297C74.3823 57.7429 81.2269 50.0183 90.1248 48.6494Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +<path d="M47.102 197.254C70.9066 197.254 90.2041 177.957 90.2041 154.152C90.2041 130.347 70.9066 111.05 47.102 111.05C23.2974 111.05 4 130.347 4 154.152C4 177.957 23.2974 197.254 47.102 197.254Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +<path d="M47.102 197.254C70.9066 197.254 90.2041 177.957 90.2041 154.152C90.2041 130.347 70.9066 111.05 47.102 111.05C23.2974 111.05 4 130.347 4 154.152C4 177.957 23.2974 197.254 47.102 197.254Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +<path d="M51.4904 151.955V126.642H55.0953V119.511H39.1084V126.642H42.7133V151.955C34.4847 153.914 28.3721 161.359 28.3721 170.136C28.3721 180.481 36.7574 188.866 47.1019 188.866C57.4464 188.866 65.8317 180.481 65.8317 170.136C65.8317 161.281 59.719 153.914 51.4904 151.955Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +<path d="M55.0953 119.435H39.1084V126.566H55.0953V119.435Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +<path d="M31.5068 159.638H62.6187" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +<path d="M152.898 197.254C176.703 197.254 196 177.957 196 154.152C196 130.347 176.703 111.05 152.898 111.05C129.093 111.05 109.796 130.347 109.796 154.152C109.796 177.957 129.093 197.254 152.898 197.254Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +<path d="M152.667 125.333L126.667 160.338H152.667L152.738 182.667L178.667 147.591H152.667V125.333Z" stroke="#00AE99" stroke-width="2.5" stroke-miterlimit="10"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/techSupport.svg b/packages/website/ts/@next/icons/illustrations/techSupport.svg new file mode 100755 index 000000000..e52084f67 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/techSupport.svg @@ -0,0 +1,13 @@ +<svg width="90" height="90" viewBox="0 0 90 90" fill="none" xmlns="http://www.w3.org/2000/svg"> +<circle cx="45" cy="45" r="43" stroke="#00AE99" stroke-width="3"/> +<circle cx="45" cy="45" r="26.5068" stroke="#00AE99" stroke-width="3"/> +<circle cx="45" cy="45" r="10.0137" stroke="#00AE99" stroke-width="3"/> +<path d="M88 45C88 49.5545 84.3079 53.2466 79.7534 53.2466C75.199 53.2466 71.5068 49.5545 71.5068 45" stroke="#00AE99" stroke-width="3"/> +<path d="M18.4932 45C18.4932 40.4455 14.801 36.7534 10.2466 36.7534C5.69212 36.7534 2 40.4455 2 45" stroke="#00AE99" stroke-width="3"/> +<path d="M37.9193 37.9193C34.6988 41.1397 29.4773 41.1397 26.2568 37.9193C23.0363 34.6988 23.0363 29.4773 26.2568 26.2568" stroke="#00AE99" stroke-width="3"/> +<path d="M63.7432 63.743C66.9637 60.5225 66.9637 55.3011 63.7432 52.0806C60.5227 48.8601 55.3013 48.8601 52.0808 52.0806" stroke="#00AE99" stroke-width="3"/> +<path d="M45 18.4932C49.5545 18.4932 53.2466 14.801 53.2466 10.2466C53.2466 5.69212 49.5545 2 45 2" stroke="#00AE99" stroke-width="3"/> +<path d="M45 88C40.4455 88 36.7534 84.3079 36.7534 79.7534C36.7534 75.199 40.4455 71.5068 45 71.5068" stroke="#00AE99" stroke-width="3"/> +<path d="M26.2568 63.7433C29.4773 66.9638 34.6988 66.9638 37.9193 63.7433C41.1397 60.5228 41.1397 55.3014 37.9193 52.0809" stroke="#00AE99" stroke-width="3"/> +<path d="M52.0808 37.9193C48.8603 34.6988 48.8603 29.4774 52.0808 26.2569C55.3013 23.0364 60.5227 23.0364 63.7432 26.2569" stroke="#00AE99" stroke-width="3"/> +</svg> diff --git a/packages/website/ts/@next/icons/illustrations/tokens.svg b/packages/website/ts/@next/icons/illustrations/tokens.svg new file mode 100644 index 000000000..966615265 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/tokens.svg @@ -0,0 +1 @@ +<svg width="249" height="251" viewBox="0 0 152 152" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M192 112c30.376 0 55-24.624 55-55S222.376 2 192 2s-55 24.624-55 55 24.624 55 55 55z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/><path d="M206.4 15.3v13.6H220" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/><path d="M220 28.9v42h-37.3V15.3h23.7L220 28.9zM177.6 98.7V85.1H164" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/><path d="M164 85.1v-42h37.3v55.6h-23.7L164 85.1zM57 113.6c30.376 0 55-24.624 55-55s-24.624-55-55-55-55 24.624-55 55 24.624 55 55 55z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/><path d="M57 102.6c24.3 0 44-19.7 44-44s-19.7-44-44-44-44 19.7-44 44 19.7 44 44 44z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/><path d="M45.4 76.2v1.5h26.7v-9.9h-7.8V36.3h-9.461l-.381.259-8.4 5.7-.658.446V54.63l2.342-1.589 6.058-4.11V67.8h-8.4V76.2z" stroke="#00AE99" stroke-width="3"/><path d="M13 58.3c9.1-1.5 16.1-9.3 16.1-18.9 0-4.3-1.4-8.2-3.8-11.4-7.5 7.9-12.2 18.6-12.3 30.3zM13 58.9c.1 11.8 4.8 22.4 12.3 30.3 2.4-3.2 3.8-7.1 3.8-11.4 0-9.6-7-17.5-16.1-18.9zM101 58.3c-9.1-1.5-16.1-9.3-16.1-18.9 0-4.3 1.4-8.2 3.8-11.4 7.5 7.9 12.2 18.6 12.3 30.3zM101 58.9c-.1 11.8-4.8 22.4-12.3 30.3-2.4-3.2-3.8-7.1-3.8-11.4 0-9.6 7-17.5 16.1-18.9zM57 248.6c30.376 0 55-24.624 55-55s-24.624-55-55-55-55 24.624-55 55 24.624 55 55 55z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/><path d="M57 248.6c30.376 0 55-24.624 55-55s-24.624-55-55-55-55 24.624-55 55 24.624 55 55 55z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/><path d="M62.6 190.8v-32.3h4.6v-9.1H46.8v9.1h4.6v32.3c-10.5 2.5-18.3 12-18.3 23.2 0 13.2 10.7 23.9 23.9 23.9s23.9-10.7 23.9-23.9c0-11.3-7.8-20.7-18.3-23.2z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/><path d="M67.2 149.3H46.8v9.1h20.4v-9.1zM37.1 200.6h39.7M192 248.6c30.376 0 55-24.624 55-55s-24.624-55-55-55-55 24.624-55 55 24.624 55 55 55z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/><path d="M192 149.6l-36.4 52.9H192l.1 35.1 36.3-53H192v-35z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/></svg>
\ No newline at end of file diff --git a/packages/website/ts/@next/icons/illustrations/vcIntroductions.svg b/packages/website/ts/@next/icons/illustrations/vcIntroductions.svg new file mode 100755 index 000000000..024cadab3 --- /dev/null +++ b/packages/website/ts/@next/icons/illustrations/vcIntroductions.svg @@ -0,0 +1,11 @@ +<svg width="90" height="90" viewBox="0 0 90 90" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M2 45C2 68.7578 21.2421 88 45 88C68.7579 88 88 68.7578 88 45C88 21.6448 69.3906 2.63278 46.1793 2.02876C45.7478 2.02876 45.3452 2 44.9137 2C21.2134 2.02876 2 21.2709 2 45Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10" stroke-linejoin="round"/> +<path d="M45 4L9 28H81L45 4Z" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M40 28L40 70" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M26 28L26 70" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M63 28L63 70" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M17 28L17 70" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M50 28L50 70" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M73 28L73 70" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +<path d="M12 72.5V71H78V72.5M71.5 79H18.5" stroke="#00AE99" stroke-width="3" stroke-miterlimit="10"/> +</svg> diff --git a/packages/website/ts/@next/icons/logo-with-type.svg b/packages/website/ts/@next/icons/logo-with-type.svg new file mode 100644 index 000000000..25abf149e --- /dev/null +++ b/packages/website/ts/@next/icons/logo-with-type.svg @@ -0,0 +1 @@ +<svg width="81" height="40" viewBox="0 0 81 40" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8.402 25.28l3.105-3.212-3.86-5.209-4.915-6.954A19.904 19.904 0 0 0 0 20c0 6.1 2.732 11.562 7.04 15.23l6.239-4.408a12.796 12.796 0 0 1-4.877-5.541zM14.72 8.402l3.212 3.105 5.209-3.86 6.954-4.915A19.904 19.904 0 0 0 20 0C13.9 0 8.438 2.732 4.77 7.04l4.408 6.239a12.795 12.795 0 0 1 5.541-4.877zM28.493 17.932l3.86 5.209 4.915 6.954A19.904 19.904 0 0 0 40 20c0-6.1-2.732-11.562-7.04-15.23L26.72 9.178a12.796 12.796 0 0 1 4.877 5.541l-3.105 3.213zM35.23 32.96l-4.408-6.239a12.795 12.795 0 0 1-5.541 4.877l-3.213-3.105-5.209 3.86-6.954 4.915A19.904 19.904 0 0 0 20 40c6.1 0 11.562-2.732 15.23-7.04z" fill="#fff"/><path fill-rule="evenodd" clip-rule="evenodd" d="M51.726 19.689c0-6.471 2.704-9.689 6.912-9.689 4.19 0 6.947 3.27 6.947 9.689 0 6.418-2.758 9.671-6.947 9.671-4.19 0-6.912-3.253-6.912-9.671zm6.894-7.59c-3.04 0-4.543 2.815-4.543 7.607 0 2.256.336 4.005.972 5.282l5.975-12.085c-.69-.542-1.485-.804-2.404-.804zm-2.351 14.428c.672.507 1.45.77 2.369.77 3.04 0 4.578-2.834 4.578-7.59 0-2.204-.318-3.936-.972-5.247l-5.975 12.067zm24.377-10.93l-3.853 6.47L81 29.027h-2.581l-3.377-5.63h-.954l-3.447 5.63h-2.51l4.224-6.872-3.8-6.559h2.44l3.11 5.334h.973l3.182-5.334h2.386z" fill="#fff"/></svg>
\ No newline at end of file diff --git a/packages/website/ts/@next/pages/about/jobs.tsx b/packages/website/ts/@next/pages/about/jobs.tsx new file mode 100644 index 000000000..2fd2c7619 --- /dev/null +++ b/packages/website/ts/@next/pages/about/jobs.tsx @@ -0,0 +1,231 @@ +import * as _ from 'lodash'; +import * as React from 'react'; +import DocumentTitle from 'react-document-title'; +import styled from 'styled-components'; + +import { AboutPageLayout } from 'ts/@next/components/aboutPageLayout'; +import { Column, FlexWrap, Section } from 'ts/@next/components/newLayout'; +import { Heading, Paragraph } from 'ts/@next/components/text'; +import { WebsiteBackendJobInfo } from 'ts/types'; +import { backendClient } from 'ts/utils/backend_client'; +import { constants } from 'ts/utils/constants'; + +const OPEN_POSITIONS_HASH = 'positions'; + +interface PositionProps { + title: string; + location: string; + href: string; +} + +interface PositionItemProps { + position: PositionProps; +} + +const Position: React.FunctionComponent<PositionItemProps> = (props: PositionItemProps) => { + const { position } = props; + return ( + <PositionWrap> + <StyledColumn width="30%"> + <Heading asElement="h3" size="small" fontWeight="400" marginBottom="0"> + <a href={position.href} target="_blank"> + {position.title} + </a> + </Heading> + </StyledColumn> + + <StyledColumn width="50%" padding="0 40px 0 0"> + <Paragraph isMuted={true} marginBottom="0"> + {position.location} + </Paragraph> + </StyledColumn> + + <StyledColumn width="20%"> + <Paragraph marginBottom="0" textAlign="right"> + <a href={position.href} target="_blank"> + Apply + </a> + </Paragraph> + </StyledColumn> + </PositionWrap> + ); +}; + +export interface NextAboutJobsProps {} +interface NextAboutJobsState { + jobInfos: WebsiteBackendJobInfo[]; +} + +export class NextAboutJobs extends React.Component<NextAboutJobsProps, NextAboutJobsState> { + private _isUnmounted: boolean; + private static _convertJobInfoToPositionProps(jobInfo: WebsiteBackendJobInfo): PositionProps { + return { + title: jobInfo.title, + location: jobInfo.office, + href: jobInfo.url, + }; + } + constructor(props: NextAboutJobsProps) { + super(props); + this.state = { + jobInfos: [], + }; + } + + public componentWillMount(): void { + // tslint:disable-next-line:no-floating-promises + this._fetchJobInfosAsync(); + } + public componentWillUnmount(): void { + this._isUnmounted = true; + } + public render(): React.ReactNode { + const positions = this.state.jobInfos.map(jobInfo => NextAboutJobs._convertJobInfoToPositionProps(jobInfo)); + return ( + <AboutPageLayout + title="Join Us in Our Mission" + description={ + <> + <Paragraph size="medium"> + To create a tokenized world where all value can flow freely. + </Paragraph> + <Paragraph size="medium"> + We are growing an ecosystem of businesses and projects by solving difficult challenges to + make our technology intuitive, flexible, and accessible to all. Join us in building + infrastructure upon which the exchange of all assets will take place. + </Paragraph> + </> + } + linkLabel="Our mission and values" + href={constants.URL_MISSION_AND_VALUES_BLOG_POST} + > + <DocumentTitle title="Jobs at 0x" /> + <Section bgColor="#F3F6F4" isFlex={true} maxWidth="1170px" wrapWidth="100%"> + <Column maxWidth="442px"> + <Heading size="medium" marginBottom="30px"> + Powered by a Diverse, Global Community + </Heading> + + <Paragraph> + We're a highly technical team with varied backgrounds in engineering, science, business, + finance, and research. While the Core Team is headquartered in San Francisco, there are 30+ + teams building on 0x and hundreds of thousands of participants behind our efforts worldwide. + We're passionate about open-source software and decentralized technology's potential to act + as an equalizing force in the world. + </Paragraph> + </Column> + + <Column maxWidth="600px"> + <ImageWrap> + <img src="/images/@next/jobs/map@2x.png" height="365" alt="Map of community" /> + </ImageWrap> + </Column> + </Section> + + <Section isFlex={true} maxWidth="1170px" wrapWidth="100%"> + <Column> + <Heading size="medium">Benefits</Heading> + </Column> + + <Column maxWidth="826px"> + <BenefitsList> + <li>Comprehensive Insurance</li> + <li>Unlimited Vacation</li> + <li>Meals and snacks provided daily</li> + <li>Flexible hours and liberal work-from-home-policy</li> + <li>Supportive of remote working</li> + <li>Transportation, phone, and wellness expense</li> + <li>Relocation assistance</li> + <li>Optional team excursions</li> + <li>Competitive salary</li> + <li>Cryptocurrency based compensation</li> + </BenefitsList> + </Column> + </Section> + + <Section id={OPEN_POSITIONS_HASH} isFlex={true} maxWidth="1170px" wrapWidth="100%"> + <Column> + <Heading size="medium"> + Current<br />Openings + </Heading> + </Column> + + <Column maxWidth="826px"> + {_.map(positions, (position, index) => ( + <Position key={`position-${index}`} position={position} /> + ))} + </Column> + </Section> + </AboutPageLayout> + ); + } + private async _fetchJobInfosAsync(): Promise<void> { + try { + if (!this._isUnmounted) { + this.setState({ + jobInfos: [], + }); + } + const jobInfos = await backendClient.getJobInfosAsync(); + if (!this._isUnmounted) { + this.setState({ + jobInfos, + }); + } + } catch (error) { + if (!this._isUnmounted) { + this.setState({ + jobInfos: [], + }); + } + } + } +} + +const BenefitsList = styled.ul` + color: #000; + font-weight: 300; + line-height: 1.444444444; + list-style: disc; + columns: auto 2; + column-gap: 80px; + + li { + margin-bottom: 1em; + } +`; + +const ImageWrap = styled.figure` + @media (min-width: 768px) { + height: 600px; + padding-left: 60px; + display: flex; + align-items: flex-end; + } +`; + +const StyledColumn = styled(Column)` + flex-shrink: 0; + + @media (max-width: 768px) { + & + & { + margin-top: 15px; + } + } +`; + +const PositionWrap = styled(FlexWrap)` + margin-bottom: 40px; + padding-bottom: 30px; + position: relative; + + &:after { + content: ''; + width: 100%; + position: absolute; + bottom: 0; + left: 0; + height: 1px; + background-color: #e3e3e3; + } +`; diff --git a/packages/website/ts/@next/pages/about/mission.tsx b/packages/website/ts/@next/pages/about/mission.tsx new file mode 100644 index 000000000..2e6530edd --- /dev/null +++ b/packages/website/ts/@next/pages/about/mission.tsx @@ -0,0 +1,97 @@ +import * as _ from 'lodash'; +import * as React from 'react'; +import DocumentTitle from 'react-document-title'; +import styled from 'styled-components'; + +import { AboutPageLayout } from 'ts/@next/components/aboutPageLayout'; +import { Definition } from 'ts/@next/components/definition'; +import { Image } from 'ts/@next/components/image'; +import { Column, Section } from 'ts/@next/components/newLayout'; +import { Heading } from 'ts/@next/components/text'; +import { constants } from 'ts/utils/constants'; + +const values = [ + { + title: 'Do The Right Thing', + description: + 'We acknowledge the broad subjectivity behind doing “the right thing,” and are committed to rigorously exploring its nuance in our decision making. We believe this responsibility drives our decision making above all else, and pledge to act in the best interest of our peers, community, and society as a whole.', + icon: 'right-thing', + }, + { + title: 'Consistently Ship', + description: + 'Achieving our mission requires dedication and diligence. We aspire to be an organization that consistently ships. We set high-impact goals that are rooted in data and pride ourselves in consistently outputting outstanding results across the organization.', + icon: 'consistently-ship', + }, + { + title: 'Focus on Long-term Impact', + description: + 'We anticipate that over time, awareness of the fundamentally disruptive nature of frictionless global exchange will cause some to see this technology as a threat. There will be setbacks, some will claim that this technology is too disruptive, and we will face adversity. Persistence and a healthy long-term focus will see us through these battles.', + icon: 'long-term-impact', + }, +]; + +export const NextAboutMission = () => ( + <AboutPageLayout + title="Creating a tokenized world where all value can flow freely." + description="0x is important infrastructure for the emerging crypto economy and enables markets to be created that couldn't have existed before. As more assets become tokenized, public blockchains provide the opportunity to establish a new financial stack that is more efficient, transparent, and equitable than any system in the past." + linkLabel="Our mission and values" + href={constants.URL_MISSION_AND_VALUES_BLOG_POST} + > + <DocumentTitle title="Our Mission - 0x" /> + <Section isFullWidth={true} isPadded={false}> + <FullWidthImage> + <Image src="/images/@next/about/about-office.png" alt="0x Offices" isCentered={true} /> + </FullWidthImage> + </Section> + + <Section isFlex={true} maxWidth="1170px" wrapWidth="100%"> + <Column> + <Heading size="medium" maxWidth="226px"> + Core Values + </Heading> + </Column> + + <Column width="70%" maxWidth="826px"> + <Column width="100%" maxWidth="800px"> + {_.map(values, (item, index) => ( + <StyledDefinition + icon={item.icon} + title={item.title} + description={item.description} + isInlineIcon={true} + iconSize="large" + /> + ))} + </Column> + </Column> + </Section> + </AboutPageLayout> +); + +const StyledDefinition = styled(Definition)` + & + & { + margin-top: 30px; + padding-top: 30px; + border-top: 1px solid #eaeaea; + } +`; + +const FullWidthImage = styled.figure` + width: 100vw; + margin-left: calc(50% - 50vw); + + img { + width: 100%; + height: 100%; + object-fit: cover; + } + + @media (min-width: 768px) { + height: 500px; + } + + @media (max-width: 768px) { + height: 400px; + } +`; diff --git a/packages/website/ts/@next/pages/about/press.tsx b/packages/website/ts/@next/pages/about/press.tsx new file mode 100644 index 000000000..030ee4c14 --- /dev/null +++ b/packages/website/ts/@next/pages/about/press.tsx @@ -0,0 +1,94 @@ +import * as _ from 'lodash'; +import * as React from 'react'; +import DocumentTitle from 'react-document-title'; +import styled from 'styled-components'; + +import { AboutPageLayout } from 'ts/@next/components/aboutPageLayout'; +import { Button } from 'ts/@next/components/button'; +import { Column, FlexWrap } from 'ts/@next/components/newLayout'; +import { Paragraph } from 'ts/@next/components/text'; + +interface HighlightProps { + logo: string; + title?: string; + text: string; + href: string; +} + +interface HighlightItemProps { + highlight: HighlightProps; +} + +const highlights: HighlightProps[] = [ + { + logo: '/images/@next/press/logo-forbes.png', + title: 'Forbes', + text: + '0x Instant is aiming to aid businesses and developers such as news sites, crypto wallets, dApps or price trackers to monetize or add a new revenue stream to their existing pipeline.', + href: + 'https://www.forbes.com/sites/rebeccacampbell1/2018/12/06/0x-launches-instant-delivers-an-easy-and-flexible-way-to-buy-crypto-tokens/#bfb73a843561', + }, + { + logo: '/images/@next/press/logo-venturebeat.png', + title: 'VentureBeat', + text: '0x leads the way for ‘tokenization’ of the world, and collectible game items are next', + href: + 'https://venturebeat.com/2018/09/24/0x-leads-the-way-for-tokenization-of-the-world-and-collectible-game-items-are-next/', + }, + { + logo: '/images/@next/press/logo-fortune.png', + title: 'Fortune', + text: + 'In the future, many traditional investments like real estate and corporate shares will come in the form of digital tokens that are bought and transferred on a blockchain.', + href: 'http://fortune.com/2018/09/06/0x-harbor-blockchain/', + }, + { + logo: '/images/@next/press/logo-techcrunch.png', + title: 'TechCrunch', + text: + '0x allows any developer to quickly build their own decentralized cryptocurrency exchange and decide their own fees.', + href: 'https://techcrunch.com/2018/07/16/0x/', + }, +]; + +export const NextAboutPress = () => ( + <AboutPageLayout + title="Press Highlights" + description={ + <> + <Paragraph size="medium" marginBottom="60px"> + Want to write about 0x? <a href="mailto:team@0xproject.com">Get in touch.</a> + </Paragraph> + + {_.map(highlights, (highlight, index) => ( + <Highlight key={`highlight-${index}`} highlight={highlight} /> + ))} + </> + } + > + <DocumentTitle title="Press Highlights - 0x" /> + </AboutPageLayout> +); + +export const Highlight: React.FunctionComponent<HighlightItemProps> = (props: HighlightItemProps) => { + const { highlight } = props; + return ( + <HighlightWrap> + <Column> + <img src={highlight.logo} alt={highlight.title} /> + </Column> + + <Column width="60%" maxWidth="560px"> + <Paragraph isMuted={false}>{highlight.text}</Paragraph> + <Button href={highlight.href} isWithArrow={true} isNoBorder={true} target="_blank"> + Read Article + </Button> + </Column> + </HighlightWrap> + ); +}; + +const HighlightWrap = styled(FlexWrap)` + border-top: 1px solid #eaeaea; + padding: 30px 0; +`; diff --git a/packages/website/ts/@next/pages/about/team.tsx b/packages/website/ts/@next/pages/about/team.tsx new file mode 100644 index 000000000..7177964be --- /dev/null +++ b/packages/website/ts/@next/pages/about/team.tsx @@ -0,0 +1,286 @@ +import * as _ from 'lodash'; +import * as React from 'react'; +import DocumentTitle from 'react-document-title'; +import styled from 'styled-components'; + +import { colors } from 'ts/style/colors'; + +import { AboutPageLayout } from 'ts/@next/components/aboutPageLayout'; +import { Column, Section } from 'ts/@next/components/newLayout'; +import { Heading, Paragraph } from 'ts/@next/components/text'; +import { WebsitePaths } from 'ts/types'; + +interface TeamMember { + name: string; + title: string; + imageUrl?: string; +} + +const team: TeamMember[] = [ + { + imageUrl: '/images/@next/team/willw.jpg', + name: 'Will Warren', + title: 'co-founder & CEO', + }, + { + imageUrl: '/images/@next/team/amirb.jpg', + name: 'Amir Bandeali', + title: 'Co-founder & CTO', + }, + { + imageUrl: '/images/@next/team/fabiob.jpg', + name: 'Fabio Berger', + title: 'senior engineer', + }, + { + imageUrl: '/images/@next/team/alexv.jpg', + name: 'Alex Xu', + title: 'Director of operations', + }, + { + imageUrl: '/images/@next/team/leonidL.jpg', + name: 'Leonid Logvinov', + title: 'engineer', + }, + { + imageUrl: '/images/@next/team/benb.jpg', + name: 'Ben Burns', + title: 'designer', + }, + { + imageUrl: '/images/@next/team/brandonm.jpg', + name: 'Brandon Millman', + title: 'senior engineer', + }, + { + imageUrl: '/images/@next/team/toms.jpg', + name: 'Tom Schmidt', + title: 'product manager', + }, + { + imageUrl: '/images/@next/team/jacobe.jpg', + name: 'Jacob Evans', + title: 'ecosystem engineer', + }, + { + imageUrl: '/images/@next/team/blake.jpg', + name: 'Blake Henderson', + title: 'ecosystem programs lead', + }, + { + imageUrl: '/images/@next/team/zack.jpg', + name: 'Zack Skelly', + title: 'lead recruiter', + }, + { + imageUrl: '/images/@next/team/greg.jpg', + name: 'Greg Hysen', + title: 'blockchain engineer', + }, + { + imageUrl: '/images/@next/team/remcoB.jpg', + name: 'Remco Bloemen', + title: 'technical fellow', + }, + { + imageUrl: '/images/@next/team/francesco.jpg', + name: 'Francesco Agosti', + title: 'engineer', + }, + { + imageUrl: '/images/@next/team/melo.jpg', + name: 'Mel Oberto', + title: 'people operations associate', + }, + { + imageUrl: '/images/@next/team/alexb.jpg', + name: 'Alex Browne', + title: 'engineer in residence', + }, + { + imageUrl: '/images/@next/team/peterz.jpg', + name: 'Peter Zeitz', + title: 'research fellow', + }, + { + imageUrl: '/images/@next/team/chrisk.jpg', + name: 'Chris Kalani', + title: 'director of design', + }, + { + imageUrl: '/images/@next/team/clayr.jpg', + name: 'Clay Robbins', + title: 'ecosystem development lead', + }, + { + imageUrl: '/images/@next/team/mattt.jpg', + name: 'Matt Taylor', + title: 'marketing lead', + }, + { + imageUrl: '/images/@next/team/eugenea.jpg', + name: 'Eugene Aumson', + title: 'engineer', + }, + { + imageUrl: '/images/@next/team/weijew.jpg', + name: 'Weijie Wu', + title: 'research fellow', + }, + { + imageUrl: '/images/@next/team/rahuls.jpg', + name: 'Rahul Singireddy', + title: 'relayer success manager', + }, + { + imageUrl: '/images/@next/team/jasons.jpg', + name: 'Jason Somensatto', + title: 'strategic legal counsel', + }, + { + imageUrl: '/images/@next/team/steveK.jpg', + name: 'Steve Klebanoff', + title: 'senior engineer', + }, + { + imageUrl: '/images/@next/team/xianny.jpg', + name: 'Xianny Ng', + title: 'engineer', + }, +]; + +const advisors: TeamMember[] = [ + { + imageUrl: '/images/@next/team/advisors/frede.jpg', + name: 'Fred Ehrsam', + title: 'Advisor', + }, + { + imageUrl: '/images/@next/team/advisors/olafc.jpg', + name: 'Olaf Carlson-Wee', + title: 'Advisor', + }, + { + imageUrl: '/images/@next/team/advisors/joeyk.jpg', + name: 'Joey Krug', + title: 'Advisor', + }, + { + imageUrl: '/images/@next/team/advisors/lindax.jpg', + name: 'Linda Xie', + title: 'Advisor', + }, + { + imageUrl: '/images/@next/team/advisors/davids.jpg', + name: 'David Sacks', + title: 'Advisor', + }, +]; + +export const NextAboutTeam = () => ( + <AboutPageLayout + title="We are a global, growing team" + description="We are a distributed team with backgrounds in engineering, academic research, business, and design. The 0x Core Team is passionate about accelerating the adoption decentralized technology and believe in its potential to be an equalizing force in the world. Join us and do the most impactful work of your life." + linkLabel="Join the team" + to={WebsitePaths.AboutJobs} + > + <DocumentTitle title="Our Team - 0x" /> + <Section maxWidth="1170px" wrapWidth="100%" isFlex={true} flexBreakpoint="900px"> + <Column> + <Heading size="medium">0x Team</Heading> + </Column> + + <Column width="70%" maxWidth="800px"> + <StyledGrid> + {_.map(team, (info: TeamMember, index: number) => ( + <Member key={`team-${index}`} name={info.name} title={info.title} imageUrl={info.imageUrl} /> + ))} + </StyledGrid> + </Column> + </Section> + + <Section bgColor="#F3F6F4" maxWidth="1170px" wrapWidth="100%" flexBreakpoint="900px" isFlex={true}> + <Column> + <Heading size="medium">Advisors</Heading> + </Column> + + <Column width="70%" maxWidth="800px"> + <StyledGrid> + {_.map(advisors, (info: TeamMember, index: number) => ( + <Member key={`advisor-${index}`} name={info.name} title={info.title} imageUrl={info.imageUrl} /> + ))} + </StyledGrid> + </Column> + </Section> + </AboutPageLayout> +); + +const StyledGrid = styled.div` + &:after { + content: ''; + clear: both; + } +`; + +const Member = ({ name, title, imageUrl }: TeamMember) => ( + <StyledMember> + <img src={imageUrl} alt={name} /> + <Name>{name}</Name> + <MemberTitle isMuted={0.5} size={14} style={{ textTransform: 'capitalize' }}> + {title} + </MemberTitle> + </StyledMember> +); + +const StyledMember = styled.div` + margin-bottom: 10px; + float: left; + width: calc(50% - 15px); + margin-right: 15px; + + @media (max-width: 600px) { + &:nth-child(2n + 1) { + clear: left; + } + } + + img, + svg { + width: 100%; + height: auto; + object-fit: contain; + margin-bottom: 10px; + } + + @media (min-width: 600px) { + width: calc(33.3333% - 30px); + margin-right: 20px; + + &:nth-child(3n + 1) { + clear: left; + } + } + + @media (min-width: 900px) { + width: calc(25% - 30px); + + &:nth-child(3n + 1) { + clear: none; + } + + &:nth-child(4n + 1) { + clear: left; + } + } +`; + +const Name = styled.h3` + color: ${colors.textDarkPrimary}; + font-size: 14px; + line-height: 1; + margin: 0; +`; + +const MemberTitle = styled(Paragraph)` + font-size: 14px; +`; diff --git a/packages/website/ts/@next/pages/community.tsx b/packages/website/ts/@next/pages/community.tsx new file mode 100644 index 000000000..a259e3438 --- /dev/null +++ b/packages/website/ts/@next/pages/community.tsx @@ -0,0 +1,289 @@ +import * as _ from 'lodash'; +import * as React from 'react'; +import styled from 'styled-components'; + +import { colors } from 'ts/style/colors'; + +import { Banner } from 'ts/@next/components/banner'; +import { Button } from 'ts/@next/components/button'; +import { Icon } from 'ts/@next/components/icon'; +import { ModalContact } from 'ts/@next/components/modals/modal_contact'; +import { Column, Section, WrapGrid } from 'ts/@next/components/newLayout'; +import { SiteWrap } from 'ts/@next/components/siteWrap'; +import { Heading, Paragraph } from 'ts/@next/components/text'; + +interface EventProps { + title: string; + date: string; + signupUrl: string; + imageUrl: string; +} + +interface CommunityLinkProps { + bgColor: string; + title?: string; + icon?: string; + url: string; +} + +const events: EventProps[] = [ + { + title: '0x London Meetup', + date: 'October 20th 2018', + imageUrl: '/images/@next/events/london.jpg', + signupUrl: '#', + }, + { + title: '0x Berlin Meetup', + date: 'October 20th 2018', + imageUrl: '/images/@next/events/berlin.jpg', + signupUrl: '#', + }, + { + title: '0x San Francisco Meetup', + date: 'October 20th 2018', + imageUrl: '/images/@next/events/sf.jpg', + signupUrl: '#', + }, +]; +const communityLinks: CommunityLinkProps[] = [ + { + bgColor: '#1DA1F2', + title: 'Twitter', + icon: 'social-twitter', + url: 'https://twitter.com/0xProject', + }, + { + bgColor: '#FF4500', + title: 'Reddit', + icon: 'social-reddit', + url: 'https://twitter.com/0xProject', + }, + { + bgColor: '#7289DA', + title: 'Twitter', + icon: 'social-discord', + url: 'https://twitter.com/0xProject', + }, + { + bgColor: '#3B5998', + title: 'Facebook', + icon: 'social-fb', + url: 'https://twitter.com/0xProject', + }, + { + bgColor: '#181717', + title: 'GitHub', + icon: 'social-github', + url: 'https://twitter.com/0xProject', + }, + { + bgColor: '#003831', + title: 'Newsletter', + icon: 'social-newsletter', + url: 'https://twitter.com/0xProject', + }, +]; + +export class NextCommunity extends React.Component { + public state = { + isContactModalOpen: false, + }; + public render(): React.ReactNode { + return ( + <SiteWrap theme="light"> + <Section isTextCentered={true}> + <Column> + <Heading size="medium" isCentered={true}> + Community + </Heading> + <Paragraph size="medium" isCentered={true} isMuted={true} marginBottom="0"> + The 0x community is a global, passionate group of crypto developers and enthusiasts. The + official channels below provide a great forum for connecting and engaging with the + community. + </Paragraph> + <LinkWrap> + <Button to="#" isWithArrow={true} isAccentColor={true}> + Join the 0x community + </Button> + </LinkWrap> + </Column> + </Section> + + <Section isFullWidth={true}> + <WrapGrid + isTextCentered={true} + isWrapped={true} + isFullWidth={false} + isCentered={false} + maxWidth="1151px" + > + {_.map(communityLinks, (link: CommunityLinkProps, index: number) => ( + <CommunityLink + key={`cl-${index}`} + icon={link.icon} + title={link.title} + bgColor={link.bgColor} + url={link.url} + /> + ))} + </WrapGrid> + </Section> + + <EventsWrapper + bgColor={colors.backgroundLight} + isFullWidth={true} + isCentered={true} + isTextCentered={true} + > + <Column maxWidth="720px"> + <Heading size="medium" asElement="h2" isCentered={true} maxWidth="507px" marginBottom="30px"> + Upcoming Events + </Heading> + <Paragraph size="medium" isCentered={true} isMuted={true}> + 0x meetups happen all over the world on a monthly basis and are hosted by devoted members of + the community. Want to host a meetup in your city? Reach out for help finding a venue, + connecting with local 0x mentors, and promoting your events. + </Paragraph> + <LinkWrap> + <Button to="#" isWithArrow={true} isAccentColor={true}> + Get in Touch + </Button> + <Button to="#" isWithArrow={true} isAccentColor={true}> + Join Newsletter + </Button> + </LinkWrap> + </Column> + <WrapGrid + isTextCentered={true} + isWrapped={true} + isFullWidth={false} + isCentered={false} + maxWidth="1149px" + > + {_.map(events, (ev: EventProps, index: number) => ( + <Event + key={`event-${index}`} + title={ev.title} + date={ev.date} + signupUrl={ev.signupUrl} + imageUrl={ev.imageUrl} + /> + ))} + </WrapGrid> + </EventsWrapper> + + <Banner + heading="Ready to get started?" + subline="Dive into our docs, or contact us if needed" + mainCta={{ text: 'Get Started', href: '/docs' }} + secondaryCta={{ text: 'Get in Touch', onClick: this._onOpenContactModal.bind(this) }} + /> + <ModalContact isOpen={this.state.isContactModalOpen} onDismiss={this._onDismissContactModal} /> + </SiteWrap> + ); + } + + public _onOpenContactModal = (): void => { + this.setState({ isContactModalOpen: true }); + }; + + public _onDismissContactModal = (): void => { + this.setState({ isContactModalOpen: false }); + }; +} + +const Event: React.FunctionComponent<EventProps> = (event: EventProps) => ( + <StyledEvent> + <EventIcon name="logo-mark" size={30} margin={0} /> + <EventImage src={event.imageUrl} alt="" /> + <EventContent> + <Heading color={colors.white} size="small" marginBottom="0"> + {event.title} + </Heading> + <Paragraph color={colors.white} isMuted={0.65}> + {event.date} + </Paragraph> + <Button color={colors.white} href={event.signupUrl} isWithArrow={true}> + Sign Up + </Button> + </EventContent> + </StyledEvent> +); + +const CommunityLink: React.FunctionComponent<CommunityLinkProps> = (props: CommunityLinkProps) => ( + <StyledCommunityLink bgColor={props.bgColor} href={props.url}> + <CommunityIcon name={props.icon} size={44} margin={0} /> + <CommunityTitle color={colors.white} isMuted={false} marginBottom="0"> + {props.title} + </CommunityTitle> + </StyledCommunityLink> +); + +// Events +const EventsWrapper = styled(Section)` + display: flex; + align-items: center; + flex-direction: column; +`; + +// Event +const StyledEvent = styled.div` + background-color: ${colors.brandDark}; + width: calc((100% / 3) - 30px); + text-align: left; + height: 424px; + margin-top: 130px; + position: relative; +`; + +const EventIcon = styled(Icon)` + position: absolute; + top: 30px; + left: 30px; +`; + +const EventImage = styled.img` + width: 100%; + height: 260px; + object-fit: cover; +`; + +const EventContent = styled.div` + padding: 30px 30px; +`; + +interface StyledCommunityLinkProps { + bgColor: string; +} +const StyledCommunityLink = styled.a` + background-color: ${(props: StyledCommunityLinkProps) => props.bgColor}; + color: ${colors.white}; + width: 175px; + height: 175px; + text-align: center; + position: relative; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +`; + +const CommunityTitle = styled(Paragraph)` + font-size: 20px; + font-weight: 400; +`; + +const CommunityIcon = styled(Icon)` + margin-bottom: 20px; +`; + +// Misc +const LinkWrap = styled.div` + display: inline-flex; + margin-top: 60px; + + a + a { + margin-left: 60px; + } +`; diff --git a/packages/website/ts/@next/pages/ecosystem.tsx b/packages/website/ts/@next/pages/ecosystem.tsx new file mode 100644 index 000000000..f78bd3bdc --- /dev/null +++ b/packages/website/ts/@next/pages/ecosystem.tsx @@ -0,0 +1,128 @@ +import * as _ from 'lodash'; +import * as React from 'react'; +import DocumentTitle from 'react-document-title'; +import styled from 'styled-components'; + +import { colors } from 'ts/style/colors'; + +import { Button } from 'ts/@next/components/button'; +import { Icon } from 'ts/@next/components/icon'; +import { Column, Section, WrapGrid } from 'ts/@next/components/newLayout'; +import { SiteWrap } from 'ts/@next/components/siteWrap'; +import { Heading, Paragraph } from 'ts/@next/components/text'; +import { constants } from 'ts/utils/constants'; + +interface BenefitProps { + title: string; + icon: string; + description: string; +} + +const benefits: BenefitProps[] = [ + { + icon: 'milestoneGrants', + title: 'Milestone Grants', + description: + 'Receive non-dilutive capital ranging from $10,000 to $100,000, with grant sizes awarded based on the quality of your team, vision, execution, and community involvement.', + }, + { + icon: 'vcIntroductions', + title: 'VC Introductions', + description: 'Connect with leading venture capital firms that could participate in your next funding round.', + }, + { + icon: 'techSupport', + title: 'Technical Support', + description: 'Receive ongoing technical assistance from knowledgeable and responsive 0x developers.', + }, + { + icon: 'recruitingSupport', + title: 'Recruiting Assistance', + description: 'Grow your team by accessing an exclusive pool of top engineering and business operations talent.', + }, + { + icon: 'eficientDesign', + title: 'Marketing and Design Help', + description: + 'Get strategic advice on product positioning, customer acquisition, and UI/UX design that can impact the growth of your business.', + }, + { + icon: 'legalResources', + title: 'Legal Resources', + description: 'Access important legal resources that will help you navigate the regulatory landscape.', + }, +]; + +export const NextEcosystem = () => ( + <SiteWrap theme="light"> + <DocumentTitle title="Ecosystem Acceleration Program: Jumpstart your Business on 0x" /> + <Section isTextCentered={true}> + <Column> + <Heading size="medium" isCentered={true}> + Jumpstart your Business on 0x + </Heading> + <Paragraph size="medium" isCentered={true} isMuted={true} marginBottom="0"> + The Ecosystem Acceleration Program gives teams access to a variety of services including funding, + dedicated technical support, and recruiting assistance. We created the Ecosystem Acceleration + Program to bolster the expansion of both infrastructure projects and relayers building on 0x. + </Paragraph> + <LinkWrap> + <Button + href={constants.URL_ECOSYSTEM_APPLY} + isWithArrow={true} + isAccentColor={true} + shouldUseAnchorTag={true} + > + Apply now + </Button> + <Button + href={constants.URL_ECOSYSTEM_BLOG_POST} + isWithArrow={true} + isAccentColor={true} + shouldUseAnchorTag={true} + target="_blank" + > + Learn More + </Button> + </LinkWrap> + </Column> + </Section> + + <Section bgColor={colors.backgroundLight} isFullWidth={true}> + <Column> + <Heading + size={34} + fontWeight="400" + asElement="h2" + isCentered={true} + maxWidth="507px" + marginBottom="70px" + > + Join a vibrant ecosystem of projects in the 0x Network. + </Heading> + </Column> + <WrapGrid isTextCentered={true} isWrapped={true} isFullWidth={true}> + {_.map(benefits, (benefit: BenefitProps, index) => ( + <Column key={`benefit-${index}`} width="33%" padding="0 45px 30px"> + <Icon name={benefit.icon} size="medium" margin={[0, 0, 'small', 0]} /> + <Heading color={colors.textDarkPrimary} size="small" marginBottom="10px" isCentered={true}> + {benefit.title} + </Heading> + <Paragraph isMuted={true} isCentered={true}> + {benefit.description} + </Paragraph> + </Column> + ))} + </WrapGrid> + </Section> + </SiteWrap> +); + +const LinkWrap = styled.div` + display: inline-flex; + margin-top: 60px; + + a + a { + margin-left: 60px; + } +`; diff --git a/packages/website/ts/@next/pages/instant.tsx b/packages/website/ts/@next/pages/instant.tsx new file mode 100644 index 000000000..d08fd566a --- /dev/null +++ b/packages/website/ts/@next/pages/instant.tsx @@ -0,0 +1,261 @@ +import { utils as sharedUtils } from '@0x/react-shared'; +import * as _ from 'lodash'; +import * as React from 'react'; +import DocumentTitle from 'react-document-title'; +import styled, { keyframes } from 'styled-components'; + +import { Banner } from 'ts/@next/components/banner'; +import { Button } from 'ts/@next/components/button'; +import { Definition } from 'ts/@next/components/definition'; +import { Hero } from 'ts/@next/components/hero'; +import { Section, SectionProps } from 'ts/@next/components/newLayout'; +import { SiteWrap } from 'ts/@next/components/siteWrap'; +import { Heading, Paragraph } from 'ts/@next/components/text'; +import { Configurator } from 'ts/@next/pages/instant/configurator'; +import { colors } from 'ts/style/colors'; +import { WebsitePaths } from 'ts/types'; +import { utils } from 'ts/utils/utils'; + +import { ModalContact } from '../components/modals/modal_contact'; + +const CONFIGURATOR_MIN_WIDTH_PX = 1050; + +export const getStartedClick = () => { + if (window.innerWidth < CONFIGURATOR_MIN_WIDTH_PX) { + utils.openUrl(`${WebsitePaths.Wiki}#Get-Started-With-Instant`); + } else { + sharedUtils.setUrlHash('configurator'); + sharedUtils.scrollToHash('configurator', ''); + } +}; + +const featuresData = [ + { + title: 'Support ERC-20 and ERC-721 tokens', + icon: 'supportForAllEthereumStandards-large', + description: + 'Seamlessly integrate token purchasing into your product experience by offering digital assets ranging from in-game items to stablecoins.', + links: [ + { + label: 'Get Started', + onClick: getStartedClick, + shouldUseAnchorTag: true, + }, + { + label: 'Explore the Docs', + url: `${WebsitePaths.Wiki}#Get-Started-With-Instant`, + }, + ], + }, + { + title: 'Generate revenue for your business', + icon: 'generateRevenueForYourBusiness-large', + description: + 'With just a few lines of code, you can earn up to 5% in affiliate fees on every transaction from your crypto wallet or dApp.', + links: [ + { + label: 'Learn about affiliate fees', + url: `${WebsitePaths.Wiki}#Learn-About-Affiliate-Fees`, + }, + ], + }, + { + title: 'Easy and flexible integration', + icon: 'flexibleIntegration0xInstant', + description: + 'Use our out-of-the-box design or customize the user interface by integrating via the AssetBuyer engine.. You can also tap into 0x networked liquidity or choose your own liquidity pool.', + links: [ + { + label: 'Explore AssetBuyer', + url: `${WebsitePaths.Docs}/asset-buyer`, + }, + ], + }, +]; + +interface Props { + theme: { + bgColor: string; + textColor: string; + linkColor: string; + }; +} + +export class Next0xInstant extends React.Component<Props> { + public state = { + isContactModalOpen: false, + }; + public render(): React.ReactNode { + return ( + <SiteWrap> + <DocumentTitle title="0x Instant: Quick and secure crypto purchasing" /> + <Hero + title="Introducing 0x Instant" + description="A free and flexible way to offer simple crypto purchasing in any app or website" + actions={<Button onClick={getStartedClick}>Get Started</Button>} + /> + + <Section isFullWidth={true} isPadded={false} padding="30px 0"> + <MarqueeWrap> + <div> + {[...Array(18)].map((item, index) => ( + <Card key={`card-${index}`} index={index}> + <img src={`/images/@next/0x-instant/widget-${index % 6 + 1}.png`} /> + </Card> + ))} + </div> + </MarqueeWrap> + </Section> + + <Section> + {_.map(featuresData, (item, index) => ( + <Definition + key={`definition-${index}`} + icon={item.icon} + title={item.title} + description={item.description} + isInlineIcon={true} + iconSize={240} + actions={item.links} + /> + ))} + </Section> + + <ConfiguratorSection + id="configurator" + maxWidth="1386px" + padding="0 58px 70px" + bgColor={colors.backgroundDark} + > + <Heading>0x Instant Configurator</Heading> + <Configurator /> + </ConfiguratorSection> + + <Banner + heading="Need more flexibility?" + subline="Dive into our docs, or contact us if needed" + mainCta={{ text: 'Explore the Docs', href: `${WebsitePaths.Wiki}#Get-Started-With-Instant` }} + secondaryCta={{ text: 'Get in Touch', onClick: this._onOpenContactModal.bind(this) }} + /> + <ModalContact isOpen={this.state.isContactModalOpen} onDismiss={this._onDismissContactModal} /> + + <Section maxWidth="1170px" isPadded={false} padding="60px 0"> + <Paragraph size="small" isMuted={0.5}> + Disclaimer: The laws and regulations applicable to the use and exchange of digital assets and + blockchain-native tokens, including through any software developed using the licensed work + created by ZeroEx Intl. (the “Work”), vary by jurisdiction. As set forth in the Apache License, + Version 2.0 applicable to the Work, developers are “solely responsible for determining the + appropriateness of using or redistributing the Work,” which includes responsibility for ensuring + compliance with any such applicable laws and regulations. + </Paragraph> + <Paragraph size="small" isMuted={0.5}> + See the Apache License, Version 2.0 for the specific language governing all applicable + permissions and limitations. + </Paragraph> + </Section> + </SiteWrap> + ); + } + + public _onOpenContactModal = (): void => { + this.setState({ isContactModalOpen: true }); + }; + + public _onDismissContactModal = (): void => { + this.setState({ isContactModalOpen: false }); + }; +} + +// scroll animation calc is simply (imageWidth * totalRepetitions) / 2 +// img width is 370px +const scroll = keyframes` + 0% { transform: translate3d(-2220px, 0, 0) } + 100% { transform: translate3d(-4440px, 0, 0) } +`; + +const scrollMobile = keyframes` + 0% { transform: translate3d(0, 0, 0) } + 100% { transform: translate3d(-1800px, 0, 0) } +`; + +const fadeUp = keyframes` + 0% { + opacity: 0; + transform: translateY(50px); + } + 100% { + opacity: 1; + transform: translateY(0px); + } +`; + +const ConfiguratorSection = + styled(Section) < + SectionProps > + ` + @media (max-width: ${CONFIGURATOR_MIN_WIDTH_PX}px) { + display: none; + } +`; + +// width = 370 * 12 +// mobile width = 300 +const MarqueeWrap = styled.div` + width: 100vw; + height: 514px; + padding-bottom: 60px; + + @media (max-width: 768px) { + width: calc(100% + 60px); + margin-left: -30px; + overflow: hidden; + } + + > div { + height: auto; + display: flex; + will-change: transform; + transform: translate3d(-2220px, 0, 0); + } + + @media (min-width: 768px) { + > div { + width: 6660px; + animation: ${scroll} 70s linear infinite; + } + } + + @media (max-width: 768px) { + > div { + width: 5400px; + animation: ${scrollMobile} 70s linear infinite; + } + } +`; + +const Card = + styled.div < + { index: number } > + ` + opacity: 0; + flex-shrink: 0; + transform: translateY(10px); + will-change: opacity, transform; + animation: ${fadeUp} 0.75s ${props => `${props.index * 0.05}s`} forwards; + + img { + height: auto; + } + + @media (min-width: 768px) { + img { + width: 370px; + } + } + + @media (max-width: 768px) { + img { + width: 300px; + } + } +`; diff --git a/packages/website/ts/@next/pages/instant/code_demo.tsx b/packages/website/ts/@next/pages/instant/code_demo.tsx new file mode 100644 index 000000000..4a3022df5 --- /dev/null +++ b/packages/website/ts/@next/pages/instant/code_demo.tsx @@ -0,0 +1,183 @@ +import * as React from 'react'; +import * as CopyToClipboard from 'react-copy-to-clipboard'; +import SyntaxHighlighter from 'react-syntax-highlighter'; + +import { Button } from 'ts/@next/components/button'; +import { Container } from 'ts/components/ui/container'; +import { styled } from 'ts/style/theme'; +import { zIndex } from 'ts/style/z_index'; + +const CustomPre = styled.pre` + margin: 0px; + line-height: 24px; + overflow: scroll; + width: 100%; + height: 100%; + max-height: 800px; + border-radius: 4px; + code { + background-color: inherit !important; + border-radius: 0px; + font-family: 'Roboto Mono', sans-serif; + border: none; + } + code:first-of-type { + background-color: #060d0d !important; + color: #999; + min-height: 100%; + text-align: center; + margin-right: 15px; + line-height: 25px; + padding: 10px 7px !important; + } + code:last-of-type { + position: relative; + top: 10px; + top: 0; + padding-top: 11px; + display: inline-block; + line-height: 25px; + } +`; + +const customStyle = { + 'hljs-comment': { + color: '#7e7887', + }, + 'hljs-quote': { + color: '#7e7887', + }, + 'hljs-variable': { + color: '#be4678', + }, + 'hljs-template-variable': { + color: '#be4678', + }, + 'hljs-attribute': { + color: '#be4678', + }, + 'hljs-regexp': { + color: '#be4678', + }, + 'hljs-link': { + color: '#be4678', + }, + 'hljs-tag': { + color: '#61f5ff', + }, + 'hljs-name': { + color: '#61f5ff', + }, + 'hljs-selector-id': { + color: '#be4678', + }, + 'hljs-selector-class': { + color: '#be4678', + }, + 'hljs-number': { + color: '#c994ff', + }, + 'hljs-meta': { + color: '#61f5ff', + }, + 'hljs-built_in': { + color: '#aa573c', + }, + 'hljs-builtin-name': { + color: '#aa573c', + }, + 'hljs-literal': { + color: '#aa573c', + }, + 'hljs-type': { + color: '#aa573c', + }, + 'hljs-params': { + color: '#aa573c', + }, + 'hljs-string': { + color: '#bcff88', + }, + 'hljs-symbol': { + color: '#2a9292', + }, + 'hljs-bullet': { + color: '#2a9292', + }, + 'hljs-title': { + color: '#576ddb', + }, + 'hljs-section': { + color: '#576ddb', + }, + 'hljs-keyword': { + color: '#955ae7', + }, + 'hljs-selector-tag': { + color: '#955ae7', + }, + 'hljs-deletion': { + color: '#19171c', + display: 'inline-block', + width: '100%', + backgroundColor: '#be4678', + }, + 'hljs-addition': { + color: '#19171c', + display: 'inline-block', + width: '100%', + backgroundColor: '#2a9292', + }, + hljs: { + display: 'block', + overflowX: 'hidden', + background: '#1B2625', + color: 'white', + fontSize: '12px', + }, + 'hljs-emphasis': { + fontStyle: 'italic', + }, + 'hljs-strong': { + fontWeight: 'bold', + }, +}; + +export interface CodeDemoProps { + children: string; +} + +export interface CodeDemoState { + didCopyCode: boolean; +} + +export class CodeDemo extends React.Component<CodeDemoProps, CodeDemoState> { + public state: CodeDemoState = { + didCopyCode: false, + }; + public render(): React.ReactNode { + const copyButtonText = this.state.didCopyCode ? 'Copied!' : 'Copy'; + return ( + <Container position="relative" height="100%"> + <Container position="absolute" top="10px" right="10px" zIndex={zIndex.overlay - 1}> + <CopyToClipboard text={this.props.children} onCopy={this._handleCopyClick}> + <StyledButton>{copyButtonText}</StyledButton> + </CopyToClipboard> + </Container> + <SyntaxHighlighter language="html" style={customStyle} showLineNumbers={true} PreTag={CustomPre}> + {this.props.children} + </SyntaxHighlighter> + </Container> + ); + } + private readonly _handleCopyClick = () => { + this.setState({ didCopyCode: true }); + }; +} + +const StyledButton = styled(Button)` + border-radius: 4px; + font-size: 15px; + font-weight: 400; + padding: 9px 21px 7px; +`; diff --git a/packages/website/ts/pages/instant/config_generator.tsx b/packages/website/ts/@next/pages/instant/config_generator.tsx index fbeeeaeaf..3f00e33e2 100644 --- a/packages/website/ts/pages/instant/config_generator.tsx +++ b/packages/website/ts/@next/pages/instant/config_generator.tsx @@ -4,21 +4,25 @@ import { assetDataUtils } from '@0x/order-utils'; import { ObjectMap } from '@0x/types'; import * as _ from 'lodash'; import * as React from 'react'; +import styled from 'styled-components'; +import { ConfigGeneratorAddressInput } from 'ts/@next/pages/instant/config_generator_address_input'; +import { FeePercentageSlider } from 'ts/@next/pages/instant/fee_percentage_slider'; import { CheckMark } from 'ts/components/ui/check_mark'; import { Container } from 'ts/components/ui/container'; import { MultiSelect } from 'ts/components/ui/multi_select'; -import { Select, SelectItemConfig } from 'ts/components/ui/select'; import { Spinner } from 'ts/components/ui/spinner'; import { Text } from 'ts/components/ui/text'; -import { ConfigGeneratorAddressInput } from 'ts/pages/instant/config_generator_address_input'; -import { FeePercentageSlider } from 'ts/pages/instant/fee_percentage_slider'; import { colors } from 'ts/style/colors'; import { WebsitePaths } from 'ts/types'; import { constants } from 'ts/utils/constants'; -import { assetMetaDataMap } from '../../../../instant/src/data/asset_meta_data_map'; -import { ERC20AssetMetaData, ZeroExInstantBaseConfig } from '../../../../instant/src/types'; +// New components +import { Heading } from 'ts/@next/components/text'; +import { Select, SelectItemConfig } from 'ts/@next/pages/instant/select'; + +import { assetMetaDataMap } from '../../../../../instant/src/data/asset_meta_data_map'; +import { ERC20AssetMetaData, ZeroExInstantBaseConfig } from '../../../../../instant/src/types'; export interface ConfigGeneratorProps { value: ZeroExInstantBaseConfig; @@ -59,8 +63,14 @@ export class ConfigGenerator extends React.Component<ConfigGeneratorProps, Confi } return ( <Container minWidth="350px"> - <ConfigGeneratorSection title="Standard relayer API endpoint"> - <Select value={value.orderSource} items={this._generateItems()} /> + <ConfigGeneratorSection title="Liquidity Source"> + <Select + shouldIncludeEmpty={false} + id="" + value={value.orderSource} + items={this._generateItems()} + onChange={this._handleSRASelection.bind(this)} + /> </ConfigGeneratorSection> <ConfigGeneratorSection {...this._getTokenSelectorProps()}> {this._renderTokenMultiSelectOrSpinner()} @@ -110,14 +120,16 @@ export class ConfigGenerator extends React.Component<ConfigGeneratorProps, Confi }; private readonly _generateItems = (): SelectItemConfig[] => { return _.map(SRA_ENDPOINTS, endpoint => ({ - text: endpoint, + label: endpoint, + value: endpoint, onClick: this._handleSRASelection.bind(this, endpoint), })); }; private readonly _handleAffiliatePercentageLearnMoreClick = (): void => { window.open(`${WebsitePaths.Wiki}#Learn-About-Affiliate-Fees`, '_blank'); }; - private readonly _handleSRASelection = (sraEndpoint: string) => { + private readonly _handleSRASelection = (event: React.ChangeEvent<HTMLSelectElement>) => { + const sraEndpoint = event.target.value; const newConfig: ZeroExInstantBaseConfig = { ...this.props.value, orderSource: sraEndpoint, @@ -249,15 +261,11 @@ export class ConfigGenerator extends React.Component<ConfigGeneratorProps, Confi renderItemContent: (isSelected: boolean) => ( <Container className="flex items-center"> <Container marginRight="10px"> - <CheckMark isChecked={isSelected} /> + <CheckMark isChecked={isSelected} color={colors.brandLight} /> </Container> - <Text - fontSize="16px" - fontColor={isSelected ? colors.mediumBlue : colors.darkerGrey} - fontWeight={300} - > - <b>{metaData.symbol.toUpperCase()}</b> — {metaData.name} - </Text> + <CheckboxText isSelected={isSelected}> + {metaData.symbol.toUpperCase()} — {metaData.name} + </CheckboxText> </Container> ), onClick: this._handleTokenClick.bind(this, assetData), @@ -285,22 +293,11 @@ export const ConfigGeneratorSection: React.StatelessComponent<ConfigGeneratorSec }) => ( <Container marginBottom={marginBottom}> <Container marginBottom="10px" className="flex justify-between items-center"> - <Container> - <Text fontColor={colors.white} fontSize="16px" lineHeight="18px" display="inline"> - {title} - </Text> - {isOptional && ( - <Text fontColor={colors.grey} fontSize="16px" lineHeight="18px" display="inline"> - {' '} - (optional) - </Text> - )} - </Container> - {actionText && ( - <Text fontSize="12px" fontColor={colors.grey} onClick={onActionTextClick}> - {actionText} - </Text> - )} + <Heading size="small" marginBottom="0" isFlex={true}> + <span>{title}</span> + {isOptional && <OptionalText> Optional</OptionalText>} + </Heading> + {actionText && <OptionalAction onClick={onActionTextClick}>{actionText}</OptionalAction>} </Container> {children} </Container> @@ -309,3 +306,27 @@ export const ConfigGeneratorSection: React.StatelessComponent<ConfigGeneratorSec ConfigGeneratorSection.defaultProps = { marginBottom: '30px', }; + +const OptionalText = styled.span` + display: inline; + font-size: 14px; + color: #999999; + flex-shrink: 0; +`; + +interface CheckboxTextProps { + isSelected?: boolean; +} + +const CheckboxText = + styled.span < + CheckboxTextProps > + ` + font-size: 14px; + line-height: 18px; + color: ${props => (props.isSelected ? colors.brandDark : '#666666')} +`; + +const OptionalAction = styled(OptionalText)` + cursor: pointer; +`; diff --git a/packages/website/ts/@next/pages/instant/config_generator_address_input.tsx b/packages/website/ts/@next/pages/instant/config_generator_address_input.tsx new file mode 100644 index 000000000..9b0e9b1d1 --- /dev/null +++ b/packages/website/ts/@next/pages/instant/config_generator_address_input.tsx @@ -0,0 +1,84 @@ +import { addressUtils } from '@0x/utils'; +import * as _ from 'lodash'; +import * as React from 'react'; +import styled from 'styled-components'; + +import { colors } from 'ts/style/colors'; + +import { Container } from 'ts/components/ui/container'; + +import { Paragraph } from 'ts/@next/components/text'; + +export interface ConfigGeneratorAddressInputProps { + value?: string; + onChange?: (address: string, isValid: boolean) => void; +} + +export interface ConfigGeneratorAddressInputState { + errMsg: string; +} + +export interface InputProps { + className?: string; + value?: string; + width?: string; + fontSize?: string; + fontColor?: string; + padding?: string; + placeholderColor?: string; + placeholder?: string; + backgroundColor?: string; + onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void; +} + +export class ConfigGeneratorAddressInput extends React.Component< + ConfigGeneratorAddressInputProps, + ConfigGeneratorAddressInputState +> { + public state = { + errMsg: '', + }; + public render(): React.ReactNode { + const { errMsg } = this.state; + const hasError = !_.isEmpty(errMsg); + return ( + <Container height="80px"> + <Input value={this.props.value} onChange={this._handleChange} placeholder="0xe99...aa8da4" /> + <Container marginTop="5px" isHidden={!hasError} height="25px"> + <Paragraph size="small" isNoMargin={true}> + {errMsg} + </Paragraph> + </Container> + </Container> + ); + } + + private readonly _handleChange = (event: React.ChangeEvent<HTMLInputElement>): void => { + const address = event.target.value; + const isValidAddress = addressUtils.isAddress(address.toLowerCase()) || address === ''; + const errMsg = isValidAddress ? '' : 'Please enter a valid Ethereum address'; + this.setState({ + errMsg, + }); + this.props.onChange(address, isValidAddress); + }; +} + +const PlainInput: React.StatelessComponent<InputProps> = ({ value, className, placeholder, onChange }) => ( + <input className={className} value={value} onChange={onChange} placeholder={placeholder} /> +); + +export const Input = styled(PlainInput)` + background-color: ${colors.white}; + color: ${colors.textDarkSecondary}; + font-size: 1rem; + width: 100%; + padding: 16px 20px 18px; + border-radius: 4px; + border: 1px solid transparent; + outline: none; + &::placeholder { + color: #333333; + opacity: 0.5; + } +`; diff --git a/packages/website/ts/pages/instant/configurator.tsx b/packages/website/ts/@next/pages/instant/configurator.tsx index 2cb1a1c1c..7c67e6333 100644 --- a/packages/website/ts/pages/instant/configurator.tsx +++ b/packages/website/ts/@next/pages/instant/configurator.tsx @@ -1,25 +1,22 @@ import * as _ from 'lodash'; import * as React from 'react'; +import styled from 'styled-components'; -import { Container } from 'ts/components/ui/container'; -import { Text } from 'ts/components/ui/text'; -import { ActionLink } from 'ts/pages/instant/action_link'; -import { CodeDemo } from 'ts/pages/instant/code_demo'; -import { ConfigGenerator } from 'ts/pages/instant/config_generator'; -import { colors } from 'ts/style/colors'; -import { WebsitePaths } from 'ts/types'; +import { CodeDemo } from 'ts/@next/pages/instant/code_demo'; +import { ConfigGenerator } from 'ts/@next/pages/instant/config_generator'; -import { ZeroExInstantBaseConfig } from '../../../../instant/src/types'; +import { Link } from 'ts/@next/components/link'; +import { Column, FlexWrap } from 'ts/@next/components/newLayout'; +import { Heading } from 'ts/@next/components/text'; +import { WebsitePaths } from 'ts/types'; -export interface ConfiguratorProps { - hash: string; -} +import { ZeroExInstantBaseConfig } from '../../../../../instant/src/types'; export interface ConfiguratorState { instantConfig: ZeroExInstantBaseConfig; } -export class Configurator extends React.Component<ConfiguratorProps> { +export class Configurator extends React.Component { public state: ConfiguratorState = { instantConfig: { orderSource: 'https://api.radarrelay.com/0x/v2/', @@ -31,36 +28,24 @@ export class Configurator extends React.Component<ConfiguratorProps> { }, }; public render(): React.ReactNode { - const { hash } = this.props; const codeToDisplay = this._generateCodeDemoCode(); return ( - <Container - className="flex justify-center py4 px3" - id={hash} - backgroundColor={colors.instantTertiaryBackground} - > - <Container className="mx3"> - <Container className="mb3"> - <Text fontSize="20px" lineHeight="28px" fontColor={colors.white} fontWeight={500}> - 0x Instant Configurator - </Text> - </Container> + <FlexWrap isFlex={true}> + <Column width="442px" padding="0 70px 0 0"> <ConfigGenerator value={this.state.instantConfig} onConfigChange={this._handleConfigChange} /> - </Container> - <Container className="mx3" height="550px"> - <Container className="mb3 flex justify-between"> - <Text fontSize="20px" lineHeight="28px" fontColor={colors.white} fontWeight={500}> + </Column> + <Column width="100%"> + <HeadingWrapper> + <Heading size="small" marginBottom="15px"> Code Snippet - </Text> - <ActionLink - displayText="Explore the Docs" - linkSrc={`${WebsitePaths.Wiki}#Get-Started-With-Instant`} - color={colors.grey} - /> - </Container> + </Heading> + <Link href={`${WebsitePaths.Wiki}#Get-Started-With-Instant`} isBlock={true} target="_blank"> + Explore the Docs + </Link> + </HeadingWrapper> <CodeDemo key={codeToDisplay}>{codeToDisplay}</CodeDemo> - </Container> - </Container> + </Column> + </FlexWrap> ); } private readonly _handleConfigChange = (config: ZeroExInstantBaseConfig) => { @@ -74,7 +59,7 @@ export class Configurator extends React.Component<ConfiguratorProps> { <html> <head> <meta charset="utf-8" /> - <script src="https://instant.0xproject.com/instant.js"></script> + <script src="https://instant.0x.org/instant.js"></script> </head> <body> <script> @@ -93,10 +78,10 @@ export class Configurator extends React.Component<ConfiguratorProps> { )}` : '' } - }, 'body'); - </script> - </body> -</html>`; + }, 'body'); + </script> + </body> + </html>`; }; private readonly _renderAvailableAssetDatasString = (availableAssetDatas: string[]): string => { const stringAvailableAssetDatas = availableAssetDatas.map(assetData => `'${assetData}'`); @@ -108,3 +93,12 @@ export class Configurator extends React.Component<ConfiguratorProps> { )}\n ]`; }; } + +const HeadingWrapper = styled.div` + display: flex; + justify-content: space-between; + + a { + transform: translateY(-8px); + } +`; diff --git a/packages/website/ts/pages/instant/fee_percentage_slider.tsx b/packages/website/ts/@next/pages/instant/fee_percentage_slider.tsx index d76cee58f..5775d6dfb 100644 --- a/packages/website/ts/pages/instant/fee_percentage_slider.tsx +++ b/packages/website/ts/@next/pages/instant/fee_percentage_slider.tsx @@ -1,64 +1,36 @@ import Slider from 'rc-slider'; -import 'rc-slider/assets/index.css'; import * as React from 'react'; +import styled from 'styled-components'; +import 'ts/@next/pages/instant/rc-slider.css'; -import { Text } from 'ts/components/ui/text'; import { colors } from 'ts/style/colors'; -import { injectGlobal } from 'ts/style/theme'; const SliderWithTooltip = (Slider as any).createSliderWithTooltip(Slider); // tslint:disable-next-line:no-unused-expression -injectGlobal` - .rc-slider-tooltip-inner { - box-shadow: none !important; - background-color: ${colors.white} !important; - border-radius: 4px !important; - padding: 3px 12px !important; - height: auto !important; - position: relative; - top: 7px; - &: after { - border: solid transparent; - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; - border-width: 6px; - bottom: 100%; - left: 100%; - border-bottom-color: ${colors.white}; - margin-left: -60%; - } - } - .rc-slider-disabled { - background-color: inherit !important; - } -`; export interface FeePercentageSliderProps { value: number; - isDisabled: boolean; + isDisabled?: boolean; onChange: (value: number) => void; } export class FeePercentageSlider extends React.Component<FeePercentageSliderProps> { public render(): React.ReactNode { return ( - <SliderWithTooltip - disabled={this.props.isDisabled} + <StyledSlider min={0} max={0.05} step={0.0025} value={this.props.value} + disabled={this.props.isDisabled} onChange={this.props.onChange} tipFormatter={this._feePercentageSliderFormatter} - tipProps={{ placement: 'bottom' }} + tipProps={{ placement: 'bottom', overlayStyle: { backgroundColor: '#fff', borderRadius: '4px' } }} trackStyle={{ - backgroundColor: '#b4b4b4', + backgroundColor: colors.brandLight, }} railStyle={{ - backgroundColor: '#696969', + backgroundColor: 'rgba(255, 255, 255, 0.2)', }} handleStyle={{ border: 'none', @@ -72,6 +44,37 @@ export class FeePercentageSlider extends React.Component<FeePercentageSliderProp ); } private readonly _feePercentageSliderFormatter = (value: number): React.ReactNode => { - return <Text fontColor={colors.black} fontSize="14px" fontWeight={700}>{`${(value * 100).toFixed(2)}%`}</Text>; + return <Text>{`${(value * 100).toFixed(2)}%`}</Text>; }; } + +const StyledSlider = styled(SliderWithTooltip)` + .rc-slider-tooltip__inner { + box-shadow: none !important; + background-color: ${colors.white} !important; + border-radius: 4px !important; + padding: 3px 12px !important; + height: auto !important; + position: relative; + top: 7px; + &:after { + border: solid transparent; + content: ' '; + height: 0; + width: 0; + position: absolute; + pointer-events: none; + border-width: 6px; + bottom: 100%; + left: 100%; + border-bottom-color: ${colors.white}; + margin-left: -60%; + } + } +`; + +const Text = styled.span` + color: #000000; + font-size: 12px; + line-height: 18px; +`; diff --git a/packages/website/ts/@next/pages/instant/rc-slider.css b/packages/website/ts/@next/pages/instant/rc-slider.css new file mode 100644 index 000000000..63038324e --- /dev/null +++ b/packages/website/ts/@next/pages/instant/rc-slider.css @@ -0,0 +1,295 @@ +.rc-slider { + position: relative; + height: 14px; + padding: 5px 0; + width: 100%; + border-radius: 6px; + -ms-touch-action: none; + touch-action: none; + box-sizing: border-box; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +.rc-slider * { + box-sizing: border-box; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +.rc-slider-rail { + position: absolute; + width: 100%; + background-color: #e9e9e9; + height: 4px; + border-radius: 6px; +} + +.rc-slider-track { + position: absolute; + left: 0; + height: 4px; + border-radius: 6px; + background-color: #abe2fb; +} + +.rc-slider-handle { + position: absolute; + margin-left: -7px; + margin-top: -5px; + width: 14px; + height: 14px; + cursor: pointer; + cursor: -webkit-grab; + cursor: grab; + border-radius: 50%; + border: solid 2px #96dbfa; + background-color: #fff; + -ms-touch-action: pan-x; + touch-action: pan-x; +} + +.rc-slider-handle:focus { + border-color: #57c5f7; + box-shadow: 0 0 0 5px #96dbfa; + outline: none; +} + +.rc-slider-handle-click-focused:focus { + border-color: #96dbfa; + box-shadow: unset; +} + +.rc-slider-handle:hover { + border-color: #57c5f7; +} + +.rc-slider-handle:active { + border-color: #57c5f7; + box-shadow: 0 0 5px #57c5f7; + cursor: -webkit-grabbing; + cursor: grabbing; +} + +.rc-slider-mark { + position: absolute; + top: 18px; + left: 0; + width: 100%; + font-size: 12px; +} + +.rc-slider-mark-text { + position: absolute; + display: inline-block; + vertical-align: middle; + text-align: center; + cursor: pointer; + color: #999; +} + +.rc-slider-mark-text-active { + color: #666; +} + +.rc-slider-step { + position: absolute; + width: 100%; + height: 4px; + background: transparent; +} + +.rc-slider-dot { + position: absolute; + bottom: -2px; + margin-left: -4px; + width: 8px; + height: 8px; + border: 2px solid #e9e9e9; + background-color: #fff; + cursor: pointer; + border-radius: 50%; + vertical-align: middle; +} + +.rc-slider-dot-active { + border-color: #96dbfa; +} + +.rc-slider-disabled { + opacity: 0.2; +} + +.rc-slider-disabled .rc-slider-track { + background-color: #ccc; +} + +.rc-slider-disabled .rc-slider-handle, +.rc-slider-disabled .rc-slider-dot { + border-color: #ccc; + box-shadow: none; + background-color: #fff; + cursor: not-allowed; +} + +.rc-slider-disabled .rc-slider-mark-text, +.rc-slider-disabled .rc-slider-dot { + cursor: not-allowed !important; +} + +.rc-slider-vertical { + width: 14px; + height: 100%; + padding: 0 5px; +} + +.rc-slider-vertical .rc-slider-rail { + height: 100%; + width: 4px; +} + +.rc-slider-vertical .rc-slider-track { + left: 5px; + bottom: 0; + width: 4px; +} + +.rc-slider-vertical .rc-slider-handle { + margin-left: -5px; + margin-bottom: -7px; + -ms-touch-action: pan-y; + touch-action: pan-y; +} + +.rc-slider-vertical .rc-slider-mark { + top: 0; + left: 18px; + height: 100%; +} + +.rc-slider-vertical .rc-slider-step { + height: 100%; + width: 4px; +} + +.rc-slider-vertical .rc-slider-dot { + left: 2px; + margin-bottom: -4px; +} + +.rc-slider-vertical .rc-slider-dot:first-child { + margin-bottom: -4px; +} + +.rc-slider-vertical .rc-slider-dot:last-child { + margin-bottom: -4px; +} + +.rc-slider-tooltip-zoom-down-enter, +.rc-slider-tooltip-zoom-down-appear { + animation-duration: .3s; + animation-fill-mode: both; + display: block !important; + animation-play-state: paused; +} + +.rc-slider-tooltip-zoom-down-leave { + animation-duration: .3s; + animation-fill-mode: both; + display: block !important; + animation-play-state: paused; +} + +.rc-slider-tooltip-zoom-down-enter.rc-slider-tooltip-zoom-down-enter-active, +.rc-slider-tooltip-zoom-down-appear.rc-slider-tooltip-zoom-down-appear-active { + animation-name: rcSliderTooltipZoomDownIn; + animation-play-state: running; +} + +.rc-slider-tooltip-zoom-down-leave.rc-slider-tooltip-zoom-down-leave-active { + animation-name: rcSliderTooltipZoomDownOut; + animation-play-state: running; +} + +.rc-slider-tooltip-zoom-down-enter, +.rc-slider-tooltip-zoom-down-appear { + transform: scale(0, 0); + animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1); +} + +.rc-slider-tooltip-zoom-down-leave { + animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); +} + +@keyframes rcSliderTooltipZoomDownIn { + 0% { + opacity: 0; + transform-origin: 50% 100%; + transform: scale(0, 0); + } + + 100% { + transform-origin: 50% 100%; + transform: scale(1, 1); + } +} + +@keyframes rcSliderTooltipZoomDownOut { + 0% { + transform-origin: 50% 100%; + transform: scale(1, 1); + } + + 100% { + opacity: 0; + transform-origin: 50% 100%; + transform: scale(0, 0); + } +} + +.rc-slider-tooltip { + position: absolute; + left: -9999px; + top: -9999px; + visibility: visible; + box-sizing: border-box; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +.rc-slider-tooltip * { + box-sizing: border-box; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +.rc-slider-tooltip-hidden { + display: none; +} + +.rc-slider-tooltip-placement-top { + padding: 4px 0 8px 0; +} + +.rc-slider-tooltip-inner { + padding: 4px 6px 4px; + min-width: 24px; + height: 24px; + font-size: 12px; + line-height: 1; + color: #000; + text-align: center; + text-decoration: none; +} + +.rc-slider-tooltip-arrow { + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} + +.rc-slider-tooltip-placement-top .rc-slider-tooltip-arrow { + bottom: 4px; + left: 50%; + margin-left: -4px; + border-width: 4px 4px 0; + border-top-color: #6c6c6c; +} diff --git a/packages/website/ts/@next/pages/instant/select.tsx b/packages/website/ts/@next/pages/instant/select.tsx new file mode 100644 index 000000000..d4146cfb0 --- /dev/null +++ b/packages/website/ts/@next/pages/instant/select.tsx @@ -0,0 +1,74 @@ +import * as React from 'react'; +import styled from 'styled-components'; + +export interface SelectItemConfig { + label: string; + value?: string; + onClick?: () => void; +} + +interface SelectProps { + value?: string; + id: string; + items: SelectItemConfig[]; + emptyText?: string; + onChange?: (ev: React.ChangeEvent<HTMLSelectElement>) => void; + shouldIncludeEmpty: boolean; +} + +export const Select: React.FunctionComponent<SelectProps> = ({ + value, + id, + items, + shouldIncludeEmpty, + emptyText, + onChange, +}) => { + return ( + <Container> + <StyledSelect id={id} onChange={onChange}> + {shouldIncludeEmpty && <option value="">{emptyText}</option>} + {items.map((item, index) => ( + <option + key={`${id}-item-${index}`} + value={item.value} + selected={item.value === value} + onClick={item.onClick} + > + {item.label} + </option> + ))} + </StyledSelect> + <Caret width="12" height="7" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path d="M11 1L6 6 1 1" stroke="#666" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> + </Caret> + </Container> + ); +}; + +Select.defaultProps = { + emptyText: 'Select...', + shouldIncludeEmpty: true, +}; + +const Container = styled.div` + background-color: #fff; + border-radius: 4px; + display: flex; + width: 100%; + position: relative; +`; + +const StyledSelect = styled.select` + appearance: none; + border: 0; + font-size: 1rem; + width: 100%; + padding: 20px 20px 20px 20px; +`; + +const Caret = styled.svg` + position: absolute; + right: 20px; + top: calc(50% - 4px); +`; diff --git a/packages/website/ts/@next/pages/landing.tsx b/packages/website/ts/@next/pages/landing.tsx new file mode 100644 index 000000000..4d47fefd9 --- /dev/null +++ b/packages/website/ts/@next/pages/landing.tsx @@ -0,0 +1,44 @@ +import * as React from 'react'; +import DocumentTitle from 'react-document-title'; + +import { SectionLandingAbout } from 'ts/@next/components/sections/landing/about'; +import { SectionLandingClients } from 'ts/@next/components/sections/landing/clients'; +import { SectionLandingCta } from 'ts/@next/components/sections/landing/cta'; +import { SectionLandingHero } from 'ts/@next/components/sections/landing/hero'; +import { SiteWrap } from 'ts/@next/components/siteWrap'; + +import { ModalContact } from 'ts/@next/components/modals/modal_contact'; + +interface Props { + theme: { + bgColor: string; + textColor: string; + linkColor: string; + }; +} + +export class NextLanding extends React.Component<Props> { + public state = { + isContactModalOpen: false, + }; + public render(): React.ReactNode { + return ( + <SiteWrap theme="dark"> + <DocumentTitle title="0x: The protocol for trading tokens on Ethereum" /> + <SectionLandingHero /> + <SectionLandingAbout /> + <SectionLandingClients /> + <SectionLandingCta onContactClick={this._onOpenContactModal} /> + <ModalContact isOpen={this.state.isContactModalOpen} onDismiss={this._onDismissContactModal} /> + </SiteWrap> + ); + } + + public _onOpenContactModal = (): void => { + this.setState({ isContactModalOpen: true }); + }; + + public _onDismissContactModal = (): void => { + this.setState({ isContactModalOpen: false }); + }; +} diff --git a/packages/website/ts/@next/pages/launch_kit.tsx b/packages/website/ts/@next/pages/launch_kit.tsx new file mode 100644 index 000000000..605bce91c --- /dev/null +++ b/packages/website/ts/@next/pages/launch_kit.tsx @@ -0,0 +1,125 @@ +import * as _ from 'lodash'; +import * as React from 'react'; +import DocumentTitle from 'react-document-title'; + +import { Hero } from 'ts/@next/components/hero'; + +import { Banner } from 'ts/@next/components/banner'; +import { Button } from 'ts/@next/components/button'; +import { Definition } from 'ts/@next/components/definition'; +import { Icon } from 'ts/@next/components/icon'; +import { SiteWrap } from 'ts/@next/components/siteWrap'; + +import { Section } from 'ts/@next/components/newLayout'; +import { constants } from 'ts/utils/constants'; + +import { ModalContact } from '../components/modals/modal_contact'; + +const offersData = [ + { + icon: 'supportForAllEthereumStandards', + title: 'Perfect for developers who need a simple drop-in marketplace', + description: ( + <ul> + <li>Quickly launch a market for your project’s token</li> + <li>Seamlessly create an in-game marketplace for digital items and collectables</li> + <li>Easily build a 0x relayer for your local market</li> + </ul> + ), + }, +]; + +export class NextLaunchKit extends React.Component { + public state = { + isContactModalOpen: false, + }; + public render(): React.ReactNode { + return ( + <SiteWrap theme="dark"> + <DocumentTitle title="0x Launch Kit: Launch a relayer in under a minute" /> + <Hero + isLargeTitle={false} + isFullWidth={false} + title="0x Launch Kit" + description="Launch a relayer in under a minute" + figure={<Icon name="launchKit" size="hero" margin={['small', 0, 'small', 0]} />} + actions={<HeroActions />} + /> + + <Section bgColor="dark" isFlex={true} maxWidth="1170px"> + <Definition + title="Networked Liquidity Pool" + titleSize="small" + description="Tap into and share liquidity with other relayers" + icon="networkedLiquidity" + iconSize="medium" + isInline={true} + /> + + <Definition + title="Extensible Code Repo" + titleSize="small" + description="Fork and extend to support modes of exchange" + icon="code-repo" + iconSize="medium" + isInline={true} + /> + + <Definition + title="Exchange Ethereum based Tokens" + titleSize="small" + description="Enable trading for any ERC-20 or ERC-721 asset" + icon="eth-based-tokens" + iconSize="medium" + isInline={true} + /> + </Section> + + <Section> + {_.map(offersData, (item, index) => ( + <Definition + key={`offers-${index}`} + icon={item.icon} + title={item.title} + description={item.description} + isInlineIcon={true} + iconSize={240} + /> + ))} + </Section> + + <Banner + heading="Need more flexibility?" + subline="Dive into our docs, or contact us if needed" + mainCta={{ + text: 'Get Started', + href: `${constants.URL_LAUNCH_KIT}/#table-of-contents`, + shouldOpenInNewTab: true, + }} + secondaryCta={{ text: 'Get in Touch', onClick: this._onOpenContactModal.bind(this) }} + /> + <ModalContact isOpen={this.state.isContactModalOpen} onDismiss={this._onDismissContactModal} /> + </SiteWrap> + ); + } + + public _onOpenContactModal = (): void => { + this.setState({ isContactModalOpen: true }); + }; + + public _onDismissContactModal = (): void => { + this.setState({ isContactModalOpen: false }); + }; +} + +const HeroActions = () => ( + <React.Fragment> + <Button href={constants.URL_LAUNCH_KIT} isInline={true} target="_blank"> + Get Started + </Button> + + <Button href={constants.URL_LAUNCH_KIT_BLOG_POST} isTransparent={true} isInline={true} target="_blank"> + Learn More! + </Button> + </React.Fragment> +); diff --git a/packages/website/ts/@next/pages/market_maker.tsx b/packages/website/ts/@next/pages/market_maker.tsx new file mode 100644 index 000000000..e2d3c75c4 --- /dev/null +++ b/packages/website/ts/@next/pages/market_maker.tsx @@ -0,0 +1,124 @@ +import * as _ from 'lodash'; +import * as React from 'react'; + +import { Banner } from 'ts/@next/components/banner'; +import { Button } from 'ts/@next/components/button'; +import { Definition } from 'ts/@next/components/definition'; +import { Hero } from 'ts/@next/components/hero'; +import { ModalContact } from 'ts/@next/components/modals/modal_contact'; +import { Section } from 'ts/@next/components/newLayout'; +import { SiteWrap } from 'ts/@next/components/siteWrap'; + +const offersData = [ + { + icon: 'supportForAllEthereumStandards', + title: 'Comprehensive Tutorials', + description: + 'Stay on the bleeding edge of crypto by learning how to market make on decentralized exchanges. The network of 0x relayers provides market makers a first-mover advantage to capture larger spreads, arbitrage markets, and access a long-tail of new tokens not currently listed on centralized exchanges.', + }, + { + icon: 'generateRevenueForYourBusiness-large', + title: 'Market Making Compensation', + description: ( + <ul> + <li>Receive an infrastructure grant of $20,000+ for completing onboarding*</li> + <li>Earn an additional $5,000 by referring other market makers to the Program*</li> + </ul> + ), + }, + { + icon: 'getInTouch', + title: 'Personalized Support', + description: + 'The 0x MM Success Manager will walk you through how to read 0x order types, spin up an Ethereum node, set up your MM bot, and execute trades on the blockchain. We are more than happy to promptly answer your questions and give you complete onboarding assistance.', + }, +]; + +export class NextMarketMaker extends React.Component { + public state = { + isContactModalOpen: false, + }; + public render(): React.ReactNode { + return ( + <SiteWrap theme="light"> + <Hero + maxWidth="865px" + maxWidthHeading="715px" + isLargeTitle={false} + isFullWidth={false} + isCenteredMobile={false} + title="Bring liquidity to the exchanges of the future" + description="Market makers (MMs) are important stakeholders in the 0x ecosystem. The Market Making Program provides a set of resources that help onboard MMs bring liquidity to the 0x network. The program includes tutorials, a robust data platform, trade compensation, and 1:1 support from our MM Success Manager." + actions={<HeroActions />} + /> + + <Section bgColor="light" isFlex={true} maxWidth="1170px"> + <Definition + title="Secure" + titleSize="small" + description="Take full custody of your assets to eliminate counterparty risk" + icon="secureTrading" + iconSize="medium" + isInline={true} + /> + + <Definition + title="Networked Liquidity Pool" + titleSize="small" + description="Use one pool of capital across multiple relayers to trade against a large group of takers" + icon="networkedLiquidity" + iconSize="medium" + isInline={true} + /> + + <Definition + title="Low Cost" + titleSize="small" + description="Pay no fees on orders except for bulk cancellations" + icon="low-cost" + iconSize="medium" + isInline={true} + /> + </Section> + + <Section> + {_.map(offersData, (item, index) => ( + <Definition + key={`offers-${index}`} + icon={item.icon} + title={item.title} + description={item.description} + isInlineIcon={true} + iconSize={240} + fontSize="medium" + /> + ))} + </Section> + + <Banner + heading="Need more flexibility?" + subline="Dive into our docs, or contact us if needed" + mainCta={{ text: 'Explore the Docs', href: '/docs' }} + secondaryCta={{ text: 'Get in Touch', onClick: this._onOpenContactModal.bind(this) }} + /> + <ModalContact isOpen={this.state.isContactModalOpen} onDismiss={this._onDismissContactModal} /> + </SiteWrap> + ); + } + + public _onOpenContactModal = (): void => { + this.setState({ isContactModalOpen: true }); + }; + + public _onDismissContactModal = (): void => { + this.setState({ isContactModalOpen: false }); + }; +} + +const HeroActions = () => ( + <> + <Button href="https://github.com/0xProject/0x-launch-kit" bgColor="dark" isInline={true}> + Get Started + </Button> + </> +); diff --git a/packages/website/ts/@next/pages/why.tsx b/packages/website/ts/@next/pages/why.tsx new file mode 100644 index 000000000..cdf7960c2 --- /dev/null +++ b/packages/website/ts/@next/pages/why.tsx @@ -0,0 +1,309 @@ +import * as _ from 'lodash'; +import * as React from 'react'; +import DocumentTitle from 'react-document-title'; +import ScrollableAnchor, { configureAnchors } from 'react-scrollable-anchor'; +import styled from 'styled-components'; + +import { Banner } from 'ts/@next/components/banner'; +import { Button } from 'ts/@next/components/button'; +import { Definition } from 'ts/@next/components/definition'; +import { Hero } from 'ts/@next/components/hero'; +import { Column, Section, WrapSticky } from 'ts/@next/components/newLayout'; +import { SiteWrap } from 'ts/@next/components/siteWrap'; +import { Slide, Slider } from 'ts/@next/components/slider/slider'; +import { Heading } from 'ts/@next/components/text'; + +import { ModalContact } from '../components/modals/modal_contact'; + +const offersData = [ + { + icon: 'robustSmartContracts', + title: 'Robust Smart Contracts', + description: `0x Protocol's smart contracts have been put through two rounds of rigorous security audits.`, + }, + { + icon: 'extensibleArchitecture', + title: 'Extensible Architecture', + description: `0x's modular pipeline enables you to plug in your own smart contracts through an extensible API.`, + }, + { + icon: 'eficientDesign', + title: 'Efficient Design', + description: `0x’s off-chain order relay with on-chain settlement is a gas efficient approach to p2p exchange, reducing blockchain bloat.`, + }, +]; + +const functionalityData = [ + { + icon: 'secureTrading', + title: 'Secure Non-custodial Trading', + description: 'Enable tokens to be traded wallet-to-wallet with no deposits or withdrawals.', + }, + { + icon: 'flexibleOrders', + title: 'Flexible Order Types', + description: 'Choose to sell assets at a specific “buy it now” price or allow potential buyers to submit bids.', + }, + { + icon: 'buildBusiness', + title: 'Build a Business', + description: + 'Monetize your product by taking fees on each transaction and join a growing number of relayers in the 0x ecosystem.', + }, +]; + +const useCaseSlides = [ + { + icon: 'gamingAndCollectibles', + title: 'Games & Collectibles', + description: + 'Artists and game makers are tokenizing digital art and in-game items known as non-fungible tokens (NFTs). 0x enables these creators to add exchange functionality by providing the ability to build marketplaces for NFT trading.', + }, + { + icon: 'predictionMarkets', + title: 'Prediction Markets', + description: + 'Decentralized prediction markets and cryptodervivative platforms generate sets of tokens that represent a financial stake in the outcomes of events. 0x allows these tokens to be instantly tradable in liquid markets.', + }, + { + icon: 'orderBooks', + title: 'Order Books', + description: + 'There are thousands of decentralized apps and protocols that have native utility tokens. 0x provides professional exchanges with the ability to host order books and facilitates the exchange of these assets.', + }, + { + icon: 'decentralisedLoans', + title: 'Decentralized Loans', + description: + 'Efficient lending requires liquid markets where investors can buy and re-sell loans. 0x enables an ecosystem of lenders to self-organize and efficiently determine market prices for all outstanding loans.', + }, + { + icon: 'stableTokens', + title: 'Stable Tokens', + description: + 'Novel economic constructs such as stable coins require efficient, liquid markets to succeed. 0x will facilitate the underlying economic mechanisms that allow these tokens to remain stable.', + }, +]; + +configureAnchors({ offset: -60 }); + +export class NextWhy extends React.Component { + public state = { + isContactModalOpen: false, + }; + public render(): React.ReactNode { + const buildAction = ( + <Button href="/docs" isWithArrow={true} isAccentColor={true}> + Build on 0x + </Button> + ); + return ( + <SiteWrap theme="dark"> + <DocumentTitle title="Features & Benefits - 0x" /> + <Hero + title="The exchange layer for the crypto economy" + description="The world's assets are becoming tokenized on public blockchains. 0x Protocol is free, open-source infrastracture that developers and businesses utilize to build products that enable the purchasing and trading of crypto tokens." + actions={buildAction} + /> + + <Section bgColor="dark" isFlex={true} maxWidth="1170px"> + <Definition + title="Support for all Ethereum Standards" + titleSize="small" + description="0x Protocol facitilites the decentralized exchange of a growing number of Ethereum-based tokens, including all ERC-20 and ERC-721 assets." + icon="supportForAllEthereumStandards" + iconSize="large" + isInline={true} + /> + + <Definition + title="Networked Liquidity" + titleSize="small" + description="0x is lowering the barrier to entry by building a layer of networked liquidity that allows businesses to tap into a shared pool of digital assets." + icon="networkedLiquidity" + iconSize="large" + isInline={true} + /> + + <Definition + title="Flexible Integration" + titleSize="small" + description="0x is a modular system that enables businesses and projects, known as relayers, to easily add exchange functionality to any product experience." + icon="flexibleIntegration" + iconSize="large" + isInline={true} + /> + </Section> + + <Section maxWidth="1170px" isFlex={true} isFullWidth={true}> + <Column> + <NavStickyWrap offsetTop="130px"> + <ChapterLink href="#benefits">Benefits</ChapterLink> + <ChapterLink href="#cases">Use Cases</ChapterLink> + <ChapterLink href="#functionality">Features</ChapterLink> + </NavStickyWrap> + </Column> + + <Column width="55%" maxWidth="826px"> + <Column width="100%" maxWidth="560px" padding="0 30px 0 0"> + <ScrollableAnchor id="benefits"> + <SectionWrap> + <SectionTitle size="medium" marginBottom="60px" isNoBorder={true}> + What 0x offers + </SectionTitle> + + {_.map(offersData, (item, index) => ( + <Definition + key={`offers-${index}`} + icon={item.icon} + title={item.title} + titleSize="small" + description={item.description} + isWithMargin={true} + /> + ))} + </SectionWrap> + </ScrollableAnchor> + + <ScrollableAnchor id="cases"> + <SectionWrap isNotRelative={true}> + <SectionTitle size="medium" marginBottom="60px"> + Use Cases + </SectionTitle> + <Slider> + {_.map(useCaseSlides, (item, index) => ( + <Slide + key={`useCaseSlide-${index}`} + heading={item.title} + text={item.description} + icon={item.icon} + /> + ))} + </Slider> + </SectionWrap> + </ScrollableAnchor> + + <ScrollableAnchor id="functionality"> + <SectionWrap> + <SectionTitle size="medium" marginBottom="60px"> + Exchange Functionality + </SectionTitle> + + {_.map(functionalityData, (item, index) => ( + <Definition + key={`functionality-${index}`} + icon={item.icon} + title={item.title} + titleSize="small" + description={item.description} + isWithMargin={true} + /> + ))} + </SectionWrap> + </ScrollableAnchor> + </Column> + </Column> + </Section> + + <Banner + heading="Ready to get started?" + subline="Dive into our docs, or contact us if needed" + mainCta={{ text: 'Get Started', href: '/docs' }} + secondaryCta={{ text: 'Get in Touch', onClick: this._onOpenContactModal.bind(this) }} + /> + <ModalContact isOpen={this.state.isContactModalOpen} onDismiss={this._onDismissContactModal} /> + </SiteWrap> + ); + } + + public _onOpenContactModal = (): void => { + this.setState({ isContactModalOpen: true }); + }; + + public _onDismissContactModal = (): void => { + this.setState({ isContactModalOpen: false }); + }; +} + +interface SectionProps { + isNotRelative?: boolean; +} + +const SectionWrap = + styled.div < + SectionProps > + ` + position: ${props => !props.isNotRelative && 'relative'}; + + & + & { + padding-top: 60px; + margin-top: 60px; + } + + @media (min-width: 768px) { + & + &:before { + width: 100vw; + } + } + + @media (max-width: 768px) { + text-align: left; + + & + &:before { + width: 100%; + } + } +`; + +interface SectionTitleProps { + isNoBorder?: boolean; +} +const SectionTitle = + styled(Heading) < + SectionTitleProps > + ` + position: relative; + + ${props => + !props.isNoBorder && + ` + &:before { + content: ''; + width: 100vw; + position: absolute; + top: -53px; + left: 0; + height: 1px; + background-color: #3d3d3d; + } + `} + + + @media (max-width: 768px) { + &:before { + width: calc(100vw - 60px); + } + } +`; + +const NavStickyWrap = styled(WrapSticky)` + padding-left: 60px; + z-index: 15; + + @media (max-width: 768px) { + display: none; + } +`; + +const ChapterLink = styled.a` + color: ${props => props.theme.textColor}; + font-size: 22px; + margin-bottom: 25px; + display: block; + opacity: 0.8; + + &:hover, + &:active { + opacity: 1; + } +`; diff --git a/packages/website/ts/components/documentation/sidebar_header.tsx b/packages/website/ts/components/documentation/sidebar_header.tsx index 9ced52c74..0ab24ab5e 100644 --- a/packages/website/ts/components/documentation/sidebar_header.tsx +++ b/packages/website/ts/components/documentation/sidebar_header.tsx @@ -24,7 +24,7 @@ export const SidebarHeader: React.StatelessComponent<SidebarHeaderProps> = ({ return ( <Container> <Container className="flex justify-bottom"> - <Container className="left pl1" width="150px"> + <Container className="col col-7 pl1"> <Text fontColor={colors.lightLinkBlue} fontSize={screenWidth === ScreenWidths.Sm ? '20px' : '22px'} @@ -37,12 +37,14 @@ export const SidebarHeader: React.StatelessComponent<SidebarHeaderProps> = ({ {!_.isUndefined(docsVersion) && !_.isUndefined(availableDocVersions) && !_.isUndefined(onVersionSelected) && ( - <div className="right" style={{ alignSelf: 'flex-end', paddingBottom: 4 }}> - <VersionDropDown - selectedVersion={docsVersion} - versions={availableDocVersions} - onVersionSelected={onVersionSelected} - /> + <div className="col col-5 pl1" style={{ alignSelf: 'flex-end', paddingBottom: 4 }}> + <Container className="right"> + <VersionDropDown + selectedVersion={docsVersion} + versions={availableDocVersions} + onVersionSelected={onVersionSelected} + /> + </Container> </div> )} </Container> diff --git a/packages/website/ts/components/eth_wrappers.tsx b/packages/website/ts/components/eth_wrappers.tsx index 4a9f3b2fe..dc597b18f 100644 --- a/packages/website/ts/components/eth_wrappers.tsx +++ b/packages/website/ts/components/eth_wrappers.tsx @@ -209,7 +209,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt <Divider /> <div className="pt2" style={{ lineHeight: 1.5 }}> The{' '} - <a href="https://blog.0xproject.com/canonical-weth-a9aa7d0279dd" target="_blank"> + <a href={constants.URL_CANONICAL_WETH_POST} target="_blank"> canonical WETH </a>{' '} contract is updated when necessary. Unwrap outdated WETH in order to
retrieve your ETH and move diff --git a/packages/website/ts/components/fill_warning_dialog.tsx b/packages/website/ts/components/fill_warning_dialog.tsx index 430abd013..feb72c2ee 100644 --- a/packages/website/ts/components/fill_warning_dialog.tsx +++ b/packages/website/ts/components/fill_warning_dialog.tsx @@ -35,7 +35,7 @@ export const FillWarningDialog = (props: FillWarningDialogProps) => { <div> At least one of the tokens in this order was not found in the token registry smart contract and may be counterfeit. It is your responsibility to verify the token addresses on Etherscan ( - <a href="https://0xproject.com/wiki#Verifying-Custom-Tokens" target="_blank"> + <a href="https://0x.org/wiki#Verifying-Custom-Tokens" target="_blank"> See this how-to guide </a>) before filling an order. <b>This action may result in the loss of funds</b>. </div> diff --git a/packages/website/ts/components/footer.tsx b/packages/website/ts/components/footer.tsx index 1098d6d0b..6366bf4ea 100644 --- a/packages/website/ts/components/footer.tsx +++ b/packages/website/ts/components/footer.tsx @@ -107,7 +107,7 @@ export class Footer extends React.Component<FooterProps, FooterState> { }, { title: this.props.translate.get(Key.Contact, Deco.Cap), - to: 'mailto:team@0xproject.com', + to: 'mailto:team@0x.org', shouldOpenInNewTab: true, }, ], diff --git a/packages/website/ts/components/onboarding/onboarding_flow.tsx b/packages/website/ts/components/onboarding/onboarding_flow.tsx index 91d5f2476..ec1b5bc42 100644 --- a/packages/website/ts/components/onboarding/onboarding_flow.tsx +++ b/packages/website/ts/components/onboarding/onboarding_flow.tsx @@ -7,8 +7,8 @@ import { OnboardingTooltip, TooltipPointerDisplay, } from 'ts/components/onboarding/onboarding_tooltip'; -import { Animation } from 'ts/components/ui/animation'; import { Container } from 'ts/components/ui/container'; +import { EaseUpFromBottomAnimation } from 'ts/components/ui/ease_up_from_bottom_animation'; import { Overlay } from 'ts/components/ui/overlay'; import { zIndex } from 'ts/style/z_index'; @@ -66,7 +66,7 @@ export class OnboardingFlow extends React.Component<OnboardingFlowProps> { let onboardingElement = null; const currentStep = this._getCurrentStep(); if (this.props.isMobile) { - onboardingElement = <Animation type="easeUpFromBottom">{this._renderOnboardingCard()}</Animation>; + onboardingElement = <EaseUpFromBottomAnimation>{this._renderOnboardingCard()}</EaseUpFromBottomAnimation>; } else if (currentStep.position.type === 'target') { const { placement, target } = currentStep.position; onboardingElement = ( diff --git a/packages/website/ts/components/ui/animation.tsx b/packages/website/ts/components/ui/animation.tsx deleted file mode 100644 index 943e3bf28..000000000 --- a/packages/website/ts/components/ui/animation.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import * as React from 'react'; -import { keyframes, styled } from 'ts/style/theme'; - -export type AnimationType = 'easeUpFromBottom'; - -export interface AnimationProps { - type: AnimationType; -} - -const PlainAnimation: React.StatelessComponent<AnimationProps> = props => <div {...props} />; - -const appearFromBottomFrames = keyframes` - from { - position: fixed; - bottom: -500px; - left: 0px; - right: 0px; - } - - to { - position: fixed; - bottom: 0px; - left: 0px; - right: 0px; - } -`; - -const stylesForAnimation: { [K in AnimationType]: string } = { - // Needed for safari - easeUpFromBottom: `position: fixed`, -}; - -const animations: { [K in AnimationType]: string } = { - easeUpFromBottom: `${appearFromBottomFrames} 1s ease 0s 1 forwards`, -}; - -export const Animation = styled(PlainAnimation)` - animation: ${props => animations[props.type]}; - ${props => stylesForAnimation[props.type]}; -`; - -Animation.displayName = 'Animation'; diff --git a/packages/website/ts/components/ui/container.tsx b/packages/website/ts/components/ui/container.tsx index ae00851e5..778f59f27 100644 --- a/packages/website/ts/components/ui/container.tsx +++ b/packages/website/ts/components/ui/container.tsx @@ -28,6 +28,7 @@ export interface ContainerProps { borderBottomRightRadius?: StringOrNum; borderBottom?: StringOrNum; borderColor?: string; + children?: React.ReactNode; maxWidth?: StringOrNum; maxHeight?: StringOrNum; width?: StringOrNum; diff --git a/packages/website/ts/components/ui/ease_up_from_bottom_animation.tsx b/packages/website/ts/components/ui/ease_up_from_bottom_animation.tsx new file mode 100644 index 000000000..ba141c01e --- /dev/null +++ b/packages/website/ts/components/ui/ease_up_from_bottom_animation.tsx @@ -0,0 +1,31 @@ +import { css, keyframes, styled } from 'ts/style/theme'; + +const appearFromBottomFrames = keyframes` + from { + position: fixed; + bottom: -500px; + left: 0px; + right: 0px; + } + + to { + position: fixed; + bottom: 0px; + left: 0px; + right: 0px; + } +`; + +const stylesForAnimation = css` + position: fixed; +`; +const animations = css` + animation: ${appearFromBottomFrames} 1s ease 0s 1 forwards; +`; + +export const EaseUpFromBottomAnimation = styled.div` + ${props => animations}; + ${props => stylesForAnimation}; +`; + +EaseUpFromBottomAnimation.displayName = 'EaseUpFromBottomAnimation'; diff --git a/packages/website/ts/components/ui/select.tsx b/packages/website/ts/components/ui/select.tsx deleted file mode 100644 index e4fb50f59..000000000 --- a/packages/website/ts/components/ui/select.tsx +++ /dev/null @@ -1,170 +0,0 @@ -import { colors } from '@0x/react-shared'; -import * as _ from 'lodash'; -import * as React from 'react'; - -import { zIndex } from 'ts/style/z_index'; - -import { Container } from './container'; -import { Overlay } from './overlay'; -import { Text } from './text'; - -export interface SelectItemConfig { - text: string; - onClick?: () => void; -} - -export interface SelectProps { - value: string; - label?: string; - items: SelectItemConfig[]; - onOpen?: () => void; - border?: string; - fontSize?: string; - iconSize?: number; - textColor?: string; - labelColor?: string; - backgroundColor?: string; -} - -export interface SelectState { - isOpen: boolean; -} - -export class Select extends React.Component<SelectProps, SelectState> { - public static defaultProps = { - items: [] as SelectItemConfig[], - textColor: colors.black, - backgroundColor: colors.white, - fontSize: '16px', - iconSize: 25, - }; - public state: SelectState = { - isOpen: false, - }; - public render(): React.ReactNode { - const { value, label, items, border, textColor, labelColor, backgroundColor, fontSize, iconSize } = this.props; - const { isOpen } = this.state; - const hasItems = !_.isEmpty(items); - const borderRadius = isOpen ? '4px 4px 0px 0px' : '4px'; - return ( - <React.Fragment> - {isOpen && ( - <Overlay - style={{ - zIndex: zIndex.overlay, - backgroundColor: 'rgba(255, 255, 255, 0)', - }} - onClick={this._closeDropdown} - /> - )} - <Container position="relative"> - <Container - cursor={hasItems ? 'pointer' : undefined} - onClick={this._handleDropdownClick} - borderRadius={borderRadius} - hasBoxShadow={isOpen} - border={border} - backgroundColor={backgroundColor} - padding="0.5em 0.8em" - width="100%" - > - <Container className="flex justify-between"> - <Text fontSize={fontSize} fontColor={textColor}> - {value} - </Text> - <Container> - {label && ( - <Text fontSize={fontSize} fontColor={labelColor}> - {label} - </Text> - )} - {hasItems && ( - <Container marginLeft="5px" display="inline-block"> - <i - className="zmdi zmdi-chevron-down" - style={{ fontSize: iconSize, color: colors.darkGrey }} - /> - </Container> - )} - </Container> - </Container> - </Container> - {isOpen && ( - <Container - width="100%" - position="absolute" - onClick={this._closeDropdown} - zIndex={zIndex.aboveOverlay} - hasBoxShadow={true} - > - {_.map(items, (item, index) => ( - <SelectItem - key={item.text} - {...item} - isLast={index === items.length - 1} - backgroundColor={backgroundColor} - textColor={textColor} - border={border} - /> - ))} - </Container> - )} - </Container> - </React.Fragment> - ); - } - private readonly _handleDropdownClick = (): void => { - if (_.isEmpty(this.props.items)) { - return; - } - const isOpen = !this.state.isOpen; - this.setState({ - isOpen, - }); - - if (isOpen && this.props.onOpen) { - this.props.onOpen(); - } - }; - private readonly _closeDropdown = (): void => { - this.setState({ - isOpen: false, - }); - }; -} - -export interface SelectItemProps extends SelectItemConfig { - text: string; - onClick?: () => void; - isLast: boolean; - backgroundColor?: string; - border?: string; - textColor?: string; - fontSize?: string; -} - -export const SelectItem: React.StatelessComponent<SelectItemProps> = ({ - text, - onClick, - isLast, - border, - backgroundColor, - textColor, - fontSize, -}) => ( - <Container - onClick={onClick} - cursor="pointer" - backgroundColor={backgroundColor} - padding="0.8em" - borderTop="0" - border={border} - shouldDarkenOnHover={true} - borderRadius={isLast ? '0px 0px 4px 4px' : undefined} - width="100%" - > - <Text fontSize={fontSize} fontColor={textColor}> - {text} - </Text> - </Container> -); diff --git a/packages/website/ts/components/ui/text.tsx b/packages/website/ts/components/ui/text.tsx index 87239a021..046442ee5 100644 --- a/packages/website/ts/components/ui/text.tsx +++ b/packages/website/ts/components/ui/text.tsx @@ -7,6 +7,7 @@ export type TextTag = 'p' | 'div' | 'span' | 'label' | 'h1' | 'h2' | 'h3' | 'h4' export interface TextProps { className?: string; + children?: any; Tag?: TextTag; fontSize?: string; fontFamily?: string; diff --git a/packages/website/ts/containers/instant.ts b/packages/website/ts/containers/instant.ts deleted file mode 100644 index 12ae7454e..000000000 --- a/packages/website/ts/containers/instant.ts +++ /dev/null @@ -1,30 +0,0 @@ -import * as React from 'react'; -import { connect } from 'react-redux'; -import { Dispatch } from 'redux'; -import { Instant as InstantComponent, InstantProps } from 'ts/pages/instant/instant'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { State } from 'ts/redux/reducer'; -import { ScreenWidths } from 'ts/types'; -import { Translate } from 'ts/utils/translate'; - -interface ConnectedState { - translate: Translate; - screenWidth: ScreenWidths; -} - -interface ConnectedDispatch { - dispatcher: Dispatcher; -} - -const mapStateToProps = (state: State, _ownProps: InstantProps): ConnectedState => ({ - translate: state.translate, - screenWidth: state.screenWidth, -}); - -const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({ - dispatcher: new Dispatcher(dispatch), -}); - -export const Instant: React.ComponentClass<InstantProps> = connect(mapStateToProps, mapDispatchToProps)( - InstantComponent, -); diff --git a/packages/website/ts/containers/order_watcher_documentation.ts b/packages/website/ts/containers/order_watcher_documentation.ts index ac92e6a22..683e1fe9f 100644 --- a/packages/website/ts/containers/order_watcher_documentation.ts +++ b/packages/website/ts/containers/order_watcher_documentation.ts @@ -24,7 +24,7 @@ const docsInfoConfig: DocsInfoConfig = { id: DocPackages.OrderWatcher, packageName: '@0x/order-watcher', type: SupportedDocJson.TypeDoc, - displayName: 'OrderWatcher', + displayName: 'Order Watcher', packageUrl: 'https://github.com/0xProject/0x-monorepo', markdownMenu: { 'getting-started': [markdownSections.introduction, markdownSections.installation], diff --git a/packages/website/ts/globals.d.ts b/packages/website/ts/globals.d.ts index eb8892aea..05f3c7f88 100644 --- a/packages/website/ts/globals.d.ts +++ b/packages/website/ts/globals.d.ts @@ -1,8 +1,15 @@ +declare module '@reach/dialog'; declare module 'truffle-contract'; declare module 'whatwg-fetch'; declare module 'thenby'; declare module 'react-document-title'; declare module 'react-ga'; +declare module 'reach__dialog'; +declare module 'react-flickity-component'; +declare module 'react-anchor-link-smooth-scroll'; +declare module 'react-responsive'; +declare module 'react-scrollable-anchor'; +declare module 'react-headroom'; declare module '*.json' { const json: any; @@ -10,6 +17,12 @@ declare module '*.json' { export default json; /* tslint:enable */ } + +declare module '*.svg' { + import { PureComponent, SVGProps } from 'react'; + export default class extends PureComponent<SVGProps<SVGSVGElement>> {} +} + declare module 'web3-provider-engine/subproviders/filters'; // This will be defined by default in TS 2.4 diff --git a/packages/website/ts/index.tsx b/packages/website/ts/index.tsx index 050c201a3..3f0c1c28c 100644 --- a/packages/website/ts/index.tsx +++ b/packages/website/ts/index.tsx @@ -4,13 +4,8 @@ import { render } from 'react-dom'; import { Provider } from 'react-redux'; import { BrowserRouter as Router, Redirect, Route, Switch } from 'react-router-dom'; import { MetaTags } from 'ts/components/meta_tags'; -import { About } from 'ts/containers/about'; import { DocsHome } from 'ts/containers/docs_home'; import { FAQ } from 'ts/containers/faq'; -import { Instant } from 'ts/containers/instant'; -import { Jobs } from 'ts/containers/jobs'; -import { Landing } from 'ts/containers/landing'; -import { LaunchKit } from 'ts/containers/launch_kit'; import { NotFound } from 'ts/containers/not_found'; import { Wiki } from 'ts/containers/wiki'; import { createLazyComponent } from 'ts/lazy_component'; @@ -20,6 +15,17 @@ import { store } from 'ts/redux/store'; import { WebsiteLegacyPaths, WebsitePaths } from 'ts/types'; import { muiTheme } from 'ts/utils/mui_theme'; +// Next (new website) routes. We should rename them later +import { NextAboutJobs } from 'ts/@next/pages/about/jobs'; +import { NextAboutMission } from 'ts/@next/pages/about/mission'; +import { NextAboutPress } from 'ts/@next/pages/about/press'; +import { NextAboutTeam } from 'ts/@next/pages/about/team'; +import { NextEcosystem } from 'ts/@next/pages/ecosystem'; +import { Next0xInstant } from 'ts/@next/pages/instant'; +import { NextLanding } from 'ts/@next/pages/landing'; +import { NextLaunchKit } from 'ts/@next/pages/launch_kit'; +import { NextWhy } from 'ts/@next/pages/why'; + // Check if we've introduced an update that requires us to clear the tradeHistory local storage entries tradeHistoryStorage.clearIfRequired(); trackedTokenStorage.clearIfRequired(); @@ -90,15 +96,29 @@ render( <Provider store={store}> <div> <Switch> - <Route exact={true} path="/" component={Landing as any} /> + {/* Next (new site) routes */} + <Route exact={true} path="/" component={NextLanding as any} /> + <Route exact={true} path={WebsitePaths.Why} component={NextWhy as any} /> + <Route exact={true} path={WebsitePaths.Instant} component={Next0xInstant as any} /> + <Route exact={true} path={WebsitePaths.LaunchKit} component={NextLaunchKit as any} /> + <Route exact={true} path={WebsitePaths.Ecosystem} component={NextEcosystem as any} /> + <Route + exact={true} + path={WebsitePaths.AboutMission} + component={NextAboutMission as any} + /> + <Route exact={true} path={WebsitePaths.AboutTeam} component={NextAboutTeam as any} /> + <Route exact={true} path={WebsitePaths.AboutPress} component={NextAboutPress as any} /> + <Route exact={true} path={WebsitePaths.AboutJobs} component={NextAboutJobs as any} /> + {/* + Note(ez): We remove/replace all old routes with next routes + once we're ready to put a ring on it. for now let's keep em there for reference + */} <Redirect from="/otc" to={`${WebsitePaths.Portal}`} /> - <Route path={WebsitePaths.LaunchKit} component={LaunchKit as any} /> - <Route path={WebsitePaths.Instant} component={Instant as any} /> - <Route path={WebsitePaths.Careers} component={Jobs as any} /> <Route path={WebsitePaths.Portal} component={LazyPortal} /> <Route path={WebsitePaths.FAQ} component={FAQ as any} /> - <Route path={WebsitePaths.About} component={About as any} /> <Route path={WebsitePaths.Wiki} component={Wiki as any} /> + <Route path={`${WebsitePaths.ZeroExJs}/:version?`} component={LazyZeroExJSDocumentation} @@ -166,7 +186,8 @@ render( path={`${WebsiteLegacyPaths.Deployer}/:version?`} component={LazySolCompilerDocumentation} /> - <Route path={WebsiteLegacyPaths.Jobs} component={Jobs as any} /> + <Redirect from={WebsiteLegacyPaths.Jobs} to={WebsitePaths.AboutJobs} /> + <Redirect from={WebsitePaths.Careers} to={WebsitePaths.AboutJobs} /> <Route component={NotFound as any} /> </Switch> </div> diff --git a/packages/website/ts/pages/documentation/docs_home.tsx b/packages/website/ts/pages/documentation/docs_home.tsx index 9dc779e96..fd3932bfa 100644 --- a/packages/website/ts/pages/documentation/docs_home.tsx +++ b/packages/website/ts/pages/documentation/docs_home.tsx @@ -58,7 +58,7 @@ const CATEGORY_TO_PACKAGES: ObjectMap<Package[]> = { [Categories.ZeroExProtocol]: [ { description: - 'A library for interacting with the 0x protocol. It is a high level package which combines a number of smaller specific-purpose packages such as [order-utils](https://0xproject.com/docs/order-utils) and [contract-wrappers](https://0xproject.com/docs/contract-wrappers).', + 'A library for interacting with the 0x protocol. It is a high level package which combines a number of smaller specific-purpose packages such as [order-utils](https://0x.org/docs/order-utils) and [contract-wrappers](https://0x.org/docs/contract-wrappers).', link: { title: '0x.js', to: WebsitePaths.ZeroExJs, @@ -100,6 +100,14 @@ const CATEGORY_TO_PACKAGES: ObjectMap<Package[]> = { }, }, { + description: 'A Python Standard Relayer API client', + link: { + title: '0x-sra-client.py', + to: 'https://pypi.org/project/0x-sra-client/', + shouldOpenInNewTab: true, + }, + }, + { description: 'An http & websocket client for interacting with relayers that have implemented the [Standard Relayer API](https://github.com/0xProject/standard-relayer-api)', link: { diff --git a/packages/website/ts/pages/instant/action_link.tsx b/packages/website/ts/pages/instant/action_link.tsx deleted file mode 100644 index c196f03ef..000000000 --- a/packages/website/ts/pages/instant/action_link.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; - -import { Container } from 'ts/components/ui/container'; -import { Text } from 'ts/components/ui/text'; -import { colors } from 'ts/style/colors'; -import { utils } from 'ts/utils/utils'; - -export interface ActionLinkProps { - displayText: string; - linkSrc?: string; - onClick?: () => void; - fontSize?: number; - color?: string; - className?: string; -} - -export class ActionLink extends React.Component<ActionLinkProps> { - public static defaultProps = { - fontSize: 16, - color: colors.white, - }; - public render(): React.ReactNode { - const { displayText, fontSize, color, className } = this.props; - return ( - <Container className={`flex items-center ${className}`} onClick={this._handleClick} cursor="pointer"> - <Container> - <Text fontSize="16px" fontColor={color}> - {displayText} - </Text> - </Container> - <Container paddingTop="1px" paddingLeft="6px"> - <i className="zmdi zmdi-chevron-right bold" style={{ fontSize, color }} /> - </Container> - </Container> - ); - } - - private readonly _handleClick = (event: React.MouseEvent<HTMLElement>) => { - if (!_.isUndefined(this.props.onClick)) { - this.props.onClick(); - } else if (!_.isUndefined(this.props.linkSrc)) { - utils.openUrl(this.props.linkSrc); - } - }; -} diff --git a/packages/website/ts/pages/instant/features.tsx b/packages/website/ts/pages/instant/features.tsx deleted file mode 100644 index ed98ceb53..000000000 --- a/packages/website/ts/pages/instant/features.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; - -import { Container } from 'ts/components/ui/container'; -import { Image } from 'ts/components/ui/image'; -import { Text } from 'ts/components/ui/text'; -import { ActionLink, ActionLinkProps } from 'ts/pages/instant/action_link'; -import { colors } from 'ts/style/colors'; -import { ScreenWidths, WebsitePaths } from 'ts/types'; - -export interface FeatureProps { - screenWidth: ScreenWidths; - onGetStartedClick: () => void; -} - -export const Features = (props: FeatureProps) => { - const isSmallScreen = props.screenWidth === ScreenWidths.Sm; - const getStartedLinkInfo = { - displayText: 'Get started', - onClick: props.onGetStartedClick, - }; - const exploreTheDocsLinkInfo = { - displayText: 'Explore the docs', - linkSrc: `${WebsitePaths.Wiki}#Get-Started-With-Instant`, - }; - const tokenLinkInfos = isSmallScreen ? [getStartedLinkInfo] : [getStartedLinkInfo, exploreTheDocsLinkInfo]; - return ( - <Container backgroundColor={colors.instantSecondaryBackground} className="py3 flex flex-column px3"> - <FeatureItem - imgSrc="images/instant/feature_1.svg" - title="Support ERC-20 and ERC-721 tokens" - description="Seamlessly integrate token purchasing into your product experience by offering digital assets ranging from in-game items to stablecoins." - linkInfos={tokenLinkInfos} - screenWidth={props.screenWidth} - /> - <FeatureItem - imgSrc="images/instant/feature_2.svg" - title="Generate revenue for your business" - description="With just a few lines of code, you can earn up to 5% in affiliate fees on every transaction from your crypto wallet or dApp." - linkInfos={[ - { - displayText: 'Learn about affiliate fees', - linkSrc: `${WebsitePaths.Wiki}#Learn-About-Affiliate-Fees`, - }, - ]} - screenWidth={props.screenWidth} - /> - <FeatureItem - imgSrc="images/instant/feature_3.svg" - title="Easy and Flexible Integration" - description="Use our out-of-the-box design or customize the user interface by integrating the AssetBuyer engine. You can also tap into 0x networked liquidity or choose your own liquidity pool." - linkInfos={[ - { - displayText: 'Explore AssetBuyer', - linkSrc: `${WebsitePaths.Docs}/asset-buyer`, - }, - ]} - screenWidth={props.screenWidth} - /> - </Container> - ); -}; - -interface FeatureItemProps { - imgSrc: string; - title: string; - description: string; - linkInfos: ActionLinkProps[]; - screenWidth: ScreenWidths; -} - -const FeatureItem = (props: FeatureItemProps) => { - const { imgSrc, title, description, linkInfos, screenWidth } = props; - const isLargeScreen = screenWidth === ScreenWidths.Lg; - const maxWidth = isLargeScreen ? '500px' : undefined; - const image = ( - <Container className="center" minWidth="435px" maxHeight="225px"> - <Image src={imgSrc} additionalStyle={{ filter: 'drop-shadow(0px 4px 4px rgba(0,0,0,.25))' }} /> - </Container> - ); - const info = ( - <Container maxWidth={maxWidth}> - <Text fontSize="24px" lineHeight="34px" fontColor={colors.white} fontWeight={500}> - {title} - </Text> - <Container marginTop="28px"> - <Text fontFamily="Roboto Mono" fontSize="14px" lineHeight="2em" fontColor={colors.grey500}> - {description} - </Text> - </Container> - <Container className="flex" marginTop="28px"> - {_.map(linkInfos, linkInfo => ( - <Container key={linkInfo.displayText} marginRight="32px"> - <ActionLink {...linkInfo} /> - </Container> - ))} - </Container> - </Container> - ); - return ( - <Container className="flex flex-column items-center py4 px3"> - {isLargeScreen ? ( - <Container className="flex"> - {image} - <Container marginLeft="115px">{info}</Container> - </Container> - ) : ( - <Container className="flex flex-column items-center" width="100%"> - {image} - <Container marginTop="48px">{info}</Container> - </Container> - )} - </Container> - ); -}; diff --git a/packages/website/ts/pages/instant/instant.tsx b/packages/website/ts/pages/instant/instant.tsx deleted file mode 100644 index d72585bfa..000000000 --- a/packages/website/ts/pages/instant/instant.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import { utils as sharedUtils } from '@0x/react-shared'; -import * as _ from 'lodash'; -import * as React from 'react'; -import * as DocumentTitle from 'react-document-title'; - -import { Footer } from 'ts/components/footer'; -import { MetaTags } from 'ts/components/meta_tags'; -import { TopBar } from 'ts/components/top_bar/top_bar'; -import { Container } from 'ts/components/ui/container'; -import { Configurator } from 'ts/pages/instant/configurator'; -import { Features } from 'ts/pages/instant/features'; -import { Introducing0xInstant } from 'ts/pages/instant/introducing_0x_instant'; -import { NeedMore } from 'ts/pages/instant/need_more'; -import { Screenshots } from 'ts/pages/instant/screenshots'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { colors } from 'ts/style/colors'; -import { ScreenWidths, WebsitePaths } from 'ts/types'; -import { Translate } from 'ts/utils/translate'; -import { utils } from 'ts/utils/utils'; - -export interface InstantProps { - location: Location; - translate: Translate; - dispatcher: Dispatcher; - screenWidth: ScreenWidths; -} - -export interface InstantState {} - -const CONFIGURATOR_HASH = 'configure'; -const THROTTLE_TIMEOUT = 100; -const DOCUMENT_TITLE = '0x Instant'; -const DOCUMENT_DESCRIPTION = '0x Instant'; - -export class Instant extends React.Component<InstantProps, InstantState> { - // TODO: consolidate this small screen scaffolding into one place (its being used in portal and docs as well) - private readonly _throttledScreenWidthUpdate: () => void; - public constructor(props: InstantProps) { - super(props); - this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT); - } - public componentDidMount(): void { - window.addEventListener('resize', this._throttledScreenWidthUpdate); - window.scrollTo(0, 0); - } - public render(): React.ReactNode { - return ( - <Container overflowX="hidden"> - <MetaTags title={DOCUMENT_TITLE} description={DOCUMENT_DESCRIPTION} /> - <DocumentTitle title={DOCUMENT_TITLE} /> - <TopBar - blockchainIsLoaded={false} - location={this.props.location} - style={{ backgroundColor: colors.instantPrimaryBackground, position: 'relative' }} - translate={this.props.translate} - isNightVersion={true} - /> - <Container backgroundColor={colors.instantPrimaryBackground} /> - <Introducing0xInstant screenWidth={this.props.screenWidth} onCTAClick={this._onGetStartedClick} /> - <Screenshots screenWidth={this.props.screenWidth} /> - <Features screenWidth={this.props.screenWidth} onGetStartedClick={this._onGetStartedClick} /> - {!this._isSmallScreen() && <Configurator hash={CONFIGURATOR_HASH} />} - <NeedMore screenWidth={this.props.screenWidth} /> - <Footer translate={this.props.translate} dispatcher={this.props.dispatcher} /> - </Container> - ); - } - private readonly _onGetStartedClick = () => { - if (this._isSmallScreen()) { - utils.openUrl(`${WebsitePaths.Wiki}#Get-Started-With-Instant`); - } else { - this._scrollToConfigurator(); - } - }; - private _isSmallScreen(): boolean { - const isSmallScreen = this.props.screenWidth === ScreenWidths.Sm; - return isSmallScreen; - } - private _scrollToConfigurator(): void { - sharedUtils.setUrlHash(CONFIGURATOR_HASH); - sharedUtils.scrollToHash(CONFIGURATOR_HASH, ''); - } - private _updateScreenWidth(): void { - const newScreenWidth = utils.getScreenWidth(); - this.props.dispatcher.updateScreenWidth(newScreenWidth); - } -} diff --git a/packages/website/ts/style/colors.ts b/packages/website/ts/style/colors.ts index f89dfc86e..356d72f7e 100644 --- a/packages/website/ts/style/colors.ts +++ b/packages/website/ts/style/colors.ts @@ -13,6 +13,14 @@ const appColors = { jobsPageOpenPositionRow: sharedColors.grey100, metaMaskOrange: '#f68c24', metaMaskTransparentOrange: 'rgba(255, 248, 242, 0.8)', + brandLight: '#00AE99', + brandDark: '#003831', + backgroundDark: '#111A19', + backgroundBlack: '#000000', + backgroundLight: '#F3F6F4', + textDarkPrimary: '#000000', + textDarkSecondary: '#5C5C5C', + white: '#fff', instantPrimaryBackground: '#222222', instantSecondaryBackground: '#333333', instantTertiaryBackground: '#444444', diff --git a/packages/website/ts/style/theme.ts b/packages/website/ts/style/theme.ts index ce7d6975d..94bd0169a 100644 --- a/packages/website/ts/style/theme.ts +++ b/packages/website/ts/style/theme.ts @@ -4,7 +4,7 @@ import * as styledComponents from 'styled-components'; const { default: styled, css, - injectGlobal, + createGlobalStyle, keyframes, ThemeProvider, } = styledComponents as styledComponents.ThemedStyledComponentsModule<IThemeInterface>; @@ -14,4 +14,4 @@ export interface IThemeInterface {} export const theme = {}; -export { styled, css, injectGlobal, keyframes, ThemeProvider }; +export { styled, css, createGlobalStyle, keyframes, ThemeProvider }; diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts index 2967fdac5..37bd73063 100644 --- a/packages/website/ts/types.ts +++ b/packages/website/ts/types.ts @@ -352,8 +352,16 @@ export enum WebsitePaths { Home = '/', FAQ = '/faq', About = '/about', + AboutMission = '/about/mission', + AboutTeam = '/about/team', + AboutPress = '/about/press', + AboutJobs = '/about/jobs', + Community = '/community', LaunchKit = '/launch-kit', Instant = '/instant', + Ecosystem = '/eap', + MarketMaker = '/market-maker', + Why = '/why', Whitepaper = '/pdfs/0x_white_paper.pdf', SmartContracts = '/docs/contracts', Connect = '/docs/connect', diff --git a/packages/website/ts/utils/configs.ts b/packages/website/ts/utils/configs.ts index 7b74eccfb..663f90249 100644 --- a/packages/website/ts/utils/configs.ts +++ b/packages/website/ts/utils/configs.ts @@ -13,9 +13,9 @@ export const configs = { // WARNING: ZRX & WETH MUST always be default trackedTokens DEFAULT_TRACKED_TOKEN_SYMBOLS: ['WETH', 'ZRX'], DOMAIN_STAGING: 'staging-0xproject.s3-website-us-east-1.amazonaws.com', - DOMAIN_DOGFOOD: 'dogfood.0xproject.com', + DOMAIN_DOGFOOD: 'dogfood.0x.org', DOMAINS_DEVELOPMENT: ['0xproject.localhost:3572', 'localhost:3572', '127.0.0.1'], - DOMAIN_PRODUCTION: '0xproject.com', + DOMAIN_PRODUCTION: '0x.org', GOOGLE_ANALYTICS_ID: 'UA-98720122-1', LAST_LOCAL_STORAGE_FILL_CLEARANCE_DATE: '2017-11-22', LAST_LOCAL_STORAGE_TRACKED_TOKEN_CLEARANCE_DATE: '2018-9-7', @@ -39,8 +39,8 @@ export const configs = { ] as OutdatedWrappedEtherByNetworkId[], // The order matters. We first try first node and only then fall back to others. PUBLIC_NODE_URLS_BY_NETWORK_ID: { - [1]: [`https://mainnet.infura.io/${INFURA_API_KEY}`, 'https://mainnet.0xproject.com'], - [42]: [`https://kovan.infura.io/${INFURA_API_KEY}`, 'https://kovan.0xproject.com'], + [1]: [`https://mainnet.infura.io/${INFURA_API_KEY}`, 'https://mainnet.0x.org'], + [42]: [`https://kovan.infura.io/${INFURA_API_KEY}`, 'https://kovan.0x.org'], [3]: [`https://ropsten.infura.io/${INFURA_API_KEY}`], [4]: [`https://rinkeby.infura.io/${INFURA_API_KEY}`], } as PublicNodeUrlsByNetworkId, diff --git a/packages/website/ts/utils/constants.ts b/packages/website/ts/utils/constants.ts index 715199515..ada8de549 100644 --- a/packages/website/ts/utils/constants.ts +++ b/packages/website/ts/utils/constants.ts @@ -2,7 +2,7 @@ import { ALink } from '@0x/react-shared'; import { BigNumber } from '@0x/utils'; import { Key, WebsitePaths } from 'ts/types'; -const URL_FORUM = 'https://forum.0xproject.com'; +const URL_FORUM = 'https://forum.0x.org'; const URL_ZEROEX_CHAT = 'https://discord.gg/d3FTX3M'; export const constants = { @@ -47,7 +47,7 @@ export const constants = { TAKER_FEE: new BigNumber(0), TESTNET_NAME: 'Kovan', NUMERAL_USD_FORMAT: '$0,0.00', - EMAIL_JOBS: 'jobs@0xproject.com', + EMAIL_JOBS: 'jobs@0x.org', PROJECT_URL_ETHFINEX: 'https://www.ethfinex.com/', PROJECT_URL_AMADEUS: 'http://amadeusrelay.org', PROJECT_URL_DDEX: 'https://ddex.io', @@ -75,9 +75,11 @@ export const constants = { URL_APACHE_LICENSE: 'http://www.apache.org/licenses/LICENSE-2.0', URL_BITLY_API: 'https://api-ssl.bitly.com', URL_BLOG: 'https://blog.0xproject.com/latest', - URL_DISCOURSE_FORUM: 'https://forum.0xproject.com', + URL_DISCOURSE_FORUM: 'https://forum.0x.org', + URL_ECOSYSTEM_APPLY: 'https://0x.smapply.io/', + URL_ECOSYSTEM_BLOG_POST: 'https://blog.0xproject.com/announcing-the-0x-ecosystem-acceleration-program-89d1cb89d565', URL_FIREFOX_U2F_ADDON: 'https://addons.mozilla.org/en-US/firefox/addon/u2f-support-add-on/', - URL_TESTNET_FAUCET: 'https://faucet.0xproject.com', + URL_TESTNET_FAUCET: 'https://faucet.0x.org', URL_GITHUB_ORG: 'https://github.com/0xProject', URL_GITHUB_WIKI: 'https://github.com/0xProject/wiki', URL_FORUM, @@ -96,7 +98,9 @@ export const constants = { URL_SANDBOX: 'https://codesandbox.io/s/1qmjyp7p5j', URL_STANDARD_RELAYER_API_GITHUB: 'https://github.com/0xProject/standard-relayer-api/blob/master/README.md', URL_TWITTER: 'https://twitter.com/0xproject', + URL_FACEBOOK: 'https://www.facebook.com/0xProject/', URL_WETH_IO: 'https://weth.io/', + URL_CANONICAL_WETH_POST: 'https://blog.0xproject.com/canonical-weth-a9aa7d0279dd', URL_ZEROEX_CHAT, URL_LAUNCH_KIT: 'https://github.com/0xProject/0x-launch-kit', URL_LAUNCH_KIT_BLOG_POST: 'https://blog.0xproject.com/introducing-the-0x-launch-kit-4acdc3453585', diff --git a/packages/website/tsconfig.json b/packages/website/tsconfig.json index 7d5f31b7f..8fbba17bb 100644 --- a/packages/website/tsconfig.json +++ b/packages/website/tsconfig.json @@ -20,5 +20,9 @@ "module": "esnext", "moduleResolution": "node" }, + "awesomeTypescriptLoaderOptions": { + "useCache": true, + "reportFiles": ["./ts/**/*"] + }, "include": ["./ts/**/*"] } diff --git a/packages/website/webpack.config.js b/packages/website/webpack.config.js index 33d5f648b..d9bdd91ad 100644 --- a/packages/website/webpack.config.js +++ b/packages/website/webpack.config.js @@ -3,6 +3,7 @@ const webpack = require('webpack'); const TerserPlugin = require('terser-webpack-plugin'); const RollbarSourceMapPlugin = require('rollbar-sourcemap-webpack-plugin'); const childProcess = require('child_process'); +const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; const GIT_SHA = childProcess .execSync('git rev-parse HEAD') @@ -55,6 +56,21 @@ const config = { test: /\.css$/, loaders: ['style-loader', 'css-loader'], }, + { + test: /\.svg$/, + use: [ + { + loader: "react-svg-loader", + options: { + svgo: { + plugins: [ + { removeViewBox: false } + ], + } + } + } + ] + }, ], }, optimization: { @@ -70,6 +86,7 @@ const config = { ], }, devServer: { + host: '0.0.0.0', port: 3572, historyApiFallback: { // Fixes issue where having dots in URL path that aren't part of fileNames causes webpack-dev-server @@ -85,6 +102,13 @@ const config = { ], }, disableHostCheck: true, + // Fixes assertion error + // Source: https://github.com/webpack/webpack-dev-server/issues/1491 + https: { + spdy: { + protocols: ['http/1.1'] + } + }, }, }; @@ -92,6 +116,9 @@ module.exports = (_env, argv) => { let plugins = []; if (argv.mode === 'development') { config.mode = 'development'; + plugins.concat([ + new BundleAnalyzerPlugin(), + ]); } else { config.mode = 'production'; plugins = plugins.concat([ @@ -109,7 +136,7 @@ module.exports = (_env, argv) => { new RollbarSourceMapPlugin({ accessToken: '32c39bfa4bb6440faedc1612a9c13d28', version: GIT_SHA, - publicPath: 'https://0xproject.com/', + publicPath: 'https://0x.org/', }), ]); } diff --git a/python-packages/sra_client/tox.ini b/python-packages/sra_client/tox.ini index 3d0be613c..69d59f4ff 100644 --- a/python-packages/sra_client/tox.ini +++ b/python-packages/sra_client/tox.ini @@ -8,3 +8,17 @@ deps=-r{toxinidir}/requirements.txt commands= nosetests \ [] + +[testenv:run_tests_against_test_deployment] +commands = + # install dependencies from real PyPI + pip install mypy_extensions pytest + # install package-under-test from test PyPI + pip install --index-url https://test.pypi.org/legacy/ 0x-sra-client + pytest test + +[testenv:run_tests_against_deployment] +deps=pytest +commands = + pip install 0x-sra-client + pytest test @@ -584,6 +584,10 @@ version "0.6.6" resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.6.6.tgz#004b98298d04c7ca3b4f50ca2035d4f60d2eed1b" +"@emotion/unitless@^0.7.0": + version "0.7.3" + resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.3.tgz#6310a047f12d21a1036fb031317219892440416f" + "@ledgerhq/hw-app-eth@^4.3.0": version "4.7.3" resolved "https://registry.yarnpkg.com/@ledgerhq/hw-app-eth/-/hw-app-eth-4.7.3.tgz#d352e19658ae296532e522c53c8ec2a1a77b64e5" @@ -1198,6 +1202,29 @@ call-me-maybe "^1.0.1" glob-to-regexp "^0.3.0" +"@reach/component-component@^0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@reach/component-component/-/component-component-0.1.1.tgz#62ea2ec290da32f5e3a9872fb51f9a3ae4370cc4" + +"@reach/dialog@^0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@reach/dialog/-/dialog-0.1.2.tgz#46a3639c01928e125110fd5ccb753281172e844d" + dependencies: + "@reach/component-component" "^0.1.1" + "@reach/portal" "^0.1.1" + "@reach/utils" "^0.1.2" + focus-trap "^3.0.0" + +"@reach/portal@^0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@reach/portal/-/portal-0.1.1.tgz#94f3f9b999c5a0dfb819309912ec23e36807e70b" + dependencies: + "@reach/component-component" "^0.1.1" + +"@reach/utils@^0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@reach/utils/-/utils-0.1.2.tgz#72f547b5c9b0401a56de303d9e508abf6d3fa56a" + "@samverschueren/stream-to-observable@^0.3.0": version "0.3.0" resolved "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz#ecdf48d532c58ea477acfcab80348424f8d0662f" @@ -1231,6 +1258,10 @@ version "0.4.1" resolved "https://registry.yarnpkg.com/@types/accounting/-/accounting-0.4.1.tgz#865d9f5694fd7c438fba34eb4bc82eec6f34cdd5" +"@types/anymatch@*": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.0.tgz#d1d55958d1fccc5527d4aba29fc9c4b942f563ff" + "@types/axios@^0.14.0": version "0.14.0" resolved "https://registry.yarnpkg.com/@types/axios/-/axios-0.14.0.tgz#ec2300fbe7d7dddd7eb9d3abf87999964cafce46" @@ -1268,6 +1299,14 @@ version "0.22.9" resolved "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.9.tgz#b5990152604c2ada749b7f88cab3476f21f39d7b" +"@types/chokidar@^1.7.5": + version "1.7.5" + resolved "https://registry.yarnpkg.com/@types/chokidar/-/chokidar-1.7.5.tgz#1fa78c8803e035bed6d98e6949e514b133b0c9b6" + integrity sha512-PDkSRY7KltW3M60hSBlerxI8SFPXsO3AL/aRVsO4Kh9IHRW74Ih75gUuTd/aE4LSSFqypb10UIX3QzOJwBQMGQ== + dependencies: + "@types/events" "*" + "@types/node" "*" + "@types/compare-versions@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/compare-versions/-/compare-versions-3.0.0.tgz#4a45dffe0ebbc00d0f2daef8a0e96ffc66cf5955" @@ -1519,6 +1558,11 @@ version "2.0.0" resolved "https://registry.yarnpkg.com/@types/p-limit/-/p-limit-2.0.0.tgz#c076b7daa9163108a35899ea6a9d927526943ea2" +"@types/pluralize@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/pluralize/-/pluralize-0.0.29.tgz#6ffa33ed1fc8813c469b859681d09707eb40d03c" + integrity sha512-BYOID+l2Aco2nBik+iYS4SZX0Lf20KPILP5RGmM1IgzdwNdTs0eebiFriOPcej1sX9mLnSoiNte5zcFxssgpGA== + "@types/prop-types@*": version "15.5.5" resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.5.5.tgz#17038dd322c2325f5da650a94d5f9974943625e3" @@ -1585,6 +1629,19 @@ dependencies: "@types/react" "*" +"@types/react-lazyload@^2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@types/react-lazyload/-/react-lazyload-2.3.1.tgz#6a1814432f668081ff693abfa8e09bff09aa3649" + dependencies: + "@types/react" "*" + +"@types/react-loadable@^5.4.2": + version "5.4.2" + resolved "https://registry.yarnpkg.com/@types/react-loadable/-/react-loadable-5.4.2.tgz#087ead218ee0494c44e41fbdec7477b0ea4b7c86" + dependencies: + "@types/react" "*" + "@types/webpack" "*" + "@types/react-redux@^4.4.37": version "4.4.47" resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-4.4.47.tgz#12af1677116e08d413fe2620d0a85560c8a0536e" @@ -1650,6 +1707,13 @@ "@types/prop-types" "*" csstype "^2.2.0" +"@types/react@^16.7.7": + version "16.7.17" + resolved "https://registry.yarnpkg.com/@types/react/-/react-16.7.17.tgz#3242e796a1ffbba4f49eae5915a67f4c079504e9" + dependencies: + "@types/prop-types" "*" + csstype "^2.2.0" + "@types/redux@^3.6.0": version "3.6.0" resolved "https://registry.yarnpkg.com/@types/redux/-/redux-3.6.0.tgz#f1ebe1e5411518072e4fdfca5c76e16e74c1399a" @@ -1711,10 +1775,28 @@ "@types/node" "*" "@types/react" "*" +"@types/styled-components@^4.1.1": + version "4.1.4" + resolved "https://registry.yarnpkg.com/@types/styled-components/-/styled-components-4.1.4.tgz#c6915ccee4413da2e1e81b4df9d7ea5b97eb56aa" + dependencies: + "@types/node" "*" + "@types/react" "*" + csstype "^2.2.0" + +"@types/tapable@*": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.4.tgz#b4ffc7dc97b498c969b360a41eee247f82616370" + "@types/tmp@^0.0.33": version "0.0.33" resolved "https://registry.yarnpkg.com/@types/tmp/-/tmp-0.0.33.tgz#1073c4bc824754ae3d10cfab88ab0237ba964e4d" +"@types/uglify-js@*": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.0.4.tgz#96beae23df6f561862a830b4288a49e86baac082" + dependencies: + source-map "^0.6.1" + "@types/uuid@^3.4.2", "@types/uuid@^3.4.3": version "3.4.3" resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-3.4.3.tgz#121ace265f5569ce40f4f6d0ff78a338c732a754" @@ -1731,6 +1813,16 @@ dependencies: "@types/ethereum-protocol" "*" +"@types/webpack@*": + version "4.4.21" + resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.4.21.tgz#1a80de6d3e465f35067dd2f4533bf6e04c2e7187" + dependencies: + "@types/anymatch" "*" + "@types/node" "*" + "@types/tapable" "*" + "@types/uglify-js" "*" + source-map "^0.6.0" + "@types/websocket@^0.0.39": version "0.0.39" resolved "https://registry.yarnpkg.com/@types/websocket/-/websocket-0.0.39.tgz#aa971e24f9c1455fe2a57ee3e69c7d395016b12a" @@ -1982,7 +2074,7 @@ acorn@^5.0.0: version "5.5.3" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.3.tgz#f473dd47e0277a08e28e9bec5aeeb04751f0b8c9" -acorn@^5.5.3, acorn@^5.6.2: +acorn@^5.5.3, acorn@^5.6.2, acorn@^5.7.3: version "5.7.3" resolved "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" @@ -2008,6 +2100,10 @@ aes-js@^0.2.3: version "0.2.4" resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-0.2.4.tgz#94b881ab717286d015fa219e08fb66709dda5a3d" +aes-js@^3.1.1: + version "3.1.2" + resolved "https://registry.npmjs.org/aes-js/-/aes-js-3.1.2.tgz#db9aabde85d5caabbfc0d4f2a4446960f627146a" + agent-base@4, agent-base@^4.1.0, agent-base@~4.2.0: version "4.2.1" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" @@ -2563,6 +2659,14 @@ babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: babel-runtime "^6.22.0" babel-types "^6.24.1" +babel-helper-builder-react-jsx@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz#39ff8313b75c8b65dceff1f31d383e0ff2a408a0" + dependencies: + babel-runtime "^6.26.0" + babel-types "^6.26.0" + esutils "^2.0.2" + babel-helper-call-delegate@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" @@ -2688,6 +2792,10 @@ babel-plugin-jest-hoist@^23.2.0: version "23.2.0" resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-23.2.0.tgz#e61fae05a1ca8801aadee57a6d66b8cefaf44167" +babel-plugin-react-svg@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/babel-plugin-react-svg/-/babel-plugin-react-svg-2.1.0.tgz#169eeba1a20fa2dee3a71ff38eedd63d08e69487" + "babel-plugin-styled-components@>= 1": version "1.8.0" resolved "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-1.8.0.tgz#9dd054c8e86825203449a852a5746f29f2dab857" @@ -2703,7 +2811,15 @@ babel-plugin-syntax-exponentiation-operator@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" -babel-plugin-syntax-object-rest-spread@^6.13.0: +babel-plugin-syntax-flow@^6.18.0: + version "6.18.0" + resolved "http://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d" + +babel-plugin-syntax-jsx@^6.18.0, babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0: + version "6.18.0" + resolved "http://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" + +babel-plugin-syntax-object-rest-spread@^6.13.0, babel-plugin-syntax-object-rest-spread@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" @@ -2895,6 +3011,48 @@ babel-plugin-transform-exponentiation-operator@^6.22.0: babel-plugin-syntax-exponentiation-operator "^6.8.0" babel-runtime "^6.22.0" +babel-plugin-transform-flow-strip-types@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz#84cb672935d43714fdc32bce84568d87441cf7cf" + dependencies: + babel-plugin-syntax-flow "^6.18.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-object-rest-spread@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06" + dependencies: + babel-plugin-syntax-object-rest-spread "^6.8.0" + babel-runtime "^6.26.0" + +babel-plugin-transform-react-display-name@^6.23.0: + version "6.25.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.25.0.tgz#67e2bf1f1e9c93ab08db96792e05392bf2cc28d1" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-react-jsx-self@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz#df6d80a9da2612a121e6ddd7558bcbecf06e636e" + dependencies: + babel-plugin-syntax-jsx "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-react-jsx-source@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz#66ac12153f5cd2d17b3c19268f4bf0197f44ecd6" + dependencies: + babel-plugin-syntax-jsx "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-react-jsx@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz#840a028e7df460dfc3a2d29f0c0d91f6376e66a3" + dependencies: + babel-helper-builder-react-jsx "^6.24.1" + babel-plugin-syntax-jsx "^6.8.0" + babel-runtime "^6.22.0" + babel-plugin-transform-regenerator@^6.22.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" @@ -2943,6 +3101,12 @@ babel-preset-env@^1.3.2: invariant "^2.2.2" semver "^5.3.0" +babel-preset-flow@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz#e71218887085ae9a24b5be4169affb599816c49d" + dependencies: + babel-plugin-transform-flow-strip-types "^6.22.0" + babel-preset-jest@^23.2.0: version "23.2.0" resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-23.2.0.tgz#8ec7a03a138f001a1a8fb1e8113652bf1a55da46" @@ -2950,6 +3114,17 @@ babel-preset-jest@^23.2.0: babel-plugin-jest-hoist "^23.2.0" babel-plugin-syntax-object-rest-spread "^6.13.0" +babel-preset-react@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-react/-/babel-preset-react-6.24.1.tgz#ba69dfaea45fc3ec639b6a4ecea6e17702c91380" + dependencies: + babel-plugin-syntax-jsx "^6.3.13" + babel-plugin-transform-react-display-name "^6.23.0" + babel-plugin-transform-react-jsx "^6.24.1" + babel-plugin-transform-react-jsx-self "^6.22.0" + babel-plugin-transform-react-jsx-source "^6.22.0" + babel-preset-flow "^6.23.0" + babel-register@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" @@ -3135,6 +3310,15 @@ beeper@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/beeper/-/beeper-1.1.1.tgz#e6d5ea8c5dad001304a70b22638447f69cb2f809" +bfj@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/bfj/-/bfj-6.1.1.tgz#05a3b7784fbd72cfa3c22e56002ef99336516c48" + dependencies: + bluebird "^3.5.1" + check-types "^7.3.0" + hoopy "^0.1.2" + tryer "^1.0.0" + big.js@^3.1.3: version "3.2.0" resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" @@ -3279,6 +3463,21 @@ body-parser@1.18.2, body-parser@^1.16.0, body-parser@^1.17.1: raw-body "2.3.2" type-is "~1.6.15" +body-parser@1.18.3: + version "1.18.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4" + dependencies: + bytes "3.0.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "~1.6.3" + iconv-lite "0.4.23" + on-finished "~2.3.0" + qs "6.5.2" + raw-body "2.3.3" + type-is "~1.6.16" + bonjour@^3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5" @@ -3470,7 +3669,7 @@ bs-logger@0.x: dependencies: fast-json-stable-stringify "^2.0.0" -bs58@=4.0.1: +bs58@=4.0.1, bs58@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" dependencies: @@ -3493,6 +3692,14 @@ bs58check@^1.0.8: bs58 "^3.1.0" create-hash "^1.1.0" +bs58check@^2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc" + dependencies: + bs58 "^4.0.0" + create-hash "^1.1.0" + safe-buffer "^5.1.2" + bser@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" @@ -3890,6 +4097,10 @@ check-error@^1.0.1, check-error@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" +check-types@^7.3.0: + version "7.4.0" + resolved "https://registry.yarnpkg.com/check-types/-/check-types-7.4.0.tgz#0378ec1b9616ec71f774931a3c6516fad8c152f4" + checkpoint-store@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/checkpoint-store/-/checkpoint-store-1.1.0.tgz#04e4cb516b91433893581e6d4601a78e9552ea06" @@ -3951,6 +4162,26 @@ chokidar@^2.0.0, chokidar@^2.0.2: optionalDependencies: fsevents "^1.1.2" +chokidar@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26" + integrity sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ== + dependencies: + anymatch "^2.0.0" + async-each "^1.0.0" + braces "^2.3.0" + glob-parent "^3.1.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + lodash.debounce "^4.0.8" + normalize-path "^2.1.1" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + upath "^1.0.5" + optionalDependencies: + fsevents "^1.2.2" + chownr@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" @@ -4230,7 +4461,7 @@ commander@2.18.0: version "2.18.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.18.0.tgz#2bf063ddee7c7891176981a2cc798e5754bc6970" -commander@^2.15.1: +commander@^2.15.1, commander@^2.18.0: version "2.19.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" @@ -4761,6 +4992,10 @@ css-loader@0.23.x: postcss-modules-values "^1.1.0" source-list-map "^0.1.4" +css-mediaquery@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/css-mediaquery/-/css-mediaquery-0.1.2.tgz#6a2c37344928618631c54bd33cedd301da18bea0" + css-select@~1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" @@ -5240,6 +5475,10 @@ des.js@^1.0.0: inherits "^2.0.1" minimalistic-assert "^1.0.0" +desandro-matches-selector@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/desandro-matches-selector/-/desandro-matches-selector-2.0.2.tgz#717beed4dc13e7d8f3762f707a6d58a6774218e1" + destroy@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" @@ -5521,6 +5760,10 @@ ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" +ejs@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.6.1.tgz#498ec0d495655abc6f23cd61868d926464071aa0" + electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.30: version "1.3.42" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.42.tgz#95c33bf01d0cc405556aec899fe61fd4d76ea0f9" @@ -6167,6 +6410,19 @@ ethereumjs-wallet@0.6.0: utf8 "^2.1.1" uuid "^2.0.1" +ethereumjs-wallet@~0.6.0: + version "0.6.2" + resolved "https://registry.npmjs.org/ethereumjs-wallet/-/ethereumjs-wallet-0.6.2.tgz#67244b6af3e8113b53d709124b25477b64aeccda" + dependencies: + aes-js "^3.1.1" + bs58check "^2.1.2" + ethereumjs-util "^5.2.0" + hdkey "^1.0.0" + safe-buffer "^5.1.2" + scrypt.js "^0.2.0" + utf8 "^3.0.0" + uuid "^3.3.2" + ethers@~4.0.4: version "4.0.4" resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.4.tgz#d3f85e8b27f4b59537e06526439b0fb15b44dc65" @@ -6212,6 +6468,10 @@ ethjs-util@^0.1.3: is-hex-prefixed "1.0.0" strip-hex-prefix "1.0.0" +ev-emitter@^1.0.0, ev-emitter@^1.0.1, ev-emitter@^1.0.2: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ev-emitter/-/ev-emitter-1.1.1.tgz#8f18b0ce5c76a5d18017f71c0a795c65b9138f2a" + event-stream@~3.3.0: version "3.3.4" resolved "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" @@ -6407,6 +6667,41 @@ express@^4.14.0, express@^4.15.2, express@^4.16.2: utils-merge "1.0.1" vary "~1.1.2" +express@^4.16.3: + version "4.16.4" + resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e" + dependencies: + accepts "~1.3.5" + array-flatten "1.1.1" + body-parser "1.18.3" + content-disposition "0.5.2" + content-type "~1.0.4" + cookie "0.3.1" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.1.1" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.2" + path-to-regexp "0.1.7" + proxy-addr "~2.0.4" + qs "6.5.2" + range-parser "~1.2.0" + safe-buffer "5.1.2" + send "0.16.2" + serve-static "1.13.2" + setprototypeof "1.1.0" + statuses "~1.4.0" + type-is "~1.6.16" + utils-merge "1.0.1" + vary "~1.1.2" + extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" @@ -6566,6 +6861,18 @@ fbjs@^0.8.0, fbjs@^0.8.1, fbjs@^0.8.16, fbjs@^0.8.5: setimmediate "^1.0.5" ua-parser-js "^0.7.9" +fbjs@^0.8.12: + version "0.8.17" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd" + dependencies: + core-js "^1.0.0" + isomorphic-fetch "^2.1.1" + loose-envify "^1.0.0" + object-assign "^4.1.0" + promise "^7.1.1" + setimmediate "^1.0.5" + ua-parser-js "^0.7.18" + fd-slicer@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" @@ -6637,6 +6944,10 @@ fileset@^2.0.2: glob "^7.0.3" minimatch "^3.0.3" +filesize@^3.6.1: + version "3.6.1" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317" + fill-range@^2.1.0: version "2.2.3" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" @@ -6751,6 +7062,12 @@ first-chunk-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz#59bfb50cd905f60d7c394cd3d9acaab4e6ad934e" +fizzy-ui-utils@^2.0.0: + version "2.0.7" + resolved "https://registry.yarnpkg.com/fizzy-ui-utils/-/fizzy-ui-utils-2.0.7.tgz#7df45dcc4eb374a08b65d39bb9a4beedf7330505" + dependencies: + desandro-matches-selector "^2.0.0" + flagged-respawn@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-1.0.0.tgz#4e79ae9b2eb38bf86b3bb56bf3e0a56aa5fcabd7" @@ -6768,6 +7085,17 @@ flatten@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" +flickity@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/flickity/-/flickity-2.1.2.tgz#f1be68a75c8d8d8d6df68fb2a49f358268279bd0" + dependencies: + desandro-matches-selector "^2.0.0" + ev-emitter "^1.0.2" + fizzy-ui-utils "^2.0.0" + get-size "^2.0.0" + tap-listener "^2.0.0" + unidragger "^2.3.0" + flush-write-stream@^1.0.0, flush-write-stream@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.3.tgz#c5d586ef38af6097650b49bc41b55fabb19f35bd" @@ -6775,6 +7103,13 @@ flush-write-stream@^1.0.0, flush-write-stream@^1.0.2: inherits "^2.0.1" readable-stream "^2.0.4" +focus-trap@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/focus-trap/-/focus-trap-3.0.0.tgz#4d2ee044ae66bf7eb6ebc6c93bd7a1039481d7dc" + dependencies: + tabbable "^3.1.0" + xtend "^4.0.1" + follow-redirects@^1.3.0: version "1.5.8" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.8.tgz#1dbfe13e45ad969f813e86c00e5296f525c885a1" @@ -6935,7 +7270,7 @@ fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" -fsevents@^1.0.0, fsevents@^1.2.3: +fsevents@^1.0.0, fsevents@^1.2.2, fsevents@^1.2.3: version "1.2.4" resolved "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" dependencies: @@ -7004,7 +7339,7 @@ ganache-core@0xProject/ganache-core#monorepo-dep: ethereumjs-tx "0xProject/ethereumjs-tx#fake-tx-include-signature-by-default" ethereumjs-util "^5.2.0" ethereumjs-vm "2.3.5" - ethereumjs-wallet "0.6.0" + ethereumjs-wallet "~0.6.0" fake-merkle-patricia-tree "~1.0.1" heap "~0.2.6" js-scrypt "^0.2.0" @@ -7124,6 +7459,10 @@ get-port@^3.2.0: version "3.2.0" resolved "http://registry.yarnpkg.com/get-port/-/get-port-3.2.0.tgz#dd7ce7de187c06c8bf353796ac71e099f0980ebc" +get-size@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/get-size/-/get-size-2.0.3.tgz#54a1d0256b20ea7ac646516756202769941ad2ef" + get-stdin@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" @@ -7545,6 +7884,13 @@ gzip-size@^4.0.0: duplexer "^0.1.1" pify "^3.0.0" +gzip-size@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-5.0.0.tgz#a55ecd99222f4c48fd8c01c625ce3b349d0a0e80" + dependencies: + duplexer "^0.1.1" + pify "^3.0.0" + handle-thing@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4" @@ -7731,6 +8077,14 @@ hdkey@^0.7.0, hdkey@^0.7.1: coinstring "^2.0.0" secp256k1 "^3.0.1" +hdkey@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/hdkey/-/hdkey-1.1.0.tgz#e74e7b01d2c47f797fa65d1d839adb7a44639f29" + dependencies: + coinstring "^2.0.0" + safe-buffer "^5.1.1" + secp256k1 "^3.0.1" + he@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" @@ -7801,6 +8155,10 @@ homedir-polyfill@^1.0.1: dependencies: parse-passwd "^1.0.0" +hoopy@^0.1.2: + version "0.1.4" + resolved "https://registry.yarnpkg.com/hoopy/-/hoopy-0.1.4.tgz#609207d661100033a9a9402ad3dea677381c1b1d" + hosted-git-info@^2.1.4: version "2.6.0" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.6.0.tgz#23235b29ab230c576aab0d4f13fc046b0b038222" @@ -7860,7 +8218,7 @@ http-errors@1.6.2: setprototypeof "1.0.3" statuses ">= 1.3.1 < 2" -http-errors@~1.6.2: +http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: version "1.6.3" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" dependencies: @@ -7947,7 +8305,7 @@ hyperquest@~1.2.0: duplexer2 "~0.0.2" through2 "~0.6.3" -hyphenate-style-name@^1.0.2: +hyphenate-style-name@^1.0.0, hyphenate-style-name@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz#31160a36930adaf1fc04c6074f7eb41465d4ec4b" @@ -7959,6 +8317,12 @@ iconv-lite@0.4.19: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" +iconv-lite@0.4.23, iconv-lite@^0.4.4: + version "0.4.23" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" + dependencies: + safer-buffer ">= 2.1.2 < 3" + iconv-lite@0.4.24, iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -7971,12 +8335,6 @@ iconv-lite@^0.4.17, iconv-lite@~0.4.13: dependencies: safer-buffer "^2.1.0" -iconv-lite@^0.4.4: - version "0.4.23" - resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" - dependencies: - safer-buffer ">= 2.1.2 < 3" - icss-replace-symbols@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" @@ -8015,6 +8373,12 @@ image-size@~0.5.0: version "0.5.5" resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c" +imagesloaded@^4.1.3: + version "4.1.4" + resolved "https://registry.yarnpkg.com/imagesloaded/-/imagesloaded-4.1.4.tgz#1376efcd162bb768c34c3727ac89cc04051f3cc7" + dependencies: + ev-emitter "^1.0.0" + immediate@^3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.2.3.tgz#d140fa8f614659bd6541233097ddaac25cdd991c" @@ -8217,6 +8581,10 @@ ipaddr.js@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.6.0.tgz#e3fa357b773da619f26e95f049d055c72796f86b" +ipaddr.js@1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e" + ipaddr.js@^1.5.2: version "1.8.1" resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.1.tgz#fa4b79fa47fd3def5e3b159825161c0a519c9427" @@ -9390,6 +9758,10 @@ jss@^9.3.3, jss@^9.7.0: symbol-observable "^1.1.0" warning "^3.0.0" +jump.js@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/jump.js/-/jump.js-1.0.1.tgz#0de2b1631ba9a1c2c6b8572ad277d877e8503600" + just-extend@^1.1.27: version "1.1.27" resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-1.1.27.tgz#ec6e79410ff914e472652abfa0e603c03d60e905" @@ -9858,6 +10230,11 @@ lodash.camelcase@^3.0.1: dependencies: lodash._createcompounder "^3.0.0" +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= + lodash.deburr@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/lodash.deburr/-/lodash.deburr-3.2.0.tgz#6da8f54334a366a7cf4c4c76ef8d80aa1b365ed5" @@ -9914,6 +10291,10 @@ lodash.isequal@^4.0.0, lodash.isequal@^4.5.0: version "4.5.0" resolved "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + lodash.keys@^3.0.0, lodash.keys@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" @@ -10248,6 +10629,12 @@ marked@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/marked/-/marked-0.4.0.tgz#9ad2c2a7a1791f10a852e0112f77b571dce10c66" +matchmediaquery@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/matchmediaquery/-/matchmediaquery-0.3.0.tgz#6f672bcdbc44de16825c6917fbcdcfb9b82607b1" + dependencies: + css-mediaquery "^0.1.2" + material-ui@^0.20.0: version "0.20.2" resolved "https://registry.npmjs.org/material-ui/-/material-ui-0.20.2.tgz#5fc9b4b62b691d3b16c89d8e54597a0412b52c7d" @@ -11409,6 +11796,10 @@ openapi3-ts@^0.11.0: version "0.11.0" resolved "https://registry.npmjs.org/openapi3-ts/-/openapi3-ts-0.11.0.tgz#8e4c51ad8d54f8f2516b895e4ce8c01550cd4854" +opener@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.1.tgz#6d2f0e77f1a0af0032aca716c2c1fbb8e7e8abed" + opn-cli@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/opn-cli/-/opn-cli-3.1.0.tgz#f819ae6cae0b411bd0149b8560fe6c88adad20f8" @@ -11973,6 +12364,7 @@ pkginfo@0.x.x: pluralize@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" + integrity sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow== pn@^1.1.0: version "1.1.0" @@ -12481,6 +12873,13 @@ proxy-addr@~2.0.3: forwarded "~0.1.2" ipaddr.js "1.6.0" +proxy-addr@~2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.8.0" + prr@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a" @@ -12631,14 +13030,14 @@ qs@6.5.1, qs@~6.5.1: version "6.5.1" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" +qs@6.5.2, qs@~6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + qs@~6.4.0: version "6.4.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" -qs@~6.5.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" - query-string@^4.1.0: version "4.3.4" resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb" @@ -12681,6 +13080,12 @@ quick-lru@^1.0.0: version "1.1.0" resolved "http://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8" +raf@^3.3.0: + version "3.4.1" + resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" + dependencies: + performance-now "^2.1.0" + raf@^3.4.0: version "3.4.0" resolved "https://registry.npmjs.org/raf/-/raf-3.4.0.tgz#a28876881b4bc2ca9117d4138163ddb80f781575" @@ -12743,6 +13148,15 @@ raw-body@2.3.2: iconv-lite "0.4.19" unpipe "1.0.0" +raw-body@2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" + dependencies: + bytes "3.0.0" + http-errors "1.6.3" + iconv-lite "0.4.23" + unpipe "1.0.0" + raw-loader@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-0.5.1.tgz#0c3d0beaed8a01c966d9787bf778281252a979aa" @@ -12871,6 +13285,25 @@ react-event-listener@^0.6.2: prop-types "^15.6.0" warning "^4.0.1" +react-flickity-component@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/react-flickity-component/-/react-flickity-component-3.1.0.tgz#3e519028e6b622ac852a6ab93a272cdbf37f6e00" + dependencies: + fbjs "^0.8.12" + flickity "^2.1.1" + imagesloaded "^4.1.3" + prop-types "^15.5.10" + react "^16.3.2" + react-dom "^16.3.2" + +react-headroom@2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/react-headroom/-/react-headroom-2.2.2.tgz#5ddea3bc87cd54be38f6f98c3fde4527e2a5fb0f" + dependencies: + prop-types "^15.5.8" + raf "^3.3.0" + shallowequal "^0.2.2" + react-helmet@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-5.2.0.tgz#a81811df21313a6d55c5f058c4aeba5d6f3d97a7" @@ -12908,6 +13341,10 @@ react-is@^16.4.2, react-is@^16.5.2: version "16.5.2" resolved "https://registry.npmjs.org/react-is/-/react-is-16.5.2.tgz#e2a7b7c3f5d48062eb769fcb123505eb928722e3" +react-is@^16.6.0: + version "16.6.3" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.6.3.tgz#d2d7462fcfcbe6ec0da56ad69047e47e56e7eac0" + react-jss@^8.1.0: version "8.6.1" resolved "https://registry.npmjs.org/react-jss/-/react-jss-8.6.1.tgz#a06e2e1d2c4d91b4d11befda865e6c07fbd75252" @@ -12918,10 +13355,20 @@ react-jss@^8.1.0: prop-types "^15.6.0" theming "^1.3.0" +react-lazyload@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/react-lazyload/-/react-lazyload-2.3.0.tgz#ccb134223012447074a96543954f44b055dc6185" + react-lifecycles-compat@^3.0.2, react-lifecycles-compat@^3.0.4: version "3.0.4" resolved "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" +react-loadable@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/react-loadable/-/react-loadable-5.5.0.tgz#582251679d3da86c32aae2c8e689c59f1196d8c4" + dependencies: + prop-types "^15.5.0" + react-markdown@^3.2.2: version "3.3.0" resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-3.3.0.tgz#a87cdd822aa9302d6add9687961dd1a82a45d02e" @@ -12954,6 +13401,14 @@ react-redux@^5.0.3, react-redux@^5.0.7: loose-envify "^1.1.0" prop-types "^15.6.0" +react-responsive@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/react-responsive/-/react-responsive-6.0.1.tgz#b6fc7772dd55f1d1e3c9352651a798f990145ece" + dependencies: + hyphenate-style-name "^1.0.0" + matchmediaquery "^0.3.0" + prop-types "^15.6.1" + react-router-dom@^4.1.1: version "4.2.2" resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-4.2.2.tgz#c8a81df3adc58bba8a76782e946cbd4eae649b8d" @@ -12984,6 +13439,13 @@ react-scroll@0xproject/react-scroll#pr-330-and-replace-state: lodash.throttle "^4.1.1" prop-types "^15.5.8" +react-scrollable-anchor@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/react-scrollable-anchor/-/react-scrollable-anchor-0.6.1.tgz#fd6e78026c744f76414053d06903b82adccb54d9" + dependencies: + jump.js "1.0.1" + prop-types "^15.5.10" + react-side-effect@^1.0.2, react-side-effect@^1.1.0: version "1.1.5" resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-1.1.5.tgz#f26059e50ed9c626d91d661b9f3c8bb38cd0ff2d" @@ -12991,6 +13453,25 @@ react-side-effect@^1.0.2, react-side-effect@^1.1.0: exenv "^1.2.1" shallowequal "^1.0.1" +react-svg-core@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/react-svg-core/-/react-svg-core-2.1.0.tgz#3700322af70117c91f83f18febb481128de3cfbb" + dependencies: + babel-core "^6.26.0" + babel-plugin-react-svg "^2.1.0" + babel-plugin-syntax-jsx "^6.18.0" + babel-plugin-transform-object-rest-spread "^6.26.0" + babel-preset-react "^6.24.1" + lodash.isplainobject "^4.0.6" + svgo "^0.7.2" + +react-svg-loader@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/react-svg-loader/-/react-svg-loader-2.1.0.tgz#ba15019413b9b11e2012e86580aea1eecc93677e" + dependencies: + loader-utils "^1.1.0" + react-svg-core "^2.1.0" + react-syntax-highlighter@^10.1.1: version "10.1.1" resolved "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-10.1.1.tgz#1bf7ad4f2f16d2978b04594407b670671b4d3316" @@ -13882,7 +14363,7 @@ safe-buffer@5.1.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, s version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" -safe-buffer@^5.1.2: +safe-buffer@5.1.2, safe-buffer@^5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -14993,6 +15474,21 @@ styled-components@^4.0.2: stylis "^3.5.0" stylis-rule-sheet "^0.0.10" +styled-components@^4.1.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-4.1.2.tgz#f8a685e3b2bcd03c5beac7f2c02bb6ad237da9b3" + dependencies: + "@emotion/is-prop-valid" "^0.6.8" + "@emotion/unitless" "^0.7.0" + babel-plugin-styled-components ">= 1" + css-to-react-native "^2.2.2" + memoize-one "^4.0.0" + prop-types "^15.5.4" + react-is "^16.6.0" + stylis "^3.5.0" + stylis-rule-sheet "^0.0.10" + supports-color "^5.5.0" + stylis-rule-sheet@^0.0.10: version "0.0.10" resolved "https://registry.npmjs.org/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz#44e64a2b076643f4b52e5ff71efc04d8c3c4a430" @@ -15040,7 +15536,7 @@ svg-react-loader@^0.4.6: traverse "0.6.6" xml2js "0.4.17" -svgo@^0.7.0: +svgo@^0.7.0, svgo@^0.7.2: version "0.7.2" resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5" dependencies: @@ -15124,6 +15620,10 @@ symbol-tree@^3.2.2: version "3.2.2" resolved "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6" +tabbable@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-3.1.1.tgz#db7512f28a9a1ed16e4275bd190131be9d5ad8e9" + table@^5.0.2: version "5.1.0" resolved "https://registry.yarnpkg.com/table/-/table-5.1.0.tgz#69a54644f6f01ad1628f8178715b408dc6bf11f7" @@ -15133,6 +15633,12 @@ table@^5.0.2: slice-ansi "1.0.0" string-width "^2.1.1" +tap-listener@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/tap-listener/-/tap-listener-2.0.0.tgz#d2e11d0d8e7c92b26a56ae4f35538a248b44ad63" + dependencies: + unipointer "^2.1.0" + tapable@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.0.0.tgz#cbb639d9002eed9c6b5975eb20598d7936f1f9f2" @@ -15590,6 +16096,10 @@ truffle-contract@2.0.1: truffle-contract-schema "0.0.5" web3 "^0.18.0" +tryer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8" + ts-jest@^23.10.3: version "23.10.3" resolved "https://registry.npmjs.org/ts-jest/-/ts-jest-23.10.3.tgz#f42de669888dfd2795b1491016b1813230d553fa" @@ -15835,6 +16345,10 @@ u2f-api@0.2.7: version "0.2.7" resolved "https://registry.yarnpkg.com/u2f-api/-/u2f-api-0.2.7.tgz#17bf196b242f6bf72353d9858e6a7566cc192720" +ua-parser-js@^0.7.18: + version "0.7.19" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.19.tgz#94151be4c0a7fb1d001af7022fdaca4642659e4b" + ua-parser-js@^0.7.9: version "0.7.17" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac" @@ -15936,6 +16450,12 @@ unherit@^1.0.4: inherits "^2.0.1" xtend "^4.0.1" +unidragger@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/unidragger/-/unidragger-2.3.0.tgz#ab9d9fd62106f3252d88fae5f3a99575e6d31d02" + dependencies: + unipointer "^2.3.0" + unified@^6.1.5: version "6.1.6" resolved "https://registry.yarnpkg.com/unified/-/unified-6.1.6.tgz#5ea7f807a0898f1f8acdeefe5f25faa010cc42b1" @@ -15957,6 +16477,12 @@ union-value@^1.0.0: is-extendable "^0.1.1" set-value "^0.4.3" +unipointer@^2.1.0, unipointer@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/unipointer/-/unipointer-2.3.0.tgz#ba0dc462ce31c2a88e80810e19c3bae0ce47ed9f" + dependencies: + ev-emitter "^1.0.1" + uniq@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" @@ -16047,6 +16573,11 @@ upath@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/upath/-/upath-1.0.4.tgz#ee2321ba0a786c50973db043a50b7bcba822361d" +upath@^1.0.5: + version "1.1.0" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd" + integrity sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw== + update-notifier@^2.3.0, update-notifier@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.5.0.tgz#d0744593e13f161e406acb1d9408b72cad08aff6" @@ -16148,6 +16679,10 @@ utf8@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/utf8/-/utf8-2.1.2.tgz#1fa0d9270e9be850d9b05027f63519bf46457d96" +utf8@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1" + util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -16687,6 +17222,23 @@ webidl-conversions@^4.0.2: version "4.0.2" resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" +webpack-bundle-analyzer@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.0.3.tgz#dbc7fff8f52058b6714a20fddf309d0790e3e0a0" + dependencies: + acorn "^5.7.3" + bfj "^6.1.1" + chalk "^2.4.1" + commander "^2.18.0" + ejs "^2.6.1" + express "^4.16.3" + filesize "^3.6.1" + gzip-size "^5.0.0" + lodash "^4.17.10" + mkdirp "^0.5.1" + opener "^1.5.1" + ws "^6.0.0" + webpack-cli@3.1.2, webpack-cli@^3.1.1: version "3.1.2" resolved "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.1.2.tgz#17d7e01b77f89f884a2bbf9db545f0f6a648e746" @@ -17019,6 +17571,12 @@ ws@^5.2.0: dependencies: async-limiter "~1.0.0" +ws@^6.0.0: + version "6.1.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.2.tgz#3cc7462e98792f0ac679424148903ded3b9c3ad8" + dependencies: + async-limiter "~1.0.0" + wsrun@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/wsrun/-/wsrun-2.2.0.tgz#fe05ca2c466e9281059d255b2773e7964dbcb3a7" |