aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.circleci/config.yml39
-rw-r--r--.github/stale.yml2
-rw-r--r--.prettierignore5
-rw-r--r--CONTRIBUTING.md15
-rw-r--r--README.md11
-rw-r--r--contracts/.solhint.json1
-rw-r--r--contracts/examples/package.json3
-rw-r--r--contracts/extensions/CHANGELOG.json26
-rw-r--r--contracts/extensions/compiler.json2
-rw-r--r--contracts/extensions/contracts/BalanceThresholdFilter/BalanceThresholdFilter.sol45
-rw-r--r--contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol135
-rw-r--r--contracts/extensions/contracts/BalanceThresholdFilter/MixinExchangeCalldata.sol103
-rw-r--r--contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IBalanceThresholdFilterCore.sol55
-rw-r--r--contracts/extensions/contracts/BalanceThresholdFilter/interfaces/IThresholdAsset.sol31
-rw-r--r--contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol54
-rw-r--r--contracts/extensions/contracts/BalanceThresholdFilter/mixins/MExchangeCalldata.sol56
-rw-r--r--contracts/extensions/contracts/Forwarder/MixinAssets.sol2
-rw-r--r--contracts/extensions/contracts/Forwarder/MixinExchangeWrapper.sol2
-rw-r--r--contracts/extensions/contracts/Forwarder/MixinForwarderCore.sol2
-rw-r--r--contracts/extensions/contracts/Forwarder/MixinWeth.sol2
-rw-r--r--contracts/extensions/contracts/Forwarder/interfaces/IAssets.sol2
-rw-r--r--contracts/extensions/contracts/Forwarder/interfaces/IForwarder.sol2
-rw-r--r--contracts/extensions/contracts/Forwarder/interfaces/IForwarderCore.sol2
-rw-r--r--contracts/extensions/contracts/Forwarder/libs/LibConstants.sol2
-rw-r--r--contracts/extensions/contracts/Forwarder/libs/LibForwarderErrors.sol2
-rw-r--r--contracts/extensions/contracts/Forwarder/mixins/MAssets.sol2
-rw-r--r--contracts/extensions/contracts/Forwarder/mixins/MExchangeWrapper.sol2
-rw-r--r--contracts/extensions/contracts/Forwarder/mixins/MWeth.sol2
-rw-r--r--contracts/extensions/contracts/OrderMatcher/MixinAssets.sol195
-rw-r--r--contracts/extensions/contracts/OrderMatcher/MixinMatchOrders.sol86
-rw-r--r--contracts/extensions/contracts/OrderMatcher/OrderMatcher.sol38
-rw-r--r--contracts/extensions/contracts/OrderMatcher/interfaces/IAssets.sol43
-rw-r--r--contracts/extensions/contracts/OrderMatcher/interfaces/IMatchOrders.sol43
-rw-r--r--contracts/extensions/contracts/OrderMatcher/interfaces/IOrderMatcher.sol31
-rw-r--r--contracts/extensions/contracts/OrderMatcher/libs/LibConstants.sol56
-rw-r--r--contracts/extensions/contracts/OrderMatcher/mixins/MAssets.sol71
-rw-r--r--contracts/extensions/contracts/OrderValidator/OrderValidator.sol (renamed from contracts/protocol/contracts/protocol/OrderValidator/OrderValidator.sol)0
-rw-r--r--contracts/extensions/package.json6
-rw-r--r--contracts/extensions/src/artifacts/index.ts6
-rw-r--r--contracts/extensions/src/wrappers/index.ts3
-rw-r--r--contracts/extensions/test/extensions/balance_threshold_filter.ts1644
-rw-r--r--contracts/extensions/test/extensions/dutch_auction.ts194
-rw-r--r--contracts/extensions/test/extensions/forwarder.ts3
-rw-r--r--contracts/extensions/test/extensions/order_matcher.ts818
-rw-r--r--contracts/extensions/test/extensions/order_validator.ts (renamed from contracts/protocol/test/exchange/order_validator.ts)23
-rw-r--r--contracts/extensions/test/utils/balance_threshold_wrapper.ts283
-rw-r--r--contracts/extensions/test/utils/dutch_auction_test_wrapper.ts62
-rw-r--r--contracts/extensions/tsconfig.json8
-rw-r--r--contracts/interfaces/contracts/protocol/AssetProxy/IAssetData.sol2
-rw-r--r--contracts/interfaces/contracts/protocol/AssetProxy/IAssetProxy.sol2
-rw-r--r--contracts/interfaces/contracts/protocol/AssetProxy/IAuthorizable.sol2
-rw-r--r--contracts/interfaces/contracts/protocol/Exchange/IAssetProxyDispatcher.sol2
-rw-r--r--contracts/interfaces/contracts/protocol/Exchange/IExchange.sol2
-rw-r--r--contracts/interfaces/contracts/protocol/Exchange/IExchangeCore.sol2
-rw-r--r--contracts/interfaces/contracts/protocol/Exchange/IMatchOrders.sol2
-rw-r--r--contracts/interfaces/contracts/protocol/Exchange/ISignatureValidator.sol2
-rw-r--r--contracts/interfaces/contracts/protocol/Exchange/ITransactions.sol2
-rw-r--r--contracts/interfaces/contracts/protocol/Exchange/IValidator.sol2
-rw-r--r--contracts/interfaces/contracts/protocol/Exchange/IWallet.sol2
-rw-r--r--contracts/interfaces/contracts/protocol/Exchange/IWrapperFunctions.sol2
-rw-r--r--contracts/interfaces/package.json3
-rw-r--r--contracts/libs/compiler.json11
-rw-r--r--contracts/libs/contracts/libs/LibAbiEncoder.sol2
-rw-r--r--contracts/libs/contracts/libs/LibAddressArray.sol84
-rw-r--r--contracts/libs/contracts/libs/LibAssetProxyErrors.sol2
-rw-r--r--contracts/libs/contracts/libs/LibConstants.sol2
-rw-r--r--contracts/libs/contracts/libs/LibEIP712.sol2
-rw-r--r--contracts/libs/contracts/libs/LibExchangeErrors.sol2
-rw-r--r--contracts/libs/contracts/libs/LibExchangeSelectors.sol152
-rw-r--r--contracts/libs/contracts/libs/LibFillResults.sol2
-rw-r--r--contracts/libs/contracts/libs/LibMath.sol2
-rw-r--r--contracts/libs/contracts/libs/LibOrder.sol2
-rw-r--r--contracts/libs/package.json3
-rw-r--r--contracts/multisig/package.json3
-rw-r--r--contracts/multisig/src/index.ts2
-rw-r--r--contracts/protocol/CHANGELOG.json17
-rw-r--r--contracts/protocol/compiler.json1
-rw-r--r--contracts/protocol/contracts/protocol/AssetProxy/MixinAuthorizable.sol2
-rw-r--r--contracts/protocol/contracts/protocol/AssetProxy/MultiAssetProxy.sol14
-rw-r--r--contracts/protocol/contracts/protocol/AssetProxy/mixins/MAuthorizable.sol2
-rw-r--r--contracts/protocol/contracts/protocol/Exchange/MixinAssetProxyDispatcher.sol2
-rw-r--r--contracts/protocol/contracts/protocol/Exchange/MixinExchangeCore.sol2
-rw-r--r--contracts/protocol/contracts/protocol/Exchange/MixinMatchOrders.sol2
-rw-r--r--contracts/protocol/contracts/protocol/Exchange/MixinSignatureValidator.sol2
-rw-r--r--contracts/protocol/contracts/protocol/Exchange/MixinTransactions.sol2
-rw-r--r--contracts/protocol/contracts/protocol/Exchange/MixinWrapperFunctions.sol2
-rw-r--r--contracts/protocol/contracts/protocol/Exchange/mixins/MAssetProxyDispatcher.sol2
-rw-r--r--contracts/protocol/contracts/protocol/Exchange/mixins/MExchangeCore.sol2
-rw-r--r--contracts/protocol/contracts/protocol/Exchange/mixins/MMatchOrders.sol2
-rw-r--r--contracts/protocol/contracts/protocol/Exchange/mixins/MSignatureValidator.sol2
-rw-r--r--contracts/protocol/contracts/protocol/Exchange/mixins/MTransactions.sol2
-rw-r--r--contracts/protocol/contracts/protocol/Exchange/mixins/MWrapperFunctions.sol2
-rw-r--r--contracts/protocol/package.json7
-rw-r--r--contracts/protocol/src/artifacts/index.ts2
-rw-r--r--contracts/protocol/src/wrappers/index.ts1
-rw-r--r--contracts/protocol/test/asset_proxy/proxies.ts64
-rw-r--r--contracts/protocol/test/exchange/core.ts31
-rw-r--r--contracts/protocol/tsconfig.json1
-rw-r--r--contracts/test-utils/src/constants.ts1
-rw-r--r--contracts/test-utils/src/types.ts1
-rw-r--r--contracts/tokens/contracts/tokens/ERC20Token/ERC20Token.sol2
-rw-r--r--contracts/tokens/contracts/tokens/ERC20Token/IERC20Token.sol2
-rw-r--r--contracts/tokens/contracts/tokens/ERC20Token/MintableERC20Token.sol2
-rw-r--r--contracts/tokens/contracts/tokens/ERC20Token/UnlimitedAllowanceERC20Token.sol2
-rw-r--r--contracts/tokens/contracts/tokens/ERC721Token/ERC721Token.sol2
-rw-r--r--contracts/tokens/contracts/tokens/ERC721Token/IERC721Receiver.sol2
-rw-r--r--contracts/tokens/contracts/tokens/ERC721Token/IERC721Token.sol2
-rw-r--r--contracts/tokens/contracts/tokens/ERC721Token/MintableERC721Token.sol2
-rw-r--r--contracts/tokens/contracts/tokens/EtherToken/IEtherToken.sol2
-rw-r--r--contracts/tokens/package.json3
-rw-r--r--contracts/tokens/src/artifacts/index.ts1
-rw-r--r--contracts/utils/contracts/utils/LibBytes/LibBytes.sol2
-rw-r--r--contracts/utils/contracts/utils/Ownable/IOwnable.sol2
-rw-r--r--contracts/utils/contracts/utils/Ownable/Ownable.sol2
-rw-r--r--contracts/utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol2
-rw-r--r--contracts/utils/contracts/utils/SafeMath/SafeMath.sol2
-rw-r--r--contracts/utils/package.json3
-rw-r--r--packages/0x.js/CHANGELOG.json10
-rw-r--r--packages/0x.js/src/index.ts7
-rw-r--r--packages/abi-gen-wrappers/CHANGELOG.json9
-rw-r--r--packages/abi-gen-wrappers/package.json2
-rw-r--r--packages/abi-gen-wrappers/src/generated-wrappers/dutch_auction.ts322
-rw-r--r--packages/abi-gen-wrappers/src/index.ts1
-rw-r--r--packages/asset-buyer/README.md2
-rw-r--r--packages/contract-addresses/CHANGELOG.json9
-rw-r--r--packages/contract-addresses/src/index.ts9
-rw-r--r--packages/contract-artifacts/CHANGELOG.json9
-rw-r--r--packages/contract-artifacts/artifacts/DutchAuction.json310
-rw-r--r--packages/contract-artifacts/src/index.ts2
-rw-r--r--packages/contract-artifacts/tsconfig.json1
-rw-r--r--packages/contract-wrappers/CHANGELOG.json21
-rw-r--r--packages/contract-wrappers/package.json2
-rw-r--r--packages/contract-wrappers/src/contract_wrappers.ts10
-rw-r--r--packages/contract-wrappers/src/contract_wrappers/dutch_auction_wrapper.ts182
-rw-r--r--packages/contract-wrappers/src/fetchers/asset_balance_and_proxy_allowance_fetcher.ts74
-rw-r--r--packages/contract-wrappers/src/index.ts15
-rw-r--r--packages/contract-wrappers/src/types.ts12
-rw-r--r--packages/contract-wrappers/src/utils/constants.ts3
-rw-r--r--packages/contract-wrappers/src/utils/decorators.ts5
-rw-r--r--packages/contract-wrappers/test/dutch_auction_wrapper_test.ts128
-rw-r--r--packages/contract-wrappers/test/utils/dutch_auction_utils.ts153
-rw-r--r--packages/fill-scenarios/CHANGELOG.json9
-rw-r--r--packages/fill-scenarios/src/fill_scenarios.ts63
-rw-r--r--packages/instant/.production.discharge.json2
-rw-r--r--packages/instant/src/components/amount_placeholder.tsx2
-rw-r--r--packages/instant/src/components/animations/slide_animation.tsx10
-rw-r--r--packages/instant/src/components/buy_button.tsx16
-rw-r--r--packages/instant/src/components/buy_order_progress.tsx2
-rw-r--r--packages/instant/src/components/buy_order_state_buttons.tsx2
-rw-r--r--packages/instant/src/components/erc20_asset_amount_input.tsx2
-rw-r--r--packages/instant/src/components/erc20_token_selector.tsx77
-rw-r--r--packages/instant/src/components/install_wallet_panel_content.tsx2
-rw-r--r--packages/instant/src/components/instant_heading.tsx2
-rw-r--r--packages/instant/src/components/order_details.tsx4
-rw-r--r--packages/instant/src/components/payment_method.tsx2
-rw-r--r--packages/instant/src/components/payment_method_dropdown.tsx2
-rw-r--r--packages/instant/src/components/placing_order_button.tsx2
-rw-r--r--packages/instant/src/components/scaling_amount_input.tsx2
-rw-r--r--packages/instant/src/components/scaling_input.tsx2
-rw-r--r--packages/instant/src/components/secondary_button.tsx1
-rw-r--r--packages/instant/src/components/section_header.tsx1
-rw-r--r--packages/instant/src/components/sliding_error.tsx4
-rw-r--r--packages/instant/src/components/sliding_panel.tsx74
-rw-r--r--packages/instant/src/components/standard_panel_content.tsx2
-rw-r--r--packages/instant/src/components/standard_sliding_panel.tsx2
-rw-r--r--packages/instant/src/components/time_counter.tsx2
-rw-r--r--packages/instant/src/components/timed_progress_bar.tsx2
-rw-r--r--packages/instant/src/components/ui/container.tsx2
-rw-r--r--packages/instant/src/components/ui/dropdown.tsx43
-rw-r--r--packages/instant/src/components/wallet_prompt.tsx2
-rw-r--r--packages/instant/src/components/zero_ex_instant.tsx2
-rw-r--r--packages/instant/src/components/zero_ex_instant_container.tsx13
-rw-r--r--packages/instant/src/components/zero_ex_instant_overlay.tsx2
-rw-r--r--packages/instant/src/components/zero_ex_instant_provider.tsx2
-rw-r--r--packages/instant/src/constants.ts1
-rw-r--r--packages/instant/src/containers/latest_error.tsx4
-rw-r--r--packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts3
-rw-r--r--packages/instant/src/types.ts2
-rw-r--r--packages/instant/src/util/analytics.ts6
-rw-r--r--packages/instant/src/util/env.ts2
-rw-r--r--packages/json-schemas/schemas/asset_pairs_request_opts_schema.json2
-rw-r--r--packages/json-schemas/schemas/call_data_schema.json6
-rw-r--r--packages/json-schemas/schemas/ec_signature_schema.json2
-rw-r--r--packages/json-schemas/schemas/js_number_schema.json (renamed from packages/json-schemas/schemas/js_number.json)2
-rw-r--r--packages/json-schemas/schemas/order_config_request_schema.json2
-rw-r--r--packages/json-schemas/schemas/order_watcher_web_socket_request_schema.json52
-rw-r--r--packages/json-schemas/schemas/order_watcher_web_socket_utf8_message_schema.json10
-rw-r--r--packages/json-schemas/schemas/orderbook_request_schema.json4
-rw-r--r--packages/json-schemas/schemas/orders_request_opts_schema.json2
-rw-r--r--packages/json-schemas/schemas/paged_request_opts_schema.json2
-rw-r--r--packages/json-schemas/schemas/request_opts_schema.json2
-rw-r--r--packages/json-schemas/schemas/tx_data_schema.json6
-rw-r--r--packages/json-schemas/src/schemas.ts6
-rw-r--r--packages/json-schemas/tsconfig.json4
-rw-r--r--packages/migrations/CHANGELOG.json9
-rw-r--r--packages/migrations/src/migration.ts9
-rw-r--r--packages/monorepo-scripts/CHANGELOG.json4
-rw-r--r--packages/monorepo-scripts/src/doc_gen_configs.ts1
-rw-r--r--packages/order-utils/CHANGELOG.json10
-rw-r--r--packages/order-utils/src/asset_data_utils.ts293
-rw-r--r--packages/order-utils/src/constants.ts66
-rw-r--r--packages/order-utils/src/exchange_transfer_simulator.ts64
-rw-r--r--packages/order-utils/src/index.ts5
-rw-r--r--packages/order-utils/src/order_state_utils.ts56
-rw-r--r--packages/order-utils/src/store/balance_and_proxy_allowance_lazy_store.ts2
-rw-r--r--packages/order-utils/test/asset_data_utils_test.ts116
-rw-r--r--packages/order-utils/test/utils/test_order_factory.ts4
-rw-r--r--packages/order-watcher/CHANGELOG.json19
-rw-r--r--packages/order-watcher/README.md88
-rw-r--r--packages/order-watcher/package.json3
-rw-r--r--packages/order-watcher/src/index.ts2
-rw-r--r--packages/order-watcher/src/order_watcher/dependent_order_hashes_tracker.ts62
-rw-r--r--packages/order-watcher/src/order_watcher/order_watcher.ts93
-rw-r--r--packages/order-watcher/src/order_watcher/order_watcher_web_socket_server.ts200
-rw-r--r--packages/order-watcher/src/types.ts66
-rw-r--r--packages/order-watcher/test/order_watcher_test.ts208
-rw-r--r--packages/order-watcher/test/order_watcher_web_socket_server_test.ts308
-rw-r--r--packages/pipeline/migrations/1545440485644-CreateCopperTables.ts103
-rw-r--r--packages/pipeline/package.json4
-rw-r--r--packages/pipeline/src/data_sources/copper/index.ts126
-rw-r--r--packages/pipeline/src/entities/copper_activity.ts41
-rw-r--r--packages/pipeline/src/entities/copper_activity_type.ts17
-rw-r--r--packages/pipeline/src/entities/copper_custom_field.ts15
-rw-r--r--packages/pipeline/src/entities/copper_lead.ts38
-rw-r--r--packages/pipeline/src/entities/copper_opportunity.ts45
-rw-r--r--packages/pipeline/src/entities/index.ts6
-rw-r--r--packages/pipeline/src/entities/token_order.ts3
-rw-r--r--packages/pipeline/src/ormconfig.ts10
-rw-r--r--packages/pipeline/src/parsers/copper/index.ts259
-rw-r--r--packages/pipeline/src/parsers/ddex_orders/index.ts8
-rw-r--r--packages/pipeline/src/parsers/events/exchange_events.ts38
-rw-r--r--packages/pipeline/src/parsers/idex_orders/index.ts12
-rw-r--r--packages/pipeline/src/parsers/oasis_orders/index.ts8
-rw-r--r--packages/pipeline/src/parsers/paradex_orders/index.ts4
-rw-r--r--packages/pipeline/src/parsers/sra_orders/index.ts20
-rw-r--r--packages/pipeline/src/scripts/pull_copper.ts129
-rw-r--r--packages/pipeline/src/scripts/pull_erc20_events.ts68
-rw-r--r--packages/pipeline/src/scripts/pull_missing_blocks.ts49
-rw-r--r--packages/pipeline/src/types.ts11
-rw-r--r--packages/pipeline/src/utils/transformers/asset_proxy_id_types.ts20
-rw-r--r--packages/pipeline/src/utils/transformers/index.ts1
-rw-r--r--packages/pipeline/src/utils/transformers/number_to_bigint.ts8
-rw-r--r--packages/pipeline/test/entities/copper_test.ts54
-rw-r--r--packages/pipeline/test/entities/util.ts4
-rw-r--r--packages/pipeline/test/fixtures/copper/api_v1_activity_types.json24
-rw-r--r--packages/pipeline/test/fixtures/copper/api_v1_activity_types.ts16
-rw-r--r--packages/pipeline/test/fixtures/copper/api_v1_custom_field_definitions.json38
-rw-r--r--packages/pipeline/test/fixtures/copper/api_v1_custom_field_definitions.ts39
-rw-r--r--packages/pipeline/test/fixtures/copper/api_v1_list_activities.json242
-rw-r--r--packages/pipeline/test/fixtures/copper/api_v1_list_activities.ts305
-rw-r--r--packages/pipeline/test/fixtures/copper/api_v1_list_leads.json583
-rw-r--r--packages/pipeline/test/fixtures/copper/api_v1_list_leads.ts229
-rw-r--r--packages/pipeline/test/fixtures/copper/api_v1_list_opportunities.json662
-rw-r--r--packages/pipeline/test/fixtures/copper/api_v1_list_opportunities.ts425
-rw-r--r--packages/pipeline/test/fixtures/copper/parsed_entities.ts5
-rw-r--r--packages/pipeline/test/parsers/copper/index_test.ts87
-rw-r--r--packages/pipeline/test/parsers/ddex_orders/index_test.ts4
-rw-r--r--packages/pipeline/test/parsers/events/exchange_events_test.ts5
-rw-r--r--packages/pipeline/test/parsers/idex_orders/index_test.ts8
-rw-r--r--packages/pipeline/test/parsers/oasis_orders/index_test.ts4
-rw-r--r--packages/pipeline/test/parsers/paradex_orders/index_test.ts4
-rw-r--r--packages/pipeline/test/parsers/sra_orders/index_test.ts5
-rw-r--r--packages/pipeline/tsconfig.json12
-rw-r--r--packages/react-shared/CHANGELOG.json10
-rw-r--r--packages/react-shared/src/components/link.tsx13
-rw-r--r--packages/react-shared/src/index.ts2
-rw-r--r--packages/sol-compiler/CHANGELOG.json13
-rw-r--r--packages/sol-compiler/package.json4
-rw-r--r--packages/sol-compiler/src/cli.ts10
-rw-r--r--packages/sol-compiler/src/compiler.ts258
-rw-r--r--packages/sol-compiler/src/utils/compiler.ts217
-rw-r--r--packages/sol-compiler/src/utils/constants.ts3
-rw-r--r--packages/sol-compiler/src/utils/types.ts9
-rw-r--r--packages/sol-compiler/test/compiler_utils_test.ts6
-rw-r--r--packages/sol-resolver/CHANGELOG.json13
-rw-r--r--packages/sol-resolver/src/index.ts1
-rw-r--r--packages/sol-resolver/src/resolvers/fs_resolver.ts5
-rw-r--r--packages/sol-resolver/src/resolvers/name_resolver.ts10
-rw-r--r--packages/sol-resolver/src/resolvers/npm_resolver.ts5
-rw-r--r--packages/sol-resolver/src/resolvers/relative_fs_resolver.ts7
-rw-r--r--packages/sol-resolver/src/resolvers/spy_resolver.ts25
-rw-r--r--packages/sol-resolver/src/resolvers/url_resolver.ts5
-rw-r--r--packages/sol-resolver/src/types.ts1
-rw-r--r--packages/sra-spec/public/index.html4
-rw-r--r--packages/types/CHANGELOG.json13
-rw-r--r--packages/types/src/index.ts32
-rw-r--r--packages/typescript-typings/tsconfig.json3
-rw-r--r--packages/utils/CHANGELOG.json18
-rw-r--r--packages/utils/package.json1
-rw-r--r--packages/utils/src/abi_encoder/abstract_data_types/types/set.ts2
-rw-r--r--packages/utils/src/abi_encoder/calldata/calldata.ts6
-rw-r--r--packages/utils/src/abi_encoder/utils/constants.ts4
-rw-r--r--packages/utils/src/abi_encoder/utils/rules.ts6
-rw-r--r--packages/utils/src/log_utils.ts5
-rw-r--r--packages/utils/test/abi_encoder/evm_data_types_test.ts16
-rw-r--r--packages/utils/test/abi_encoder/methods_test.ts4
-rw-r--r--packages/utils/test/abi_encoder/optimizer_test.ts4
-rw-r--r--packages/utils/test/abi_encoder/return_values_test.ts2
-rw-r--r--packages/website/.gitignore1
-rw-r--r--packages/website/README.md4
-rw-r--r--packages/website/less/all.less2
-rw-r--r--packages/website/less/normalize.less349
-rw-r--r--packages/website/md/docs/0xjs/0.0.1/installation.md2
-rw-r--r--packages/website/md/docs/0xjs/1.0.1/installation.md2
-rw-r--r--packages/website/md/docs/0xjs/2.0.0/installation.md2
-rw-r--r--packages/website/md/docs/asset_buyer/introduction.md2
-rw-r--r--packages/website/md/docs/connect/1/installation.md2
-rw-r--r--packages/website/md/docs/connect/3/installation.md2
-rw-r--r--packages/website/md/docs/migrations/1/introduction.md2
-rw-r--r--packages/website/md/docs/smart_contracts/2/introduction.md2
-rw-r--r--packages/website/md/docs/sol_cov/1/usage.md4
-rw-r--r--packages/website/md/docs/sol_cov/2/usage.md4
-rw-r--r--packages/website/md/docs/subproviders/1/introduction.md2
-rw-r--r--packages/website/package.json41
-rw-r--r--packages/website/public/css/formular.css45
-rw-r--r--packages/website/public/fonts/Formular-Light.woffbin0 -> 44630 bytes
-rw-r--r--packages/website/public/fonts/Formular-Light.woff2bin0 -> 34337 bytes
-rw-r--r--packages/website/public/fonts/Formular-Regular.woffbin0 -> 45102 bytes
-rw-r--r--packages/website/public/fonts/Formular-Regular.woff2bin0 -> 34607 bytes
-rw-r--r--packages/website/public/images/0x-instant/0x-instant-widgets.pngbin0 -> 64041 bytes
-rw-r--r--packages/website/public/images/0x-instant/0x-instant-widgets@2x.pngbin0 -> 190593 bytes
-rwxr-xr-xpackages/website/public/images/0x-instant/widget-1.pngbin0 -> 27160 bytes
-rwxr-xr-xpackages/website/public/images/0x-instant/widget-2.pngbin0 -> 47878 bytes
-rwxr-xr-xpackages/website/public/images/0x-instant/widget-3.pngbin0 -> 27505 bytes
-rwxr-xr-xpackages/website/public/images/0x-instant/widget-4.pngbin0 -> 30727 bytes
-rwxr-xr-xpackages/website/public/images/0x-instant/widget-5.pngbin0 -> 144454 bytes
-rwxr-xr-xpackages/website/public/images/0x-instant/widget-6.pngbin0 -> 28382 bytes
-rwxr-xr-xpackages/website/public/images/about/about-office.pngbin0 -> 474673 bytes
-rw-r--r--packages/website/public/images/advisors/david.pngbin29962 -> 0 bytes
-rw-r--r--packages/website/public/images/advisors/fred.jpgbin4619 -> 0 bytes
-rw-r--r--packages/website/public/images/advisors/joey.jpgbin13493 -> 0 bytes
-rw-r--r--packages/website/public/images/advisors/linda.jpgbin6580 -> 0 bytes
-rw-r--r--packages/website/public/images/advisors/olaf.pngbin26365 -> 0 bytes
-rw-r--r--packages/website/public/images/banner/bottomofcta.pngbin0 -> 15803 bytes
-rw-r--r--packages/website/public/images/banner/topofcta.pngbin0 -> 13342 bytes
-rw-r--r--packages/website/public/images/clients/bamboo.svg17
-rw-r--r--packages/website/public/images/clients/emoon.svg8
-rw-r--r--packages/website/public/images/clients/ercdex.svg16
-rw-r--r--packages/website/public/images/clients/godsUnchained.svg16
-rw-r--r--packages/website/public/images/clients/instex.svg40
-rw-r--r--packages/website/public/images/clients/laketrade.svg13
-rw-r--r--packages/website/public/images/clients/ledgerdex.svg19
-rw-r--r--packages/website/public/images/clients/openrelay.svg22
-rw-r--r--packages/website/public/images/clients/paradex.svg9
-rw-r--r--packages/website/public/images/clients/radar-relay.svg13
-rw-r--r--packages/website/public/images/clients/sharkrelay.svg32
-rw-r--r--packages/website/public/images/clients/starbitex.svg22
-rw-r--r--packages/website/public/images/clients/tokenjar.svg13
-rw-r--r--packages/website/public/images/clients/veil.svg4
-rw-r--r--packages/website/public/images/events/berlin.jpgbin0 -> 108690 bytes
-rw-r--r--packages/website/public/images/events/event-sample.jpgbin0 -> 24594 bytes
-rw-r--r--packages/website/public/images/events/london.jpgbin0 -> 138979 bytes
-rw-r--r--packages/website/public/images/events/sf.jpgbin0 -> 108324 bytes
-rw-r--r--packages/website/public/images/instant/dai_screenshot.pngbin105373 -> 0 bytes
-rw-r--r--packages/website/public/images/instant/feature_1.svg33
-rw-r--r--packages/website/public/images/instant/feature_2.svg15
-rw-r--r--packages/website/public/images/instant/feature_3.svg195
-rw-r--r--packages/website/public/images/instant/gnt_screenshot.pngbin106656 -> 0 bytes
-rw-r--r--packages/website/public/images/instant/gods_screenshot.pngbin585005 -> 0 bytes
-rw-r--r--packages/website/public/images/instant/kitty_screenshot.pngbin208899 -> 0 bytes
-rw-r--r--packages/website/public/images/instant/nmr_screenshot.pngbin104794 -> 0 bytes
-rw-r--r--packages/website/public/images/instant/rep_screenshot.pngbin106740 -> 0 bytes
-rw-r--r--packages/website/public/images/jobs/calendar-icon.svg15
-rw-r--r--packages/website/public/images/jobs/heart-icon.svg3
-rw-r--r--packages/website/public/images/jobs/hero-dots-left.svg17
-rw-r--r--packages/website/public/images/jobs/hero-dots-right.svg16
-rw-r--r--packages/website/public/images/jobs/map@2x.pngbin0 -> 27904 bytes
-rw-r--r--packages/website/public/images/jobs/ship-icon.svg6
-rw-r--r--packages/website/public/images/jobs/world-map.svg64
-rw-r--r--packages/website/public/images/og_image.pngbin192500 -> 51927 bytes
-rw-r--r--packages/website/public/images/press/logo-forbes.pngbin0 -> 2420 bytes
-rw-r--r--packages/website/public/images/press/logo-fortune.pngbin0 -> 1800 bytes
-rw-r--r--packages/website/public/images/press/logo-techcrunch.pngbin0 -> 2332 bytes
-rw-r--r--packages/website/public/images/press/logo-venturebeat.pngbin0 -> 2660 bytes
-rwxr-xr-xpackages/website/public/images/relayer-logos/logo.pngbin0 -> 6758 bytes
-rwxr-xr-xpackages/website/public/images/relayer-logos/logo_1.pngbin0 -> 7951 bytes
-rwxr-xr-xpackages/website/public/images/relayer-logos/logo_2.1.pngbin0 -> 4942 bytes
-rwxr-xr-xpackages/website/public/images/relayer-logos/logo_2.2.pngbin0 -> 5115 bytes
-rwxr-xr-xpackages/website/public/images/relayer-logos/logo_2.3.pngbin0 -> 8685 bytes
-rwxr-xr-xpackages/website/public/images/relayer-logos/logo_2.pngbin0 -> 6479 bytes
-rwxr-xr-xpackages/website/public/images/relayer-logos/logo_3.pngbin0 -> 7888 bytes
-rwxr-xr-xpackages/website/public/images/relayer-logos/logo_4.pngbin0 -> 9083 bytes
-rwxr-xr-xpackages/website/public/images/relayer-logos/logo_5.pngbin0 -> 5768 bytes
-rwxr-xr-xpackages/website/public/images/team/advisors/davids.jpgbin0 -> 25263 bytes
-rwxr-xr-xpackages/website/public/images/team/advisors/frede.jpgbin0 -> 17015 bytes
-rwxr-xr-xpackages/website/public/images/team/advisors/joeyk.jpgbin0 -> 23496 bytes
-rwxr-xr-xpackages/website/public/images/team/advisors/lindax.jpgbin0 -> 20576 bytes
-rwxr-xr-xpackages/website/public/images/team/advisors/olafc.jpgbin0 -> 18024 bytes
-rw-r--r--packages/website/public/images/team/alex.jpgbin7271 -> 0 bytes
-rwxr-xr-xpackages/website/public/images/team/alexb.jpgbin0 -> 17441 bytes
-rw-r--r--packages/website/public/images/team/alexbrowne.pngbin146699 -> 0 bytes
-rwxr-xr-xpackages/website/public/images/team/alexv.jpgbin0 -> 16969 bytes
-rw-r--r--packages/website/public/images/team/amir.pngbin116488 -> 0 bytes
-rwxr-xr-xpackages/website/public/images/team/amirb.jpgbin0 -> 21075 bytes
-rw-r--r--packages/website/public/images/team/anyone.pngbin4794 -> 0 bytes
-rw-r--r--packages/website/public/images/team/ben.jpgbin25486 -> 0 bytes
-rwxr-xr-xpackages/website/public/images/team/benb.jpgbin0 -> 17571 bytes
-rwxr-xr-x[-rw-r--r--]packages/website/public/images/team/blake.jpgbin29743 -> 17515 bytes
-rw-r--r--packages/website/public/images/team/brandon.pngbin30180 -> 0 bytes
-rwxr-xr-xpackages/website/public/images/team/brandonm.jpgbin0 -> 18765 bytes
-rw-r--r--packages/website/public/images/team/chris.pngbin96388 -> 0 bytes
-rwxr-xr-xpackages/website/public/images/team/chrisk.jpgbin0 -> 16316 bytes
-rw-r--r--packages/website/public/images/team/clay.pngbin85774 -> 0 bytes
-rwxr-xr-xpackages/website/public/images/team/clayr.jpgbin0 -> 17222 bytes
-rwxr-xr-xpackages/website/public/images/team/eugenea.jpgbin0 -> 23527 bytes
-rw-r--r--packages/website/public/images/team/fabio.jpgbin17125 -> 0 bytes
-rwxr-xr-xpackages/website/public/images/team/fabiob.jpgbin0 -> 15358 bytes
-rw-r--r--packages/website/public/images/team/fragosti.pngbin26209 -> 0 bytes
-rwxr-xr-xpackages/website/public/images/team/francesco.jpgbin0 -> 17467 bytes
-rw-r--r--packages/website/public/images/team/gene.jpgbin44173 -> 0 bytes
-rw-r--r--packages/website/public/images/team/greg.jpegbin4100 -> 0 bytes
-rwxr-xr-xpackages/website/public/images/team/greg.jpgbin0 -> 21163 bytes
-rw-r--r--packages/website/public/images/team/jacob.jpgbin27088 -> 0 bytes
-rwxr-xr-xpackages/website/public/images/team/jacobe.jpgbin0 -> 28977 bytes
-rw-r--r--packages/website/public/images/team/jason.pngbin45572 -> 0 bytes
-rwxr-xr-xpackages/website/public/images/team/jasons.jpgbin0 -> 20455 bytes
-rw-r--r--packages/website/public/images/team/leonid.pngbin35014 -> 0 bytes
-rwxr-xr-xpackages/website/public/images/team/leonidL.jpgbin0 -> 14413 bytes
-rw-r--r--packages/website/public/images/team/matt.jpgbin769216 -> 0 bytes
-rwxr-xr-xpackages/website/public/images/team/mattt.jpgbin0 -> 18348 bytes
-rw-r--r--packages/website/public/images/team/mel.pngbin110351 -> 0 bytes
-rwxr-xr-xpackages/website/public/images/team/melo.jpgbin0 -> 19188 bytes
-rw-r--r--packages/website/public/images/team/peter.jpgbin26748 -> 0 bytes
-rwxr-xr-xpackages/website/public/images/team/peterz.jpgbin0 -> 30404 bytes
-rw-r--r--packages/website/public/images/team/rahul.pngbin29636 -> 0 bytes
-rwxr-xr-xpackages/website/public/images/team/rahuls.jpgbin0 -> 21412 bytes
-rw-r--r--packages/website/public/images/team/remco.jpegbin14807 -> 0 bytes
-rwxr-xr-xpackages/website/public/images/team/remcoB.jpgbin0 -> 24435 bytes
-rw-r--r--packages/website/public/images/team/steve.pngbin49008 -> 0 bytes
-rwxr-xr-xpackages/website/public/images/team/steveK.jpgbin0 -> 39082 bytes
-rw-r--r--packages/website/public/images/team/tom.jpgbin14565 -> 0 bytes
-rwxr-xr-xpackages/website/public/images/team/toms.jpgbin0 -> 13682 bytes
-rwxr-xr-xpackages/website/public/images/team/weijew.jpgbin0 -> 22031 bytes
-rw-r--r--packages/website/public/images/team/weijie.pngbin38401 -> 0 bytes
-rw-r--r--packages/website/public/images/team/will.jpgbin11493 -> 0 bytes
-rwxr-xr-xpackages/website/public/images/team/willw.jpgbin0 -> 25440 bytes
-rwxr-xr-xpackages/website/public/images/team/xianny.jpgbin0 -> 29992 bytes
-rw-r--r--packages/website/public/images/team/xianny.pngbin49783 -> 0 bytes
-rw-r--r--packages/website/public/images/team/zach.pngbin119387 -> 0 bytes
-rwxr-xr-xpackages/website/public/images/team/zack.jpgbin0 -> 19292 bytes
-rw-r--r--packages/website/public/index.html3
-rw-r--r--packages/website/translations/chinese.json2
-rw-r--r--packages/website/translations/english.json2
-rw-r--r--packages/website/translations/korean.json2
-rw-r--r--packages/website/translations/russian.json2
-rw-r--r--packages/website/translations/spanish.json2
-rw-r--r--packages/website/ts/components/aboutPageLayout.tsx71
-rw-r--r--packages/website/ts/components/animatedChatIcon.tsx106
-rw-r--r--packages/website/ts/components/animatedCompassIcon.tsx53
-rw-r--r--packages/website/ts/components/banner.tsx147
-rw-r--r--packages/website/ts/components/blockIconLink.tsx84
-rw-r--r--packages/website/ts/components/button.tsx107
-rw-r--r--packages/website/ts/components/chapter_link.tsx15
-rw-r--r--packages/website/ts/components/definition.tsx145
-rw-r--r--packages/website/ts/components/dialogs/u2f_not_supported_dialog.tsx46
-rw-r--r--packages/website/ts/components/dialogs/wrapped_eth_section_notice_dialog.tsx33
-rw-r--r--packages/website/ts/components/documentation/sidebar_header.tsx16
-rw-r--r--packages/website/ts/components/dropdowns/dropdown_developers.tsx184
-rw-r--r--packages/website/ts/components/dropdowns/dropdown_products.tsx48
-rw-r--r--packages/website/ts/components/eth_wrappers.tsx2
-rw-r--r--packages/website/ts/components/fill_warning_dialog.tsx2
-rw-r--r--packages/website/ts/components/footer.tsx368
-rw-r--r--packages/website/ts/components/forms/subscribe_form.tsx127
-rw-r--r--packages/website/ts/components/hamburger.tsx72
-rw-r--r--packages/website/ts/components/header.tsx252
-rw-r--r--packages/website/ts/components/hero.tsx152
-rw-r--r--packages/website/ts/components/heroAnimation.tsx123
-rw-r--r--packages/website/ts/components/heroImage.tsx27
-rw-r--r--packages/website/ts/components/icon.tsx72
-rw-r--r--packages/website/ts/components/image.tsx20
-rw-r--r--packages/website/ts/components/link.tsx64
-rw-r--r--packages/website/ts/components/logo.tsx41
-rw-r--r--packages/website/ts/components/mobileNav.tsx121
-rw-r--r--packages/website/ts/components/modals/input.tsx95
-rw-r--r--packages/website/ts/components/modals/modal_contact.tsx395
-rw-r--r--packages/website/ts/components/newLayout.tsx152
-rw-r--r--packages/website/ts/components/newsletter_form.tsx202
-rw-r--r--packages/website/ts/components/old_footer.tsx228
-rw-r--r--packages/website/ts/components/onboarding/onboarding_flow.tsx4
-rw-r--r--packages/website/ts/components/redirector.tsx9
-rw-r--r--packages/website/ts/components/sections/landing/about.tsx81
-rw-r--r--packages/website/ts/components/sections/landing/clients.tsx113
-rw-r--r--packages/website/ts/components/sections/landing/cta.tsx29
-rw-r--r--packages/website/ts/components/sections/landing/hero.tsx31
-rw-r--r--packages/website/ts/components/siteWrap.tsx149
-rw-r--r--packages/website/ts/components/slider/slider.tsx177
-rw-r--r--packages/website/ts/components/text.tsx83
-rw-r--r--packages/website/ts/components/ui/animation.tsx42
-rw-r--r--packages/website/ts/components/ui/container.tsx1
-rw-r--r--packages/website/ts/components/ui/ease_up_from_bottom_animation.tsx31
-rw-r--r--packages/website/ts/components/ui/filled_image.tsx18
-rw-r--r--packages/website/ts/components/ui/input.tsx49
-rw-r--r--packages/website/ts/components/ui/select.tsx170
-rw-r--r--packages/website/ts/components/ui/simple_loading.tsx17
-rw-r--r--packages/website/ts/components/ui/text.tsx1
-rw-r--r--packages/website/ts/components/ui/typed_text.tsx75
-rw-r--r--packages/website/ts/constants/.gitkeep (renamed from python-packages/order_utils/stubs/jsonschema/exceptions.pyi)0
-rw-r--r--packages/website/ts/constants/animations.tsx18
-rw-r--r--packages/website/ts/constants/cssReset.js50
-rw-r--r--packages/website/ts/constants/globalStyle.tsx109
-rw-r--r--packages/website/ts/constants/utilities.tsx22
-rw-r--r--packages/website/ts/containers/about.ts25
-rw-r--r--packages/website/ts/containers/instant.ts30
-rw-r--r--packages/website/ts/containers/jobs.ts28
-rw-r--r--packages/website/ts/containers/landing.ts27
-rw-r--r--packages/website/ts/containers/launch_kit.ts27
-rw-r--r--packages/website/ts/containers/order_watcher_documentation.ts2
-rw-r--r--packages/website/ts/globals.d.ts13
-rwxr-xr-xpackages/website/ts/icons/illustrations/0x.svg14
-rwxr-xr-xpackages/website/ts/icons/illustrations/buildBusiness.svg6
-rw-r--r--packages/website/ts/icons/illustrations/checkmark.svg1
-rw-r--r--packages/website/ts/icons/illustrations/code-repo.svg7
-rw-r--r--packages/website/ts/icons/illustrations/coin.svg1
-rw-r--r--packages/website/ts/icons/illustrations/consistently-ship.svg6
-rw-r--r--packages/website/ts/icons/illustrations/customize.svg1
-rwxr-xr-xpackages/website/ts/icons/illustrations/decentralisedLoans.svg13
-rwxr-xr-xpackages/website/ts/icons/illustrations/description.svg21
-rwxr-xr-xpackages/website/ts/icons/illustrations/descriptionBolt.svg4
-rwxr-xr-xpackages/website/ts/icons/illustrations/descriptionCoin.svg9
-rwxr-xr-xpackages/website/ts/icons/illustrations/descriptionCopy.svg7
-rwxr-xr-xpackages/website/ts/icons/illustrations/descriptionFlask.svg7
-rwxr-xr-xpackages/website/ts/icons/illustrations/eficientDesign.svg11
-rw-r--r--packages/website/ts/icons/illustrations/eth-based-tokens.svg6
-rwxr-xr-xpackages/website/ts/icons/illustrations/extensibleArchitecture.svg11
-rwxr-xr-xpackages/website/ts/icons/illustrations/flexibleIntegration.svg12
-rwxr-xr-xpackages/website/ts/icons/illustrations/flexibleIntegration0xInstant.svg17
-rwxr-xr-xpackages/website/ts/icons/illustrations/flexibleOrders.svg4
-rwxr-xr-xpackages/website/ts/icons/illustrations/gamingAndCollectibles.svg18
-rwxr-xr-xpackages/website/ts/icons/illustrations/generateRevenueForYourBusiness-large.svg28
-rwxr-xr-xpackages/website/ts/icons/illustrations/getInTouch.svg13
-rw-r--r--packages/website/ts/icons/illustrations/getStarted.svg13
-rw-r--r--packages/website/ts/icons/illustrations/launchKit.svg18
-rwxr-xr-xpackages/website/ts/icons/illustrations/launchKit_versionB.svg7
-rwxr-xr-xpackages/website/ts/icons/illustrations/legalResources.svg4
-rw-r--r--packages/website/ts/icons/illustrations/logo-mark.svg6
-rw-r--r--packages/website/ts/icons/illustrations/logo-outlined.svg14
-rw-r--r--packages/website/ts/icons/illustrations/long-term-impact.svg9
-rw-r--r--packages/website/ts/icons/illustrations/low-cost.svg30
-rwxr-xr-xpackages/website/ts/icons/illustrations/marketingDesignHelp.svg11
-rwxr-xr-xpackages/website/ts/icons/illustrations/milestoneGrants.svg7
-rwxr-xr-xpackages/website/ts/icons/illustrations/networkedLiquidity-small.svg20
-rwxr-xr-xpackages/website/ts/icons/illustrations/networkedLiquidity.svg28
-rwxr-xr-xpackages/website/ts/icons/illustrations/orderBooks.svg8
-rwxr-xr-xpackages/website/ts/icons/illustrations/predictionMarkets.svg7
-rw-r--r--packages/website/ts/icons/illustrations/protocol.svg1
-rw-r--r--packages/website/ts/icons/illustrations/ready-to-build.svg1
-rwxr-xr-xpackages/website/ts/icons/illustrations/recruitingSupport.svg7
-rw-r--r--packages/website/ts/icons/illustrations/right-thing.svg6
-rwxr-xr-xpackages/website/ts/icons/illustrations/robustSmartContracts.svg6
-rw-r--r--packages/website/ts/icons/illustrations/rocketship.svg9
-rwxr-xr-xpackages/website/ts/icons/illustrations/secureTrading.svg15
-rw-r--r--packages/website/ts/icons/illustrations/social-discord.svg3
-rw-r--r--packages/website/ts/icons/illustrations/social-fb.svg3
-rw-r--r--packages/website/ts/icons/illustrations/social-github.svg3
-rw-r--r--packages/website/ts/icons/illustrations/social-newsletter.svg3
-rw-r--r--packages/website/ts/icons/illustrations/social-reddit.svg3
-rw-r--r--packages/website/ts/icons/illustrations/social-twitter.svg3
-rwxr-xr-xpackages/website/ts/icons/illustrations/stableTokens.svg10
-rwxr-xr-xpackages/website/ts/icons/illustrations/standardForExchange.svg12
-rw-r--r--packages/website/ts/icons/illustrations/support.svg1
-rwxr-xr-xpackages/website/ts/icons/illustrations/supportForAllEthereumStandards-large.svg28
-rwxr-xr-xpackages/website/ts/icons/illustrations/supportForAllEthereumStandards.svg21
-rwxr-xr-xpackages/website/ts/icons/illustrations/techSupport.svg13
-rw-r--r--packages/website/ts/icons/illustrations/tokens.svg1
-rwxr-xr-xpackages/website/ts/icons/illustrations/vcIntroductions.svg11
-rw-r--r--packages/website/ts/icons/logo-with-type.svg1
-rw-r--r--packages/website/ts/index.tsx49
-rw-r--r--packages/website/ts/pages/about/about.tsx421
-rw-r--r--packages/website/ts/pages/about/jobs.tsx236
-rw-r--r--packages/website/ts/pages/about/mission.tsx97
-rw-r--r--packages/website/ts/pages/about/press.tsx94
-rw-r--r--packages/website/ts/pages/about/profile.tsx80
-rw-r--r--packages/website/ts/pages/about/team.tsx286
-rw-r--r--packages/website/ts/pages/community.tsx289
-rw-r--r--packages/website/ts/pages/documentation/docs_home.tsx10
-rw-r--r--packages/website/ts/pages/ecosystem.tsx128
-rw-r--r--packages/website/ts/pages/faq/faq.tsx2
-rw-r--r--packages/website/ts/pages/instant.tsx261
-rw-r--r--packages/website/ts/pages/instant/action_link.tsx46
-rw-r--r--packages/website/ts/pages/instant/code_demo.tsx30
-rw-r--r--packages/website/ts/pages/instant/config_generator.tsx79
-rw-r--r--packages/website/ts/pages/instant/config_generator_address_input.tsx55
-rw-r--r--packages/website/ts/pages/instant/configurator.tsx72
-rw-r--r--packages/website/ts/pages/instant/features.tsx115
-rw-r--r--packages/website/ts/pages/instant/fee_percentage_slider.tsx77
-rw-r--r--packages/website/ts/pages/instant/instant.tsx87
-rw-r--r--packages/website/ts/pages/instant/introducing_0x_instant.tsx57
-rw-r--r--packages/website/ts/pages/instant/need_more.tsx62
-rw-r--r--packages/website/ts/pages/instant/rc-slider.css295
-rw-r--r--packages/website/ts/pages/instant/screenshots.tsx35
-rw-r--r--packages/website/ts/pages/instant/select.tsx74
-rw-r--r--packages/website/ts/pages/jobs/benefits.tsx158
-rw-r--r--packages/website/ts/pages/jobs/jobs.tsx71
-rw-r--r--packages/website/ts/pages/jobs/join_0x.tsx64
-rw-r--r--packages/website/ts/pages/jobs/mission.tsx47
-rw-r--r--packages/website/ts/pages/jobs/open_positions.tsx179
-rw-r--r--packages/website/ts/pages/jobs/photo_rail.tsx22
-rw-r--r--packages/website/ts/pages/landing.tsx44
-rw-r--r--packages/website/ts/pages/landing/landing.tsx620
-rw-r--r--packages/website/ts/pages/launch_kit.tsx125
-rw-r--r--packages/website/ts/pages/launch_kit/launch_kit.tsx335
-rw-r--r--packages/website/ts/pages/market_maker.tsx162
-rw-r--r--packages/website/ts/pages/not_found.tsx2
-rw-r--r--packages/website/ts/pages/why.tsx309
-rw-r--r--packages/website/ts/style/colors.ts8
-rw-r--r--packages/website/ts/style/theme.ts4
-rw-r--r--packages/website/ts/types.ts8
-rw-r--r--packages/website/ts/utils/configs.ts4
-rw-r--r--packages/website/ts/utils/constants.ts12
-rw-r--r--packages/website/tsconfig.json4
-rw-r--r--packages/website/webpack.config.js29
-rw-r--r--python-packages/json_schemas/.discharge.json13
-rw-r--r--python-packages/json_schemas/.pylintrc3
-rw-r--r--python-packages/json_schemas/README.md45
-rwxr-xr-xpython-packages/json_schemas/setup.py191
-rw-r--r--python-packages/json_schemas/src/conf.py54
-rw-r--r--python-packages/json_schemas/src/doc_static/.gitkeep0
-rw-r--r--python-packages/json_schemas/src/index.rst18
-rw-r--r--python-packages/json_schemas/src/zero_ex/__init__.py2
-rw-r--r--python-packages/json_schemas/src/zero_ex/json_schemas/__init__.py (renamed from python-packages/order_utils/src/zero_ex/json_schemas/__init__.py)51
-rw-r--r--python-packages/json_schemas/src/zero_ex/json_schemas/py.typed0
l---------python-packages/json_schemas/src/zero_ex/json_schemas/schemas (renamed from python-packages/order_utils/src/zero_ex/json_schemas/schemas)0
-rw-r--r--python-packages/json_schemas/stubs/distutils/__init__.pyi0
-rw-r--r--python-packages/json_schemas/stubs/distutils/command/__init__.pyi0
-rw-r--r--python-packages/json_schemas/stubs/distutils/command/clean.pyi7
-rw-r--r--python-packages/json_schemas/stubs/jsonschema/__init__.pyi (renamed from python-packages/order_utils/stubs/jsonschema/__init__.pyi)0
-rw-r--r--python-packages/json_schemas/stubs/jsonschema/exceptions.pyi0
-rw-r--r--python-packages/json_schemas/stubs/pytest/__init__.pyi0
-rw-r--r--python-packages/json_schemas/stubs/pytest/raises.pyi1
-rw-r--r--python-packages/json_schemas/stubs/setuptools/__init__.pyi8
-rw-r--r--python-packages/json_schemas/stubs/setuptools/command/__init__.pyi0
-rw-r--r--python-packages/json_schemas/stubs/setuptools/command/test.pyi3
-rw-r--r--python-packages/json_schemas/stubs/stringcase/__init__.pyi2
-rw-r--r--python-packages/json_schemas/test/__init__.py1
-rw-r--r--python-packages/json_schemas/test/test_doctest.py25
-rw-r--r--python-packages/json_schemas/test/test_json_schemas.py (renamed from python-packages/order_utils/test/test_json_schemas.py)22
-rw-r--r--python-packages/json_schemas/tox.ini25
-rwxr-xr-xpython-packages/order_utils/setup.py3
-rw-r--r--python-packages/order_utils/src/index.rst3
-rw-r--r--python-packages/order_utils/stubs/web3/__init___BASE_31011.pyi26
-rw-r--r--python-packages/sra_client/README.md29
-rw-r--r--python-packages/sra_client/tox.ini14
-rw-r--r--yarn.lock559
643 files changed, 20768 insertions, 4950 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 12d82693c..0206c514e 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -200,14 +200,25 @@ jobs:
key: deps9-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
- run:
command: |
+ cd python-packages/json_schemas
+ python -m ensurepip
+ python -m pip install .[dev]
+ # HACK! installing the package should do the following
+ # copy for us, but it's not working in CircleCI for some
+ # reason. Zendesk support ticket raised (#43979) with
+ # CircleCI.
+ mkdir /usr/local/lib/python3.7/site-packages/zero_ex/json_schemas/schemas
+ cp -R src/zero_ex/json_schemas/schemas/* /usr/local/lib/python3.7/site-packages/zero_ex/json_schemas/schemas
+ - run:
+ command: |
cd python-packages/order_utils
python -m ensurepip
- python -m pip install -e .[dev]
+ python -m pip install .[dev]
- run:
command: |
cd python-packages/sra_client
python -m ensurepip
- python -m pip install -e .
+ python -m pip install .[dev]
- save_cache:
key: deps9-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
paths:
@@ -219,6 +230,10 @@ jobs:
- '.tox'
- run:
command: |
+ cd python-packages/json_schemas
+ coverage run setup.py test
+ - run:
+ command: |
cd python-packages/order_utils
coverage run setup.py test
- run:
@@ -226,6 +241,10 @@ jobs:
cd python-packages/sra_client
coverage run setup.py test
- save_cache:
+ key: coverage-python-json-schemas-{{ .Environment.CIRCLE_SHA1 }}
+ paths:
+ - ~/repo/python-packages/json_schemas/.coverage
+ - save_cache:
key: coverage-python-order-utils-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/python-packages/order_utils/.coverage
@@ -247,7 +266,7 @@ jobs:
command: |
cd python-packages/order_utils
python -m ensurepip
- python -m pip install -e .[dev]
+ python -m pip install .
- save_cache:
key: deps9-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
paths:
@@ -273,9 +292,14 @@ jobs:
key: deps9-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
- run:
command: |
+ cd python-packages/json_schemas
+ python -m ensurepip
+ python -m pip install .[dev]
+ - run:
+ command: |
cd python-packages/order_utils
python -m ensurepip
- python -m pip install -e .[dev]
+ python -m pip install .[dev]
- save_cache:
key: deps9-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
paths:
@@ -283,6 +307,10 @@ jobs:
- '/usr/local/lib/python3.7/site-packages'
- run:
command: |
+ cd python-packages/json_schemas
+ python setup.py lint
+ - run:
+ command: |
cd python-packages/order_utils
python setup.py lint
static-tests:
@@ -355,6 +383,9 @@ jobs:
- coverage-contracts-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
+ - coverage-python-json-schemas-{{ .Environment.CIRCLE_SHA1 }}
+ - restore_cache:
+ keys:
- coverage-python-order-utils-{{ .Environment.CIRCLE_SHA1 }}
- run: yarn report_coverage
workflows:
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/.prettierignore b/.prettierignore
index 7f8662b0a..d0be9ca09 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -20,10 +20,13 @@ lib
/packages/contract-artifacts/artifacts
/python-packages/order_utils/src/zero_ex/contract_artifacts/artifacts
/packages/json-schemas/schemas
-/python-packages/order_utils/src/zero_ex/json_schemas/schemas
+/python-packages/json_schemas/src/zero_ex/json_schemas/schemas
/packages/metacoin/src/contract_wrappers
/packages/metacoin/artifacts
/packages/sra-spec/public/
package.json
scripts/postpublish_utils.js
packages/sol-cov/test/fixtures/artifacts
+.pytest_cache
+.mypy_cache
+.tox
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/README.md b/README.md
index fd96c2b86..30f78b504 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-<img src="https://github.com/0xProject/branding/blob/master/0x_Black_CMYK.png" width="200px" >
+<img src="https://github.com/0xProject/branding/blob/master/0x%20Logo/PNG/0x-Logo-Black.png" width="150px" >
---
@@ -24,10 +24,11 @@ Visit our [developer portal](https://0xproject.com/docs/order-utils) for a compr
### Python Packages
-| Package | Version | Description |
-| ------------------------------------------------ | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
-| [`0x-order-utils`](/python-packages/order_utils) | [![PyPI](https://img.shields.io/pypi/v/0x-order-utils.svg)](https://pypi.org/project/0x-order-utils/) | A set of utilities for generating, parsing, signing and validating 0x orders |
-| [`0x-sra-client`](/python-packages/sra_client) | [![PyPI](https://img.shields.io/pypi/v/0x-sra-client.svg)](https://pypi.org/project/0x-sra-client/) | A Python client for interacting with servers conforming to the Standard Relayer API specification |
+| Package | Version | Description |
+| -------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
+| [`0x-json-schemas`](/python-packages/json_schemas) | [![PyPI](https://img.shields.io/pypi/v/0x-json-schemas.svg)](https://pypi.org/project/0x-json-schemas/) | 0x-related JSON schemas |
+| [`0x-order-utils`](/python-packages/order_utils) | [![PyPI](https://img.shields.io/pypi/v/0x-order-utils.svg)](https://pypi.org/project/0x-order-utils/) | A set of utilities for generating, parsing, signing and validating 0x orders |
+| [`0x-sra-client`](/python-packages/sra_client) | [![PyPI](https://img.shields.io/pypi/v/0x-sra-client.svg)](https://pypi.org/project/0x-sra-client/) | A Python client for interacting with servers conforming to the Standard Relayer API specification |
### Typescript/Javascript Packages
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..40e25565e 100644
--- a/contracts/extensions/CHANGELOG.json
+++ b/contracts/extensions/CHANGELOG.json
@@ -1,5 +1,31 @@
[
{
+ "version": "1.2.0",
+ "changes": [
+ {
+ "note": "Added Dutch Auction Wrapper",
+ "pr": 1465
+ }
+ ]
+ },
+ {
+ "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..aee995645 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",
@@ -44,6 +45,7 @@
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
"devDependencies": {
"@0x/abi-gen": "^1.0.19",
+ "@0x/contract-wrappers": "^4.1.3",
"@0x/contracts-test-utils": "^1.0.2",
"@0x/dev-utils": "^1.0.21",
"@0x/sol-compiler": "^1.1.16",
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/dutch_auction.ts b/contracts/extensions/test/extensions/dutch_auction.ts
index 6c3b2f0f3..22b3caa16 100644
--- a/contracts/extensions/test/extensions/dutch_auction.ts
+++ b/contracts/extensions/test/extensions/dutch_auction.ts
@@ -1,3 +1,4 @@
+import { DutchAuctionWrapper } from '@0x/contract-wrappers';
import {
artifacts as protocolArtifacts,
ERC20Wrapper,
@@ -29,12 +30,11 @@ import { RevertReason, SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import * as chai from 'chai';
-import ethAbi = require('ethereumjs-abi');
-import * as ethUtil from 'ethereumjs-util';
import * as _ from 'lodash';
import { DutchAuctionContract } from '../../generated-wrappers/dutch_auction';
import { artifacts } from '../../src/artifacts';
+import { DutchAuctionTestWrapper } from '../utils/dutch_auction_test_wrapper';
chaiSetup.configure();
const expect = chai.expect;
@@ -68,19 +68,8 @@ describe(ContractName.DutchAuction, () => {
let erc721MakerAssetIds: BigNumber[];
const tenMinutesInSeconds = 10 * 60;
- function extendMakerAssetData(makerAssetData: string, beginTimeSeconds: BigNumber, beginAmount: BigNumber): string {
- return ethUtil.bufferToHex(
- Buffer.concat([
- ethUtil.toBuffer(makerAssetData),
- ethUtil.toBuffer(
- (ethAbi as any).rawEncode(
- ['uint256', 'uint256'],
- [beginTimeSeconds.toString(), beginAmount.toString()],
- ),
- ),
- ]),
- );
- }
+ let dutchAuctionTestWrapper: DutchAuctionTestWrapper;
+ let defaultERC20MakerAssetData: string;
before(async () => {
await blockchainLifecycle.startAsync();
@@ -136,6 +125,7 @@ describe(ContractName.DutchAuction, () => {
dutchAuctionInstance.address,
provider,
);
+ dutchAuctionTestWrapper = new DutchAuctionTestWrapper(dutchAuctionInstance, provider);
defaultMakerAssetAddress = erc20TokenA.address;
const defaultTakerAssetAddress = wethContract.address;
@@ -174,7 +164,7 @@ describe(ContractName.DutchAuction, () => {
feeRecipientAddress,
// taker address or sender address should be set to the ducth auction contract
takerAddress: dutchAuctionContract.address,
- makerAssetData: extendMakerAssetData(
+ makerAssetData: DutchAuctionWrapper.encodeDutchAuctionAssetData(
assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
auctionBeginTimeSeconds,
auctionBeginAmount,
@@ -199,6 +189,7 @@ describe(ContractName.DutchAuction, () => {
const takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(takerAddress)];
sellerOrderFactory = new OrderFactory(makerPrivateKey, sellerDefaultOrderParams);
buyerOrderFactory = new OrderFactory(takerPrivateKey, buyerDefaultOrderParams);
+ defaultERC20MakerAssetData = assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress);
});
after(async () => {
await blockchainLifecycle.revertAsync();
@@ -215,49 +206,41 @@ describe(ContractName.DutchAuction, () => {
describe('matchOrders', () => {
it('should be worth the begin price at the begining of the auction', async () => {
auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp + 2);
- sellOrder = await sellerOrderFactory.newSignedOrderAsync({
- makerAssetData: extendMakerAssetData(
- assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
- auctionBeginTimeSeconds,
- auctionBeginAmount,
- ),
- });
- const auctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder);
+ const makerAssetData = DutchAuctionWrapper.encodeDutchAuctionAssetData(
+ defaultERC20MakerAssetData,
+ auctionBeginTimeSeconds,
+ auctionBeginAmount,
+ );
+ sellOrder = await sellerOrderFactory.newSignedOrderAsync({ makerAssetData });
+ const auctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
+ expect(auctionDetails.currentTimeSeconds).to.be.bignumber.lte(auctionBeginTimeSeconds);
expect(auctionDetails.currentAmount).to.be.bignumber.equal(auctionBeginAmount);
expect(auctionDetails.beginAmount).to.be.bignumber.equal(auctionBeginAmount);
});
it('should be be worth the end price at the end of the auction', async () => {
auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds * 2);
auctionEndTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds);
+ const makerAssetData = DutchAuctionWrapper.encodeDutchAuctionAssetData(
+ defaultERC20MakerAssetData,
+ auctionBeginTimeSeconds,
+ auctionBeginAmount,
+ );
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
- makerAssetData: extendMakerAssetData(
- assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
- auctionBeginTimeSeconds,
- auctionBeginAmount,
- ),
+ makerAssetData,
expirationTimeSeconds: auctionEndTimeSeconds,
});
- const auctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder);
+ const auctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
+ expect(auctionDetails.currentTimeSeconds).to.be.bignumber.gte(auctionEndTimeSeconds);
expect(auctionDetails.currentAmount).to.be.bignumber.equal(auctionEndAmount);
expect(auctionDetails.beginAmount).to.be.bignumber.equal(auctionBeginAmount);
});
it('should match orders at current amount and send excess to buyer', async () => {
- const beforeAuctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder);
+ const beforeAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
buyOrder = await buyerOrderFactory.newSignedOrderAsync({
makerAssetAmount: beforeAuctionDetails.currentAmount.times(2),
});
- await web3Wrapper.awaitTransactionSuccessAsync(
- await dutchAuctionContract.matchOrders.sendTransactionAsync(
- buyOrder,
- sellOrder,
- buyOrder.signature,
- sellOrder.signature,
- {
- from: takerAddress,
- },
- ),
- );
- const afterAuctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder);
+ await dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
+ const afterAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
const newBalances = await erc20Wrapper.getBalancesAsync();
expect(newBalances[dutchAuctionContract.address][wethContract.address]).to.be.bignumber.equal(
constants.ZERO_AMOUNT,
@@ -276,17 +259,8 @@ describe(ContractName.DutchAuction, () => {
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
makerFee: new BigNumber(1),
});
- const txHash = await dutchAuctionContract.matchOrders.sendTransactionAsync(
- buyOrder,
- sellOrder,
- buyOrder.signature,
- sellOrder.signature,
- {
- from: takerAddress,
- },
- );
- await web3Wrapper.awaitTransactionSuccessAsync(txHash);
- const afterAuctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder);
+ await dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
+ const afterAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
const newBalances = await erc20Wrapper.getBalancesAsync();
expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.gte(
erc20Balances[makerAddress][wethContract.address].plus(afterAuctionDetails.currentAmount),
@@ -299,18 +273,9 @@ describe(ContractName.DutchAuction, () => {
buyOrder = await buyerOrderFactory.newSignedOrderAsync({
makerFee: new BigNumber(1),
});
- const txHash = await dutchAuctionContract.matchOrders.sendTransactionAsync(
- buyOrder,
- sellOrder,
- buyOrder.signature,
- sellOrder.signature,
- {
- from: takerAddress,
- },
- );
- await web3Wrapper.awaitTransactionSuccessAsync(txHash);
+ await dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
const newBalances = await erc20Wrapper.getBalancesAsync();
- const afterAuctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder);
+ const afterAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.gte(
erc20Balances[makerAddress][wethContract.address].plus(afterAuctionDetails.currentAmount),
);
@@ -321,24 +286,17 @@ describe(ContractName.DutchAuction, () => {
it('should revert when auction expires', async () => {
auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds * 2);
auctionEndTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds);
+ const makerAssetData = DutchAuctionWrapper.encodeDutchAuctionAssetData(
+ defaultERC20MakerAssetData,
+ auctionBeginTimeSeconds,
+ auctionBeginAmount,
+ );
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
expirationTimeSeconds: auctionEndTimeSeconds,
- makerAssetData: extendMakerAssetData(
- assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
- auctionBeginTimeSeconds,
- auctionBeginAmount,
- ),
+ makerAssetData,
});
return expectTransactionFailedAsync(
- dutchAuctionContract.matchOrders.sendTransactionAsync(
- buyOrder,
- sellOrder,
- buyOrder.signature,
- sellOrder.signature,
- {
- from: takerAddress,
- },
- ),
+ dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress),
RevertReason.AuctionExpired,
);
});
@@ -347,15 +305,7 @@ describe(ContractName.DutchAuction, () => {
makerAssetAmount: sellOrder.takerAssetAmount,
});
return expectTransactionFailedAsync(
- dutchAuctionContract.matchOrders.sendTransactionAsync(
- buyOrder,
- sellOrder,
- buyOrder.signature,
- sellOrder.signature,
- {
- from: takerAddress,
- },
- ),
+ dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress),
RevertReason.AuctionInvalidAmount,
);
});
@@ -364,38 +314,23 @@ describe(ContractName.DutchAuction, () => {
takerAssetAmount: auctionBeginAmount.plus(1),
});
return expectTransactionFailedAsync(
- dutchAuctionContract.matchOrders.sendTransactionAsync(
- buyOrder,
- sellOrder,
- buyOrder.signature,
- sellOrder.signature,
- {
- from: takerAddress,
- },
- ),
+ dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress),
RevertReason.AuctionInvalidAmount,
);
});
it('begin time is less than end time', async () => {
auctionBeginTimeSeconds = new BigNumber(auctionEndTimeSeconds).plus(tenMinutesInSeconds);
+ const makerAssetData = DutchAuctionWrapper.encodeDutchAuctionAssetData(
+ defaultERC20MakerAssetData,
+ auctionBeginTimeSeconds,
+ auctionBeginAmount,
+ );
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
expirationTimeSeconds: auctionEndTimeSeconds,
- makerAssetData: extendMakerAssetData(
- assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
- auctionBeginTimeSeconds,
- auctionBeginAmount,
- ),
+ makerAssetData,
});
return expectTransactionFailedAsync(
- dutchAuctionContract.matchOrders.sendTransactionAsync(
- buyOrder,
- sellOrder,
- buyOrder.signature,
- sellOrder.signature,
- {
- from: takerAddress,
- },
- ),
+ dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress),
RevertReason.AuctionInvalidBeginTime,
);
});
@@ -404,45 +339,30 @@ describe(ContractName.DutchAuction, () => {
makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
});
return expectTransactionFailedAsync(
- dutchAuctionContract.matchOrders.sendTransactionAsync(
- buyOrder,
- sellOrder,
- buyOrder.signature,
- sellOrder.signature,
- {
- from: takerAddress,
- },
- ),
+ dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress),
RevertReason.InvalidAssetData,
);
});
+
describe('ERC721', () => {
it('should match orders when ERC721', async () => {
const makerAssetId = erc721MakerAssetIds[0];
+ const erc721MakerAssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId);
+ const makerAssetData = DutchAuctionWrapper.encodeDutchAuctionAssetData(
+ erc721MakerAssetData,
+ auctionBeginTimeSeconds,
+ auctionBeginAmount,
+ );
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
makerAssetAmount: new BigNumber(1),
- makerAssetData: extendMakerAssetData(
- assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- auctionBeginTimeSeconds,
- auctionBeginAmount,
- ),
+ makerAssetData,
});
buyOrder = await buyerOrderFactory.newSignedOrderAsync({
takerAssetAmount: new BigNumber(1),
takerAssetData: sellOrder.makerAssetData,
});
- await web3Wrapper.awaitTransactionSuccessAsync(
- await dutchAuctionContract.matchOrders.sendTransactionAsync(
- buyOrder,
- sellOrder,
- buyOrder.signature,
- sellOrder.signature,
- {
- from: takerAddress,
- },
- ),
- );
- const afterAuctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder);
+ await dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
+ const afterAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
const newBalances = await erc20Wrapper.getBalancesAsync();
// HACK gte used here due to a bug in ganache where the timestamp can change
// between multiple calls to the same block. Which can move the amount in our case
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/test/utils/dutch_auction_test_wrapper.ts b/contracts/extensions/test/utils/dutch_auction_test_wrapper.ts
new file mode 100644
index 000000000..c1e2f2070
--- /dev/null
+++ b/contracts/extensions/test/utils/dutch_auction_test_wrapper.ts
@@ -0,0 +1,62 @@
+import { artifacts as protocolArtifacts } from '@0x/contracts-protocol';
+import { LogDecoder } from '@0x/contracts-test-utils';
+import { artifacts as tokensArtifacts } from '@0x/contracts-tokens';
+import { DutchAuctionDetails, SignedOrder } from '@0x/types';
+import { Web3Wrapper } from '@0x/web3-wrapper';
+import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
+import * as _ from 'lodash';
+
+import { DutchAuctionContract } from '../../generated-wrappers/dutch_auction';
+import { artifacts } from '../../src/artifacts';
+
+export class DutchAuctionTestWrapper {
+ private readonly _dutchAuctionContract: DutchAuctionContract;
+ private readonly _web3Wrapper: Web3Wrapper;
+ private readonly _logDecoder: LogDecoder;
+
+ constructor(contractInstance: DutchAuctionContract, provider: Provider) {
+ this._dutchAuctionContract = contractInstance;
+ this._web3Wrapper = new Web3Wrapper(provider);
+ this._logDecoder = new LogDecoder(this._web3Wrapper, {
+ ...artifacts,
+ ...tokensArtifacts,
+ ...protocolArtifacts,
+ });
+ }
+ /**
+ * Matches the buy and sell orders at an amount given the following: the current block time, the auction
+ * start time and the auction begin amount. The sell order is a an order at the lowest amount
+ * at the end of the auction. Excess from the match is transferred to the seller.
+ * Over time the price moves from beginAmount to endAmount given the current block.timestamp.
+ * @param buyOrder The Buyer's order. This order is for the current expected price of the auction.
+ * @param sellOrder The Seller's order. This order is for the lowest amount (at the end of the auction).
+ * @param from Address the transaction is being sent from.
+ * @return Transaction receipt with decoded logs.
+ */
+ public async matchOrdersAsync(
+ buyOrder: SignedOrder,
+ sellOrder: SignedOrder,
+ from: string,
+ ): Promise<TransactionReceiptWithDecodedLogs> {
+ const txHash = await this._dutchAuctionContract.matchOrders.sendTransactionAsync(
+ buyOrder,
+ sellOrder,
+ buyOrder.signature,
+ sellOrder.signature,
+ {
+ from,
+ },
+ );
+ const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
+ return tx;
+ }
+ /**
+ * Calculates the Auction Details for the given order
+ * @param sellOrder The Seller's order. This order is for the lowest amount (at the end of the auction).
+ * @return The dutch auction details.
+ */
+ public async getAuctionDetailsAsync(sellOrder: SignedOrder): Promise<DutchAuctionDetails> {
+ const auctionDetails = await this._dutchAuctionContract.getAuctionDetails.callAsync(sellOrder);
+ return auctionDetails;
+ }
+}
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..bbb44f402 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';
@@ -713,7 +715,7 @@ describe('Asset Transfer Proxies', () => {
const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
const amounts = [erc20Amount];
const nestedAssetData = [erc20AssetData];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+ const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
@@ -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);
@@ -746,7 +778,7 @@ describe('Asset Transfer Proxies', () => {
const erc20AssetData2 = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
const amounts = [erc20Amount1, erc20Amount2];
const nestedAssetData = [erc20AssetData1, erc20AssetData2];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+ const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
@@ -779,7 +811,7 @@ describe('Asset Transfer Proxies', () => {
const erc20AssetData2 = assetDataUtils.encodeERC20AssetData(erc20TokenB.address);
const amounts = [erc20Amount1, erc20Amount2];
const nestedAssetData = [erc20AssetData1, erc20AssetData2];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+ const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
@@ -817,7 +849,7 @@ describe('Asset Transfer Proxies', () => {
const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
const amounts = [erc721Amount];
const nestedAssetData = [erc721AssetData];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+ const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
@@ -849,7 +881,7 @@ describe('Asset Transfer Proxies', () => {
const erc721Amount = new BigNumber(1);
const amounts = [erc721Amount, erc721Amount];
const nestedAssetData = [erc721AssetData1, erc721AssetData2];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+ const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
@@ -881,7 +913,7 @@ describe('Asset Transfer Proxies', () => {
const erc721Amount = new BigNumber(1);
const amounts = [erc721Amount, erc721Amount];
const nestedAssetData = [erc721AssetData1, erc721AssetData2];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+ const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
@@ -914,7 +946,7 @@ describe('Asset Transfer Proxies', () => {
const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
const amounts = [erc20Amount, erc721Amount];
const nestedAssetData = [erc20AssetData, erc721AssetData];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+ const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
@@ -952,10 +984,7 @@ describe('Asset Transfer Proxies', () => {
const amounts = [erc20Amount, erc721Amount];
const nestedAssetData = [erc20AssetData, erc721AssetData];
const extraData = '0102030405060708';
- const assetData = `${assetDataInterface.MultiAsset.getABIEncodedTransactionData(
- amounts,
- nestedAssetData,
- )}${extraData}`;
+ const assetData = `${assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData)}${extraData}`;
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
@@ -992,7 +1021,7 @@ describe('Asset Transfer Proxies', () => {
const erc20AssetData2 = assetDataUtils.encodeERC20AssetData(erc20TokenB.address);
const amounts = [erc20Amount1, erc20Amount2];
const nestedAssetData = [erc20AssetData1, erc20AssetData2];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+ const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
@@ -1053,7 +1082,7 @@ describe('Asset Transfer Proxies', () => {
erc721AssetData3,
erc721AssetData4,
];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+ const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
@@ -1111,7 +1140,7 @@ describe('Asset Transfer Proxies', () => {
const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
const amounts = [erc20Amount, erc721Amount];
const nestedAssetData = [erc20AssetData, erc721AssetData];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+ const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
@@ -1137,6 +1166,7 @@ describe('Asset Transfer Proxies', () => {
const invalidErc721AssetData = `${invalidProxyId}${erc721AssetData.slice(10)}`;
const amounts = [erc20Amount, erc721Amount];
const nestedAssetData = [erc20AssetData, invalidErc721AssetData];
+ // HACK: This is used to get around validation built into assetDataUtils
const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
@@ -1160,6 +1190,7 @@ describe('Asset Transfer Proxies', () => {
const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
const amounts = [erc20Amount];
const nestedAssetData = [erc20AssetData, erc721AssetData];
+ // HACK: This is used to get around validation built into assetDataUtils
const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
@@ -1182,7 +1213,7 @@ describe('Asset Transfer Proxies', () => {
const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
const amounts = [erc20Amount];
const nestedAssetData = [erc20AssetData];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+ const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
@@ -1206,6 +1237,7 @@ describe('Asset Transfer Proxies', () => {
const erc721AssetData = '0x123456';
const amounts = [erc20Amount, erc721Amount];
const nestedAssetData = [erc20AssetData, erc721AssetData];
+ // HACK: This is used to get around validation built into assetDataUtils
const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
@@ -1230,7 +1262,7 @@ describe('Asset Transfer Proxies', () => {
const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
const amounts = [erc20Amount, erc721Amount];
const nestedAssetData = [erc20AssetData, erc721AssetData];
- const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+ const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
diff --git a/contracts/protocol/test/exchange/core.ts b/contracts/protocol/test/exchange/core.ts
index 9b948f991..42db8623d 100644
--- a/contracts/protocol/test/exchange/core.ts
+++ b/contracts/protocol/test/exchange/core.ts
@@ -1,4 +1,3 @@
-import { artifacts as interfacesArtifacts, IAssetDataContract } from '@0x/contracts-interfaces';
import {
chaiSetup,
constants,
@@ -43,11 +42,6 @@ import { ExchangeWrapper } from '../utils/exchange_wrapper';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-const assetDataInterface = new IAssetDataContract(
- interfacesArtifacts.IAssetData.compilerOutput.abi,
- constants.NULL_ADDRESS,
- provider,
-);
// tslint:disable:no-unnecessary-type-assertion
describe('Exchange core', () => {
let makerAddress: string;
@@ -777,10 +771,7 @@ describe('Exchange core', () => {
assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
];
- const makerAssetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
- makerAmounts,
- makerNestedAssetData,
- );
+ const makerAssetData = assetDataUtils.encodeMultiAssetData(makerAmounts, makerNestedAssetData);
const makerAssetAmount = new BigNumber(1);
const takerAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
const takerAssetAmount = new BigNumber(10);
@@ -830,10 +821,7 @@ describe('Exchange core', () => {
assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
];
- const makerAssetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
- makerAmounts,
- makerNestedAssetData,
- );
+ const makerAssetData = assetDataUtils.encodeMultiAssetData(makerAmounts, makerNestedAssetData);
const makerAssetAmount = new BigNumber(1);
const takerAmounts = [new BigNumber(10), new BigNumber(1)];
const takerAssetId = erc721TakerAssetIds[0];
@@ -841,10 +829,7 @@ describe('Exchange core', () => {
assetDataUtils.encodeERC20AssetData(zrxToken.address),
assetDataUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
];
- const takerAssetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
- takerAmounts,
- takerNestedAssetData,
- );
+ const takerAssetData = assetDataUtils.encodeMultiAssetData(takerAmounts, takerNestedAssetData);
const takerAssetAmount = new BigNumber(1);
signedOrder = await orderFactory.newSignedOrderAsync({
makerAssetData,
@@ -900,10 +885,7 @@ describe('Exchange core', () => {
assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
];
- const makerAssetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
- makerAmounts,
- makerNestedAssetData,
- );
+ const makerAssetData = assetDataUtils.encodeMultiAssetData(makerAmounts, makerNestedAssetData);
const makerAssetAmount = new BigNumber(30);
const takerAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
const takerAssetAmount = new BigNumber(10);
@@ -980,10 +962,7 @@ describe('Exchange core', () => {
assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
];
- const takerAssetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
- takerAmounts,
- takerNestedAssetData,
- );
+ const takerAssetData = assetDataUtils.encodeMultiAssetData(takerAmounts, takerNestedAssetData);
const takerAssetAmount = new BigNumber(30);
const makerAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
const makerAssetAmount = 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/tokens/src/artifacts/index.ts b/contracts/tokens/src/artifacts/index.ts
index 63b808748..977d01c3e 100644
--- a/contracts/tokens/src/artifacts/index.ts
+++ b/contracts/tokens/src/artifacts/index.ts
@@ -22,6 +22,7 @@ import * as UnlimitedAllowanceToken_v1 from '../../generated-artifacts/Unlimited
import * as WETH9 from '../../generated-artifacts/WETH9.json';
import * as ZRXToken from '../../generated-artifacts/ZRXToken.json';
+// tslint:disable:no-unnecessary-type-assertion
export const artifacts = {
DummyERC20Token: DummyERC20Token as ContractArtifact,
DummyMultipleReturnERC20Token: DummyMultipleReturnERC20Token as ContractArtifact,
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/0x.js/CHANGELOG.json b/packages/0x.js/CHANGELOG.json
index 32351ad82..f73de96aa 100644
--- a/packages/0x.js/CHANGELOG.json
+++ b/packages/0x.js/CHANGELOG.json
@@ -1,5 +1,15 @@
[
{
+ "version": "3.0.0",
+ "changes": [
+ {
+ "note":
+ "Export `MultiAssetData`, `MultiAssetDataWithRecursiveDecoding`, `ObjectMap`, and `SingleAssetData` from types. No longer export `AssetData`.",
+ "pr": 1363
+ }
+ ]
+ },
+ {
"version": "2.0.8",
"changes": [
{
diff --git a/packages/0x.js/src/index.ts b/packages/0x.js/src/index.ts
index 2df360b96..006e4cf29 100644
--- a/packages/0x.js/src/index.ts
+++ b/packages/0x.js/src/index.ts
@@ -4,6 +4,7 @@ export { assetDataUtils, signatureUtils, generatePseudoRandomSalt, orderHashUtil
export {
ContractWrappers,
+ DutchAuctionWrapper,
ERC20TokenWrapper,
ERC721TokenWrapper,
EtherTokenWrapper,
@@ -27,6 +28,7 @@ export {
OrderAndTraderInfo,
TraderInfo,
ValidateOrderFillableOpts,
+ DutchAuctionData,
} from '@0x/contract-wrappers';
export {
@@ -80,11 +82,16 @@ export {
OrderState,
AssetProxyId,
AssetData,
+ SingleAssetData,
ERC20AssetData,
ERC721AssetData,
+ MultiAssetData,
+ MultiAssetDataWithRecursiveDecoding,
SignatureType,
+ ObjectMap,
OrderRelevantState,
Stats,
+ DutchAuctionDetails,
} from '@0x/types';
export {
diff --git a/packages/abi-gen-wrappers/CHANGELOG.json b/packages/abi-gen-wrappers/CHANGELOG.json
index d46e828f4..214920a08 100644
--- a/packages/abi-gen-wrappers/CHANGELOG.json
+++ b/packages/abi-gen-wrappers/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "2.1.0",
+ "changes": [
+ {
+ "note": "Added Dutch Auction Wrapper",
+ "pr": 1465
+ }
+ ]
+ },
+ {
"version": "2.0.2",
"changes": [
{
diff --git a/packages/abi-gen-wrappers/package.json b/packages/abi-gen-wrappers/package.json
index 25ba3a6e0..38b5e9a9b 100644
--- a/packages/abi-gen-wrappers/package.json
+++ b/packages/abi-gen-wrappers/package.json
@@ -18,7 +18,7 @@
"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 src/generated-wrappers --backend ethers"
},
"config": {
- "abis": "../contract-artifacts/artifacts/@(AssetProxyOwner|DummyERC20Token|DummyERC721Token|ERC20Proxy|ERC20Token|ERC721Proxy|ERC721Token|Exchange|Forwarder|IValidator|IWallet|OrderValidator|WETH9|ZRXToken).json"
+ "abis": "../contract-artifacts/artifacts/@(AssetProxyOwner|DutchAuction|DummyERC20Token|DummyERC721Token|ERC20Proxy|ERC20Token|ERC721Proxy|ERC721Token|Exchange|Forwarder|IValidator|IWallet|OrderValidator|WETH9|ZRXToken).json"
},
"repository": {
"type": "git",
diff --git a/packages/abi-gen-wrappers/src/generated-wrappers/dutch_auction.ts b/packages/abi-gen-wrappers/src/generated-wrappers/dutch_auction.ts
new file mode 100644
index 000000000..90e233756
--- /dev/null
+++ b/packages/abi-gen-wrappers/src/generated-wrappers/dutch_auction.ts
@@ -0,0 +1,322 @@
+// tslint:disable:no-consecutive-blank-lines ordered-imports align trailing-comma whitespace class-name
+// tslint:disable:no-unused-variable
+// tslint:disable:no-unbound-method
+import { BaseContract } from '@0x/base-contract';
+import { BlockParam, BlockParamLiteral, CallData, ContractAbi, ContractArtifact, DecodedLogArgs, MethodAbi, Provider, TxData, TxDataPayable } from 'ethereum-types';
+import { BigNumber, classUtils, logUtils } from '@0x/utils';
+import { SimpleContractArtifact } from '@0x/types';
+import { Web3Wrapper } from '@0x/web3-wrapper';
+import * as ethers from 'ethers';
+import * as _ from 'lodash';
+// tslint:enable:no-unused-variable
+
+
+/* istanbul ignore next */
+// tslint:disable:no-parameter-reassignment
+// tslint:disable-next-line:class-name
+export class DutchAuctionContract extends BaseContract {
+ public getAuctionDetails = {
+ async sendTransactionAsync(
+ order: {makerAddress: string;takerAddress: string;feeRecipientAddress: string;senderAddress: string;makerAssetAmount: BigNumber;takerAssetAmount: BigNumber;makerFee: BigNumber;takerFee: BigNumber;expirationTimeSeconds: BigNumber;salt: BigNumber;makerAssetData: string;takerAssetData: string},
+ txData: Partial<TxData> = {},
+ ): Promise<string> {
+ const self = this as any as DutchAuctionContract;
+ const inputAbi = self._lookupAbi('getAuctionDetails({address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes})').inputs;
+ [order
+ ] = BaseContract._formatABIDataItemList(inputAbi, [order
+ ], BaseContract._bigNumberToString.bind(self));
+ BaseContract.strictArgumentEncodingCheck(inputAbi, [order
+ ]);
+ const encodedData = self._lookupEthersInterface('getAuctionDetails({address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes})').functions.getAuctionDetails.encode([order
+ ]);
+ const txDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
+ {
+ to: self.address,
+ ...txData,
+ data: encodedData,
+ },
+ self._web3Wrapper.getContractDefaults(),
+ self.getAuctionDetails.estimateGasAsync.bind(
+ self,
+ order
+ ),
+ );
+ const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults);
+ return txHash;
+ },
+ async estimateGasAsync(
+ order: {makerAddress: string;takerAddress: string;feeRecipientAddress: string;senderAddress: string;makerAssetAmount: BigNumber;takerAssetAmount: BigNumber;makerFee: BigNumber;takerFee: BigNumber;expirationTimeSeconds: BigNumber;salt: BigNumber;makerAssetData: string;takerAssetData: string},
+ txData: Partial<TxData> = {},
+ ): Promise<number> {
+ const self = this as any as DutchAuctionContract;
+ const inputAbi = self._lookupAbi('getAuctionDetails({address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes})').inputs;
+ [order
+ ] = BaseContract._formatABIDataItemList(inputAbi, [order
+ ], BaseContract._bigNumberToString);
+ const encodedData = self._lookupEthersInterface('getAuctionDetails({address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes})').functions.getAuctionDetails.encode([order
+ ]);
+ const txDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
+ {
+ to: self.address,
+ ...txData,
+ data: encodedData,
+ },
+ self._web3Wrapper.getContractDefaults(),
+ );
+ const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults);
+ return gas;
+ },
+ getABIEncodedTransactionData(
+ order: {makerAddress: string;takerAddress: string;feeRecipientAddress: string;senderAddress: string;makerAssetAmount: BigNumber;takerAssetAmount: BigNumber;makerFee: BigNumber;takerFee: BigNumber;expirationTimeSeconds: BigNumber;salt: BigNumber;makerAssetData: string;takerAssetData: string},
+ ): string {
+ const self = this as any as DutchAuctionContract;
+ const inputAbi = self._lookupAbi('getAuctionDetails({address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes})').inputs;
+ [order
+ ] = BaseContract._formatABIDataItemList(inputAbi, [order
+ ], BaseContract._bigNumberToString);
+ const abiEncodedTransactionData = self._lookupEthersInterface('getAuctionDetails({address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes})').functions.getAuctionDetails.encode([order
+ ]);
+ return abiEncodedTransactionData;
+ },
+ async callAsync(
+ order: {makerAddress: string;takerAddress: string;feeRecipientAddress: string;senderAddress: string;makerAssetAmount: BigNumber;takerAssetAmount: BigNumber;makerFee: BigNumber;takerFee: BigNumber;expirationTimeSeconds: BigNumber;salt: BigNumber;makerAssetData: string;takerAssetData: string},
+ callData: Partial<CallData> = {},
+ defaultBlock?: BlockParam,
+ ): Promise<{beginTimeSeconds: BigNumber;endTimeSeconds: BigNumber;beginAmount: BigNumber;endAmount: BigNumber;currentAmount: BigNumber;currentTimeSeconds: BigNumber}
+ > {
+ const self = this as any as DutchAuctionContract;
+ const functionSignature = 'getAuctionDetails({address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes})';
+ const inputAbi = self._lookupAbi(functionSignature).inputs;
+ [order
+ ] = BaseContract._formatABIDataItemList(inputAbi, [order
+ ], BaseContract._bigNumberToString.bind(self));
+ BaseContract.strictArgumentEncodingCheck(inputAbi, [order
+ ]);
+ const ethersFunction = self._lookupEthersInterface(functionSignature).functions.getAuctionDetails;
+ const encodedData = ethersFunction.encode([order
+ ]);
+ const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
+ {
+ to: self.address,
+ ...callData,
+ data: encodedData,
+ },
+ self._web3Wrapper.getContractDefaults(),
+ );
+ const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock);
+ BaseContract._throwIfRevertWithReasonCallResult(rawCallResult);
+ let resultArray = ethersFunction.decode(rawCallResult);
+ const outputAbi = (_.find(self.abi, {name: 'getAuctionDetails'}) as MethodAbi).outputs;
+ resultArray = BaseContract._formatABIDataItemList(outputAbi, resultArray, BaseContract._lowercaseAddress.bind(this));
+ resultArray = BaseContract._formatABIDataItemList(outputAbi, resultArray, BaseContract._bnToBigNumber.bind(this));
+ return resultArray[0];
+ },
+ };
+ public matchOrders = {
+ async sendTransactionAsync(
+ buyOrder: {makerAddress: string;takerAddress: string;feeRecipientAddress: string;senderAddress: string;makerAssetAmount: BigNumber;takerAssetAmount: BigNumber;makerFee: BigNumber;takerFee: BigNumber;expirationTimeSeconds: BigNumber;salt: BigNumber;makerAssetData: string;takerAssetData: string},
+ sellOrder: {makerAddress: string;takerAddress: string;feeRecipientAddress: string;senderAddress: string;makerAssetAmount: BigNumber;takerAssetAmount: BigNumber;makerFee: BigNumber;takerFee: BigNumber;expirationTimeSeconds: BigNumber;salt: BigNumber;makerAssetData: string;takerAssetData: string},
+ buySignature: string,
+ sellSignature: string,
+ txData: Partial<TxData> = {},
+ ): Promise<string> {
+ const self = this as any as DutchAuctionContract;
+ const inputAbi = self._lookupAbi('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)').inputs;
+ [buyOrder,
+ sellOrder,
+ buySignature,
+ sellSignature
+ ] = BaseContract._formatABIDataItemList(inputAbi, [buyOrder,
+ sellOrder,
+ buySignature,
+ sellSignature
+ ], BaseContract._bigNumberToString.bind(self));
+ BaseContract.strictArgumentEncodingCheck(inputAbi, [buyOrder,
+ sellOrder,
+ buySignature,
+ sellSignature
+ ]);
+ const encodedData = self._lookupEthersInterface('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)').functions.matchOrders.encode([buyOrder,
+ sellOrder,
+ buySignature,
+ sellSignature
+ ]);
+ const txDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
+ {
+ to: self.address,
+ ...txData,
+ data: encodedData,
+ },
+ self._web3Wrapper.getContractDefaults(),
+ self.matchOrders.estimateGasAsync.bind(
+ self,
+ buyOrder,
+ sellOrder,
+ buySignature,
+ sellSignature
+ ),
+ );
+ const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults);
+ return txHash;
+ },
+ async estimateGasAsync(
+ buyOrder: {makerAddress: string;takerAddress: string;feeRecipientAddress: string;senderAddress: string;makerAssetAmount: BigNumber;takerAssetAmount: BigNumber;makerFee: BigNumber;takerFee: BigNumber;expirationTimeSeconds: BigNumber;salt: BigNumber;makerAssetData: string;takerAssetData: string},
+ sellOrder: {makerAddress: string;takerAddress: string;feeRecipientAddress: string;senderAddress: string;makerAssetAmount: BigNumber;takerAssetAmount: BigNumber;makerFee: BigNumber;takerFee: BigNumber;expirationTimeSeconds: BigNumber;salt: BigNumber;makerAssetData: string;takerAssetData: string},
+ buySignature: string,
+ sellSignature: string,
+ txData: Partial<TxData> = {},
+ ): Promise<number> {
+ const self = this as any as DutchAuctionContract;
+ const inputAbi = self._lookupAbi('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)').inputs;
+ [buyOrder,
+ sellOrder,
+ buySignature,
+ sellSignature
+ ] = BaseContract._formatABIDataItemList(inputAbi, [buyOrder,
+ sellOrder,
+ buySignature,
+ sellSignature
+ ], BaseContract._bigNumberToString);
+ const encodedData = self._lookupEthersInterface('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)').functions.matchOrders.encode([buyOrder,
+ sellOrder,
+ buySignature,
+ sellSignature
+ ]);
+ const txDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
+ {
+ to: self.address,
+ ...txData,
+ data: encodedData,
+ },
+ self._web3Wrapper.getContractDefaults(),
+ );
+ const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults);
+ return gas;
+ },
+ getABIEncodedTransactionData(
+ buyOrder: {makerAddress: string;takerAddress: string;feeRecipientAddress: string;senderAddress: string;makerAssetAmount: BigNumber;takerAssetAmount: BigNumber;makerFee: BigNumber;takerFee: BigNumber;expirationTimeSeconds: BigNumber;salt: BigNumber;makerAssetData: string;takerAssetData: string},
+ sellOrder: {makerAddress: string;takerAddress: string;feeRecipientAddress: string;senderAddress: string;makerAssetAmount: BigNumber;takerAssetAmount: BigNumber;makerFee: BigNumber;takerFee: BigNumber;expirationTimeSeconds: BigNumber;salt: BigNumber;makerAssetData: string;takerAssetData: string},
+ buySignature: string,
+ sellSignature: string,
+ ): string {
+ const self = this as any as DutchAuctionContract;
+ const inputAbi = self._lookupAbi('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)').inputs;
+ [buyOrder,
+ sellOrder,
+ buySignature,
+ sellSignature
+ ] = BaseContract._formatABIDataItemList(inputAbi, [buyOrder,
+ sellOrder,
+ buySignature,
+ sellSignature
+ ], BaseContract._bigNumberToString);
+ const abiEncodedTransactionData = self._lookupEthersInterface('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)').functions.matchOrders.encode([buyOrder,
+ sellOrder,
+ buySignature,
+ sellSignature
+ ]);
+ return abiEncodedTransactionData;
+ },
+ async callAsync(
+ buyOrder: {makerAddress: string;takerAddress: string;feeRecipientAddress: string;senderAddress: string;makerAssetAmount: BigNumber;takerAssetAmount: BigNumber;makerFee: BigNumber;takerFee: BigNumber;expirationTimeSeconds: BigNumber;salt: BigNumber;makerAssetData: string;takerAssetData: string},
+ sellOrder: {makerAddress: string;takerAddress: string;feeRecipientAddress: string;senderAddress: string;makerAssetAmount: BigNumber;takerAssetAmount: BigNumber;makerFee: BigNumber;takerFee: BigNumber;expirationTimeSeconds: BigNumber;salt: BigNumber;makerAssetData: string;takerAssetData: string},
+ buySignature: string,
+ sellSignature: string,
+ callData: Partial<CallData> = {},
+ defaultBlock?: BlockParam,
+ ): Promise<{left: {makerAssetFilledAmount: BigNumber;takerAssetFilledAmount: BigNumber;makerFeePaid: BigNumber;takerFeePaid: BigNumber};right: {makerAssetFilledAmount: BigNumber;takerAssetFilledAmount: BigNumber;makerFeePaid: BigNumber;takerFeePaid: BigNumber};leftMakerAssetSpreadAmount: BigNumber}
+ > {
+ const self = this as any as DutchAuctionContract;
+ const functionSignature = '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)';
+ const inputAbi = self._lookupAbi(functionSignature).inputs;
+ [buyOrder,
+ sellOrder,
+ buySignature,
+ sellSignature
+ ] = BaseContract._formatABIDataItemList(inputAbi, [buyOrder,
+ sellOrder,
+ buySignature,
+ sellSignature
+ ], BaseContract._bigNumberToString.bind(self));
+ BaseContract.strictArgumentEncodingCheck(inputAbi, [buyOrder,
+ sellOrder,
+ buySignature,
+ sellSignature
+ ]);
+ const ethersFunction = self._lookupEthersInterface(functionSignature).functions.matchOrders;
+ const encodedData = ethersFunction.encode([buyOrder,
+ sellOrder,
+ buySignature,
+ sellSignature
+ ]);
+ const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
+ {
+ to: self.address,
+ ...callData,
+ data: encodedData,
+ },
+ self._web3Wrapper.getContractDefaults(),
+ );
+ const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock);
+ BaseContract._throwIfRevertWithReasonCallResult(rawCallResult);
+ let resultArray = ethersFunction.decode(rawCallResult);
+ const outputAbi = (_.find(self.abi, {name: 'matchOrders'}) as MethodAbi).outputs;
+ resultArray = BaseContract._formatABIDataItemList(outputAbi, resultArray, BaseContract._lowercaseAddress.bind(this));
+ resultArray = BaseContract._formatABIDataItemList(outputAbi, resultArray, BaseContract._bnToBigNumber.bind(this));
+ return resultArray[0];
+ },
+ };
+ public static async deployFrom0xArtifactAsync(
+ artifact: ContractArtifact | SimpleContractArtifact,
+ provider: Provider,
+ txDefaults: Partial<TxData>,
+ _exchange: string,
+ ): Promise<DutchAuctionContract> {
+ if (_.isUndefined(artifact.compilerOutput)) {
+ throw new Error('Compiler output not found in the artifact file');
+ }
+ const bytecode = artifact.compilerOutput.evm.bytecode.object;
+ const abi = artifact.compilerOutput.abi;
+ return DutchAuctionContract.deployAsync(bytecode, abi, provider, txDefaults, _exchange
+);
+ }
+ public static async deployAsync(
+ bytecode: string,
+ abi: ContractAbi,
+ provider: Provider,
+ txDefaults: Partial<TxData>,
+ _exchange: string,
+ ): Promise<DutchAuctionContract> {
+ const constructorAbi = BaseContract._lookupConstructorAbi(abi);
+ [_exchange
+] = BaseContract._formatABIDataItemList(
+ constructorAbi.inputs,
+ [_exchange
+],
+ BaseContract._bigNumberToString,
+ );
+ const iface = new ethers.utils.Interface(abi);
+ const deployInfo = iface.deployFunction;
+ const txData = deployInfo.encode(bytecode, [_exchange
+]);
+ const web3Wrapper = new Web3Wrapper(provider);
+ const txDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
+ {data: txData},
+ txDefaults,
+ web3Wrapper.estimateGasAsync.bind(web3Wrapper),
+ );
+ const txHash = await web3Wrapper.sendTransactionAsync(txDataWithDefaults);
+ logUtils.log(`transactionHash: ${txHash}`);
+ const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash);
+ logUtils.log(`DutchAuction successfully deployed at ${txReceipt.contractAddress}`);
+ const contractInstance = new DutchAuctionContract(abi, txReceipt.contractAddress as string, provider, txDefaults);
+ contractInstance.constructorArgs = [_exchange
+];
+ return contractInstance;
+ }
+ constructor(abi: ContractAbi, address: string, provider: Provider, txDefaults?: Partial<TxData>) {
+ super('DutchAuction', abi, address, provider, txDefaults);
+ classUtils.bindAll(this, ['_ethersInterfacesByFunctionSignature', 'address', 'abi', '_web3Wrapper']);
+ }
+} // tslint:disable:max-file-line-count
+// tslint:enable:no-unbound-method
diff --git a/packages/abi-gen-wrappers/src/index.ts b/packages/abi-gen-wrappers/src/index.ts
index de418214b..b5a7d0cfe 100644
--- a/packages/abi-gen-wrappers/src/index.ts
+++ b/packages/abi-gen-wrappers/src/index.ts
@@ -1,6 +1,7 @@
export * from './generated-wrappers/asset_proxy_owner';
export * from './generated-wrappers/dummy_erc20_token';
export * from './generated-wrappers/dummy_erc721_token';
+export * from './generated-wrappers/dutch_auction';
export * from './generated-wrappers/erc20_proxy';
export * from './generated-wrappers/erc20_token';
export * from './generated-wrappers/erc721_proxy';
diff --git a/packages/asset-buyer/README.md b/packages/asset-buyer/README.md
index 383a3836a..b854bda11 100644
--- a/packages/asset-buyer/README.md
+++ b/packages/asset-buyer/README.md
@@ -1,7 +1,5 @@
## @0x/asset-buyer
-**Warning: In Beta, has not been extensively tested.**
-
Convenience package for buying assets represented on the Ethereum blockchain using 0x. In its simplest form, the package helps in the usage of the [0x forwarder contract](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/forwarder-specification.md), which allows users to execute [Wrapped Ether](https://weth.io/) based 0x orders without having to set allowances, wrap Ether or own ZRX, meaning they can buy tokens with Ether alone. Given some liquidity (0x signed orders), it helps estimate the Ether cost of buying a certain asset (giving a range) and then buying that asset.
In its more advanced and useful form, it integrates with the [Standard Relayer API](https://github.com/0xProject/standard-relayer-api) and takes care of sourcing liquidity for you given an SRA compliant endpoint. The final result is a library that tells you what assets are available, provides an Ether based quote for any asset desired, and allows you to buy that asset using Ether alone.
diff --git a/packages/contract-addresses/CHANGELOG.json b/packages/contract-addresses/CHANGELOG.json
index 21ffaf510..ca79290da 100644
--- a/packages/contract-addresses/CHANGELOG.json
+++ b/packages/contract-addresses/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "2.1.0",
+ "changes": [
+ {
+ "note": "Added testnet entries for Dutch Auction contract (kovan,rinkeby,ropsten)",
+ "pr": 1465
+ }
+ ]
+ },
+ {
"version": "2.0.0",
"changes": [
{
diff --git a/packages/contract-addresses/src/index.ts b/packages/contract-addresses/src/index.ts
index 7989631e3..d181a1bec 100644
--- a/packages/contract-addresses/src/index.ts
+++ b/packages/contract-addresses/src/index.ts
@@ -9,6 +9,7 @@ export interface ContractAddresses {
assetProxyOwner: string;
forwarder: string;
orderValidator: string;
+ dutchAuction: string;
}
export enum NetworkId {
@@ -19,6 +20,8 @@ export enum NetworkId {
Ganache = 50,
}
+const NULL_ADDRESS = '0x0000000000000000000000000000000000000000';
+
const networkToAddresses: { [networkId: number]: ContractAddresses } = {
1: {
erc20Proxy: '0x2240dab907db71e64d3e0dba4800c83b5c502d4e',
@@ -29,6 +32,8 @@ const networkToAddresses: { [networkId: number]: ContractAddresses } = {
assetProxyOwner: '0x17992e4ffb22730138e4b62aaa6367fa9d3699a6',
forwarder: '0x5468a1dc173652ee28d249c271fa9933144746b1',
orderValidator: '0x9463e518dea6810309563c81d5266c1b1d149138',
+ // @todo hysz/dekz: Add mainnet address once deployed.
+ dutchAuction: NULL_ADDRESS,
},
3: {
erc20Proxy: '0xb1408f4c245a23c31b98d2c626777d4c0d766caa',
@@ -39,6 +44,7 @@ const networkToAddresses: { [networkId: number]: ContractAddresses } = {
assetProxyOwner: '0xf5fa5b5fed2727a0e44ac67f6772e97977aa358b',
forwarder: '0x2240dab907db71e64d3e0dba4800c83b5c502d4e',
orderValidator: '0x90431a90516ab49af23a0530e04e8c7836e7122f',
+ dutchAuction: '0x2df6b59309f35ada230ec7d61d7d97355017a1df',
},
4: {
exchange: '0xbce0b5f6eb618c565c3e5f5cd69652bbc279f44e',
@@ -49,6 +55,7 @@ const networkToAddresses: { [networkId: number]: ContractAddresses } = {
assetProxyOwner: '0xe1703da878afcebff5b7624a826902af475b9c03',
forwarder: '0x2d40589abbdee84961f3a7656b9af7adb0ee5ab4',
orderValidator: '0x0c5173a51e26b29d6126c686756fb9fbef71f762',
+ dutchAuction: '0xdd7bd6437e67c422879364740ab5855fe3dc41f7',
},
42: {
erc20Proxy: '0xf1ec01d6236d3cd881a0bf0130ea25fe4234003e',
@@ -59,6 +66,7 @@ const networkToAddresses: { [networkId: number]: ContractAddresses } = {
assetProxyOwner: '0x2c824d2882baa668e0d5202b1e7f2922278703f8',
forwarder: '0x17992e4ffb22730138e4b62aaa6367fa9d3699a6',
orderValidator: '0xb389da3d204b412df2f75c6afb3d0a7ce0bc283d',
+ dutchAuction: '0xe11667fb51f34c5367f40d7e379327ce32ee7150',
},
// NetworkId 50 represents our Ganache snapshot generated from migrations.
50: {
@@ -70,6 +78,7 @@ const networkToAddresses: { [networkId: number]: ContractAddresses } = {
assetProxyOwner: '0x34d402f14d58e001d8efbe6585051bf9706aa064',
forwarder: '0xb69e673309512a9d726f87304c6984054f87a93b',
orderValidator: '0xe86bb98fcf9bff3512c74589b78fb168200cc546',
+ dutchAuction: '0xdc688d29394a3f1e6f1e5100862776691afaf3d2',
},
};
diff --git a/packages/contract-artifacts/CHANGELOG.json b/packages/contract-artifacts/CHANGELOG.json
index 03c88e71a..b033943d2 100644
--- a/packages/contract-artifacts/CHANGELOG.json
+++ b/packages/contract-artifacts/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "1.2.0",
+ "changes": [
+ {
+ "pr": 1465,
+ "note": "Added artifact for Dutch Auction contract"
+ }
+ ]
+ },
+ {
"version": "1.1.2",
"changes": [
{
diff --git a/packages/contract-artifacts/artifacts/DutchAuction.json b/packages/contract-artifacts/artifacts/DutchAuction.json
new file mode 100644
index 000000000..3c1cb8c4c
--- /dev/null
+++ b/packages/contract-artifacts/artifacts/DutchAuction.json
@@ -0,0 +1,310 @@
+{
+ "schemaVersion": "2.0.0",
+ "contractName": "DutchAuction",
+ "compilerOutput": {
+ "abi": [
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "components": [
+ {
+ "name": "makerAddress",
+ "type": "address"
+ },
+ {
+ "name": "takerAddress",
+ "type": "address"
+ },
+ {
+ "name": "feeRecipientAddress",
+ "type": "address"
+ },
+ {
+ "name": "senderAddress",
+ "type": "address"
+ },
+ {
+ "name": "makerAssetAmount",
+ "type": "uint256"
+ },
+ {
+ "name": "takerAssetAmount",
+ "type": "uint256"
+ },
+ {
+ "name": "makerFee",
+ "type": "uint256"
+ },
+ {
+ "name": "takerFee",
+ "type": "uint256"
+ },
+ {
+ "name": "expirationTimeSeconds",
+ "type": "uint256"
+ },
+ {
+ "name": "salt",
+ "type": "uint256"
+ },
+ {
+ "name": "makerAssetData",
+ "type": "bytes"
+ },
+ {
+ "name": "takerAssetData",
+ "type": "bytes"
+ }
+ ],
+ "name": "order",
+ "type": "tuple"
+ }
+ ],
+ "name": "getAuctionDetails",
+ "outputs": [
+ {
+ "components": [
+ {
+ "name": "beginTimeSeconds",
+ "type": "uint256"
+ },
+ {
+ "name": "endTimeSeconds",
+ "type": "uint256"
+ },
+ {
+ "name": "beginAmount",
+ "type": "uint256"
+ },
+ {
+ "name": "endAmount",
+ "type": "uint256"
+ },
+ {
+ "name": "currentAmount",
+ "type": "uint256"
+ },
+ {
+ "name": "currentTimeSeconds",
+ "type": "uint256"
+ }
+ ],
+ "name": "auctionDetails",
+ "type": "tuple"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "components": [
+ {
+ "name": "makerAddress",
+ "type": "address"
+ },
+ {
+ "name": "takerAddress",
+ "type": "address"
+ },
+ {
+ "name": "feeRecipientAddress",
+ "type": "address"
+ },
+ {
+ "name": "senderAddress",
+ "type": "address"
+ },
+ {
+ "name": "makerAssetAmount",
+ "type": "uint256"
+ },
+ {
+ "name": "takerAssetAmount",
+ "type": "uint256"
+ },
+ {
+ "name": "makerFee",
+ "type": "uint256"
+ },
+ {
+ "name": "takerFee",
+ "type": "uint256"
+ },
+ {
+ "name": "expirationTimeSeconds",
+ "type": "uint256"
+ },
+ {
+ "name": "salt",
+ "type": "uint256"
+ },
+ {
+ "name": "makerAssetData",
+ "type": "bytes"
+ },
+ {
+ "name": "takerAssetData",
+ "type": "bytes"
+ }
+ ],
+ "name": "buyOrder",
+ "type": "tuple"
+ },
+ {
+ "components": [
+ {
+ "name": "makerAddress",
+ "type": "address"
+ },
+ {
+ "name": "takerAddress",
+ "type": "address"
+ },
+ {
+ "name": "feeRecipientAddress",
+ "type": "address"
+ },
+ {
+ "name": "senderAddress",
+ "type": "address"
+ },
+ {
+ "name": "makerAssetAmount",
+ "type": "uint256"
+ },
+ {
+ "name": "takerAssetAmount",
+ "type": "uint256"
+ },
+ {
+ "name": "makerFee",
+ "type": "uint256"
+ },
+ {
+ "name": "takerFee",
+ "type": "uint256"
+ },
+ {
+ "name": "expirationTimeSeconds",
+ "type": "uint256"
+ },
+ {
+ "name": "salt",
+ "type": "uint256"
+ },
+ {
+ "name": "makerAssetData",
+ "type": "bytes"
+ },
+ {
+ "name": "takerAssetData",
+ "type": "bytes"
+ }
+ ],
+ "name": "sellOrder",
+ "type": "tuple"
+ },
+ {
+ "name": "buySignature",
+ "type": "bytes"
+ },
+ {
+ "name": "sellSignature",
+ "type": "bytes"
+ }
+ ],
+ "name": "matchOrders",
+ "outputs": [
+ {
+ "components": [
+ {
+ "components": [
+ {
+ "name": "makerAssetFilledAmount",
+ "type": "uint256"
+ },
+ {
+ "name": "takerAssetFilledAmount",
+ "type": "uint256"
+ },
+ {
+ "name": "makerFeePaid",
+ "type": "uint256"
+ },
+ {
+ "name": "takerFeePaid",
+ "type": "uint256"
+ }
+ ],
+ "name": "left",
+ "type": "tuple"
+ },
+ {
+ "components": [
+ {
+ "name": "makerAssetFilledAmount",
+ "type": "uint256"
+ },
+ {
+ "name": "takerAssetFilledAmount",
+ "type": "uint256"
+ },
+ {
+ "name": "makerFeePaid",
+ "type": "uint256"
+ },
+ {
+ "name": "takerFeePaid",
+ "type": "uint256"
+ }
+ ],
+ "name": "right",
+ "type": "tuple"
+ },
+ {
+ "name": "leftMakerAssetSpreadAmount",
+ "type": "uint256"
+ }
+ ],
+ "name": "matchedFillResults",
+ "type": "tuple"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "name": "_exchange",
+ "type": "address"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ }
+ ],
+ "evm": {
+ "bytecode": {
+ "linkReferences": {},
+ "object": "0x608060405234801561001057600080fd5b50604051602080611352833981018060405261002f9190810190610067565b60008054600160a060020a031916600160a060020a0392909216919091179055610099565b6000610060825161008d565b9392505050565b60006020828403121561007957600080fd5b60006100858484610054565b949350505050565b600160a060020a031690565b6112aa806100a86000396000f30060806040526004361061004b5763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416632e9cd03381146100505780633c28d86114610086575b600080fd5b34801561005c57600080fd5b5061007061006b366004610b25565b6100b3565b60405161007d919061110a565b60405180910390f35b34801561009257600080fd5b506100a66100a1366004610b5a565b61029c565b60405161007d9190611118565b6100bb6107b1565b610140820151516000808080808080606488101561010e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610105906110aa565b60405180910390fd5b6101408a0151610146907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08a0163ffffffff6105f216565b6101408b0151909750610181907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08a0163ffffffff6105f216565b9550868a61010001511115156101c3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610105906110ba565b868a61010001510394508960a001519350838611151561020f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610105906110fa565b50505083865261010087018051602088015260408701849052606087018290524260a088018190529051828503919081900386821015610255576080890186905261028f565b6101008a0151821061026d576080890184905261028f565b6102898461028461027e8487610607565b8861066d565b610684565b60808a01525b5050505050505050919050565b6102a46107e8565b6102ac6107b1565b6000606060008060006102be8a6100b3565b805160a08201519197501115610300576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610105906110ea565b60a08601516101008b015111610342576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610105906110ca565b608080870151908c01511015610384576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610105906110fa565b6000546040517f3c28d86100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690633c28d861906103e0908e908e908e908e90600401611127565b61012060405180830381600087803b1580156103fb57600080fd5b505af115801561040f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506104339190810190610b06565b96508660400151945060008511156105e4576101608a0151935061045e84601063ffffffff6106c316565b92506104728b608001518760800151610724565b915061047e8583610724565b905060008111156105325789516040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85169163a9059cbb916104de9190859060040161105f565b602060405180830381600087803b1580156104f857600080fd5b505af115801561050c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506105309190810190610ae0565b505b60008211156105e4578a516040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85169163a9059cbb916105909190869060040161105f565b602060405180830381600087803b1580156105aa57600080fd5b505af11580156105be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506105e29190810190610ae0565b505b505050505050949350505050565b60006105fe8383610766565b90505b92915050565b60008083151561061a5760009150610666565b5082820282848281151561062a57fe5b0414610662576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101059061109a565b8091505b5092915050565b600080828481151561067b57fe5b04949350505050565b600082820183811015610662576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101059061109a565b600081601401835110151515610705576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610105906110da565b50016014015173ffffffffffffffffffffffffffffffffffffffff1690565b600082821115610760576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101059061107a565b50900390565b6000816020018351101515156107a8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101059061108a565b50016020015190565b60c0604051908101604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b610120604051908101604052806107fd610817565b815260200161080a610817565b8152602001600081525090565b608060405190810160405280600081526020016000815260200160008152602001600081525090565b600061084c82356111ef565b9392505050565b600061084c825161120b565b6000601f8201831361087057600080fd5b813561088361087e826111a5565b61117e565b9150808252602083016020830185838301111561089f57600080fd5b6108aa838284611210565b50505092915050565b6000608082840312156108c557600080fd5b6108cf608061117e565b905060006108dd8484610ad4565b82525060206108ee84848301610ad4565b602083015250604061090284828501610ad4565b604083015250606061091684828501610ad4565b60608301525092915050565b6000610120828403121561093557600080fd5b61093f606061117e565b9050600061094d84846108b3565b825250608061095e848483016108b3565b60208301525061010061097384828501610ad4565b60408301525092915050565b6000610180828403121561099257600080fd5b61099d61018061117e565b905060006109ab8484610840565b82525060206109bc84848301610840565b60208301525060406109d084828501610840565b60408301525060606109e484828501610840565b60608301525060806109f884828501610ac8565b60808301525060a0610a0c84828501610ac8565b60a08301525060c0610a2084828501610ac8565b60c08301525060e0610a3484828501610ac8565b60e083015250610100610a4984828501610ac8565b61010083015250610120610a5f84828501610ac8565b6101208301525061014082013567ffffffffffffffff811115610a8157600080fd5b610a8d8482850161085f565b6101408301525061016082013567ffffffffffffffff811115610aaf57600080fd5b610abb8482850161085f565b6101608301525092915050565b600061084c8235611208565b600061084c8251611208565b600060208284031215610af257600080fd5b6000610afe8484610853565b949350505050565b60006101208284031215610b1957600080fd5b6000610afe8484610922565b600060208284031215610b3757600080fd5b813567ffffffffffffffff811115610b4e57600080fd5b610afe8482850161097f565b60008060008060808587031215610b7057600080fd5b843567ffffffffffffffff811115610b8757600080fd5b610b938782880161097f565b945050602085013567ffffffffffffffff811115610bb057600080fd5b610bbc8782880161097f565b935050604085013567ffffffffffffffff811115610bd957600080fd5b610be58782880161085f565b925050606085013567ffffffffffffffff811115610c0257600080fd5b610c0e8782880161085f565b91505092959194509250565b610c23816111ef565b82525050565b6000610c34826111eb565b808452610c4881602086016020860161121c565b610c5181611248565b9093016020019392505050565b601181527f55494e543235365f554e444552464c4f57000000000000000000000000000000602082015260400190565b602681527f475245415445525f4f525f455155414c5f544f5f33325f4c454e4754485f524560208201527f5155495245440000000000000000000000000000000000000000000000000000604082015260600190565b601081527f55494e543235365f4f564552464c4f5700000000000000000000000000000000602082015260400190565b601281527f494e56414c49445f41535345545f444154410000000000000000000000000000602082015260400190565b601281527f494e56414c49445f424547494e5f54494d450000000000000000000000000000602082015260400190565b600f81527f41554354494f4e5f455850495245440000000000000000000000000000000000602082015260400190565b602681527f475245415445525f4f525f455155414c5f544f5f32305f4c454e4754485f524560208201527f5155495245440000000000000000000000000000000000000000000000000000604082015260600190565b601381527f41554354494f4e5f4e4f545f5354415254454400000000000000000000000000602082015260400190565b600e81527f494e56414c49445f414d4f554e54000000000000000000000000000000000000602082015260400190565b805160c0830190610e6b8482611056565b506020820151610e7e6020850182611056565b506040820151610e916040850182611056565b506060820151610ea46060850182611056565b506080820151610eb76080850182611056565b5060a0820151610eca60a0850182611056565b50505050565b80516080830190610ee18482611056565b506020820151610ef46020850182611056565b506040820151610f076040850182611056565b506060820151610eca6060850182611056565b8051610120830190610f2c8482610ed0565b506020820151610f3f6080850182610ed0565b506040820151610eca610100850182611056565b8051600090610180840190610f688582610c1a565b506020830151610f7b6020860182610c1a565b506040830151610f8e6040860182610c1a565b506060830151610fa16060860182610c1a565b506080830151610fb46080860182611056565b5060a0830151610fc760a0860182611056565b5060c0830151610fda60c0860182611056565b5060e0830151610fed60e0860182611056565b50610100830151611002610100860182611056565b50610120830151611017610120860182611056565b506101408301518482036101408601526110318282610c29565b91505061016083015184820361016086015261104d8282610c29565b95945050505050565b610c2381611208565b6040810161106d8285610c1a565b61084c6020830184611056565b6020808252810161060181610c5e565b6020808252810161060181610c8e565b6020808252810161060181610ce4565b6020808252810161060181610d14565b6020808252810161060181610d44565b6020808252810161060181610d74565b6020808252810161060181610da4565b6020808252810161060181610dfa565b6020808252810161060181610e2a565b60c081016106018284610e5a565b61012081016106018284610f1a565b608080825281016111388187610f53565b9050818103602083015261114c8186610f53565b905081810360408301526111608185610c29565b905081810360608301526111748184610c29565b9695505050505050565b60405181810167ffffffffffffffff8111828210171561119d57600080fd5b604052919050565b600067ffffffffffffffff8211156111bc57600080fd5b506020601f919091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160190565b5190565b73ffffffffffffffffffffffffffffffffffffffff1690565b90565b151590565b82818337506000910152565b60005b8381101561123757818101518382015260200161121f565b83811115610eca5750506000910152565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016905600a265627a7a723058209cf70b04b75fc23e6762ae4c6c8f25ccad25dfcb39cf1dd3966eb27ce513de036c6578706572696d656e74616cf50037",
+ "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP1 PUSH2 0x1352 DUP4 CODECOPY DUP2 ADD DUP1 PUSH1 0x40 MSTORE PUSH2 0x2F SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0x67 JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB NOT AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB SWAP3 SWAP1 SWAP3 AND SWAP2 SWAP1 SWAP2 OR SWAP1 SSTORE PUSH2 0x99 JUMP JUMPDEST PUSH1 0x0 PUSH2 0x60 DUP3 MLOAD PUSH2 0x8D JUMP JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x79 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x0 PUSH2 0x85 DUP5 DUP5 PUSH2 0x54 JUMP JUMPDEST SWAP5 SWAP4 POP POP POP POP JUMP JUMPDEST PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB AND SWAP1 JUMP JUMPDEST PUSH2 0x12AA DUP1 PUSH2 0xA8 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN STOP PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH2 0x4B JUMPI PUSH4 0xFFFFFFFF PUSH29 0x100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 CALLDATALOAD DIV AND PUSH4 0x2E9CD033 DUP2 EQ PUSH2 0x50 JUMPI DUP1 PUSH4 0x3C28D861 EQ PUSH2 0x86 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x5C JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x70 PUSH2 0x6B CALLDATASIZE PUSH1 0x4 PUSH2 0xB25 JUMP JUMPDEST PUSH2 0xB3 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x7D SWAP2 SWAP1 PUSH2 0x110A JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x92 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0xA6 PUSH2 0xA1 CALLDATASIZE PUSH1 0x4 PUSH2 0xB5A JUMP JUMPDEST PUSH2 0x29C JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x7D SWAP2 SWAP1 PUSH2 0x1118 JUMP JUMPDEST PUSH2 0xBB PUSH2 0x7B1 JUMP JUMPDEST PUSH2 0x140 DUP3 ADD MLOAD MLOAD PUSH1 0x0 DUP1 DUP1 DUP1 DUP1 DUP1 DUP1 PUSH1 0x64 DUP9 LT ISZERO PUSH2 0x10E JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x105 SWAP1 PUSH2 0x10AA JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH2 0x140 DUP11 ADD MLOAD PUSH2 0x146 SWAP1 PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0 DUP11 ADD PUSH4 0xFFFFFFFF PUSH2 0x5F2 AND JUMP JUMPDEST PUSH2 0x140 DUP12 ADD MLOAD SWAP1 SWAP8 POP PUSH2 0x181 SWAP1 PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 DUP11 ADD PUSH4 0xFFFFFFFF PUSH2 0x5F2 AND JUMP JUMPDEST SWAP6 POP DUP7 DUP11 PUSH2 0x100 ADD MLOAD GT ISZERO ISZERO PUSH2 0x1C3 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x105 SWAP1 PUSH2 0x10BA JUMP JUMPDEST DUP7 DUP11 PUSH2 0x100 ADD MLOAD SUB SWAP5 POP DUP10 PUSH1 0xA0 ADD MLOAD SWAP4 POP DUP4 DUP7 GT ISZERO ISZERO PUSH2 0x20F JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x105 SWAP1 PUSH2 0x10FA JUMP JUMPDEST POP POP POP DUP4 DUP7 MSTORE PUSH2 0x100 DUP8 ADD DUP1 MLOAD PUSH1 0x20 DUP9 ADD MSTORE PUSH1 0x40 DUP8 ADD DUP5 SWAP1 MSTORE PUSH1 0x60 DUP8 ADD DUP3 SWAP1 MSTORE TIMESTAMP PUSH1 0xA0 DUP9 ADD DUP2 SWAP1 MSTORE SWAP1 MLOAD DUP3 DUP6 SUB SWAP2 SWAP1 DUP2 SWAP1 SUB DUP7 DUP3 LT ISZERO PUSH2 0x255 JUMPI PUSH1 0x80 DUP10 ADD DUP7 SWAP1 MSTORE PUSH2 0x28F JUMP JUMPDEST PUSH2 0x100 DUP11 ADD MLOAD DUP3 LT PUSH2 0x26D JUMPI PUSH1 0x80 DUP10 ADD DUP5 SWAP1 MSTORE PUSH2 0x28F JUMP JUMPDEST PUSH2 0x289 DUP5 PUSH2 0x284 PUSH2 0x27E DUP5 DUP8 PUSH2 0x607 JUMP JUMPDEST DUP9 PUSH2 0x66D JUMP JUMPDEST PUSH2 0x684 JUMP JUMPDEST PUSH1 0x80 DUP11 ADD MSTORE JUMPDEST POP POP POP POP POP POP POP POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH2 0x2A4 PUSH2 0x7E8 JUMP JUMPDEST PUSH2 0x2AC PUSH2 0x7B1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x60 PUSH1 0x0 DUP1 PUSH1 0x0 PUSH2 0x2BE DUP11 PUSH2 0xB3 JUMP JUMPDEST DUP1 MLOAD PUSH1 0xA0 DUP3 ADD MLOAD SWAP2 SWAP8 POP GT ISZERO PUSH2 0x300 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x105 SWAP1 PUSH2 0x10EA JUMP JUMPDEST PUSH1 0xA0 DUP7 ADD MLOAD PUSH2 0x100 DUP12 ADD MLOAD GT PUSH2 0x342 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x105 SWAP1 PUSH2 0x10CA JUMP JUMPDEST PUSH1 0x80 DUP1 DUP8 ADD MLOAD SWAP1 DUP13 ADD MLOAD LT ISZERO PUSH2 0x384 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x105 SWAP1 PUSH2 0x10FA JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH1 0x40 MLOAD PUSH32 0x3C28D86100000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND SWAP1 PUSH4 0x3C28D861 SWAP1 PUSH2 0x3E0 SWAP1 DUP15 SWAP1 DUP15 SWAP1 DUP15 SWAP1 DUP15 SWAP1 PUSH1 0x4 ADD PUSH2 0x1127 JUMP JUMPDEST PUSH2 0x120 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x3FB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x40F JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x1F NOT PUSH1 0x1F DUP3 ADD AND DUP3 ADD DUP1 PUSH1 0x40 MSTORE POP PUSH2 0x433 SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0xB06 JUMP JUMPDEST SWAP7 POP DUP7 PUSH1 0x40 ADD MLOAD SWAP5 POP PUSH1 0x0 DUP6 GT ISZERO PUSH2 0x5E4 JUMPI PUSH2 0x160 DUP11 ADD MLOAD SWAP4 POP PUSH2 0x45E DUP5 PUSH1 0x10 PUSH4 0xFFFFFFFF PUSH2 0x6C3 AND JUMP JUMPDEST SWAP3 POP PUSH2 0x472 DUP12 PUSH1 0x80 ADD MLOAD DUP8 PUSH1 0x80 ADD MLOAD PUSH2 0x724 JUMP JUMPDEST SWAP2 POP PUSH2 0x47E DUP6 DUP4 PUSH2 0x724 JUMP JUMPDEST SWAP1 POP PUSH1 0x0 DUP2 GT ISZERO PUSH2 0x532 JUMPI DUP10 MLOAD PUSH1 0x40 MLOAD PUSH32 0xA9059CBB00000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 AND SWAP2 PUSH4 0xA9059CBB SWAP2 PUSH2 0x4DE SWAP2 SWAP1 DUP6 SWAP1 PUSH1 0x4 ADD PUSH2 0x105F JUMP JUMPDEST PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x4F8 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x50C JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x1F NOT PUSH1 0x1F DUP3 ADD AND DUP3 ADD DUP1 PUSH1 0x40 MSTORE POP PUSH2 0x530 SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0xAE0 JUMP JUMPDEST POP JUMPDEST PUSH1 0x0 DUP3 GT ISZERO PUSH2 0x5E4 JUMPI DUP11 MLOAD PUSH1 0x40 MLOAD PUSH32 0xA9059CBB00000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 AND SWAP2 PUSH4 0xA9059CBB SWAP2 PUSH2 0x590 SWAP2 SWAP1 DUP7 SWAP1 PUSH1 0x4 ADD PUSH2 0x105F JUMP JUMPDEST PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x5AA JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x5BE JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x1F NOT PUSH1 0x1F DUP3 ADD AND DUP3 ADD DUP1 PUSH1 0x40 MSTORE POP PUSH2 0x5E2 SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0xAE0 JUMP JUMPDEST POP JUMPDEST POP POP POP POP POP POP SWAP5 SWAP4 POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x5FE DUP4 DUP4 PUSH2 0x766 JUMP JUMPDEST SWAP1 POP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 DUP4 ISZERO ISZERO PUSH2 0x61A JUMPI PUSH1 0x0 SWAP2 POP PUSH2 0x666 JUMP JUMPDEST POP DUP3 DUP3 MUL DUP3 DUP5 DUP3 DUP2 ISZERO ISZERO PUSH2 0x62A JUMPI INVALID JUMPDEST DIV EQ PUSH2 0x662 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x105 SWAP1 PUSH2 0x109A JUMP JUMPDEST DUP1 SWAP2 POP JUMPDEST POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 DUP3 DUP5 DUP2 ISZERO ISZERO PUSH2 0x67B JUMPI INVALID JUMPDEST DIV SWAP5 SWAP4 POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 DUP3 ADD DUP4 DUP2 LT ISZERO PUSH2 0x662 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x105 SWAP1 PUSH2 0x109A JUMP JUMPDEST PUSH1 0x0 DUP2 PUSH1 0x14 ADD DUP4 MLOAD LT ISZERO ISZERO ISZERO PUSH2 0x705 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x105 SWAP1 PUSH2 0x10DA JUMP JUMPDEST POP ADD PUSH1 0x14 ADD MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP3 DUP3 GT ISZERO PUSH2 0x760 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x105 SWAP1 PUSH2 0x107A JUMP JUMPDEST POP SWAP1 SUB SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP2 PUSH1 0x20 ADD DUP4 MLOAD LT ISZERO ISZERO ISZERO PUSH2 0x7A8 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x105 SWAP1 PUSH2 0x108A JUMP JUMPDEST POP ADD PUSH1 0x20 ADD MLOAD SWAP1 JUMP JUMPDEST PUSH1 0xC0 PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST PUSH2 0x120 PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 PUSH2 0x7FD PUSH2 0x817 JUMP JUMPDEST DUP2 MSTORE PUSH1 0x20 ADD PUSH2 0x80A PUSH2 0x817 JUMP JUMPDEST DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST PUSH1 0x80 PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH2 0x84C DUP3 CALLDATALOAD PUSH2 0x11EF JUMP JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x84C DUP3 MLOAD PUSH2 0x120B JUMP JUMPDEST PUSH1 0x0 PUSH1 0x1F DUP3 ADD DUP4 SGT PUSH2 0x870 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH2 0x883 PUSH2 0x87E DUP3 PUSH2 0x11A5 JUMP JUMPDEST PUSH2 0x117E JUMP JUMPDEST SWAP2 POP DUP1 DUP3 MSTORE PUSH1 0x20 DUP4 ADD PUSH1 0x20 DUP4 ADD DUP6 DUP4 DUP4 ADD GT ISZERO PUSH2 0x89F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x8AA DUP4 DUP3 DUP5 PUSH2 0x1210 JUMP JUMPDEST POP POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x80 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x8C5 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x8CF PUSH1 0x80 PUSH2 0x117E JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0x8DD DUP5 DUP5 PUSH2 0xAD4 JUMP JUMPDEST DUP3 MSTORE POP PUSH1 0x20 PUSH2 0x8EE DUP5 DUP5 DUP4 ADD PUSH2 0xAD4 JUMP JUMPDEST PUSH1 0x20 DUP4 ADD MSTORE POP PUSH1 0x40 PUSH2 0x902 DUP5 DUP3 DUP6 ADD PUSH2 0xAD4 JUMP JUMPDEST PUSH1 0x40 DUP4 ADD MSTORE POP PUSH1 0x60 PUSH2 0x916 DUP5 DUP3 DUP6 ADD PUSH2 0xAD4 JUMP JUMPDEST PUSH1 0x60 DUP4 ADD MSTORE POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x120 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x935 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x93F PUSH1 0x60 PUSH2 0x117E JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0x94D DUP5 DUP5 PUSH2 0x8B3 JUMP JUMPDEST DUP3 MSTORE POP PUSH1 0x80 PUSH2 0x95E DUP5 DUP5 DUP4 ADD PUSH2 0x8B3 JUMP JUMPDEST PUSH1 0x20 DUP4 ADD MSTORE POP PUSH2 0x100 PUSH2 0x973 DUP5 DUP3 DUP6 ADD PUSH2 0xAD4 JUMP JUMPDEST PUSH1 0x40 DUP4 ADD MSTORE POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x180 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x992 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x99D PUSH2 0x180 PUSH2 0x117E JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0x9AB DUP5 DUP5 PUSH2 0x840 JUMP JUMPDEST DUP3 MSTORE POP PUSH1 0x20 PUSH2 0x9BC DUP5 DUP5 DUP4 ADD PUSH2 0x840 JUMP JUMPDEST PUSH1 0x20 DUP4 ADD MSTORE POP PUSH1 0x40 PUSH2 0x9D0 DUP5 DUP3 DUP6 ADD PUSH2 0x840 JUMP JUMPDEST PUSH1 0x40 DUP4 ADD MSTORE POP PUSH1 0x60 PUSH2 0x9E4 DUP5 DUP3 DUP6 ADD PUSH2 0x840 JUMP JUMPDEST PUSH1 0x60 DUP4 ADD MSTORE POP PUSH1 0x80 PUSH2 0x9F8 DUP5 DUP3 DUP6 ADD PUSH2 0xAC8 JUMP JUMPDEST PUSH1 0x80 DUP4 ADD MSTORE POP PUSH1 0xA0 PUSH2 0xA0C DUP5 DUP3 DUP6 ADD PUSH2 0xAC8 JUMP JUMPDEST PUSH1 0xA0 DUP4 ADD MSTORE POP PUSH1 0xC0 PUSH2 0xA20 DUP5 DUP3 DUP6 ADD PUSH2 0xAC8 JUMP JUMPDEST PUSH1 0xC0 DUP4 ADD MSTORE POP PUSH1 0xE0 PUSH2 0xA34 DUP5 DUP3 DUP6 ADD PUSH2 0xAC8 JUMP JUMPDEST PUSH1 0xE0 DUP4 ADD MSTORE POP PUSH2 0x100 PUSH2 0xA49 DUP5 DUP3 DUP6 ADD PUSH2 0xAC8 JUMP JUMPDEST PUSH2 0x100 DUP4 ADD MSTORE POP PUSH2 0x120 PUSH2 0xA5F DUP5 DUP3 DUP6 ADD PUSH2 0xAC8 JUMP JUMPDEST PUSH2 0x120 DUP4 ADD MSTORE POP PUSH2 0x140 DUP3 ADD CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0xA81 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xA8D DUP5 DUP3 DUP6 ADD PUSH2 0x85F JUMP JUMPDEST PUSH2 0x140 DUP4 ADD MSTORE POP PUSH2 0x160 DUP3 ADD CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0xAAF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xABB DUP5 DUP3 DUP6 ADD PUSH2 0x85F JUMP JUMPDEST PUSH2 0x160 DUP4 ADD MSTORE POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x84C DUP3 CALLDATALOAD PUSH2 0x1208 JUMP JUMPDEST PUSH1 0x0 PUSH2 0x84C DUP3 MLOAD PUSH2 0x1208 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0xAF2 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x0 PUSH2 0xAFE DUP5 DUP5 PUSH2 0x853 JUMP JUMPDEST SWAP5 SWAP4 POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x120 DUP3 DUP5 SUB SLT ISZERO PUSH2 0xB19 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x0 PUSH2 0xAFE DUP5 DUP5 PUSH2 0x922 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0xB37 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0xB4E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xAFE DUP5 DUP3 DUP6 ADD PUSH2 0x97F JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP1 PUSH1 0x80 DUP6 DUP8 SUB SLT ISZERO PUSH2 0xB70 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP5 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0xB87 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xB93 DUP8 DUP3 DUP9 ADD PUSH2 0x97F JUMP JUMPDEST SWAP5 POP POP PUSH1 0x20 DUP6 ADD CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0xBB0 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xBBC DUP8 DUP3 DUP9 ADD PUSH2 0x97F JUMP JUMPDEST SWAP4 POP POP PUSH1 0x40 DUP6 ADD CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0xBD9 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xBE5 DUP8 DUP3 DUP9 ADD PUSH2 0x85F JUMP JUMPDEST SWAP3 POP POP PUSH1 0x60 DUP6 ADD CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0xC02 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xC0E DUP8 DUP3 DUP9 ADD PUSH2 0x85F JUMP JUMPDEST SWAP2 POP POP SWAP3 SWAP6 SWAP2 SWAP5 POP SWAP3 POP JUMP JUMPDEST PUSH2 0xC23 DUP2 PUSH2 0x11EF JUMP JUMPDEST DUP3 MSTORE POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0xC34 DUP3 PUSH2 0x11EB JUMP JUMPDEST DUP1 DUP5 MSTORE PUSH2 0xC48 DUP2 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP7 ADD PUSH2 0x121C JUMP JUMPDEST PUSH2 0xC51 DUP2 PUSH2 0x1248 JUMP JUMPDEST SWAP1 SWAP4 ADD PUSH1 0x20 ADD SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x11 DUP2 MSTORE PUSH32 0x55494E543235365F554E444552464C4F57000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x40 ADD SWAP1 JUMP JUMPDEST PUSH1 0x26 DUP2 MSTORE PUSH32 0x475245415445525F4F525F455155414C5F544F5F33325F4C454E4754485F5245 PUSH1 0x20 DUP3 ADD MSTORE PUSH32 0x5155495245440000000000000000000000000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x10 DUP2 MSTORE PUSH32 0x55494E543235365F4F564552464C4F5700000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x40 ADD SWAP1 JUMP JUMPDEST PUSH1 0x12 DUP2 MSTORE PUSH32 0x494E56414C49445F41535345545F444154410000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x40 ADD SWAP1 JUMP JUMPDEST PUSH1 0x12 DUP2 MSTORE PUSH32 0x494E56414C49445F424547494E5F54494D450000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x40 ADD SWAP1 JUMP JUMPDEST PUSH1 0xF DUP2 MSTORE PUSH32 0x41554354494F4E5F455850495245440000000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x40 ADD SWAP1 JUMP JUMPDEST PUSH1 0x26 DUP2 MSTORE PUSH32 0x475245415445525F4F525F455155414C5F544F5F32305F4C454E4754485F5245 PUSH1 0x20 DUP3 ADD MSTORE PUSH32 0x5155495245440000000000000000000000000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x13 DUP2 MSTORE PUSH32 0x41554354494F4E5F4E4F545F5354415254454400000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x40 ADD SWAP1 JUMP JUMPDEST PUSH1 0xE DUP2 MSTORE PUSH32 0x494E56414C49445F414D4F554E54000000000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x40 ADD SWAP1 JUMP JUMPDEST DUP1 MLOAD PUSH1 0xC0 DUP4 ADD SWAP1 PUSH2 0xE6B DUP5 DUP3 PUSH2 0x1056 JUMP JUMPDEST POP PUSH1 0x20 DUP3 ADD MLOAD PUSH2 0xE7E PUSH1 0x20 DUP6 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST POP PUSH1 0x40 DUP3 ADD MLOAD PUSH2 0xE91 PUSH1 0x40 DUP6 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST POP PUSH1 0x60 DUP3 ADD MLOAD PUSH2 0xEA4 PUSH1 0x60 DUP6 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST POP PUSH1 0x80 DUP3 ADD MLOAD PUSH2 0xEB7 PUSH1 0x80 DUP6 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST POP PUSH1 0xA0 DUP3 ADD MLOAD PUSH2 0xECA PUSH1 0xA0 DUP6 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST POP POP POP POP JUMP JUMPDEST DUP1 MLOAD PUSH1 0x80 DUP4 ADD SWAP1 PUSH2 0xEE1 DUP5 DUP3 PUSH2 0x1056 JUMP JUMPDEST POP PUSH1 0x20 DUP3 ADD MLOAD PUSH2 0xEF4 PUSH1 0x20 DUP6 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST POP PUSH1 0x40 DUP3 ADD MLOAD PUSH2 0xF07 PUSH1 0x40 DUP6 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST POP PUSH1 0x60 DUP3 ADD MLOAD PUSH2 0xECA PUSH1 0x60 DUP6 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST DUP1 MLOAD PUSH2 0x120 DUP4 ADD SWAP1 PUSH2 0xF2C DUP5 DUP3 PUSH2 0xED0 JUMP JUMPDEST POP PUSH1 0x20 DUP3 ADD MLOAD PUSH2 0xF3F PUSH1 0x80 DUP6 ADD DUP3 PUSH2 0xED0 JUMP JUMPDEST POP PUSH1 0x40 DUP3 ADD MLOAD PUSH2 0xECA PUSH2 0x100 DUP6 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST DUP1 MLOAD PUSH1 0x0 SWAP1 PUSH2 0x180 DUP5 ADD SWAP1 PUSH2 0xF68 DUP6 DUP3 PUSH2 0xC1A JUMP JUMPDEST POP PUSH1 0x20 DUP4 ADD MLOAD PUSH2 0xF7B PUSH1 0x20 DUP7 ADD DUP3 PUSH2 0xC1A JUMP JUMPDEST POP PUSH1 0x40 DUP4 ADD MLOAD PUSH2 0xF8E PUSH1 0x40 DUP7 ADD DUP3 PUSH2 0xC1A JUMP JUMPDEST POP PUSH1 0x60 DUP4 ADD MLOAD PUSH2 0xFA1 PUSH1 0x60 DUP7 ADD DUP3 PUSH2 0xC1A JUMP JUMPDEST POP PUSH1 0x80 DUP4 ADD MLOAD PUSH2 0xFB4 PUSH1 0x80 DUP7 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST POP PUSH1 0xA0 DUP4 ADD MLOAD PUSH2 0xFC7 PUSH1 0xA0 DUP7 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST POP PUSH1 0xC0 DUP4 ADD MLOAD PUSH2 0xFDA PUSH1 0xC0 DUP7 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST POP PUSH1 0xE0 DUP4 ADD MLOAD PUSH2 0xFED PUSH1 0xE0 DUP7 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST POP PUSH2 0x100 DUP4 ADD MLOAD PUSH2 0x1002 PUSH2 0x100 DUP7 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST POP PUSH2 0x120 DUP4 ADD MLOAD PUSH2 0x1017 PUSH2 0x120 DUP7 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST POP PUSH2 0x140 DUP4 ADD MLOAD DUP5 DUP3 SUB PUSH2 0x140 DUP7 ADD MSTORE PUSH2 0x1031 DUP3 DUP3 PUSH2 0xC29 JUMP JUMPDEST SWAP2 POP POP PUSH2 0x160 DUP4 ADD MLOAD DUP5 DUP3 SUB PUSH2 0x160 DUP7 ADD MSTORE PUSH2 0x104D DUP3 DUP3 PUSH2 0xC29 JUMP JUMPDEST SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH2 0xC23 DUP2 PUSH2 0x1208 JUMP JUMPDEST PUSH1 0x40 DUP2 ADD PUSH2 0x106D DUP3 DUP6 PUSH2 0xC1A JUMP JUMPDEST PUSH2 0x84C PUSH1 0x20 DUP4 ADD DUP5 PUSH2 0x1056 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE DUP2 ADD PUSH2 0x601 DUP2 PUSH2 0xC5E JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE DUP2 ADD PUSH2 0x601 DUP2 PUSH2 0xC8E JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE DUP2 ADD PUSH2 0x601 DUP2 PUSH2 0xCE4 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE DUP2 ADD PUSH2 0x601 DUP2 PUSH2 0xD14 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE DUP2 ADD PUSH2 0x601 DUP2 PUSH2 0xD44 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE DUP2 ADD PUSH2 0x601 DUP2 PUSH2 0xD74 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE DUP2 ADD PUSH2 0x601 DUP2 PUSH2 0xDA4 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE DUP2 ADD PUSH2 0x601 DUP2 PUSH2 0xDFA JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE DUP2 ADD PUSH2 0x601 DUP2 PUSH2 0xE2A JUMP JUMPDEST PUSH1 0xC0 DUP2 ADD PUSH2 0x601 DUP3 DUP5 PUSH2 0xE5A JUMP JUMPDEST PUSH2 0x120 DUP2 ADD PUSH2 0x601 DUP3 DUP5 PUSH2 0xF1A JUMP JUMPDEST PUSH1 0x80 DUP1 DUP3 MSTORE DUP2 ADD PUSH2 0x1138 DUP2 DUP8 PUSH2 0xF53 JUMP JUMPDEST SWAP1 POP DUP2 DUP2 SUB PUSH1 0x20 DUP4 ADD MSTORE PUSH2 0x114C DUP2 DUP7 PUSH2 0xF53 JUMP JUMPDEST SWAP1 POP DUP2 DUP2 SUB PUSH1 0x40 DUP4 ADD MSTORE PUSH2 0x1160 DUP2 DUP6 PUSH2 0xC29 JUMP JUMPDEST SWAP1 POP DUP2 DUP2 SUB PUSH1 0x60 DUP4 ADD MSTORE PUSH2 0x1174 DUP2 DUP5 PUSH2 0xC29 JUMP JUMPDEST SWAP7 SWAP6 POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x40 MLOAD DUP2 DUP2 ADD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT DUP3 DUP3 LT OR ISZERO PUSH2 0x119D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x40 MSTORE SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 PUSH8 0xFFFFFFFFFFFFFFFF DUP3 GT ISZERO PUSH2 0x11BC JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x20 PUSH1 0x1F SWAP2 SWAP1 SWAP2 ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND ADD SWAP1 JUMP JUMPDEST MLOAD SWAP1 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 JUMP JUMPDEST SWAP1 JUMP JUMPDEST ISZERO ISZERO SWAP1 JUMP JUMPDEST DUP3 DUP2 DUP4 CALLDATACOPY POP PUSH1 0x0 SWAP2 ADD MSTORE JUMP JUMPDEST PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x1237 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x121F JUMP JUMPDEST DUP4 DUP2 GT ISZERO PUSH2 0xECA JUMPI POP POP PUSH1 0x0 SWAP2 ADD MSTORE JUMP JUMPDEST PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP1 JUMP STOP LOG2 PUSH6 0x627A7A723058 KECCAK256 SWAP13 0xf7 SIGNEXTEND DIV 0xb7 0x5f 0xc2 RETURNDATACOPY PUSH8 0x62AE4C6C8F25CCAD 0x25 0xdf 0xcb CODECOPY 0xcf SAR 0xd3 SWAP7 PUSH15 0xB27CE513DE036C6578706572696D65 PUSH15 0x74616CF50037000000000000000000 ",
+ "sourceMap": "986:9378:28:-;;;1673:99;8:9:-1;5:2;;;30:1;27;20:12;5:2;1673:99:28;;;;;;;;;;;;;;;;;;;;;;1734:8;:31;;-1:-1:-1;;;;;;1734:31:28;-1:-1:-1;;;;;1734:31:28;;;;;;;;;;986:9378;;5:122:-1;;83:39;114:6;108:13;83:39;;;74:48;68:59;-1:-1;;;68:59;134:263;;249:2;237:9;228:7;224:23;220:32;217:2;;;265:1;262;255:12;217:2;300:1;317:64;373:7;353:9;317:64;;;307:74;211:186;-1:-1;;;;211:186;404:128;-1:-1;;;;;473:54;;456:76;;986:9378:28;;;;;;"
+ },
+ "deployedBytecode": {
+ "linkReferences": {},
+ "object": "0x60806040526004361061004b5763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416632e9cd03381146100505780633c28d86114610086575b600080fd5b34801561005c57600080fd5b5061007061006b366004610b25565b6100b3565b60405161007d919061110a565b60405180910390f35b34801561009257600080fd5b506100a66100a1366004610b5a565b61029c565b60405161007d9190611118565b6100bb6107b1565b610140820151516000808080808080606488101561010e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610105906110aa565b60405180910390fd5b6101408a0151610146907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08a0163ffffffff6105f216565b6101408b0151909750610181907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08a0163ffffffff6105f216565b9550868a61010001511115156101c3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610105906110ba565b868a61010001510394508960a001519350838611151561020f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610105906110fa565b50505083865261010087018051602088015260408701849052606087018290524260a088018190529051828503919081900386821015610255576080890186905261028f565b6101008a0151821061026d576080890184905261028f565b6102898461028461027e8487610607565b8861066d565b610684565b60808a01525b5050505050505050919050565b6102a46107e8565b6102ac6107b1565b6000606060008060006102be8a6100b3565b805160a08201519197501115610300576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610105906110ea565b60a08601516101008b015111610342576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610105906110ca565b608080870151908c01511015610384576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610105906110fa565b6000546040517f3c28d86100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690633c28d861906103e0908e908e908e908e90600401611127565b61012060405180830381600087803b1580156103fb57600080fd5b505af115801561040f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506104339190810190610b06565b96508660400151945060008511156105e4576101608a0151935061045e84601063ffffffff6106c316565b92506104728b608001518760800151610724565b915061047e8583610724565b905060008111156105325789516040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85169163a9059cbb916104de9190859060040161105f565b602060405180830381600087803b1580156104f857600080fd5b505af115801561050c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506105309190810190610ae0565b505b60008211156105e4578a516040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85169163a9059cbb916105909190869060040161105f565b602060405180830381600087803b1580156105aa57600080fd5b505af11580156105be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506105e29190810190610ae0565b505b505050505050949350505050565b60006105fe8383610766565b90505b92915050565b60008083151561061a5760009150610666565b5082820282848281151561062a57fe5b0414610662576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101059061109a565b8091505b5092915050565b600080828481151561067b57fe5b04949350505050565b600082820183811015610662576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101059061109a565b600081601401835110151515610705576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610105906110da565b50016014015173ffffffffffffffffffffffffffffffffffffffff1690565b600082821115610760576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101059061107a565b50900390565b6000816020018351101515156107a8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101059061108a565b50016020015190565b60c0604051908101604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b610120604051908101604052806107fd610817565b815260200161080a610817565b8152602001600081525090565b608060405190810160405280600081526020016000815260200160008152602001600081525090565b600061084c82356111ef565b9392505050565b600061084c825161120b565b6000601f8201831361087057600080fd5b813561088361087e826111a5565b61117e565b9150808252602083016020830185838301111561089f57600080fd5b6108aa838284611210565b50505092915050565b6000608082840312156108c557600080fd5b6108cf608061117e565b905060006108dd8484610ad4565b82525060206108ee84848301610ad4565b602083015250604061090284828501610ad4565b604083015250606061091684828501610ad4565b60608301525092915050565b6000610120828403121561093557600080fd5b61093f606061117e565b9050600061094d84846108b3565b825250608061095e848483016108b3565b60208301525061010061097384828501610ad4565b60408301525092915050565b6000610180828403121561099257600080fd5b61099d61018061117e565b905060006109ab8484610840565b82525060206109bc84848301610840565b60208301525060406109d084828501610840565b60408301525060606109e484828501610840565b60608301525060806109f884828501610ac8565b60808301525060a0610a0c84828501610ac8565b60a08301525060c0610a2084828501610ac8565b60c08301525060e0610a3484828501610ac8565b60e083015250610100610a4984828501610ac8565b61010083015250610120610a5f84828501610ac8565b6101208301525061014082013567ffffffffffffffff811115610a8157600080fd5b610a8d8482850161085f565b6101408301525061016082013567ffffffffffffffff811115610aaf57600080fd5b610abb8482850161085f565b6101608301525092915050565b600061084c8235611208565b600061084c8251611208565b600060208284031215610af257600080fd5b6000610afe8484610853565b949350505050565b60006101208284031215610b1957600080fd5b6000610afe8484610922565b600060208284031215610b3757600080fd5b813567ffffffffffffffff811115610b4e57600080fd5b610afe8482850161097f565b60008060008060808587031215610b7057600080fd5b843567ffffffffffffffff811115610b8757600080fd5b610b938782880161097f565b945050602085013567ffffffffffffffff811115610bb057600080fd5b610bbc8782880161097f565b935050604085013567ffffffffffffffff811115610bd957600080fd5b610be58782880161085f565b925050606085013567ffffffffffffffff811115610c0257600080fd5b610c0e8782880161085f565b91505092959194509250565b610c23816111ef565b82525050565b6000610c34826111eb565b808452610c4881602086016020860161121c565b610c5181611248565b9093016020019392505050565b601181527f55494e543235365f554e444552464c4f57000000000000000000000000000000602082015260400190565b602681527f475245415445525f4f525f455155414c5f544f5f33325f4c454e4754485f524560208201527f5155495245440000000000000000000000000000000000000000000000000000604082015260600190565b601081527f55494e543235365f4f564552464c4f5700000000000000000000000000000000602082015260400190565b601281527f494e56414c49445f41535345545f444154410000000000000000000000000000602082015260400190565b601281527f494e56414c49445f424547494e5f54494d450000000000000000000000000000602082015260400190565b600f81527f41554354494f4e5f455850495245440000000000000000000000000000000000602082015260400190565b602681527f475245415445525f4f525f455155414c5f544f5f32305f4c454e4754485f524560208201527f5155495245440000000000000000000000000000000000000000000000000000604082015260600190565b601381527f41554354494f4e5f4e4f545f5354415254454400000000000000000000000000602082015260400190565b600e81527f494e56414c49445f414d4f554e54000000000000000000000000000000000000602082015260400190565b805160c0830190610e6b8482611056565b506020820151610e7e6020850182611056565b506040820151610e916040850182611056565b506060820151610ea46060850182611056565b506080820151610eb76080850182611056565b5060a0820151610eca60a0850182611056565b50505050565b80516080830190610ee18482611056565b506020820151610ef46020850182611056565b506040820151610f076040850182611056565b506060820151610eca6060850182611056565b8051610120830190610f2c8482610ed0565b506020820151610f3f6080850182610ed0565b506040820151610eca610100850182611056565b8051600090610180840190610f688582610c1a565b506020830151610f7b6020860182610c1a565b506040830151610f8e6040860182610c1a565b506060830151610fa16060860182610c1a565b506080830151610fb46080860182611056565b5060a0830151610fc760a0860182611056565b5060c0830151610fda60c0860182611056565b5060e0830151610fed60e0860182611056565b50610100830151611002610100860182611056565b50610120830151611017610120860182611056565b506101408301518482036101408601526110318282610c29565b91505061016083015184820361016086015261104d8282610c29565b95945050505050565b610c2381611208565b6040810161106d8285610c1a565b61084c6020830184611056565b6020808252810161060181610c5e565b6020808252810161060181610c8e565b6020808252810161060181610ce4565b6020808252810161060181610d14565b6020808252810161060181610d44565b6020808252810161060181610d74565b6020808252810161060181610da4565b6020808252810161060181610dfa565b6020808252810161060181610e2a565b60c081016106018284610e5a565b61012081016106018284610f1a565b608080825281016111388187610f53565b9050818103602083015261114c8186610f53565b905081810360408301526111608185610c29565b905081810360608301526111748184610c29565b9695505050505050565b60405181810167ffffffffffffffff8111828210171561119d57600080fd5b604052919050565b600067ffffffffffffffff8211156111bc57600080fd5b506020601f919091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160190565b5190565b73ffffffffffffffffffffffffffffffffffffffff1690565b90565b151590565b82818337506000910152565b60005b8381101561123757818101518382015260200161121f565b83811115610eca5750506000910152565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016905600a265627a7a723058209cf70b04b75fc23e6762ae4c6c8f25ccad25dfcb39cf1dd3966eb27ce513de036c6578706572696d656e74616cf50037",
+ "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH2 0x4B JUMPI PUSH4 0xFFFFFFFF PUSH29 0x100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 CALLDATALOAD DIV AND PUSH4 0x2E9CD033 DUP2 EQ PUSH2 0x50 JUMPI DUP1 PUSH4 0x3C28D861 EQ PUSH2 0x86 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x5C JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x70 PUSH2 0x6B CALLDATASIZE PUSH1 0x4 PUSH2 0xB25 JUMP JUMPDEST PUSH2 0xB3 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x7D SWAP2 SWAP1 PUSH2 0x110A JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x92 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0xA6 PUSH2 0xA1 CALLDATASIZE PUSH1 0x4 PUSH2 0xB5A JUMP JUMPDEST PUSH2 0x29C JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x7D SWAP2 SWAP1 PUSH2 0x1118 JUMP JUMPDEST PUSH2 0xBB PUSH2 0x7B1 JUMP JUMPDEST PUSH2 0x140 DUP3 ADD MLOAD MLOAD PUSH1 0x0 DUP1 DUP1 DUP1 DUP1 DUP1 DUP1 PUSH1 0x64 DUP9 LT ISZERO PUSH2 0x10E JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x105 SWAP1 PUSH2 0x10AA JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH2 0x140 DUP11 ADD MLOAD PUSH2 0x146 SWAP1 PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0 DUP11 ADD PUSH4 0xFFFFFFFF PUSH2 0x5F2 AND JUMP JUMPDEST PUSH2 0x140 DUP12 ADD MLOAD SWAP1 SWAP8 POP PUSH2 0x181 SWAP1 PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 DUP11 ADD PUSH4 0xFFFFFFFF PUSH2 0x5F2 AND JUMP JUMPDEST SWAP6 POP DUP7 DUP11 PUSH2 0x100 ADD MLOAD GT ISZERO ISZERO PUSH2 0x1C3 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x105 SWAP1 PUSH2 0x10BA JUMP JUMPDEST DUP7 DUP11 PUSH2 0x100 ADD MLOAD SUB SWAP5 POP DUP10 PUSH1 0xA0 ADD MLOAD SWAP4 POP DUP4 DUP7 GT ISZERO ISZERO PUSH2 0x20F JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x105 SWAP1 PUSH2 0x10FA JUMP JUMPDEST POP POP POP DUP4 DUP7 MSTORE PUSH2 0x100 DUP8 ADD DUP1 MLOAD PUSH1 0x20 DUP9 ADD MSTORE PUSH1 0x40 DUP8 ADD DUP5 SWAP1 MSTORE PUSH1 0x60 DUP8 ADD DUP3 SWAP1 MSTORE TIMESTAMP PUSH1 0xA0 DUP9 ADD DUP2 SWAP1 MSTORE SWAP1 MLOAD DUP3 DUP6 SUB SWAP2 SWAP1 DUP2 SWAP1 SUB DUP7 DUP3 LT ISZERO PUSH2 0x255 JUMPI PUSH1 0x80 DUP10 ADD DUP7 SWAP1 MSTORE PUSH2 0x28F JUMP JUMPDEST PUSH2 0x100 DUP11 ADD MLOAD DUP3 LT PUSH2 0x26D JUMPI PUSH1 0x80 DUP10 ADD DUP5 SWAP1 MSTORE PUSH2 0x28F JUMP JUMPDEST PUSH2 0x289 DUP5 PUSH2 0x284 PUSH2 0x27E DUP5 DUP8 PUSH2 0x607 JUMP JUMPDEST DUP9 PUSH2 0x66D JUMP JUMPDEST PUSH2 0x684 JUMP JUMPDEST PUSH1 0x80 DUP11 ADD MSTORE JUMPDEST POP POP POP POP POP POP POP POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH2 0x2A4 PUSH2 0x7E8 JUMP JUMPDEST PUSH2 0x2AC PUSH2 0x7B1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x60 PUSH1 0x0 DUP1 PUSH1 0x0 PUSH2 0x2BE DUP11 PUSH2 0xB3 JUMP JUMPDEST DUP1 MLOAD PUSH1 0xA0 DUP3 ADD MLOAD SWAP2 SWAP8 POP GT ISZERO PUSH2 0x300 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x105 SWAP1 PUSH2 0x10EA JUMP JUMPDEST PUSH1 0xA0 DUP7 ADD MLOAD PUSH2 0x100 DUP12 ADD MLOAD GT PUSH2 0x342 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x105 SWAP1 PUSH2 0x10CA JUMP JUMPDEST PUSH1 0x80 DUP1 DUP8 ADD MLOAD SWAP1 DUP13 ADD MLOAD LT ISZERO PUSH2 0x384 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x105 SWAP1 PUSH2 0x10FA JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH1 0x40 MLOAD PUSH32 0x3C28D86100000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND SWAP1 PUSH4 0x3C28D861 SWAP1 PUSH2 0x3E0 SWAP1 DUP15 SWAP1 DUP15 SWAP1 DUP15 SWAP1 DUP15 SWAP1 PUSH1 0x4 ADD PUSH2 0x1127 JUMP JUMPDEST PUSH2 0x120 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x3FB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x40F JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x1F NOT PUSH1 0x1F DUP3 ADD AND DUP3 ADD DUP1 PUSH1 0x40 MSTORE POP PUSH2 0x433 SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0xB06 JUMP JUMPDEST SWAP7 POP DUP7 PUSH1 0x40 ADD MLOAD SWAP5 POP PUSH1 0x0 DUP6 GT ISZERO PUSH2 0x5E4 JUMPI PUSH2 0x160 DUP11 ADD MLOAD SWAP4 POP PUSH2 0x45E DUP5 PUSH1 0x10 PUSH4 0xFFFFFFFF PUSH2 0x6C3 AND JUMP JUMPDEST SWAP3 POP PUSH2 0x472 DUP12 PUSH1 0x80 ADD MLOAD DUP8 PUSH1 0x80 ADD MLOAD PUSH2 0x724 JUMP JUMPDEST SWAP2 POP PUSH2 0x47E DUP6 DUP4 PUSH2 0x724 JUMP JUMPDEST SWAP1 POP PUSH1 0x0 DUP2 GT ISZERO PUSH2 0x532 JUMPI DUP10 MLOAD PUSH1 0x40 MLOAD PUSH32 0xA9059CBB00000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 AND SWAP2 PUSH4 0xA9059CBB SWAP2 PUSH2 0x4DE SWAP2 SWAP1 DUP6 SWAP1 PUSH1 0x4 ADD PUSH2 0x105F JUMP JUMPDEST PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x4F8 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x50C JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x1F NOT PUSH1 0x1F DUP3 ADD AND DUP3 ADD DUP1 PUSH1 0x40 MSTORE POP PUSH2 0x530 SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0xAE0 JUMP JUMPDEST POP JUMPDEST PUSH1 0x0 DUP3 GT ISZERO PUSH2 0x5E4 JUMPI DUP11 MLOAD PUSH1 0x40 MLOAD PUSH32 0xA9059CBB00000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 AND SWAP2 PUSH4 0xA9059CBB SWAP2 PUSH2 0x590 SWAP2 SWAP1 DUP7 SWAP1 PUSH1 0x4 ADD PUSH2 0x105F JUMP JUMPDEST PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x5AA JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x5BE JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x1F NOT PUSH1 0x1F DUP3 ADD AND DUP3 ADD DUP1 PUSH1 0x40 MSTORE POP PUSH2 0x5E2 SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0xAE0 JUMP JUMPDEST POP JUMPDEST POP POP POP POP POP POP SWAP5 SWAP4 POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x5FE DUP4 DUP4 PUSH2 0x766 JUMP JUMPDEST SWAP1 POP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 DUP4 ISZERO ISZERO PUSH2 0x61A JUMPI PUSH1 0x0 SWAP2 POP PUSH2 0x666 JUMP JUMPDEST POP DUP3 DUP3 MUL DUP3 DUP5 DUP3 DUP2 ISZERO ISZERO PUSH2 0x62A JUMPI INVALID JUMPDEST DIV EQ PUSH2 0x662 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x105 SWAP1 PUSH2 0x109A JUMP JUMPDEST DUP1 SWAP2 POP JUMPDEST POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 DUP3 DUP5 DUP2 ISZERO ISZERO PUSH2 0x67B JUMPI INVALID JUMPDEST DIV SWAP5 SWAP4 POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 DUP3 ADD DUP4 DUP2 LT ISZERO PUSH2 0x662 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x105 SWAP1 PUSH2 0x109A JUMP JUMPDEST PUSH1 0x0 DUP2 PUSH1 0x14 ADD DUP4 MLOAD LT ISZERO ISZERO ISZERO PUSH2 0x705 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x105 SWAP1 PUSH2 0x10DA JUMP JUMPDEST POP ADD PUSH1 0x14 ADD MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP3 DUP3 GT ISZERO PUSH2 0x760 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x105 SWAP1 PUSH2 0x107A JUMP JUMPDEST POP SWAP1 SUB SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP2 PUSH1 0x20 ADD DUP4 MLOAD LT ISZERO ISZERO ISZERO PUSH2 0x7A8 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x105 SWAP1 PUSH2 0x108A JUMP JUMPDEST POP ADD PUSH1 0x20 ADD MLOAD SWAP1 JUMP JUMPDEST PUSH1 0xC0 PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST PUSH2 0x120 PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 PUSH2 0x7FD PUSH2 0x817 JUMP JUMPDEST DUP2 MSTORE PUSH1 0x20 ADD PUSH2 0x80A PUSH2 0x817 JUMP JUMPDEST DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST PUSH1 0x80 PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH2 0x84C DUP3 CALLDATALOAD PUSH2 0x11EF JUMP JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x84C DUP3 MLOAD PUSH2 0x120B JUMP JUMPDEST PUSH1 0x0 PUSH1 0x1F DUP3 ADD DUP4 SGT PUSH2 0x870 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH2 0x883 PUSH2 0x87E DUP3 PUSH2 0x11A5 JUMP JUMPDEST PUSH2 0x117E JUMP JUMPDEST SWAP2 POP DUP1 DUP3 MSTORE PUSH1 0x20 DUP4 ADD PUSH1 0x20 DUP4 ADD DUP6 DUP4 DUP4 ADD GT ISZERO PUSH2 0x89F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x8AA DUP4 DUP3 DUP5 PUSH2 0x1210 JUMP JUMPDEST POP POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x80 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x8C5 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x8CF PUSH1 0x80 PUSH2 0x117E JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0x8DD DUP5 DUP5 PUSH2 0xAD4 JUMP JUMPDEST DUP3 MSTORE POP PUSH1 0x20 PUSH2 0x8EE DUP5 DUP5 DUP4 ADD PUSH2 0xAD4 JUMP JUMPDEST PUSH1 0x20 DUP4 ADD MSTORE POP PUSH1 0x40 PUSH2 0x902 DUP5 DUP3 DUP6 ADD PUSH2 0xAD4 JUMP JUMPDEST PUSH1 0x40 DUP4 ADD MSTORE POP PUSH1 0x60 PUSH2 0x916 DUP5 DUP3 DUP6 ADD PUSH2 0xAD4 JUMP JUMPDEST PUSH1 0x60 DUP4 ADD MSTORE POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x120 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x935 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x93F PUSH1 0x60 PUSH2 0x117E JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0x94D DUP5 DUP5 PUSH2 0x8B3 JUMP JUMPDEST DUP3 MSTORE POP PUSH1 0x80 PUSH2 0x95E DUP5 DUP5 DUP4 ADD PUSH2 0x8B3 JUMP JUMPDEST PUSH1 0x20 DUP4 ADD MSTORE POP PUSH2 0x100 PUSH2 0x973 DUP5 DUP3 DUP6 ADD PUSH2 0xAD4 JUMP JUMPDEST PUSH1 0x40 DUP4 ADD MSTORE POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x180 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x992 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x99D PUSH2 0x180 PUSH2 0x117E JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0x9AB DUP5 DUP5 PUSH2 0x840 JUMP JUMPDEST DUP3 MSTORE POP PUSH1 0x20 PUSH2 0x9BC DUP5 DUP5 DUP4 ADD PUSH2 0x840 JUMP JUMPDEST PUSH1 0x20 DUP4 ADD MSTORE POP PUSH1 0x40 PUSH2 0x9D0 DUP5 DUP3 DUP6 ADD PUSH2 0x840 JUMP JUMPDEST PUSH1 0x40 DUP4 ADD MSTORE POP PUSH1 0x60 PUSH2 0x9E4 DUP5 DUP3 DUP6 ADD PUSH2 0x840 JUMP JUMPDEST PUSH1 0x60 DUP4 ADD MSTORE POP PUSH1 0x80 PUSH2 0x9F8 DUP5 DUP3 DUP6 ADD PUSH2 0xAC8 JUMP JUMPDEST PUSH1 0x80 DUP4 ADD MSTORE POP PUSH1 0xA0 PUSH2 0xA0C DUP5 DUP3 DUP6 ADD PUSH2 0xAC8 JUMP JUMPDEST PUSH1 0xA0 DUP4 ADD MSTORE POP PUSH1 0xC0 PUSH2 0xA20 DUP5 DUP3 DUP6 ADD PUSH2 0xAC8 JUMP JUMPDEST PUSH1 0xC0 DUP4 ADD MSTORE POP PUSH1 0xE0 PUSH2 0xA34 DUP5 DUP3 DUP6 ADD PUSH2 0xAC8 JUMP JUMPDEST PUSH1 0xE0 DUP4 ADD MSTORE POP PUSH2 0x100 PUSH2 0xA49 DUP5 DUP3 DUP6 ADD PUSH2 0xAC8 JUMP JUMPDEST PUSH2 0x100 DUP4 ADD MSTORE POP PUSH2 0x120 PUSH2 0xA5F DUP5 DUP3 DUP6 ADD PUSH2 0xAC8 JUMP JUMPDEST PUSH2 0x120 DUP4 ADD MSTORE POP PUSH2 0x140 DUP3 ADD CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0xA81 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xA8D DUP5 DUP3 DUP6 ADD PUSH2 0x85F JUMP JUMPDEST PUSH2 0x140 DUP4 ADD MSTORE POP PUSH2 0x160 DUP3 ADD CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0xAAF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xABB DUP5 DUP3 DUP6 ADD PUSH2 0x85F JUMP JUMPDEST PUSH2 0x160 DUP4 ADD MSTORE POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x84C DUP3 CALLDATALOAD PUSH2 0x1208 JUMP JUMPDEST PUSH1 0x0 PUSH2 0x84C DUP3 MLOAD PUSH2 0x1208 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0xAF2 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x0 PUSH2 0xAFE DUP5 DUP5 PUSH2 0x853 JUMP JUMPDEST SWAP5 SWAP4 POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x120 DUP3 DUP5 SUB SLT ISZERO PUSH2 0xB19 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x0 PUSH2 0xAFE DUP5 DUP5 PUSH2 0x922 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0xB37 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0xB4E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xAFE DUP5 DUP3 DUP6 ADD PUSH2 0x97F JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP1 PUSH1 0x80 DUP6 DUP8 SUB SLT ISZERO PUSH2 0xB70 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP5 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0xB87 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xB93 DUP8 DUP3 DUP9 ADD PUSH2 0x97F JUMP JUMPDEST SWAP5 POP POP PUSH1 0x20 DUP6 ADD CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0xBB0 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xBBC DUP8 DUP3 DUP9 ADD PUSH2 0x97F JUMP JUMPDEST SWAP4 POP POP PUSH1 0x40 DUP6 ADD CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0xBD9 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xBE5 DUP8 DUP3 DUP9 ADD PUSH2 0x85F JUMP JUMPDEST SWAP3 POP POP PUSH1 0x60 DUP6 ADD CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0xC02 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xC0E DUP8 DUP3 DUP9 ADD PUSH2 0x85F JUMP JUMPDEST SWAP2 POP POP SWAP3 SWAP6 SWAP2 SWAP5 POP SWAP3 POP JUMP JUMPDEST PUSH2 0xC23 DUP2 PUSH2 0x11EF JUMP JUMPDEST DUP3 MSTORE POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0xC34 DUP3 PUSH2 0x11EB JUMP JUMPDEST DUP1 DUP5 MSTORE PUSH2 0xC48 DUP2 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP7 ADD PUSH2 0x121C JUMP JUMPDEST PUSH2 0xC51 DUP2 PUSH2 0x1248 JUMP JUMPDEST SWAP1 SWAP4 ADD PUSH1 0x20 ADD SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x11 DUP2 MSTORE PUSH32 0x55494E543235365F554E444552464C4F57000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x40 ADD SWAP1 JUMP JUMPDEST PUSH1 0x26 DUP2 MSTORE PUSH32 0x475245415445525F4F525F455155414C5F544F5F33325F4C454E4754485F5245 PUSH1 0x20 DUP3 ADD MSTORE PUSH32 0x5155495245440000000000000000000000000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x10 DUP2 MSTORE PUSH32 0x55494E543235365F4F564552464C4F5700000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x40 ADD SWAP1 JUMP JUMPDEST PUSH1 0x12 DUP2 MSTORE PUSH32 0x494E56414C49445F41535345545F444154410000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x40 ADD SWAP1 JUMP JUMPDEST PUSH1 0x12 DUP2 MSTORE PUSH32 0x494E56414C49445F424547494E5F54494D450000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x40 ADD SWAP1 JUMP JUMPDEST PUSH1 0xF DUP2 MSTORE PUSH32 0x41554354494F4E5F455850495245440000000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x40 ADD SWAP1 JUMP JUMPDEST PUSH1 0x26 DUP2 MSTORE PUSH32 0x475245415445525F4F525F455155414C5F544F5F32305F4C454E4754485F5245 PUSH1 0x20 DUP3 ADD MSTORE PUSH32 0x5155495245440000000000000000000000000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x13 DUP2 MSTORE PUSH32 0x41554354494F4E5F4E4F545F5354415254454400000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x40 ADD SWAP1 JUMP JUMPDEST PUSH1 0xE DUP2 MSTORE PUSH32 0x494E56414C49445F414D4F554E54000000000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x40 ADD SWAP1 JUMP JUMPDEST DUP1 MLOAD PUSH1 0xC0 DUP4 ADD SWAP1 PUSH2 0xE6B DUP5 DUP3 PUSH2 0x1056 JUMP JUMPDEST POP PUSH1 0x20 DUP3 ADD MLOAD PUSH2 0xE7E PUSH1 0x20 DUP6 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST POP PUSH1 0x40 DUP3 ADD MLOAD PUSH2 0xE91 PUSH1 0x40 DUP6 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST POP PUSH1 0x60 DUP3 ADD MLOAD PUSH2 0xEA4 PUSH1 0x60 DUP6 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST POP PUSH1 0x80 DUP3 ADD MLOAD PUSH2 0xEB7 PUSH1 0x80 DUP6 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST POP PUSH1 0xA0 DUP3 ADD MLOAD PUSH2 0xECA PUSH1 0xA0 DUP6 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST POP POP POP POP JUMP JUMPDEST DUP1 MLOAD PUSH1 0x80 DUP4 ADD SWAP1 PUSH2 0xEE1 DUP5 DUP3 PUSH2 0x1056 JUMP JUMPDEST POP PUSH1 0x20 DUP3 ADD MLOAD PUSH2 0xEF4 PUSH1 0x20 DUP6 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST POP PUSH1 0x40 DUP3 ADD MLOAD PUSH2 0xF07 PUSH1 0x40 DUP6 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST POP PUSH1 0x60 DUP3 ADD MLOAD PUSH2 0xECA PUSH1 0x60 DUP6 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST DUP1 MLOAD PUSH2 0x120 DUP4 ADD SWAP1 PUSH2 0xF2C DUP5 DUP3 PUSH2 0xED0 JUMP JUMPDEST POP PUSH1 0x20 DUP3 ADD MLOAD PUSH2 0xF3F PUSH1 0x80 DUP6 ADD DUP3 PUSH2 0xED0 JUMP JUMPDEST POP PUSH1 0x40 DUP3 ADD MLOAD PUSH2 0xECA PUSH2 0x100 DUP6 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST DUP1 MLOAD PUSH1 0x0 SWAP1 PUSH2 0x180 DUP5 ADD SWAP1 PUSH2 0xF68 DUP6 DUP3 PUSH2 0xC1A JUMP JUMPDEST POP PUSH1 0x20 DUP4 ADD MLOAD PUSH2 0xF7B PUSH1 0x20 DUP7 ADD DUP3 PUSH2 0xC1A JUMP JUMPDEST POP PUSH1 0x40 DUP4 ADD MLOAD PUSH2 0xF8E PUSH1 0x40 DUP7 ADD DUP3 PUSH2 0xC1A JUMP JUMPDEST POP PUSH1 0x60 DUP4 ADD MLOAD PUSH2 0xFA1 PUSH1 0x60 DUP7 ADD DUP3 PUSH2 0xC1A JUMP JUMPDEST POP PUSH1 0x80 DUP4 ADD MLOAD PUSH2 0xFB4 PUSH1 0x80 DUP7 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST POP PUSH1 0xA0 DUP4 ADD MLOAD PUSH2 0xFC7 PUSH1 0xA0 DUP7 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST POP PUSH1 0xC0 DUP4 ADD MLOAD PUSH2 0xFDA PUSH1 0xC0 DUP7 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST POP PUSH1 0xE0 DUP4 ADD MLOAD PUSH2 0xFED PUSH1 0xE0 DUP7 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST POP PUSH2 0x100 DUP4 ADD MLOAD PUSH2 0x1002 PUSH2 0x100 DUP7 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST POP PUSH2 0x120 DUP4 ADD MLOAD PUSH2 0x1017 PUSH2 0x120 DUP7 ADD DUP3 PUSH2 0x1056 JUMP JUMPDEST POP PUSH2 0x140 DUP4 ADD MLOAD DUP5 DUP3 SUB PUSH2 0x140 DUP7 ADD MSTORE PUSH2 0x1031 DUP3 DUP3 PUSH2 0xC29 JUMP JUMPDEST SWAP2 POP POP PUSH2 0x160 DUP4 ADD MLOAD DUP5 DUP3 SUB PUSH2 0x160 DUP7 ADD MSTORE PUSH2 0x104D DUP3 DUP3 PUSH2 0xC29 JUMP JUMPDEST SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH2 0xC23 DUP2 PUSH2 0x1208 JUMP JUMPDEST PUSH1 0x40 DUP2 ADD PUSH2 0x106D DUP3 DUP6 PUSH2 0xC1A JUMP JUMPDEST PUSH2 0x84C PUSH1 0x20 DUP4 ADD DUP5 PUSH2 0x1056 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE DUP2 ADD PUSH2 0x601 DUP2 PUSH2 0xC5E JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE DUP2 ADD PUSH2 0x601 DUP2 PUSH2 0xC8E JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE DUP2 ADD PUSH2 0x601 DUP2 PUSH2 0xCE4 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE DUP2 ADD PUSH2 0x601 DUP2 PUSH2 0xD14 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE DUP2 ADD PUSH2 0x601 DUP2 PUSH2 0xD44 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE DUP2 ADD PUSH2 0x601 DUP2 PUSH2 0xD74 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE DUP2 ADD PUSH2 0x601 DUP2 PUSH2 0xDA4 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE DUP2 ADD PUSH2 0x601 DUP2 PUSH2 0xDFA JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE DUP2 ADD PUSH2 0x601 DUP2 PUSH2 0xE2A JUMP JUMPDEST PUSH1 0xC0 DUP2 ADD PUSH2 0x601 DUP3 DUP5 PUSH2 0xE5A JUMP JUMPDEST PUSH2 0x120 DUP2 ADD PUSH2 0x601 DUP3 DUP5 PUSH2 0xF1A JUMP JUMPDEST PUSH1 0x80 DUP1 DUP3 MSTORE DUP2 ADD PUSH2 0x1138 DUP2 DUP8 PUSH2 0xF53 JUMP JUMPDEST SWAP1 POP DUP2 DUP2 SUB PUSH1 0x20 DUP4 ADD MSTORE PUSH2 0x114C DUP2 DUP7 PUSH2 0xF53 JUMP JUMPDEST SWAP1 POP DUP2 DUP2 SUB PUSH1 0x40 DUP4 ADD MSTORE PUSH2 0x1160 DUP2 DUP6 PUSH2 0xC29 JUMP JUMPDEST SWAP1 POP DUP2 DUP2 SUB PUSH1 0x60 DUP4 ADD MSTORE PUSH2 0x1174 DUP2 DUP5 PUSH2 0xC29 JUMP JUMPDEST SWAP7 SWAP6 POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x40 MLOAD DUP2 DUP2 ADD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT DUP3 DUP3 LT OR ISZERO PUSH2 0x119D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x40 MSTORE SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 PUSH8 0xFFFFFFFFFFFFFFFF DUP3 GT ISZERO PUSH2 0x11BC JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x20 PUSH1 0x1F SWAP2 SWAP1 SWAP2 ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND ADD SWAP1 JUMP JUMPDEST MLOAD SWAP1 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 JUMP JUMPDEST SWAP1 JUMP JUMPDEST ISZERO ISZERO SWAP1 JUMP JUMPDEST DUP3 DUP2 DUP4 CALLDATACOPY POP PUSH1 0x0 SWAP2 ADD MSTORE JUMP JUMPDEST PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x1237 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x121F JUMP JUMPDEST DUP4 DUP2 GT ISZERO PUSH2 0xECA JUMPI POP POP PUSH1 0x0 SWAP2 ADD MSTORE JUMP JUMPDEST PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP1 JUMP STOP LOG2 PUSH6 0x627A7A723058 KECCAK256 SWAP13 0xf7 SIGNEXTEND DIV 0xb7 0x5f 0xc2 RETURNDATACOPY PUSH8 0x62AE4C6C8F25CCAD 0x25 0xdf 0xcb CODECOPY 0xcf SAR 0xd3 SWAP7 PUSH15 0xB27CE513DE036C6578706572696D65 PUSH15 0x74616CF50037000000000000000000 ",
+ "sourceMap": "986:9378:28:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;7335:3027;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;7335:3027:28;;;;;;;;;;;;;;;;;;;;;;;;;3690:3508;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;3690:3508:28;;;;;;;;;;;;;;;;;7335:3027;7437:36;;:::i;:::-;7520:20;;;;:27;7489:28;;;;;;;8295:3;8271:27;;;8250:92;;;;;;;;;;;;;;;;;;;;;;8386:20;;;;:59;;8419:25;;;8386:59;:32;:59;:::i;:::-;8484:20;;;;8352:93;;-1:-1:-1;8484:59:28;;8517:25;;;8484:59;:32;:59;:::i;:::-;8455:88;;8657:23;8627:5;:27;;;:53;8606:118;;;;;;;;;;;;;;;;8795:23;8767:5;:27;;;:51;8734:84;;8900:5;:22;;;8880:42;;8974:9;8953:18;:30;8932:91;;;;;;;;;;;;;;;;-1:-1:-1;;;9192:57:28;;;9291:27;;;;;9259:29;;;:59;9328:26;;;:47;;;9385:24;;;:36;;;9167:15;9431:33;;;:45;;;9522:27;;9055:28;;;;9167:15;9522:37;;;9573:35;;;9569:756;;;9717:28;;;:49;;;9569:756;;;9800:27;;;;9787:40;;9783:542;;10009:28;;;:40;;;9783:542;;;10111:203;10136:9;10163:137;10192:46;10200:24;10226:11;10192:7;:46::i;:::-;10260:22;10163:7;:137::i;:::-;10111:7;:203::i;:::-;10080:28;;;:234;9783:542;7335:3027;;;;;;;;;;;:::o;3690:3508::-;3901:59;;:::i;:::-;3976:36;;:::i;:::-;5398:34;6127:22;6190:13;6404:25;6510:26;4015:28;4033:9;4015:17;:28::i;:::-;4161:31;;4124:33;;;;3976:67;;-1:-1:-1;;4124:68:28;4103:134;;;;;;;;;;;;;;4413:33;;;;4379:31;;;;:67;4358:129;;;;;;;;;;;;;;4627:28;;;;;4598:25;;;;:57;;4577:118;;;;;;;;;;;;;;4780:8;;:128;;;;;:8;;;;;:20;;:128;;4814:8;;4836:9;;4859:12;;4885:13;;4780:128;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;4780:128:28;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;4780:128:28;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;4780:128:28;;;;;;;;;4759:149;;5435:18;:45;;;5398:82;;5523:1;5494:26;:30;5490:1667;;;6152:24;;;;;-1:-1:-1;6206:25:28;6152:24;6228:2;6206:25;:21;:25;:::i;:::-;6190:41;;6432:64;6440:8;:25;;;6467:14;:28;;;6432:7;:64::i;:::-;6404:92;;6539:54;6547:26;6575:17;6539:7;:54::i;:::-;6510:83;;6766:1;6745:18;:22;6741:132;;;6815:22;;6787:71;;;;;:27;;;;;;:71;;6815:22;6839:18;;6787:71;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;6787:71:28;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;6787:71:28;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;6787:71:28;;;;;;;;;;6741:132;7042:1;7022:17;:21;7018:129;;;7091:21;;7063:69;;;;;:27;;;;;;:69;;7091:21;7114:17;;7063:69;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;7063:69:28;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;7063:69:28;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;7063:69:28;;;;;;;;;;7018:129;3690:3508;;;;;;;;;;;;:::o;14708:220:17:-;14829:14;14876:21;14888:1;14891:5;14876:11;:21::i;:::-;14868:30;-1:-1:-1;14708:220:17;;;;;:::o;51:288:20:-;137:7;;164:6;;160:45;;;193:1;186:8;;;;160:45;-1:-1:-1;226:5:20;;;230:1;226;:5;262;;;;;;;;:10;241:73;;;;;;;;;;;;;;331:1;324:8;;51:288;;;;;;:::o;345:151::-;431:7;454:9;470:1;466;:5;;;;;;;;;345:151;-1:-1:-1;;;;345:151:20:o;716:230::-;802:7;837:5;;;873:6;;;;852:69;;;;;;;;;;;;;10268:886:17;10389:14;10452:5;10460:2;10452:10;10440:1;:8;:22;;10419:135;;;;;;;;;;;;;;;;-1:-1:-1;11056:13:17;10801:2;11056:13;11050:20;11072:42;11046:69;;10268:886::o;502:208:20:-;588:7;632:6;;;;611:70;;;;;;;;;;;;;;-1:-1:-1;698:5:20;;;502:208::o;13290:490:17:-;13411:14;13474:5;13482:2;13474:10;13462:1;:8;:22;;13441:107;;;;;;;;;;;;;;;;-1:-1:-1;13727:13:17;13629:2;13727:13;13721:20;;13290:490::o;986:9378:28:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;5:118:-1:-;;72:46;110:6;97:20;72:46;;;63:55;57:66;-1:-1;;;57:66;130:116;;205:36;233:6;227:13;205:36;;254:432;;344:4;332:17;;328:27;-1:-1;318:2;;369:1;366;359:12;318:2;406:6;393:20;428:60;443:44;480:6;443:44;;;428:60;;;419:69;;508:6;501:5;494:21;544:4;536:6;532:17;577:4;570:5;566:16;612:3;603:6;598:3;594:16;591:25;588:2;;;629:1;626;619:12;588:2;639:41;673:6;668:3;663;639:41;;;311:375;;;;;;;;1183:861;;1308:4;1296:9;1291:3;1287:19;1283:30;1280:2;;;1326:1;1323;1316:12;1280:2;1344:20;1359:4;1344:20;;;1335:29;-1:-1;1432:1;1463:60;1519:3;1499:9;1463:60;;;1439:85;;-1:-1;1603:2;1636:60;1692:3;1668:22;;;1636:60;;;1629:4;1622:5;1618:16;1611:86;1545:163;1766:2;1799:60;1855:3;1846:6;1835:9;1831:22;1799:60;;;1792:4;1785:5;1781:16;1774:86;1718:153;1929:2;1962:60;2018:3;2009:6;1998:9;1994:22;1962:60;;;1955:4;1948:5;1944:16;1937:86;1881:153;1274:770;;;;;2098:741;;2234:5;2222:9;2217:3;2213:19;2209:31;2206:2;;;2253:1;2250;2243:12;2206:2;2271:20;2286:4;2271:20;;;2262:29;-1:-1;2341:1;2372:85;2453:3;2433:9;2372:85;;;2348:110;;-1:-1;2520:3;2554:85;2635:3;2611:22;;;2554:85;;;2547:4;2540:5;2536:16;2529:111;2479:172;2723:3;2757:60;2813:3;2804:6;2793:9;2789:22;2757:60;;;2750:4;2743:5;2739:16;2732:86;2661:168;2200:639;;;;;2874:2208;;2985:5;2973:9;2968:3;2964:19;2960:31;2957:2;;;3004:1;3001;2994:12;2957:2;3022:21;3037:5;3022:21;;;3013:30;-1:-1;3101:1;3132:49;3177:3;3157:9;3132:49;;;3108:74;;-1:-1;3251:2;3284:49;3329:3;3305:22;;;3284:49;;;3277:4;3270:5;3266:16;3259:75;3203:142;3410:2;3443:49;3488:3;3479:6;3468:9;3464:22;3443:49;;;3436:4;3429:5;3425:16;3418:75;3355:149;3563:2;3596:49;3641:3;3632:6;3621:9;3617:22;3596:49;;;3589:4;3582:5;3578:16;3571:75;3514:143;3719:3;3753:49;3798:3;3789:6;3778:9;3774:22;3753:49;;;3746:4;3739:5;3735:16;3728:75;3667:147;3876:3;3910:49;3955:3;3946:6;3935:9;3931:22;3910:49;;;3903:4;3896:5;3892:16;3885:75;3824:147;4025:3;4059:49;4104:3;4095:6;4084:9;4080:22;4059:49;;;4052:4;4045:5;4041:16;4034:75;3981:139;4174:3;4208:49;4253:3;4244:6;4233:9;4229:22;4208:49;;;4201:4;4194:5;4190:16;4183:75;4130:139;4336:3;4371:49;4416:3;4407:6;4396:9;4392:22;4371:49;;;4363:5;4356;4352:17;4345:76;4279:153;4482:3;4517:49;4562:3;4553:6;4542:9;4538:22;4517:49;;;4509:5;4502;4498:17;4491:76;4442:136;4666:3;4655:9;4651:19;4638:33;4691:18;4683:6;4680:30;4677:2;;;4723:1;4720;4713:12;4677:2;4759:54;4809:3;4800:6;4789:9;4785:22;4759:54;;;4751:5;4744;4740:17;4733:81;4588:237;4913:3;4902:9;4898:19;4885:33;4938:18;4930:6;4927:30;4924:2;;;4970:1;4967;4960:12;4924:2;5006:54;5056:3;5047:6;5036:9;5032:22;5006:54;;;4998:5;4991;4987:17;4980:81;4835:237;2951:2131;;;;;5089:118;;5156:46;5194:6;5181:20;5156:46;;5214:122;;5292:39;5323:6;5317:13;5292:39;;5343:257;;5455:2;5443:9;5434:7;5430:23;5426:32;5423:2;;;5471:1;5468;5461:12;5423:2;5506:1;5523:61;5576:7;5556:9;5523:61;;;5513:71;5417:183;-1:-1;;;;5417:183;5607:336;;5758:3;5746:9;5737:7;5733:23;5729:33;5726:2;;;5775:1;5772;5765:12;5726:2;5810:1;5827:100;5919:7;5899:9;5827:100;;5950:371;;6076:2;6064:9;6055:7;6051:23;6047:32;6044:2;;;6092:1;6089;6082:12;6044:2;6127:31;;6178:18;6167:30;;6164:2;;;6210:1;6207;6200:12;6164:2;6230:75;6297:7;6288:6;6277:9;6273:22;6230:75;;6328:1085;;;;;6545:3;6533:9;6524:7;6520:23;6516:33;6513:2;;;6562:1;6559;6552:12;6513:2;6597:31;;6648:18;6637:30;;6634:2;;;6680:1;6677;6670:12;6634:2;6700:75;6767:7;6758:6;6747:9;6743:22;6700:75;;;6690:85;;6576:205;6840:2;6829:9;6825:18;6812:32;6864:18;6856:6;6853:30;6850:2;;;6896:1;6893;6886:12;6850:2;6916:75;6983:7;6974:6;6963:9;6959:22;6916:75;;;6906:85;;6791:206;7056:2;7045:9;7041:18;7028:32;7080:18;7072:6;7069:30;7066:2;;;7112:1;7109;7102:12;7066:2;7132:62;7186:7;7177:6;7166:9;7162:22;7132:62;;;7122:72;;7007:193;7259:2;7248:9;7244:18;7231:32;7283:18;7275:6;7272:30;7269:2;;;7315:1;7312;7305:12;7269:2;7335:62;7389:7;7380:6;7369:9;7365:22;7335:62;;;7325:72;;7210:193;6507:906;;;;;;;;7420:110;7493:31;7518:5;7493:31;;;7488:3;7481:44;7475:55;;;7537:297;;7637:38;7669:5;7637:38;;;7692:6;7687:3;7680:19;7704:63;7760:6;7753:4;7748:3;7744:14;7737:4;7730:5;7726:16;7704:63;;;7799:29;7821:6;7799:29;;;7779:50;;;7792:4;7779:50;;7617:217;-1:-1;;;7617:217;8138:296;8293:2;8281:15;;8330:66;8325:2;8316:12;;8309:88;8425:2;8416:12;;8274:160;8443:397;8598:2;8586:15;;8635:66;8630:2;8621:12;;8614:88;8736:66;8731:2;8722:12;;8715:88;8831:2;8822:12;;8579:261;8849:296;9004:2;8992:15;;9041:66;9036:2;9027:12;;9020:88;9136:2;9127:12;;8985:160;9154:296;9309:2;9297:15;;9346:66;9341:2;9332:12;;9325:88;9441:2;9432:12;;9290:160;9459:296;9614:2;9602:15;;9651:66;9646:2;9637:12;;9630:88;9746:2;9737:12;;9595:160;9764:296;9919:2;9907:15;;9956:66;9951:2;9942:12;;9935:88;10051:2;10042:12;;9900:160;10069:397;10224:2;10212:15;;10261:66;10256:2;10247:12;;10240:88;10362:66;10357:2;10348:12;;10341:88;10457:2;10448:12;;10205:261;10475:296;10630:2;10618:15;;10667:66;10662:2;10653:12;;10646:88;10762:2;10753:12;;10611:160;10780:296;10935:2;10923:15;;10972:66;10967:2;10958:12;;10951:88;11067:2;11058:12;;10916:160;11163:1231;11387:22;;11306:4;11297:14;;;11421:61;11301:3;11387:22;11421:61;;;11326:168;11580:4;11573:5;11569:16;11563:23;11598:62;11654:4;11649:3;11645:14;11632:11;11598:62;;;11504:168;11755:4;11748:5;11744:16;11738:23;11773:62;11829:4;11824:3;11820:14;11807:11;11773:62;;;11682:165;11928:4;11921:5;11917:16;11911:23;11946:62;12002:4;11997:3;11993:14;11980:11;11946:62;;;11857:163;12105:4;12098:5;12094:16;12088:23;12123:62;12179:4;12174:3;12170:14;12157:11;12123:62;;;12030:167;12287:4;12280:5;12276:16;12270:23;12305:62;12361:4;12356:3;12352:14;12339:11;12305:62;;;12207:172;11279:1115;;;;12478:884;12702:22;;12615:4;12606:14;;;12736:61;12610:3;12702:22;12736:61;;;12635:174;12903:4;12896:5;12892:16;12886:23;12921:62;12977:4;12972:3;12968:14;12955:11;12921:62;;;12819:176;13079:4;13072:5;13068:16;13062:23;13097:62;13153:4;13148:3;13144:14;13131:11;13097:62;;;13005:166;13255:4;13248:5;13244:16;13238:23;13273:62;13329:4;13324:3;13320:14;13307:11;13273:62;;13460:815;13685:22;;13615:5;13606:15;;;13719:115;13610:3;13685:22;13719:115;;;13636:210;13923:4;13916:5;13912:16;13906:23;13941:116;14051:4;14046:3;14042:14;14029:11;13941:116;;;13856:213;14167:4;14160:5;14156:16;14150:23;14185:63;14241:5;14236:3;14232:15;14219:11;14185:63;;14335:2417;14548:22;;14335:2417;;14470:5;14461:15;;;14582:61;14465:3;14548:22;14582:61;;;14491:164;14739:4;14732:5;14728:16;14722:23;14757:62;14813:4;14808:3;14804:14;14791:11;14757:62;;;14665:166;14922:4;14915:5;14911:16;14905:23;14940:62;14996:4;14991:3;14987:14;14974:11;14940:62;;;14841:173;15099:4;15092:5;15088:16;15082:23;15117:62;15173:4;15168:3;15164:14;15151:11;15117:62;;;15024:167;15279:4;15272:5;15268:16;15262:23;15297:62;15353:4;15348:3;15344:14;15331:11;15297:62;;;15201:170;15459:4;15452:5;15448:16;15442:23;15477:62;15533:4;15528:3;15524:14;15511:11;15477:62;;;15381:170;15631:4;15624:5;15620:16;15614:23;15649:62;15705:4;15700:3;15696:14;15683:11;15649:62;;;15561:162;15803:4;15796:5;15792:16;15786:23;15821:62;15877:4;15872:3;15868:14;15855:11;15821:62;;;15733:162;15988:5;15981;15977:17;15971:24;16007:63;16063:5;16058:3;16054:15;16041:11;16007:63;;;15905:177;16158:5;16151;16147:17;16141:24;16177:63;16233:5;16228:3;16224:15;16211:11;16177:63;;;16092:160;16338:5;16331;16327:17;16321:24;16391:3;16385:4;16381:14;16373:5;16368:3;16364:15;16357:39;16411:66;16472:4;16459:11;16411:66;;;16403:74;;16262:227;16575:5;16568;16564:17;16558:24;16628:3;16622:4;16618:14;16610:5;16605:3;16601:15;16594:39;16648:66;16709:4;16696:11;16648:66;;;16640:74;14443:2309;-1:-1;;;;;14443:2309;16759:110;16832:31;16857:5;16832:31;;16876:294;17012:2;16997:18;;17026:61;17001:9;17060:6;17026:61;;;17098:62;17156:2;17145:9;17141:18;17132:6;17098:62;;17177:387;17358:2;17372:47;;;17343:18;;17433:121;17343:18;17433:121;;17571:387;17752:2;17766:47;;;17737:18;;17827:121;17737:18;17827:121;;17965:387;18146:2;18160:47;;;18131:18;;18221:121;18131:18;18221:121;;18359:387;18540:2;18554:47;;;18525:18;;18615:121;18525:18;18615:121;;18753:387;18934:2;18948:47;;;18919:18;;19009:121;18919:18;19009:121;;19147:387;19328:2;19342:47;;;19313:18;;19403:121;19313:18;19403:121;;19541:387;19722:2;19736:47;;;19707:18;;19797:121;19707:18;19797:121;;19935:387;20116:2;20130:47;;;20101:18;;20191:121;20101:18;20191:121;;20329:387;20510:2;20524:47;;;20495:18;;20585:121;20495:18;20585:121;;20723:314;20891:3;20876:19;;20906:121;20880:9;21000:6;20906:121;;21044:338;21224:3;21209:19;;21239:133;21213:9;21345:6;21239:133;;21389:937;21705:3;21720:47;;;21690:19;;21781:92;21690:19;21859:6;21781:92;;;21773:100;;21921:9;21915:4;21911:20;21906:2;21895:9;21891:18;21884:48;21946:92;22033:4;22024:6;21946:92;;;21938:100;;22086:9;22080:4;22076:20;22071:2;22060:9;22056:18;22049:48;22111:66;22172:4;22163:6;22111:66;;;22103:74;;22225:9;22219:4;22215:20;22210:2;22199:9;22195:18;22188:48;22250:66;22311:4;22302:6;22250:66;;;22242:74;21676:650;-1:-1;;;;;;21676:650;22333:256;22395:2;22389:9;22421:17;;;22496:18;22481:34;;22517:22;;;22478:62;22475:2;;;22553:1;22550;22543:12;22475:2;22569;22562:22;22373:216;;-1:-1;22373:216;22596:254;;22735:18;22727:6;22724:30;22721:2;;;22767:1;22764;22757:12;22721:2;-1:-1;22840:4;22811;22788:17;;;;22807:9;22784:33;22830:15;;22658:192;23122:87;23192:12;;23176:33;23314:128;23394:42;23383:54;;23366:76;23449:79;23518:5;23501:27;23670:92;23743:13;23736:21;;23719:43;23856:145;23937:6;23932:3;23927;23914:30;-1:-1;23993:1;23975:16;;23968:27;23907:94;24010:268;24075:1;24082:101;24096:6;24093:1;24090:13;24082:101;;;24163:11;;;24157:18;24144:11;;;24137:39;24118:2;24111:10;24082:101;;;24198:6;24195:1;24192:13;24189:2;;;-1:-1;;24263:1;24245:16;;24238:27;24059:219;24286:97;24374:2;24354:14;24370:7;24350:28;;24334:49"
+ }
+ }
+ },
+ "networks": {}
+}
diff --git a/packages/contract-artifacts/src/index.ts b/packages/contract-artifacts/src/index.ts
index f30276dd9..bd5f8fee3 100644
--- a/packages/contract-artifacts/src/index.ts
+++ b/packages/contract-artifacts/src/index.ts
@@ -1,4 +1,5 @@
import * as AssetProxyOwner from '../artifacts/AssetProxyOwner.json';
+import * as DutchAuction from '../artifacts/DutchAuction.json';
import * as DummyERC20Token from '../artifacts/DummyERC20Token.json';
import * as DummyERC721Token from '../artifacts/DummyERC721Token.json';
import * as ERC20Proxy from '../artifacts/ERC20Proxy.json';
@@ -15,6 +16,7 @@ import * as ZRXToken from '../artifacts/ZRXToken.json';
export {
AssetProxyOwner,
+ DutchAuction,
DummyERC20Token,
DummyERC721Token,
ERC20Proxy,
diff --git a/packages/contract-artifacts/tsconfig.json b/packages/contract-artifacts/tsconfig.json
index cce086209..59169fceb 100644
--- a/packages/contract-artifacts/tsconfig.json
+++ b/packages/contract-artifacts/tsconfig.json
@@ -8,6 +8,7 @@
"include": ["./src/**/*"],
"files": [
"./artifacts/AssetProxyOwner.json",
+ "./artifacts/DutchAuction.json",
"./artifacts/DummyERC20Token.json",
"./artifacts/DummyERC721Token.json",
"./artifacts/ERC20Proxy.json",
diff --git a/packages/contract-wrappers/CHANGELOG.json b/packages/contract-wrappers/CHANGELOG.json
index 9475e5a88..677292030 100644
--- a/packages/contract-wrappers/CHANGELOG.json
+++ b/packages/contract-wrappers/CHANGELOG.json
@@ -1,5 +1,26 @@
[
{
+ "version": "4.2.0",
+ "changes": [
+ {
+ "note": "Added Dutch Auction wrapper",
+ "pr": 1465
+ }
+ ]
+ },
+ {
+ "version": "4.1.4",
+ "changes": [
+ {
+ "note": "Add support for Trust Wallet signature denial error"
+ },
+ {
+ "note": "Add balance and allowance queries for `MultiAssetProxy`",
+ "pr": 1363
+ }
+ ]
+ },
+ {
"version": "4.1.3",
"changes": [
{
diff --git a/packages/contract-wrappers/package.json b/packages/contract-wrappers/package.json
index f3f7301fd..e4de75ab2 100644
--- a/packages/contract-wrappers/package.json
+++ b/packages/contract-wrappers/package.json
@@ -69,6 +69,7 @@
"@0x/assert": "^1.0.20",
"@0x/contract-addresses": "^2.0.0",
"@0x/contract-artifacts": "^1.1.2",
+ "@0x/contracts-test-utils": "^1.0.2",
"@0x/fill-scenarios": "^1.0.16",
"@0x/json-schemas": "^2.1.4",
"@0x/order-utils": "^3.0.7",
@@ -76,6 +77,7 @@
"@0x/typescript-typings": "^3.0.6",
"@0x/utils": "^2.0.8",
"@0x/web3-wrapper": "^3.2.1",
+ "ethereumjs-abi": "0.6.5",
"ethereum-types": "^1.1.4",
"ethereumjs-blockstream": "6.0.0",
"ethereumjs-util": "^5.1.1",
diff --git a/packages/contract-wrappers/src/contract_wrappers.ts b/packages/contract-wrappers/src/contract_wrappers.ts
index 0c535bd5c..4e594593e 100644
--- a/packages/contract-wrappers/src/contract_wrappers.ts
+++ b/packages/contract-wrappers/src/contract_wrappers.ts
@@ -12,6 +12,7 @@ import { Web3Wrapper } from '@0x/web3-wrapper';
import { Provider } from 'ethereum-types';
import * as _ from 'lodash';
+import { DutchAuctionWrapper } from './contract_wrappers/dutch_auction_wrapper';
import { ERC20ProxyWrapper } from './contract_wrappers/erc20_proxy_wrapper';
import { ERC20TokenWrapper } from './contract_wrappers/erc20_token_wrapper';
import { ERC721ProxyWrapper } from './contract_wrappers/erc721_proxy_wrapper';
@@ -65,6 +66,10 @@ export class ContractWrappers {
* An instance of the OrderValidatorWrapper class containing methods for interacting with any OrderValidator smart contract.
*/
public orderValidator: OrderValidatorWrapper;
+ /**
+ * An instance of the DutchAuctionWrapper class containing methods for interacting with any DutchAuction smart contract.
+ */
+ public dutchAuction: DutchAuctionWrapper;
private readonly _web3Wrapper: Web3Wrapper;
/**
@@ -141,6 +146,11 @@ export class ContractWrappers {
config.networkId,
contractAddresses.orderValidator,
);
+ this.dutchAuction = new DutchAuctionWrapper(
+ this._web3Wrapper,
+ config.networkId,
+ contractAddresses.dutchAuction,
+ );
}
/**
* Unsubscribes from all subscriptions for all contracts.
diff --git a/packages/contract-wrappers/src/contract_wrappers/dutch_auction_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/dutch_auction_wrapper.ts
new file mode 100644
index 000000000..c1aceff47
--- /dev/null
+++ b/packages/contract-wrappers/src/contract_wrappers/dutch_auction_wrapper.ts
@@ -0,0 +1,182 @@
+import { DutchAuctionContract } from '@0x/abi-gen-wrappers';
+import { DutchAuction } from '@0x/contract-artifacts';
+import { schemas } from '@0x/json-schemas';
+import { assetDataUtils } from '@0x/order-utils';
+import { DutchAuctionDetails, SignedOrder } from '@0x/types';
+import { BigNumber } from '@0x/utils';
+import { Web3Wrapper } from '@0x/web3-wrapper';
+import { ContractAbi } from 'ethereum-types';
+import * as ethAbi from 'ethereumjs-abi';
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
+import { orderTxOptsSchema } from '../schemas/order_tx_opts_schema';
+import { txOptsSchema } from '../schemas/tx_opts_schema';
+import { DutchAuctionData, DutchAuctionWrapperError, OrderTransactionOpts } from '../types';
+import { assert } from '../utils/assert';
+import { _getDefaultContractAddresses } from '../utils/contract_addresses';
+
+import { ContractWrapper } from './contract_wrapper';
+
+export class DutchAuctionWrapper extends ContractWrapper {
+ public abi: ContractAbi = DutchAuction.compilerOutput.abi;
+ public address: string;
+ private _dutchAuctionContractIfExists?: DutchAuctionContract;
+ /**
+ * Dutch auction details are encoded with the asset data for a 0x order. This function produces a hex
+ * encoded assetData string, containing information both about the asset being traded and the
+ * dutch auction; which is usable in the makerAssetData or takerAssetData fields in a 0x order.
+ * @param assetData Hex encoded assetData string for the asset being auctioned.
+ * @param beginTimeSeconds Begin time of the dutch auction.
+ * @param beginAmount Starting amount being sold in the dutch auction.
+ * @return The hex encoded assetData string.
+ */
+ public static encodeDutchAuctionAssetData(
+ assetData: string,
+ beginTimeSeconds: BigNumber,
+ beginAmount: BigNumber,
+ ): string {
+ const assetDataBuffer = ethUtil.toBuffer(assetData);
+ const abiEncodedAuctionData = (ethAbi as any).rawEncode(
+ ['uint256', 'uint256'],
+ [beginTimeSeconds.toString(), beginAmount.toString()],
+ );
+ const abiEncodedAuctionDataBuffer = ethUtil.toBuffer(abiEncodedAuctionData);
+ const dutchAuctionDataBuffer = Buffer.concat([assetDataBuffer, abiEncodedAuctionDataBuffer]);
+ const dutchAuctionData = ethUtil.bufferToHex(dutchAuctionDataBuffer);
+ return dutchAuctionData;
+ }
+ /**
+ * Dutch auction details are encoded with the asset data for a 0x order. This function decodes a hex
+ * encoded assetData string, containing information both about the asset being traded and the
+ * dutch auction.
+ * @param dutchAuctionData Hex encoded assetData string for the asset being auctioned.
+ * @return An object containing the auction asset, auction begin time and auction begin amount.
+ */
+ public static decodeDutchAuctionData(dutchAuctionData: string): DutchAuctionData {
+ const dutchAuctionDataBuffer = ethUtil.toBuffer(dutchAuctionData);
+ // Decode asset data
+ const dutchAuctionDataLengthInBytes = 64;
+ const assetDataBuffer = dutchAuctionDataBuffer.slice(
+ 0,
+ dutchAuctionDataBuffer.byteLength - dutchAuctionDataLengthInBytes,
+ );
+ const assetDataHex = ethUtil.bufferToHex(assetDataBuffer);
+ const assetData = assetDataUtils.decodeAssetDataOrThrow(assetDataHex);
+ // Decode auction details
+ const dutchAuctionDetailsBuffer = dutchAuctionDataBuffer.slice(
+ dutchAuctionDataBuffer.byteLength - dutchAuctionDataLengthInBytes,
+ );
+ const [beginTimeSecondsAsBN, beginAmountAsBN] = ethAbi.rawDecode(
+ ['uint256', 'uint256'],
+ dutchAuctionDetailsBuffer,
+ );
+ const beginTimeSeconds = new BigNumber(`0x${beginTimeSecondsAsBN.toString()}`);
+ const beginAmount = new BigNumber(`0x${beginAmountAsBN.toString()}`);
+ return {
+ assetData,
+ beginTimeSeconds,
+ beginAmount,
+ };
+ }
+ /**
+ * Instantiate DutchAuctionWrapper
+ * @param web3Wrapper Web3Wrapper instance to use.
+ * @param networkId Desired networkId.
+ * @param address The address of the Dutch Auction contract. If undefined, will
+ * default to the known address corresponding to the networkId.
+ */
+ public constructor(web3Wrapper: Web3Wrapper, networkId: number, address?: string) {
+ super(web3Wrapper, networkId);
+ this.address = _.isUndefined(address) ? _getDefaultContractAddresses(networkId).dutchAuction : address;
+ }
+ /**
+ * Matches the buy and sell orders at an amount given the following: the current block time, the auction
+ * start time and the auction begin amount. The sell order is a an order at the lowest amount
+ * at the end of the auction. Excess from the match is transferred to the seller.
+ * Over time the price moves from beginAmount to endAmount given the current block.timestamp.
+ * @param buyOrder The Buyer's order. This order is for the current expected price of the auction.
+ * @param sellOrder The Seller's order. This order is for the lowest amount (at the end of the auction).
+ * @param takerAddress The user Ethereum address who would like to fill this order. Must be available via the supplied
+ * Provider provided at instantiation.
+ * @return Transaction hash.
+ */
+ public async matchOrdersAsync(
+ buyOrder: SignedOrder,
+ sellOrder: SignedOrder,
+ takerAddress: string,
+ orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true },
+ ): Promise<string> {
+ // type assertions
+ assert.doesConformToSchema('buyOrder', buyOrder, schemas.signedOrderSchema);
+ assert.doesConformToSchema('sellOrder', sellOrder, schemas.signedOrderSchema);
+ await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
+ assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]);
+ const normalizedTakerAddress = takerAddress.toLowerCase();
+ // other assertions
+ if (
+ sellOrder.makerAssetData !== buyOrder.takerAssetData ||
+ sellOrder.takerAssetData !== buyOrder.makerAssetData
+ ) {
+ throw new Error(DutchAuctionWrapperError.AssetDataMismatch);
+ }
+ // get contract
+ const dutchAuctionInstance = await this._getDutchAuctionContractAsync();
+ // validate transaction
+ if (orderTransactionOpts.shouldValidate) {
+ await dutchAuctionInstance.matchOrders.callAsync(
+ buyOrder,
+ sellOrder,
+ buyOrder.signature,
+ sellOrder.signature,
+ {
+ from: normalizedTakerAddress,
+ gas: orderTransactionOpts.gasLimit,
+ gasPrice: orderTransactionOpts.gasPrice,
+ nonce: orderTransactionOpts.nonce,
+ },
+ );
+ }
+ // send transaction
+ const txHash = await dutchAuctionInstance.matchOrders.sendTransactionAsync(
+ buyOrder,
+ sellOrder,
+ buyOrder.signature,
+ sellOrder.signature,
+ {
+ from: normalizedTakerAddress,
+ gas: orderTransactionOpts.gasLimit,
+ gasPrice: orderTransactionOpts.gasPrice,
+ nonce: orderTransactionOpts.nonce,
+ },
+ );
+ return txHash;
+ }
+ /**
+ * Fetches the Auction Details for the given order
+ * @param sellOrder The Seller's order. This order is for the lowest amount (at the end of the auction).
+ * @return The dutch auction details.
+ */
+ public async getAuctionDetailsAsync(sellOrder: SignedOrder): Promise<DutchAuctionDetails> {
+ // type assertions
+ assert.doesConformToSchema('sellOrder', sellOrder, schemas.signedOrderSchema);
+ // get contract
+ const dutchAuctionInstance = await this._getDutchAuctionContractAsync();
+ // call contract
+ const auctionDetails = await dutchAuctionInstance.getAuctionDetails.callAsync(sellOrder);
+ return auctionDetails;
+ }
+ private async _getDutchAuctionContractAsync(): Promise<DutchAuctionContract> {
+ if (!_.isUndefined(this._dutchAuctionContractIfExists)) {
+ return this._dutchAuctionContractIfExists;
+ }
+ const contractInstance = new DutchAuctionContract(
+ this.abi,
+ this.address,
+ this._web3Wrapper.getProvider(),
+ this._web3Wrapper.getContractDefaults(),
+ );
+ this._dutchAuctionContractIfExists = contractInstance;
+ return this._dutchAuctionContractIfExists;
+ }
+}
diff --git a/packages/contract-wrappers/src/fetchers/asset_balance_and_proxy_allowance_fetcher.ts b/packages/contract-wrappers/src/fetchers/asset_balance_and_proxy_allowance_fetcher.ts
index d10cffe57..1ff130a48 100644
--- a/packages/contract-wrappers/src/fetchers/asset_balance_and_proxy_allowance_fetcher.ts
+++ b/packages/contract-wrappers/src/fetchers/asset_balance_and_proxy_allowance_fetcher.ts
@@ -1,8 +1,7 @@
-// tslint:disable:no-unnecessary-type-assertion
import { AbstractBalanceAndProxyAllowanceFetcher, assetDataUtils } from '@0x/order-utils';
-import { AssetProxyId, ERC20AssetData, ERC721AssetData } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { BlockParamLiteral } from 'ethereum-types';
+import * as _ from 'lodash';
import { ERC20TokenWrapper } from '../contract_wrappers/erc20_token_wrapper';
import { ERC721TokenWrapper } from '../contract_wrappers/erc721_token_wrapper';
@@ -18,42 +17,45 @@ export class AssetBalanceAndProxyAllowanceFetcher implements AbstractBalanceAndP
}
public async getBalanceAsync(assetData: string, userAddress: string): Promise<BigNumber> {
const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
- if (decodedAssetData.assetProxyId === AssetProxyId.ERC20) {
- const decodedERC20AssetData = decodedAssetData as ERC20AssetData;
- const balance = await this._erc20Token.getBalanceAsync(decodedERC20AssetData.tokenAddress, userAddress, {
+ let balance: BigNumber | undefined;
+ if (assetDataUtils.isERC20AssetData(decodedAssetData)) {
+ balance = await this._erc20Token.getBalanceAsync(decodedAssetData.tokenAddress, userAddress, {
defaultBlock: this._stateLayer,
});
- return balance;
- } else {
- const decodedERC721AssetData = decodedAssetData as ERC721AssetData;
+ } else if (assetDataUtils.isERC721AssetData(decodedAssetData)) {
const tokenOwner = await this._erc721Token.getOwnerOfAsync(
- decodedERC721AssetData.tokenAddress,
- decodedERC721AssetData.tokenId,
+ decodedAssetData.tokenAddress,
+ decodedAssetData.tokenId,
{
defaultBlock: this._stateLayer,
},
);
- const balance = tokenOwner === userAddress ? new BigNumber(1) : new BigNumber(0);
- return balance;
+ balance = tokenOwner === userAddress ? new BigNumber(1) : new BigNumber(0);
+ } else if (assetDataUtils.isMultiAssetData(decodedAssetData)) {
+ // The `balance` for MultiAssetData is the total units of the entire `assetData` that are held by the `userAddress`.
+ for (const [index, nestedAssetDataElement] of decodedAssetData.nestedAssetData.entries()) {
+ const nestedAmountElement = decodedAssetData.amounts[index];
+ const nestedAssetBalance = (await this.getBalanceAsync(
+ nestedAssetDataElement,
+ userAddress,
+ )).dividedToIntegerBy(nestedAmountElement);
+ if (_.isUndefined(balance) || nestedAssetBalance.lessThan(balance)) {
+ balance = nestedAssetBalance;
+ }
+ }
}
+ return balance as BigNumber;
}
public async getProxyAllowanceAsync(assetData: string, userAddress: string): Promise<BigNumber> {
const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
- if (decodedAssetData.assetProxyId === AssetProxyId.ERC20) {
- const decodedERC20AssetData = decodedAssetData as ERC20AssetData;
- const proxyAllowance = await this._erc20Token.getProxyAllowanceAsync(
- decodedERC20AssetData.tokenAddress,
- userAddress,
- {
- defaultBlock: this._stateLayer,
- },
- );
- return proxyAllowance;
- } else {
- const decodedERC721AssetData = decodedAssetData as ERC721AssetData;
-
+ let proxyAllowance: BigNumber | undefined;
+ if (assetDataUtils.isERC20AssetData(decodedAssetData)) {
+ proxyAllowance = await this._erc20Token.getProxyAllowanceAsync(decodedAssetData.tokenAddress, userAddress, {
+ defaultBlock: this._stateLayer,
+ });
+ } else if (assetDataUtils.isERC721AssetData(decodedAssetData)) {
const isApprovedForAll = await this._erc721Token.isProxyApprovedForAllAsync(
- decodedERC721AssetData.tokenAddress,
+ decodedAssetData.tokenAddress,
userAddress,
{
defaultBlock: this._stateLayer,
@@ -63,15 +65,27 @@ export class AssetBalanceAndProxyAllowanceFetcher implements AbstractBalanceAndP
return new BigNumber(this._erc20Token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
} else {
const isApproved = await this._erc721Token.isProxyApprovedAsync(
- decodedERC721AssetData.tokenAddress,
- decodedERC721AssetData.tokenId,
+ decodedAssetData.tokenAddress,
+ decodedAssetData.tokenId,
{
defaultBlock: this._stateLayer,
},
);
- const proxyAllowance = isApproved ? new BigNumber(1) : new BigNumber(0);
- return proxyAllowance;
+ proxyAllowance = isApproved ? new BigNumber(1) : new BigNumber(0);
+ }
+ } else if (assetDataUtils.isMultiAssetData(decodedAssetData)) {
+ // The `proxyAllowance` for MultiAssetData is the total units of the entire `assetData` that the proxies have been approved to spend by the `userAddress`.
+ for (const [index, nestedAssetDataElement] of decodedAssetData.nestedAssetData.entries()) {
+ const nestedAmountElement = decodedAssetData.amounts[index];
+ const nestedAssetAllowance = (await this.getProxyAllowanceAsync(
+ nestedAssetDataElement,
+ userAddress,
+ )).dividedToIntegerBy(nestedAmountElement);
+ if (_.isUndefined(proxyAllowance) || nestedAssetAllowance.lessThan(proxyAllowance)) {
+ proxyAllowance = nestedAssetAllowance;
+ }
}
}
+ return proxyAllowance as BigNumber;
}
}
diff --git a/packages/contract-wrappers/src/index.ts b/packages/contract-wrappers/src/index.ts
index d66ff5c9c..69bbe3c91 100644
--- a/packages/contract-wrappers/src/index.ts
+++ b/packages/contract-wrappers/src/index.ts
@@ -34,6 +34,7 @@ export { ERC20ProxyWrapper } from './contract_wrappers/erc20_proxy_wrapper';
export { ERC721ProxyWrapper } from './contract_wrappers/erc721_proxy_wrapper';
export { ForwarderWrapper } from './contract_wrappers/forwarder_wrapper';
export { OrderValidatorWrapper } from './contract_wrappers/order_validator_wrapper';
+export { DutchAuctionWrapper } from './contract_wrappers/dutch_auction_wrapper';
export { TransactionEncoder } from './utils/transaction_encoder';
@@ -54,9 +55,21 @@ export {
OrderAndTraderInfo,
TraderInfo,
ValidateOrderFillableOpts,
+ DutchAuctionData,
} from './types';
-export { Order, SignedOrder, AssetProxyId } from '@0x/types';
+export {
+ AssetData,
+ ERC20AssetData,
+ ERC721AssetData,
+ SingleAssetData,
+ MultiAssetData,
+ MultiAssetDataWithRecursiveDecoding,
+ DutchAuctionDetails,
+ Order,
+ SignedOrder,
+ AssetProxyId,
+} from '@0x/types';
export {
BlockParamLiteral,
diff --git a/packages/contract-wrappers/src/types.ts b/packages/contract-wrappers/src/types.ts
index 14d4649ae..945ca88cd 100644
--- a/packages/contract-wrappers/src/types.ts
+++ b/packages/contract-wrappers/src/types.ts
@@ -9,7 +9,7 @@ import {
WETH9Events,
} from '@0x/abi-gen-wrappers';
import { ContractAddresses } from '@0x/contract-addresses';
-import { OrderState, SignedOrder } from '@0x/types';
+import { AssetData, OrderState, SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { BlockParam, ContractEventArg, DecodedLogArgs, LogEntryEvent, LogWithDecodedArgs } from 'ethereum-types';
@@ -206,3 +206,13 @@ export interface BalanceAndAllowance {
balance: BigNumber;
allowance: BigNumber;
}
+
+export enum DutchAuctionWrapperError {
+ AssetDataMismatch = 'ASSET_DATA_MISMATCH',
+}
+
+export interface DutchAuctionData {
+ assetData: AssetData;
+ beginTimeSeconds: BigNumber;
+ beginAmount: BigNumber;
+}
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/contract-wrappers/test/dutch_auction_wrapper_test.ts b/packages/contract-wrappers/test/dutch_auction_wrapper_test.ts
new file mode 100644
index 000000000..d7a6ca015
--- /dev/null
+++ b/packages/contract-wrappers/test/dutch_auction_wrapper_test.ts
@@ -0,0 +1,128 @@
+import { expectTransactionFailedAsync, getLatestBlockTimestampAsync } from '@0x/contracts-test-utils';
+import { BlockchainLifecycle } from '@0x/dev-utils';
+import { assetDataUtils } from '@0x/order-utils';
+import { RevertReason, SignedOrder } from '@0x/types';
+import { BigNumber } from '@0x/utils';
+import * as chai from 'chai';
+import 'mocha';
+
+import { ContractWrappers } from '../src';
+
+import { chaiSetup } from './utils/chai_setup';
+import { constants } from './utils/constants';
+import { DutchAuctionUtils } from './utils/dutch_auction_utils';
+import { migrateOnceAsync } from './utils/migrate';
+import { tokenUtils } from './utils/token_utils';
+import { provider, web3Wrapper } from './utils/web3_wrapper';
+
+chaiSetup.configure();
+const expect = chai.expect;
+const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
+
+// tslint:disable:custom-no-magic-numbers
+describe('DutchAuctionWrapper', () => {
+ const makerAssetAmount = new BigNumber(5);
+ const auctionEndTakerAmount = new BigNumber(10);
+ const auctionBeginTakerAmount = auctionEndTakerAmount.times(2);
+ const tenMinutesInSeconds = 10 * 60;
+ let contractWrappers: ContractWrappers;
+ let exchangeContractAddress: string;
+ let userAddresses: string[];
+ let makerAddress: string;
+ let takerAddress: string;
+ let makerTokenAddress: string;
+ let takerTokenAddress: string;
+ let buyOrder: SignedOrder;
+ let sellOrder: SignedOrder;
+ let makerTokenAssetData: string;
+ let takerTokenAssetData: string;
+ let auctionBeginTimeSeconds: BigNumber;
+ let auctionEndTimeSeconds: BigNumber;
+ before(async () => {
+ // setup contract wrappers & addresses
+ const contractAddresses = await migrateOnceAsync();
+ await blockchainLifecycle.startAsync();
+ const config = {
+ networkId: constants.TESTRPC_NETWORK_ID,
+ contractAddresses,
+ blockPollingIntervalMs: 10,
+ };
+ contractWrappers = new ContractWrappers(provider, config);
+ exchangeContractAddress = contractWrappers.exchange.address;
+ userAddresses = await web3Wrapper.getAvailableAddressesAsync();
+ [, makerAddress, takerAddress] = userAddresses;
+ [makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses();
+ // construct asset data for tokens being swapped
+ [makerTokenAssetData, takerTokenAssetData] = [
+ assetDataUtils.encodeERC20AssetData(makerTokenAddress),
+ assetDataUtils.encodeERC20AssetData(takerTokenAddress),
+ ];
+ // setup auction details in maker asset data
+ const currentBlockTimestamp: number = await getLatestBlockTimestampAsync();
+ auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds);
+ auctionEndTimeSeconds = new BigNumber(currentBlockTimestamp + tenMinutesInSeconds);
+ // create auction orders
+ const coinbase = userAddresses[0];
+ const dutchAuctionUtils = new DutchAuctionUtils(
+ web3Wrapper,
+ coinbase,
+ exchangeContractAddress,
+ contractWrappers.erc20Proxy.address,
+ );
+ sellOrder = await dutchAuctionUtils.createSignedSellOrderAsync(
+ auctionBeginTimeSeconds,
+ auctionEndTimeSeconds,
+ auctionBeginTakerAmount,
+ auctionEndTakerAmount,
+ makerAssetAmount,
+ makerTokenAssetData,
+ takerTokenAssetData,
+ makerAddress,
+ constants.NULL_ADDRESS,
+ );
+ buyOrder = await dutchAuctionUtils.createSignedBuyOrderAsync(sellOrder, takerAddress);
+ });
+ after(async () => {
+ await blockchainLifecycle.revertAsync();
+ });
+ beforeEach(async () => {
+ await blockchainLifecycle.startAsync();
+ });
+ afterEach(async () => {
+ await blockchainLifecycle.revertAsync();
+ });
+ describe('#matchOrdersAsync', () => {
+ it('should match two orders', async () => {
+ const txHash = await contractWrappers.dutchAuction.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
+ await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS);
+ });
+ it('should throw when invalid transaction and shouldValidate is true', async () => {
+ // request match with bad buy/sell orders
+ const badSellOrder = buyOrder;
+ const badBuyOrder = sellOrder;
+ return expectTransactionFailedAsync(
+ contractWrappers.dutchAuction.matchOrdersAsync(badBuyOrder, badSellOrder, takerAddress, {
+ shouldValidate: true,
+ }),
+ RevertReason.InvalidAssetData,
+ );
+ });
+ });
+
+ describe('#getAuctionDetailsAsync', () => {
+ it('should get auction details', async () => {
+ // get auction details
+ const auctionDetails = await contractWrappers.dutchAuction.getAuctionDetailsAsync(sellOrder);
+ // run some basic sanity checks on the return value
+ expect(auctionDetails.beginTimeSeconds, 'auctionDetails.beginTimeSeconds').to.be.bignumber.equal(
+ auctionBeginTimeSeconds,
+ );
+ expect(auctionDetails.beginAmount, 'auctionDetails.beginAmount').to.be.bignumber.equal(
+ auctionBeginTakerAmount,
+ );
+ expect(auctionDetails.endTimeSeconds, 'auctionDetails.endTimeSeconds').to.be.bignumber.equal(
+ auctionEndTimeSeconds,
+ );
+ });
+ });
+});
diff --git a/packages/contract-wrappers/test/utils/dutch_auction_utils.ts b/packages/contract-wrappers/test/utils/dutch_auction_utils.ts
new file mode 100644
index 000000000..8e2aef217
--- /dev/null
+++ b/packages/contract-wrappers/test/utils/dutch_auction_utils.ts
@@ -0,0 +1,153 @@
+import { DummyERC20TokenContract } from '@0x/abi-gen-wrappers';
+import * as artifacts from '@0x/contract-artifacts';
+import { assetDataUtils } from '@0x/order-utils';
+import { orderFactory } from '@0x/order-utils/lib/src/order_factory';
+import { SignedOrder } from '@0x/types';
+import { BigNumber } from '@0x/utils';
+import { Web3Wrapper } from '@0x/web3-wrapper';
+
+import { DutchAuctionWrapper } from '../../src/contract_wrappers/dutch_auction_wrapper';
+
+import { constants } from './constants';
+
+export class DutchAuctionUtils {
+ private readonly _web3Wrapper: Web3Wrapper;
+ private readonly _coinbase: string;
+ private readonly _exchangeAddress: string;
+ private readonly _erc20ProxyAddress: string;
+
+ constructor(web3Wrapper: Web3Wrapper, coinbase: string, exchangeAddress: string, erc20ProxyAddress: string) {
+ this._web3Wrapper = web3Wrapper;
+ this._coinbase = coinbase;
+ this._exchangeAddress = exchangeAddress;
+ this._erc20ProxyAddress = erc20ProxyAddress;
+ }
+ public async createSignedSellOrderAsync(
+ auctionBeginTimeSections: BigNumber,
+ acutionEndTimeSeconds: BigNumber,
+ auctionBeginTakerAssetAmount: BigNumber,
+ auctionEndTakerAssetAmount: BigNumber,
+ makerAssetAmount: BigNumber,
+ makerAssetData: string,
+ takerAssetData: string,
+ makerAddress: string,
+ takerAddress: string,
+ senderAddress?: string,
+ makerFee?: BigNumber,
+ takerFee?: BigNumber,
+ feeRecipientAddress?: string,
+ ): Promise<SignedOrder> {
+ // Notes on sell order:
+ // - The `takerAssetAmount` is set to the `auctionEndTakerAssetAmount`, which is the lowest amount the
+ // the seller can expect to receive
+ // - The `makerAssetData` is overloaded to include the auction begin time and begin taker asset amount
+ const makerAssetDataWithAuctionDetails = DutchAuctionWrapper.encodeDutchAuctionAssetData(
+ makerAssetData,
+ auctionBeginTimeSections,
+ auctionBeginTakerAssetAmount,
+ );
+ const signedOrder = await orderFactory.createSignedOrderAsync(
+ this._web3Wrapper.getProvider(),
+ makerAddress,
+ makerAssetAmount,
+ makerAssetDataWithAuctionDetails,
+ auctionEndTakerAssetAmount,
+ takerAssetData,
+ this._exchangeAddress,
+ {
+ takerAddress,
+ senderAddress,
+ makerFee,
+ takerFee,
+ feeRecipientAddress,
+ expirationTimeSeconds: acutionEndTimeSeconds,
+ },
+ );
+ const erc20AssetData = assetDataUtils.decodeERC20AssetData(makerAssetData);
+ await this._increaseERC20BalanceAndAllowanceAsync(erc20AssetData.tokenAddress, makerAddress, makerAssetAmount);
+ return signedOrder;
+ }
+ public async createSignedBuyOrderAsync(
+ sellOrder: SignedOrder,
+ buyerAddress: string,
+ senderAddress?: string,
+ makerFee?: BigNumber,
+ takerFee?: BigNumber,
+ feeRecipientAddress?: string,
+ expirationTimeSeconds?: BigNumber,
+ ): Promise<SignedOrder> {
+ const dutchAuctionData = DutchAuctionWrapper.decodeDutchAuctionData(sellOrder.makerAssetData);
+ // Notes on buy order:
+ // - The `makerAssetAmount` is set to `dutchAuctionData.beginAmount`, which is
+ // the highest amount the buyer would have to pay out at any point during the auction.
+ // - The `takerAssetAmount` is set to the seller's `makerAssetAmount`, as the buyer
+ // receives the entire amount being sold by the seller.
+ // - The `makerAssetData`/`takerAssetData` are reversed from the sell order
+ const signedOrder = await orderFactory.createSignedOrderAsync(
+ this._web3Wrapper.getProvider(),
+ buyerAddress,
+ dutchAuctionData.beginAmount,
+ sellOrder.takerAssetData,
+ sellOrder.makerAssetAmount,
+ sellOrder.makerAssetData,
+ sellOrder.exchangeAddress,
+ {
+ senderAddress,
+ makerFee,
+ takerFee,
+ feeRecipientAddress,
+ expirationTimeSeconds,
+ },
+ );
+ const buyerERC20AssetData = assetDataUtils.decodeERC20AssetData(sellOrder.takerAssetData);
+ await this._increaseERC20BalanceAndAllowanceAsync(
+ buyerERC20AssetData.tokenAddress,
+ buyerAddress,
+ dutchAuctionData.beginAmount,
+ );
+ return signedOrder;
+ }
+ private async _increaseERC20BalanceAndAllowanceAsync(
+ tokenAddress: string,
+ address: string,
+ amount: BigNumber,
+ ): Promise<void> {
+ if (amount.isZero() || address === constants.NULL_ADDRESS) {
+ return; // noop
+ }
+ await Promise.all([
+ this._increaseERC20BalanceAsync(tokenAddress, address, amount),
+ this._increaseERC20AllowanceAsync(tokenAddress, address, amount),
+ ]);
+ }
+ private async _increaseERC20BalanceAsync(tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
+ const erc20Token = new DummyERC20TokenContract(
+ artifacts.DummyERC20Token.compilerOutput.abi,
+ tokenAddress,
+ this._web3Wrapper.getProvider(),
+ this._web3Wrapper.getContractDefaults(),
+ );
+ const txHash = await erc20Token.transfer.sendTransactionAsync(address, amount, {
+ from: this._coinbase,
+ });
+ await this._web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS);
+ }
+ private async _increaseERC20AllowanceAsync(
+ tokenAddress: string,
+ address: string,
+ amount: BigNumber,
+ ): Promise<void> {
+ const erc20Token = new DummyERC20TokenContract(
+ artifacts.DummyERC20Token.compilerOutput.abi,
+ tokenAddress,
+ this._web3Wrapper.getProvider(),
+ this._web3Wrapper.getContractDefaults(),
+ );
+ const oldMakerAllowance = await erc20Token.allowance.callAsync(address, this._erc20ProxyAddress);
+ const newMakerAllowance = oldMakerAllowance.plus(amount);
+ const txHash = await erc20Token.approve.sendTransactionAsync(this._erc20ProxyAddress, newMakerAllowance, {
+ from: address,
+ });
+ await this._web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS);
+ }
+}
diff --git a/packages/fill-scenarios/CHANGELOG.json b/packages/fill-scenarios/CHANGELOG.json
index ca256399a..2c3e261cb 100644
--- a/packages/fill-scenarios/CHANGELOG.json
+++ b/packages/fill-scenarios/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "1.1.0",
+ "changes": [
+ {
+ "note": "Add support for MultiAssetProxy",
+ "pr": 1363
+ }
+ ]
+ },
+ {
"version": "1.0.16",
"changes": [
{
diff --git a/packages/fill-scenarios/src/fill_scenarios.ts b/packages/fill-scenarios/src/fill_scenarios.ts
index 0154bcd0a..ce1f7f9ff 100644
--- a/packages/fill-scenarios/src/fill_scenarios.ts
+++ b/packages/fill-scenarios/src/fill_scenarios.ts
@@ -2,7 +2,7 @@ import { DummyERC20TokenContract, DummyERC721TokenContract, ExchangeContract } f
import * as artifacts from '@0x/contract-artifacts';
import { assetDataUtils } from '@0x/order-utils';
import { orderFactory } from '@0x/order-utils/lib/src/order_factory';
-import { AssetProxyId, ERC721AssetData, OrderWithoutExchangeAddress, SignedOrder } from '@0x/types';
+import { OrderWithoutExchangeAddress, SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import { Provider } from 'ethereum-types';
@@ -150,39 +150,8 @@ export class FillScenarios {
feeRecipientAddress: string,
expirationTimeSeconds?: BigNumber,
): Promise<SignedOrder> {
- const decodedMakerAssetData = assetDataUtils.decodeAssetDataOrThrow(makerAssetData);
- if (decodedMakerAssetData.assetProxyId === AssetProxyId.ERC20) {
- await this._increaseERC20BalanceAndAllowanceAsync(
- decodedMakerAssetData.tokenAddress,
- makerAddress,
- makerFillableAmount,
- );
- } else {
- if (!makerFillableAmount.equals(1)) {
- throw new Error(`ERC721 makerFillableAmount should be equal 1. Found: ${makerFillableAmount}`);
- }
- await this._increaseERC721BalanceAndAllowanceAsync(
- decodedMakerAssetData.tokenAddress,
- makerAddress,
- // tslint:disable-next-line:no-unnecessary-type-assertion
- (decodedMakerAssetData as ERC721AssetData).tokenId,
- );
- }
- const decodedTakerAssetData = assetDataUtils.decodeAssetDataOrThrow(takerAssetData);
- if (decodedTakerAssetData.assetProxyId === AssetProxyId.ERC20) {
- const takerTokenAddress = decodedTakerAssetData.tokenAddress;
- await this._increaseERC20BalanceAndAllowanceAsync(takerTokenAddress, takerAddress, takerFillableAmount);
- } else {
- if (!takerFillableAmount.equals(1)) {
- throw new Error(`ERC721 takerFillableAmount should be equal 1. Found: ${takerFillableAmount}`);
- }
- await this._increaseERC721BalanceAndAllowanceAsync(
- decodedTakerAssetData.tokenAddress,
- takerAddress,
- // tslint:disable-next-line:no-unnecessary-type-assertion
- (decodedMakerAssetData as ERC721AssetData).tokenId,
- );
- }
+ await this._increaseBalanceAndAllowanceWithAssetDataAsync(makerAssetData, makerAddress, makerFillableAmount);
+ await this._increaseBalanceAndAllowanceWithAssetDataAsync(takerAssetData, takerAddress, takerFillableAmount);
// Fees
await Promise.all([
this._increaseERC20BalanceAndAllowanceAsync(this._zrxTokenAddress, makerAddress, makerFee),
@@ -298,4 +267,30 @@ export class FillScenarios {
});
await this._web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS);
}
+ private async _increaseBalanceAndAllowanceWithAssetDataAsync(
+ assetData: string,
+ userAddress: string,
+ amount: BigNumber,
+ ): Promise<void> {
+ const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
+ if (assetDataUtils.isERC20AssetData(decodedAssetData)) {
+ await this._increaseERC20BalanceAndAllowanceAsync(decodedAssetData.tokenAddress, userAddress, amount);
+ } else if (assetDataUtils.isERC721AssetData(decodedAssetData)) {
+ await this._increaseERC721BalanceAndAllowanceAsync(
+ decodedAssetData.tokenAddress,
+ userAddress,
+ decodedAssetData.tokenId,
+ );
+ } else if (assetDataUtils.isMultiAssetData(decodedAssetData)) {
+ for (const [index, nestedAssetDataElement] of decodedAssetData.nestedAssetData.entries()) {
+ const amountsElement = decodedAssetData.amounts[index];
+ const totalAmount = amount.times(amountsElement);
+ await this._increaseBalanceAndAllowanceWithAssetDataAsync(
+ nestedAssetDataElement,
+ userAddress,
+ totalAmount,
+ );
+ }
+ }
+ }
}
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/amount_placeholder.tsx b/packages/instant/src/components/amount_placeholder.tsx
index 29ce8fafb..290e34a07 100644
--- a/packages/instant/src/components/amount_placeholder.tsx
+++ b/packages/instant/src/components/amount_placeholder.tsx
@@ -30,3 +30,5 @@ export const AmountPlaceholder: React.StatelessComponent<AmountPlaceholderProps>
return <PlainPlaceholder color={props.color} />;
}
};
+
+AmountPlaceholder.displayName = 'AmountPlaceholder';
diff --git a/packages/instant/src/components/animations/slide_animation.tsx b/packages/instant/src/components/animations/slide_animation.tsx
index 5992bcba7..6ac47e9a6 100644
--- a/packages/instant/src/components/animations/slide_animation.tsx
+++ b/packages/instant/src/components/animations/slide_animation.tsx
@@ -11,6 +11,7 @@ export interface SlideAnimationProps {
slideOutSettings: OptionallyScreenSpecific<PositionAnimationSettings>;
zIndex?: OptionallyScreenSpecific<number>;
height?: string;
+ onAnimationEnd?: () => void;
}
export const SlideAnimation: React.StatelessComponent<SlideAnimationProps> = props => {
@@ -19,8 +20,15 @@ export const SlideAnimation: React.StatelessComponent<SlideAnimationProps> = pro
}
const positionSettings = props.animationState === 'slidIn' ? props.slideInSettings : props.slideOutSettings;
return (
- <PositionAnimation height={props.height} positionSettings={positionSettings} zIndex={props.zIndex}>
+ <PositionAnimation
+ onAnimationEnd={props.onAnimationEnd}
+ height={props.height}
+ positionSettings={positionSettings}
+ zIndex={props.zIndex}
+ >
{props.children}
</PositionAnimation>
);
};
+
+SlideAnimation.displayName = 'SlideAnimation';
diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx
index 1489b94d4..551e857a5 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';
@@ -31,7 +32,7 @@ export interface BuyButtonProps {
onBuyFailure: (buyQuote: BuyQuote, txHash: string) => void;
}
-export class BuyButton extends React.Component<BuyButtonProps> {
+export class BuyButton extends React.PureComponent<BuyButtonProps> {
public static defaultProps = {
onClick: util.boundNoop,
onBuySuccess: util.boundNoop,
@@ -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/buy_order_progress.tsx b/packages/instant/src/components/buy_order_progress.tsx
index a19f5a4d0..11ac5d5e0 100644
--- a/packages/instant/src/components/buy_order_progress.tsx
+++ b/packages/instant/src/components/buy_order_progress.tsx
@@ -31,3 +31,5 @@ export const BuyOrderProgress: React.StatelessComponent<BuyOrderProgressProps> =
}
return null;
};
+
+BuyOrderProgress.displayName = 'BuyOrderProgress';
diff --git a/packages/instant/src/components/buy_order_state_buttons.tsx b/packages/instant/src/components/buy_order_state_buttons.tsx
index 833818900..1214559d1 100644
--- a/packages/instant/src/components/buy_order_state_buttons.tsx
+++ b/packages/instant/src/components/buy_order_state_buttons.tsx
@@ -71,3 +71,5 @@ export const BuyOrderStateButtons: React.StatelessComponent<BuyOrderStateButtonP
/>
);
};
+
+BuyOrderStateButtons.displayName = 'BuyOrderStateButtons';
diff --git a/packages/instant/src/components/erc20_asset_amount_input.tsx b/packages/instant/src/components/erc20_asset_amount_input.tsx
index 4da82eb73..0418f9165 100644
--- a/packages/instant/src/components/erc20_asset_amount_input.tsx
+++ b/packages/instant/src/components/erc20_asset_amount_input.tsx
@@ -31,7 +31,7 @@ export interface ERC20AssetAmountInputState {
currentFontSizePx: number;
}
-export class ERC20AssetAmountInput extends React.Component<ERC20AssetAmountInputProps, ERC20AssetAmountInputState> {
+export class ERC20AssetAmountInput extends React.PureComponent<ERC20AssetAmountInputProps, ERC20AssetAmountInputState> {
public static defaultProps = {
onChange: util.boundNoop,
isDisabled: false,
diff --git a/packages/instant/src/components/erc20_token_selector.tsx b/packages/instant/src/components/erc20_token_selector.tsx
index cb8a8c797..a26fb5cf5 100644
--- a/packages/instant/src/components/erc20_token_selector.tsx
+++ b/packages/instant/src/components/erc20_token_selector.tsx
@@ -21,12 +21,12 @@ export interface ERC20TokenSelectorState {
searchQuery: string;
}
-export class ERC20TokenSelector extends React.Component<ERC20TokenSelectorProps> {
+export class ERC20TokenSelector extends React.PureComponent<ERC20TokenSelectorProps> {
public state: ERC20TokenSelectorState = {
searchQuery: '',
};
public render(): React.ReactNode {
- const { tokens, onTokenSelect } = this.props;
+ const { tokens } = this.props;
return (
<Container height="100%">
<Container marginBottom="10px">
@@ -42,12 +42,11 @@ export class ERC20TokenSelector extends React.Component<ERC20TokenSelectorProps>
tabIndex={-1}
/>
<Container overflow="scroll" height="calc(100% - 90px)" marginTop="10px">
- {_.map(tokens, token => {
- if (!this._isTokenQueryMatch(token)) {
- return null;
- }
- return <TokenSelectorRow key={token.assetData} token={token} onClick={onTokenSelect} />;
- })}
+ <TokenRowFilter
+ tokens={tokens}
+ onClick={this._handleTokenClick}
+ searchQuery={this.state.searchQuery}
+ />
</Container>
</Container>
);
@@ -59,8 +58,32 @@ export class ERC20TokenSelector extends React.Component<ERC20TokenSelectorProps>
});
analytics.trackTokenSelectorSearched(searchQuery);
};
+ private readonly _handleTokenClick = (token: ERC20Asset): void => {
+ this.props.onTokenSelect(token);
+ };
+}
+
+interface TokenRowFilterProps {
+ tokens: ERC20Asset[];
+ onClick: (token: ERC20Asset) => void;
+ searchQuery: string;
+}
+
+class TokenRowFilter extends React.Component<TokenRowFilterProps> {
+ public render(): React.ReactNode {
+ return _.map(this.props.tokens, token => {
+ if (!this._isTokenQueryMatch(token)) {
+ return null;
+ }
+ return <TokenSelectorRow key={token.assetData} token={token} onClick={this.props.onClick} />;
+ });
+ }
+ public shouldComponentUpdate(nextProps: TokenRowFilterProps): boolean {
+ const arePropsDeeplyEqual = _.isEqual(nextProps, this.props);
+ return !arePropsDeeplyEqual;
+ }
private readonly _isTokenQueryMatch = (token: ERC20Asset): boolean => {
- const { searchQuery } = this.state;
+ const { searchQuery } = this.props;
const searchQueryLowerCase = searchQuery.toLowerCase().trim();
if (searchQueryLowerCase === '') {
return true;
@@ -76,7 +99,7 @@ interface TokenSelectorRowProps {
onClick: (token: ERC20Asset) => void;
}
-class TokenSelectorRow extends React.Component<TokenSelectorRowProps> {
+class TokenSelectorRow extends React.PureComponent<TokenSelectorRowProps> {
public render(): React.ReactNode {
const { token } = this.props;
const circleColor = token.metaData.primaryColor || 'black';
@@ -131,21 +154,23 @@ const getTokenIcon = (symbol: string): React.StatelessComponent | undefined => {
}
};
-const TokenSelectorRowIcon: React.StatelessComponent<TokenSelectorRowIconProps> = props => {
- const { token } = props;
- const iconUrlIfExists = token.metaData.iconUrl;
+class TokenSelectorRowIcon extends React.PureComponent<TokenSelectorRowIconProps> {
+ public render(): React.ReactNode {
+ const { token } = this.props;
+ const iconUrlIfExists = token.metaData.iconUrl;
- const TokenIcon = getTokenIcon(token.metaData.symbol);
- const displaySymbol = assetUtils.bestNameForAsset(token);
- if (!_.isUndefined(iconUrlIfExists)) {
- return <img src={iconUrlIfExists} />;
- } else if (!_.isUndefined(TokenIcon)) {
- return <TokenIcon />;
- } else {
- return (
- <Text fontColor={ColorOption.white} fontSize="8px">
- {displaySymbol}
- </Text>
- );
+ const TokenIcon = getTokenIcon(token.metaData.symbol);
+ const displaySymbol = assetUtils.bestNameForAsset(token);
+ if (!_.isUndefined(iconUrlIfExists)) {
+ return <img src={iconUrlIfExists} />;
+ } else if (!_.isUndefined(TokenIcon)) {
+ return <TokenIcon />;
+ } else {
+ return (
+ <Text fontColor={ColorOption.white} fontSize="8px">
+ {displaySymbol}
+ </Text>
+ );
+ }
}
-};
+}
diff --git a/packages/instant/src/components/install_wallet_panel_content.tsx b/packages/instant/src/components/install_wallet_panel_content.tsx
index 481d82da0..1af3dafbb 100644
--- a/packages/instant/src/components/install_wallet_panel_content.tsx
+++ b/packages/instant/src/components/install_wallet_panel_content.tsx
@@ -18,7 +18,7 @@ import { Button } from './ui/button';
export interface InstallWalletPanelContentProps {}
-export class InstallWalletPanelContent extends React.Component<InstallWalletPanelContentProps> {
+export class InstallWalletPanelContent extends React.PureComponent<InstallWalletPanelContentProps> {
public render(): React.ReactNode {
const panelProps = this._getStandardPanelContentProps();
return <StandardPanelContent {...panelProps} />;
diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx
index 5b1f9592d..e943f68d7 100644
--- a/packages/instant/src/components/instant_heading.tsx
+++ b/packages/instant/src/components/instant_heading.tsx
@@ -28,7 +28,7 @@ const ICON_WIDTH = 34;
const ICON_HEIGHT = 34;
const ICON_COLOR = ColorOption.white;
-export class InstantHeading extends React.Component<InstantHeadingProps, {}> {
+export class InstantHeading extends React.PureComponent<InstantHeadingProps, {}> {
public render(): React.ReactNode {
const iconOrAmounts = this._renderIcon() || this._renderAmountsSection();
return (
diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx
index 9c10ef9e6..4db20b13e 100644
--- a/packages/instant/src/components/order_details.tsx
+++ b/packages/instant/src/components/order_details.tsx
@@ -26,7 +26,7 @@ export interface OrderDetailsProps {
onBaseCurrencySwitchEth: () => void;
onBaseCurrencySwitchUsd: () => void;
}
-export class OrderDetails extends React.Component<OrderDetailsProps> {
+export class OrderDetails extends React.PureComponent<OrderDetailsProps> {
public render(): React.ReactNode {
const shouldShowUsdError = this.props.baseCurrency === BaseCurrency.USD && this._hadErrorFetchingUsdPrice();
return (
@@ -200,7 +200,7 @@ export interface OrderDetailsRowProps {
primaryValue: React.ReactNode;
secondaryValue?: React.ReactNode;
}
-export class OrderDetailsRow extends React.Component<OrderDetailsRowProps, {}> {
+export class OrderDetailsRow extends React.PureComponent<OrderDetailsRowProps, {}> {
public render(): React.ReactNode {
return (
<Container padding="10px 0px" borderTop="1px dashed" borderColor={ColorOption.feintGrey}>
diff --git a/packages/instant/src/components/payment_method.tsx b/packages/instant/src/components/payment_method.tsx
index abadf4bd6..ada9f7bab 100644
--- a/packages/instant/src/components/payment_method.tsx
+++ b/packages/instant/src/components/payment_method.tsx
@@ -24,7 +24,7 @@ export interface PaymentMethodProps {
onUnlockWalletClick: () => void;
}
-export class PaymentMethod extends React.Component<PaymentMethodProps> {
+export class PaymentMethod extends React.PureComponent<PaymentMethodProps> {
public render(): React.ReactNode {
return (
<Container width="100%" height="120px" padding="20px 20px 0px 20px">
diff --git a/packages/instant/src/components/payment_method_dropdown.tsx b/packages/instant/src/components/payment_method_dropdown.tsx
index 872ac0831..e463e3eae 100644
--- a/packages/instant/src/components/payment_method_dropdown.tsx
+++ b/packages/instant/src/components/payment_method_dropdown.tsx
@@ -16,7 +16,7 @@ export interface PaymentMethodDropdownProps {
network: Network;
}
-export class PaymentMethodDropdown extends React.Component<PaymentMethodDropdownProps> {
+export class PaymentMethodDropdown extends React.PureComponent<PaymentMethodDropdownProps> {
public render(): React.ReactNode {
const { accountAddress, accountEthBalanceInWei } = this.props;
const value = format.ethAddress(accountAddress);
diff --git a/packages/instant/src/components/placing_order_button.tsx b/packages/instant/src/components/placing_order_button.tsx
index 2516b90b1..528a305dc 100644
--- a/packages/instant/src/components/placing_order_button.tsx
+++ b/packages/instant/src/components/placing_order_button.tsx
@@ -14,3 +14,5 @@ export const PlacingOrderButton: React.StatelessComponent<{}> = props => (
Placing Order&hellip;
</Button>
);
+
+PlacingOrderButton.displayName = 'PlacingOrderButton';
diff --git a/packages/instant/src/components/scaling_amount_input.tsx b/packages/instant/src/components/scaling_amount_input.tsx
index 4feb0502d..7dc1fdc0c 100644
--- a/packages/instant/src/components/scaling_amount_input.tsx
+++ b/packages/instant/src/components/scaling_amount_input.tsx
@@ -26,7 +26,7 @@ interface ScalingAmountInputState {
}
const { stringToMaybeBigNumber, areMaybeBigNumbersEqual } = maybeBigNumberUtil;
-export class ScalingAmountInput extends React.Component<ScalingAmountInputProps, ScalingAmountInputState> {
+export class ScalingAmountInput extends React.PureComponent<ScalingAmountInputProps, ScalingAmountInputState> {
public static defaultProps = {
onAmountChange: util.boundNoop,
onFontSizeChange: util.boundNoop,
diff --git a/packages/instant/src/components/scaling_input.tsx b/packages/instant/src/components/scaling_input.tsx
index 00aea37da..c31de1fb5 100644
--- a/packages/instant/src/components/scaling_input.tsx
+++ b/packages/instant/src/components/scaling_input.tsx
@@ -51,7 +51,7 @@ const defaultScalingSettings: ScalingSettings = {
additionalInputSpaceInCh: 0.4,
};
-export class ScalingInput extends React.Component<ScalingInputProps> {
+export class ScalingInput extends React.PureComponent<ScalingInputProps> {
public static defaultProps = {
onChange: util.boundNoop,
onFontSizeChange: util.boundNoop,
diff --git a/packages/instant/src/components/secondary_button.tsx b/packages/instant/src/components/secondary_button.tsx
index 705390e28..0714ce287 100644
--- a/packages/instant/src/components/secondary_button.tsx
+++ b/packages/instant/src/components/secondary_button.tsx
@@ -24,3 +24,4 @@ export const SecondaryButton: React.StatelessComponent<SecondaryButtonProps> = p
SecondaryButton.defaultProps = {
width: '100%',
};
+SecondaryButton.displayName = 'SecondaryButton';
diff --git a/packages/instant/src/components/section_header.tsx b/packages/instant/src/components/section_header.tsx
index d0974ebdc..2185b67ba 100644
--- a/packages/instant/src/components/section_header.tsx
+++ b/packages/instant/src/components/section_header.tsx
@@ -18,3 +18,4 @@ export const SectionHeader: React.StatelessComponent<SectionHeaderProps> = props
</Text>
);
};
+SectionHeader.displayName = 'SectionHeader';
diff --git a/packages/instant/src/components/sliding_error.tsx b/packages/instant/src/components/sliding_error.tsx
index b59e2a905..c7c6732cf 100644
--- a/packages/instant/src/components/sliding_error.tsx
+++ b/packages/instant/src/components/sliding_error.tsx
@@ -38,6 +38,8 @@ export const Error: React.StatelessComponent<ErrorProps> = props => (
</Container>
);
+Error.displayName = 'Error';
+
export interface SlidingErrorProps extends ErrorProps {
animationState: SlideAnimationState;
}
@@ -94,3 +96,5 @@ export const SlidingError: React.StatelessComponent<SlidingErrorProps> = props =
</SlideAnimation>
);
};
+
+SlidingError.displayName = 'SlidingError';
diff --git a/packages/instant/src/components/sliding_panel.tsx b/packages/instant/src/components/sliding_panel.tsx
index 7f9037049..9b09a0d80 100644
--- a/packages/instant/src/components/sliding_panel.tsx
+++ b/packages/instant/src/components/sliding_panel.tsx
@@ -26,42 +26,48 @@ export const Panel: React.StatelessComponent<PanelProps> = ({ children, onClose
</Container>
);
+Panel.displayName = 'Panel';
+
export interface SlidingPanelProps extends PanelProps {
animationState: SlideAnimationState;
+ onAnimationEnd?: () => void;
}
-export const SlidingPanel: React.StatelessComponent<SlidingPanelProps> = props => {
- if (props.animationState === 'none') {
- return null;
+export class SlidingPanel extends React.PureComponent<SlidingPanelProps> {
+ public render(): React.ReactNode {
+ if (this.props.animationState === 'none') {
+ return null;
+ }
+ const { animationState, onAnimationEnd, ...rest } = this.props;
+ const slideAmount = '100%';
+ const slideUpSettings: PositionAnimationSettings = {
+ duration: '0.3s',
+ timingFunction: 'ease-in-out',
+ top: {
+ from: slideAmount,
+ to: '0px',
+ },
+ position: 'absolute',
+ };
+ const slideDownSettings: PositionAnimationSettings = {
+ duration: '0.3s',
+ timingFunction: 'ease-out',
+ top: {
+ from: '0px',
+ to: slideAmount,
+ },
+ position: 'absolute',
+ };
+ return (
+ <SlideAnimation
+ slideInSettings={slideUpSettings}
+ slideOutSettings={slideDownSettings}
+ animationState={animationState}
+ height="100%"
+ onAnimationEnd={onAnimationEnd}
+ >
+ <Panel {...rest} />
+ </SlideAnimation>
+ );
}
- const { animationState, ...rest } = props;
- const slideAmount = '100%';
- const slideUpSettings: PositionAnimationSettings = {
- duration: '0.3s',
- timingFunction: 'ease-in-out',
- top: {
- from: slideAmount,
- to: '0px',
- },
- position: 'absolute',
- };
- const slideDownSettings: PositionAnimationSettings = {
- duration: '0.3s',
- timingFunction: 'ease-out',
- top: {
- from: '0px',
- to: slideAmount,
- },
- position: 'absolute',
- };
- return (
- <SlideAnimation
- slideInSettings={slideUpSettings}
- slideOutSettings={slideDownSettings}
- animationState={animationState}
- height="100%"
- >
- <Panel {...rest} />
- </SlideAnimation>
- );
-};
+}
diff --git a/packages/instant/src/components/standard_panel_content.tsx b/packages/instant/src/components/standard_panel_content.tsx
index 79b7bff24..f2987df82 100644
--- a/packages/instant/src/components/standard_panel_content.tsx
+++ b/packages/instant/src/components/standard_panel_content.tsx
@@ -71,3 +71,5 @@ export const StandardPanelContent: React.StatelessComponent<StandardPanelContent
<Container>{action}</Container>
</Container>
);
+
+StandardPanelContent.displayName = 'StandardPanelContent';
diff --git a/packages/instant/src/components/standard_sliding_panel.tsx b/packages/instant/src/components/standard_sliding_panel.tsx
index 9f517d273..bcc9d3dce 100644
--- a/packages/instant/src/components/standard_sliding_panel.tsx
+++ b/packages/instant/src/components/standard_sliding_panel.tsx
@@ -9,7 +9,7 @@ export interface StandardSlidingPanelProps extends StandardSlidingPanelSettings
onClose: () => void;
}
-export class StandardSlidingPanel extends React.Component<StandardSlidingPanelProps> {
+export class StandardSlidingPanel extends React.PureComponent<StandardSlidingPanelProps> {
public render(): React.ReactNode {
const { animationState, content, onClose } = this.props;
return (
diff --git a/packages/instant/src/components/time_counter.tsx b/packages/instant/src/components/time_counter.tsx
index f9b68163c..93dc497d5 100644
--- a/packages/instant/src/components/time_counter.tsx
+++ b/packages/instant/src/components/time_counter.tsx
@@ -16,7 +16,7 @@ interface TimeCounterState {
elapsedSeconds: number;
}
-export class TimeCounter extends React.Component<TimeCounterProps, TimeCounterState> {
+export class TimeCounter extends React.PureComponent<TimeCounterProps, TimeCounterState> {
public state = {
elapsedSeconds: 0,
};
diff --git a/packages/instant/src/components/timed_progress_bar.tsx b/packages/instant/src/components/timed_progress_bar.tsx
index fb3927088..b1644b871 100644
--- a/packages/instant/src/components/timed_progress_bar.tsx
+++ b/packages/instant/src/components/timed_progress_bar.tsx
@@ -17,7 +17,7 @@ export interface TimedProgressBarProps {
* Goes from 0% -> PROGRESS_STALL_AT_WIDTH over time of expectedTimeMs
* When hasEnded set to true, goes to 100% through animation of PROGRESS_FINISH_ANIMATION_TIME_MS length of time
*/
-export class TimedProgressBar extends React.Component<TimedProgressBarProps, {}> {
+export class TimedProgressBar extends React.PureComponent<TimedProgressBarProps, {}> {
private readonly _barRef = React.createRef<HTMLDivElement>();
public render(): React.ReactNode {
diff --git a/packages/instant/src/components/ui/container.tsx b/packages/instant/src/components/ui/container.tsx
index 636eb8fc9..58d7d5871 100644
--- a/packages/instant/src/components/ui/container.tsx
+++ b/packages/instant/src/components/ui/container.tsx
@@ -36,6 +36,7 @@ export interface ContainerProps {
cursor?: string;
overflow?: string;
darkenOnHover?: boolean;
+ rawHoverColor?: string;
boxShadowOnHover?: boolean;
flexGrow?: string | number;
}
@@ -87,6 +88,7 @@ export const Container =
background-color: ${props => getBackgroundColor(props.theme, props.backgroundColor, props.rawBackgroundColor)};
border-color: ${props => (props.borderColor ? props.theme[props.borderColor] : 'none')};
&:hover {
+ ${props => (props.rawHoverColor ? `background-color: ${props.rawHoverColor}` : '')}
${props =>
props.darkenOnHover
? `background-color: ${
diff --git a/packages/instant/src/components/ui/dropdown.tsx b/packages/instant/src/components/ui/dropdown.tsx
index 02e87d639..8788d3d59 100644
--- a/packages/instant/src/components/ui/dropdown.tsx
+++ b/packages/instant/src/components/ui/dropdown.tsx
@@ -1,7 +1,8 @@
import * as _ from 'lodash';
+import { transparentize } from 'polished';
import * as React from 'react';
-import { ColorOption, completelyTransparent } from '../../style/theme';
+import { ColorOption, completelyTransparent, ThemeConsumer } from '../../style/theme';
import { zIndex } from '../../style/z_index';
import { Container } from './container';
@@ -26,7 +27,7 @@ export interface DropdownState {
isOpen: boolean;
}
-export class Dropdown extends React.Component<DropdownProps, DropdownState> {
+export class Dropdown extends React.PureComponent<DropdownProps, DropdownState> {
public static defaultProps = {
items: [],
};
@@ -121,20 +122,26 @@ export interface DropdownItemProps extends DropdownItemConfig {
}
export const DropdownItem: React.StatelessComponent<DropdownItemProps> = ({ text, onClick, isLast }) => (
- <Container
- onClick={onClick}
- cursor="pointer"
- darkenOnHover={true}
- backgroundColor={ColorOption.white}
- padding="0.8em"
- borderTop="0"
- border="1px solid"
- borderRadius={isLast ? '0px 0px 4px 4px' : undefined}
- width="100%"
- borderColor={ColorOption.feintGrey}
- >
- <Text fontSize="14px" fontColor={ColorOption.darkGrey}>
- {text}
- </Text>
- </Container>
+ <ThemeConsumer>
+ {theme => (
+ <Container
+ onClick={onClick}
+ cursor="pointer"
+ rawHoverColor={transparentize(0.9, theme[ColorOption.primaryColor])}
+ backgroundColor={ColorOption.white}
+ padding="0.8em"
+ borderTop="0"
+ border="1px solid"
+ borderRadius={isLast ? '0px 0px 4px 4px' : undefined}
+ width="100%"
+ borderColor={ColorOption.feintGrey}
+ >
+ <Text fontSize="14px" fontColor={ColorOption.darkGrey}>
+ {text}
+ </Text>
+ </Container>
+ )}
+ </ThemeConsumer>
);
+
+DropdownItem.displayName = 'DropdownItem';
diff --git a/packages/instant/src/components/wallet_prompt.tsx b/packages/instant/src/components/wallet_prompt.tsx
index c07cfe7b5..10433767f 100644
--- a/packages/instant/src/components/wallet_prompt.tsx
+++ b/packages/instant/src/components/wallet_prompt.tsx
@@ -45,3 +45,5 @@ WalletPrompt.defaultProps = {
primaryColor: ColorOption.darkOrange,
secondaryColor: ColorOption.lightOrange,
};
+
+WalletPrompt.displayName = 'WalletPrompt';
diff --git a/packages/instant/src/components/zero_ex_instant.tsx b/packages/instant/src/components/zero_ex_instant.tsx
index 2267b4dbf..e9cb48e61 100644
--- a/packages/instant/src/components/zero_ex_instant.tsx
+++ b/packages/instant/src/components/zero_ex_instant.tsx
@@ -17,3 +17,5 @@ export const ZeroExInstant: React.StatelessComponent<ZeroExInstantProps> = props
</div>
);
};
+
+ZeroExInstant.displayName = 'ZeroExInstant';
diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx
index 0337c7714..e8c64d5d1 100644
--- a/packages/instant/src/components/zero_ex_instant_container.tsx
+++ b/packages/instant/src/components/zero_ex_instant_container.tsx
@@ -24,7 +24,10 @@ export interface ZeroExInstantContainerState {
tokenSelectionPanelAnimationState: SlideAnimationState;
}
-export class ZeroExInstantContainer extends React.Component<ZeroExInstantContainerProps, ZeroExInstantContainerState> {
+export class ZeroExInstantContainer extends React.PureComponent<
+ ZeroExInstantContainerProps,
+ ZeroExInstantContainerState
+> {
public state = {
tokenSelectionPanelAnimationState: 'none' as SlideAnimationState,
};
@@ -60,6 +63,7 @@ export class ZeroExInstantContainer extends React.Component<ZeroExInstantContain
<SlidingPanel
animationState={this.state.tokenSelectionPanelAnimationState}
onClose={this._handlePanelCloseClickedX}
+ onAnimationEnd={this._handleSlidingPanelAnimationEnd}
>
<AvailableERC20TokenSelector onTokenSelect={this._handlePanelCloseAfterChose} />
</SlidingPanel>
@@ -98,4 +102,11 @@ export class ZeroExInstantContainer extends React.Component<ZeroExInstantContain
tokenSelectionPanelAnimationState: 'slidOut',
});
};
+ private readonly _handleSlidingPanelAnimationEnd = (): void => {
+ if (this.state.tokenSelectionPanelAnimationState === 'slidOut') {
+ // When the slidOut animation completes, don't keep the panel mounted.
+ // Performance optimization
+ this.setState({ tokenSelectionPanelAnimationState: 'none' });
+ }
+ };
}
diff --git a/packages/instant/src/components/zero_ex_instant_overlay.tsx b/packages/instant/src/components/zero_ex_instant_overlay.tsx
index 96e560691..38a716091 100644
--- a/packages/instant/src/components/zero_ex_instant_overlay.tsx
+++ b/packages/instant/src/components/zero_ex_instant_overlay.tsx
@@ -49,3 +49,5 @@ export const ZeroExInstantOverlay: React.StatelessComponent<ZeroExInstantOverlay
</ZeroExInstantProvider>
);
};
+
+ZeroExInstantOverlay.displayName = 'ZeroExInstantOverlay';
diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx
index 2de327cd7..ec8e82ee3 100644
--- a/packages/instant/src/components/zero_ex_instant_provider.tsx
+++ b/packages/instant/src/components/zero_ex_instant_provider.tsx
@@ -21,7 +21,7 @@ import { providerStateFactory } from '../util/provider_state_factory';
export type ZeroExInstantProviderProps = ZeroExInstantBaseConfig;
-export class ZeroExInstantProvider extends React.Component<ZeroExInstantProviderProps> {
+export class ZeroExInstantProvider extends React.PureComponent<ZeroExInstantProviderProps> {
private readonly _store: Store;
private _accountUpdateHeartbeat?: Heartbeater;
private _buyQuoteHeartbeat?: Heartbeater;
diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts
index 975dfcbea..22f0cb6a4 100644
--- a/packages/instant/src/constants.ts
+++ b/packages/instant/src/constants.ts
@@ -72,5 +72,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_error.tsx b/packages/instant/src/containers/latest_error.tsx
index 0d4349124..6da4558ef 100644
--- a/packages/instant/src/containers/latest_error.tsx
+++ b/packages/instant/src/containers/latest_error.tsx
@@ -14,7 +14,7 @@ import { zIndex } from '../style/z_index';
import { Asset, DisplayStatus, Omit, SlideAnimationState } from '../types';
import { errorFlasher } from '../util/error_flasher';
-export interface LatestErrorComponentProps {
+interface LatestErrorComponentProps {
asset?: Asset;
latestErrorMessage?: string;
animationState: SlideAnimationState;
@@ -22,7 +22,7 @@ export interface LatestErrorComponentProps {
onOverlayClick: () => void;
}
-export const LatestErrorComponent: React.StatelessComponent<LatestErrorComponentProps> = props => {
+const LatestErrorComponent: React.StatelessComponent<LatestErrorComponentProps> = props => {
if (!props.latestErrorMessage) {
// Render a hidden SlidingError such that instant does not move when a real error is rendered.
return (
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/types.ts b/packages/instant/src/types.ts
index e7c920f36..ae672c919 100644
--- a/packages/instant/src/types.ts
+++ b/packages/instant/src/types.ts
@@ -96,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;
@@ -181,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 6c63907dc..4faeaaf5a 100644
--- a/packages/instant/src/util/analytics.ts
+++ b/packages/instant/src/util/analytics.ts
@@ -46,6 +46,7 @@ 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',
@@ -189,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),
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/json-schemas/schemas/asset_pairs_request_opts_schema.json b/packages/json-schemas/schemas/asset_pairs_request_opts_schema.json
index 174a8fdc3..fad0bd371 100644
--- a/packages/json-schemas/schemas/asset_pairs_request_opts_schema.json
+++ b/packages/json-schemas/schemas/asset_pairs_request_opts_schema.json
@@ -1,5 +1,5 @@
{
- "id": "/AssetPairsRequestOpts",
+ "id": "/AssetPairsRequestOptsSchema",
"type": "object",
"properties": {
"assetDataA": { "$ref": "/hexSchema" },
diff --git a/packages/json-schemas/schemas/call_data_schema.json b/packages/json-schemas/schemas/call_data_schema.json
index c5972e8c1..e5e6e3282 100644
--- a/packages/json-schemas/schemas/call_data_schema.json
+++ b/packages/json-schemas/schemas/call_data_schema.json
@@ -4,13 +4,13 @@
"from": { "$ref": "/addressSchema" },
"to": { "$ref": "/addressSchema" },
"value": {
- "oneOf": [{ "$ref": "/numberSchema" }, { "$ref": "/jsNumber" }]
+ "oneOf": [{ "$ref": "/numberSchema" }, { "$ref": "/jsNumberSchema" }]
},
"gas": {
- "oneOf": [{ "$ref": "/numberSchema" }, { "$ref": "/jsNumber" }]
+ "oneOf": [{ "$ref": "/numberSchema" }, { "$ref": "/jsNumberSchema" }]
},
"gasPrice": {
- "oneOf": [{ "$ref": "/numberSchema" }, { "$ref": "/jsNumber" }]
+ "oneOf": [{ "$ref": "/numberSchema" }, { "$ref": "/jsNumberSchema" }]
},
"data": {
"type": "string",
diff --git a/packages/json-schemas/schemas/ec_signature_schema.json b/packages/json-schemas/schemas/ec_signature_schema.json
index bc79ca5e9..52ccfe7bb 100644
--- a/packages/json-schemas/schemas/ec_signature_schema.json
+++ b/packages/json-schemas/schemas/ec_signature_schema.json
@@ -1,5 +1,5 @@
{
- "id": "/ECSignature",
+ "id": "/ecSignatureSchema",
"properties": {
"v": {
"type": "number",
diff --git a/packages/json-schemas/schemas/js_number.json b/packages/json-schemas/schemas/js_number_schema.json
index 6a72d92c0..7df1c4747 100644
--- a/packages/json-schemas/schemas/js_number.json
+++ b/packages/json-schemas/schemas/js_number_schema.json
@@ -1,5 +1,5 @@
{
- "id": "/jsNumber",
+ "id": "/jsNumberSchema",
"type": "number",
"minimum": 0
}
diff --git a/packages/json-schemas/schemas/order_config_request_schema.json b/packages/json-schemas/schemas/order_config_request_schema.json
index ca9b2e30e..19b043e7f 100644
--- a/packages/json-schemas/schemas/order_config_request_schema.json
+++ b/packages/json-schemas/schemas/order_config_request_schema.json
@@ -1,5 +1,5 @@
{
- "id": "/OrderConfigRequest",
+ "id": "/OrderConfigRequestSchema",
"type": "object",
"properties": {
"makerAddress": { "$ref": "/addressSchema" },
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/schemas/orderbook_request_schema.json b/packages/json-schemas/schemas/orderbook_request_schema.json
index 27848bdcb..5ce6e8ab0 100644
--- a/packages/json-schemas/schemas/orderbook_request_schema.json
+++ b/packages/json-schemas/schemas/orderbook_request_schema.json
@@ -1,9 +1,9 @@
{
- "id": "/OrderBookRequest",
+ "id": "/OrderbookRequestSchema",
"type": "object",
"properties": {
"baseAssetData": { "$ref": "/hexSchema" },
"quoteAssetData": { "$ref": "/hexSchema" }
},
"required": ["baseAssetData", "quoteAssetData"]
-} \ No newline at end of file
+}
diff --git a/packages/json-schemas/schemas/orders_request_opts_schema.json b/packages/json-schemas/schemas/orders_request_opts_schema.json
index 10da51060..4c1b9b4e9 100644
--- a/packages/json-schemas/schemas/orders_request_opts_schema.json
+++ b/packages/json-schemas/schemas/orders_request_opts_schema.json
@@ -1,5 +1,5 @@
{
- "id": "/OrdersRequestOpts",
+ "id": "/OrdersRequestOptsSchema",
"type": "object",
"properties": {
"makerAssetProxyId": { "$ref": "/hexSchema" },
diff --git a/packages/json-schemas/schemas/paged_request_opts_schema.json b/packages/json-schemas/schemas/paged_request_opts_schema.json
index 7cfc73947..f143c28b0 100644
--- a/packages/json-schemas/schemas/paged_request_opts_schema.json
+++ b/packages/json-schemas/schemas/paged_request_opts_schema.json
@@ -1,5 +1,5 @@
{
- "id": "/PagedRequestOpts",
+ "id": "/PagedRequestOptsSchema",
"type": "object",
"properties": {
"page": { "type": "number" },
diff --git a/packages/json-schemas/schemas/request_opts_schema.json b/packages/json-schemas/schemas/request_opts_schema.json
index b50547d18..2206f5016 100644
--- a/packages/json-schemas/schemas/request_opts_schema.json
+++ b/packages/json-schemas/schemas/request_opts_schema.json
@@ -1,5 +1,5 @@
{
- "id": "/RequestOpts",
+ "id": "/RequestOptsSchema",
"type": "object",
"properties": {
"networkId": { "type": "number" }
diff --git a/packages/json-schemas/schemas/tx_data_schema.json b/packages/json-schemas/schemas/tx_data_schema.json
index 4643521ce..8c3daba4e 100644
--- a/packages/json-schemas/schemas/tx_data_schema.json
+++ b/packages/json-schemas/schemas/tx_data_schema.json
@@ -4,13 +4,13 @@
"from": { "$ref": "/addressSchema" },
"to": { "$ref": "/addressSchema" },
"value": {
- "oneOf": [{ "$ref": "/numberSchema" }, { "$ref": "/jsNumber" }]
+ "oneOf": [{ "$ref": "/numberSchema" }, { "$ref": "/jsNumberSchema" }]
},
"gas": {
- "oneOf": [{ "$ref": "/numberSchema" }, { "$ref": "/jsNumber" }]
+ "oneOf": [{ "$ref": "/numberSchema" }, { "$ref": "/jsNumberSchema" }]
},
"gasPrice": {
- "oneOf": [{ "$ref": "/numberSchema" }, { "$ref": "/jsNumber" }]
+ "oneOf": [{ "$ref": "/numberSchema" }, { "$ref": "/jsNumberSchema" }]
},
"data": {
"type": "string",
diff --git a/packages/json-schemas/src/schemas.ts b/packages/json-schemas/src/schemas.ts
index 21a6f424c..9e8eb6959 100644
--- a/packages/json-schemas/src/schemas.ts
+++ b/packages/json-schemas/src/schemas.ts
@@ -8,7 +8,7 @@ import * as ecSignatureSchema from '../schemas/ec_signature_schema.json';
import * as eip712TypedDataSchema from '../schemas/eip712_typed_data_schema.json';
import * as hexSchema from '../schemas/hex_schema.json';
import * as indexFilterValuesSchema from '../schemas/index_filter_values_schema.json';
-import * as jsNumber from '../schemas/js_number.json';
+import * as jsNumber from '../schemas/js_number_schema.json';
import * as numberSchema from '../schemas/number_schema.json';
import * as orderCancellationRequestsSchema from '../schemas/order_cancel_schema.json';
import * as orderConfigRequestSchema from '../schemas/order_config_request_schema.json';
@@ -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..7d7ce1d7e 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",
@@ -40,7 +42,7 @@
"./schemas/relayer_api_orders_schema.json",
"./schemas/signed_orders_schema.json",
"./schemas/token_schema.json",
- "./schemas/js_number.json",
+ "./schemas/js_number_schema.json",
"./schemas/zero_ex_transaction_schema.json",
"./schemas/tx_data_schema.json",
"./schemas/index_filter_values_schema.json",
diff --git a/packages/migrations/CHANGELOG.json b/packages/migrations/CHANGELOG.json
index e7b18f12b..cee64a69f 100644
--- a/packages/migrations/CHANGELOG.json
+++ b/packages/migrations/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "2.3.0",
+ "changes": [
+ {
+ "note": "Added migrations for Dutch Auction contract",
+ "pr": 1465
+ }
+ ]
+ },
+ {
"version": "2.2.2",
"changes": [
{
diff --git a/packages/migrations/src/migration.ts b/packages/migrations/src/migration.ts
index c684c4970..99d1719f1 100644
--- a/packages/migrations/src/migration.ts
+++ b/packages/migrations/src/migration.ts
@@ -141,6 +141,14 @@ export async function runMigrationsAsync(provider: Provider, txDefaults: Partial
zrxAssetData,
);
+ // DutchAuction
+ const dutchAuction = await wrappers.DutchAuctionContract.deployFrom0xArtifactAsync(
+ artifacts.DutchAuction,
+ provider,
+ txDefaults,
+ exchange.address,
+ );
+
// Fund the Forwarder with ZRX
const zrxDecimals = await zrxToken.decimals.callAsync();
const zrxForwarderAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(5000), zrxDecimals);
@@ -157,6 +165,7 @@ export async function runMigrationsAsync(provider: Provider, txDefaults: Partial
assetProxyOwner: assetProxyOwner.address,
forwarder: forwarder.address,
orderValidator: orderValidator.address,
+ dutchAuction: dutchAuction.address,
};
}
diff --git a/packages/monorepo-scripts/CHANGELOG.json b/packages/monorepo-scripts/CHANGELOG.json
index 428168437..cebe7ec72 100644
--- a/packages/monorepo-scripts/CHANGELOG.json
+++ b/packages/monorepo-scripts/CHANGELOG.json
@@ -17,6 +17,10 @@
{
"note": "Fix a bug when hardcoded CHANGELOG paths cause fetching release notes to fail",
"pr": 1311
+ },
+ {
+ "note": "Added DutchAuctionWrapper to the CLASSES_WITH_HIDDEN_CONSTRUCTORS array",
+ "pr": 1465
}
]
},
diff --git a/packages/monorepo-scripts/src/doc_gen_configs.ts b/packages/monorepo-scripts/src/doc_gen_configs.ts
index 7a14f8664..dfbe98028 100644
--- a/packages/monorepo-scripts/src/doc_gen_configs.ts
+++ b/packages/monorepo-scripts/src/doc_gen_configs.ts
@@ -37,6 +37,7 @@ export const docGenConfigs: DocGenConfigs = {
// and getting confused. Any class name in this list will not have it's constructor rendered in our docs.
CLASSES_WITH_HIDDEN_CONSTRUCTORS: [
'AssetBuyer',
+ 'DutchAuctionWrapper',
'ERC20ProxyWrapper',
'ERC20TokenWrapper',
'ERC721ProxyWrapper',
diff --git a/packages/order-utils/CHANGELOG.json b/packages/order-utils/CHANGELOG.json
index 11889b92e..292f7a57b 100644
--- a/packages/order-utils/CHANGELOG.json
+++ b/packages/order-utils/CHANGELOG.json
@@ -1,5 +1,15 @@
[
{
+ "version": "3.1.0",
+ "changes": [
+ {
+ "note":
+ "Use new ABI encoder, add encoding/decoding logic for MultiAsset assetData, and add information to return values in orderStateUtils",
+ "pr": 1363
+ }
+ ]
+ },
+ {
"version": "3.0.7",
"changes": [
{
diff --git a/packages/order-utils/src/asset_data_utils.ts b/packages/order-utils/src/asset_data_utils.ts
index 9bbef3a23..f314891e2 100644
--- a/packages/order-utils/src/asset_data_utils.ts
+++ b/packages/order-utils/src/asset_data_utils.ts
@@ -1,10 +1,19 @@
-import { AssetData, AssetProxyId, ERC20AssetData, ERC721AssetData } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import ethAbi = require('ethereumjs-abi');
-import ethUtil = require('ethereumjs-util');
+import {
+ AssetProxyId,
+ ERC20AssetData,
+ ERC721AssetData,
+ MultiAssetData,
+ MultiAssetDataWithRecursiveDecoding,
+ SingleAssetData,
+} from '@0x/types';
+import { AbiEncoder, BigNumber } from '@0x/utils';
+import * as _ from 'lodash';
import { constants } from './constants';
+const encodingRules: AbiEncoder.EncodingRules = { shouldOptimize: true };
+const decodingRules: AbiEncoder.DecodingRules = { shouldConvertStructsToObjects: true };
+
export const assetDataUtils = {
/**
* Encodes an ERC20 token address into a hex encoded assetData string, usable in the makerAssetData or
@@ -13,7 +22,10 @@ export const assetDataUtils = {
* @return The hex encoded assetData string
*/
encodeERC20AssetData(tokenAddress: string): string {
- return ethUtil.bufferToHex(ethAbi.simpleEncode('ERC20Token(address)', tokenAddress));
+ const abiEncoder = new AbiEncoder.Method(constants.ERC20_METHOD_ABI);
+ const args = [tokenAddress];
+ const assetData = abiEncoder.encode(args, encodingRules);
+ return assetData;
},
/**
* Decodes an ERC20 assetData hex string into it's corresponding ERC20 tokenAddress & assetProxyId
@@ -21,26 +33,14 @@ export const assetDataUtils = {
* @return An object containing the decoded tokenAddress & assetProxyId
*/
decodeERC20AssetData(assetData: string): ERC20AssetData {
- const data = ethUtil.toBuffer(assetData);
- if (data.byteLength < constants.ERC20_ASSET_DATA_BYTE_LENGTH) {
- throw new Error(
- `Could not decode ERC20 Proxy Data. Expected length of encoded data to be at least ${
- constants.ERC20_ASSET_DATA_BYTE_LENGTH
- }. Got ${data.byteLength}`,
- );
- }
- const assetProxyId = ethUtil.bufferToHex(data.slice(0, constants.SELECTOR_LENGTH));
- if (assetProxyId !== AssetProxyId.ERC20) {
- throw new Error(
- `Could not decode ERC20 Proxy Data. Expected Asset Proxy Id to be ERC20 (${
- AssetProxyId.ERC20
- }), but got ${assetProxyId}`,
- );
- }
- const [tokenAddress] = ethAbi.rawDecode(['address'], data.slice(constants.SELECTOR_LENGTH));
+ assetDataUtils.assertIsERC20AssetData(assetData);
+ const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
+ const abiEncoder = new AbiEncoder.Method(constants.ERC20_METHOD_ABI);
+ const decodedAssetData = abiEncoder.decode(assetData, decodingRules);
return {
assetProxyId,
- tokenAddress: ethUtil.addHexPrefix(tokenAddress),
+ // TODO(abandeali1): fix return types for `AbiEncoder.Method.decode` so that we can remove type assertion
+ tokenAddress: (decodedAssetData as any).tokenContract,
};
},
/**
@@ -51,14 +51,10 @@ export const assetDataUtils = {
* @return The hex encoded assetData string
*/
encodeERC721AssetData(tokenAddress: string, tokenId: BigNumber): string {
- // TODO: Pass `tokendId` as a BigNumber.
- return ethUtil.bufferToHex(
- ethAbi.simpleEncode(
- 'ERC721Token(address,uint256)',
- tokenAddress,
- `0x${tokenId.toString(constants.BASE_16)}`,
- ),
- );
+ const abiEncoder = new AbiEncoder.Method(constants.ERC721_METHOD_ABI);
+ const args = [tokenAddress, tokenId];
+ const assetData = abiEncoder.encode(args, encodingRules);
+ return assetData;
},
/**
* Decodes an ERC721 assetData hex string into it's corresponding ERC721 tokenAddress, tokenId & assetProxyId
@@ -66,27 +62,99 @@ export const assetDataUtils = {
* @return An object containing the decoded tokenAddress, tokenId & assetProxyId
*/
decodeERC721AssetData(assetData: string): ERC721AssetData {
- const data = ethUtil.toBuffer(assetData);
- if (data.byteLength < constants.ERC721_ASSET_DATA_MINIMUM_BYTE_LENGTH) {
+ assetDataUtils.assertIsERC721AssetData(assetData);
+ const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
+ const abiEncoder = new AbiEncoder.Method(constants.ERC721_METHOD_ABI);
+ const decodedAssetData = abiEncoder.decode(assetData, decodingRules);
+ return {
+ assetProxyId,
+ // TODO(abandeali1): fix return types for `AbiEncoder.Method.decode` so that we can remove type assertion
+ tokenAddress: (decodedAssetData as any).tokenContract,
+ tokenId: (decodedAssetData as any).tokenId,
+ };
+ },
+ /**
+ * Encodes assetData for multiple AssetProxies into a single hex encoded assetData string, usable in the makerAssetData or
+ * takerAssetData fields in a 0x order.
+ * @param amounts Amounts of each asset that correspond to a single unit within an order.
+ * @param nestedAssetData assetData strings that correspond to a valid assetProxyId.
+ * @return The hex encoded assetData string
+ */
+ encodeMultiAssetData(amounts: BigNumber[], nestedAssetData: string[]): string {
+ if (amounts.length !== nestedAssetData.length) {
throw new Error(
- `Could not decode ERC721 Asset Data. Expected length of encoded data to be at least ${
- constants.ERC721_ASSET_DATA_MINIMUM_BYTE_LENGTH
- }. Got ${data.byteLength}`,
+ `Invalid MultiAsset arguments. Expected length of 'amounts' (${
+ amounts.length
+ }) to equal length of 'nestedAssetData' (${nestedAssetData.length})`,
);
}
- const assetProxyId = ethUtil.bufferToHex(data.slice(0, constants.SELECTOR_LENGTH));
- if (assetProxyId !== AssetProxyId.ERC721) {
+ _.forEach(nestedAssetData, assetDataElement => assetDataUtils.validateAssetDataOrThrow(assetDataElement));
+ const abiEncoder = new AbiEncoder.Method(constants.MULTI_ASSET_METHOD_ABI);
+ const args = [amounts, nestedAssetData];
+ const assetData = abiEncoder.encode(args, encodingRules);
+ return assetData;
+ },
+ /**
+ * Decodes a MultiAsset assetData hex string into it's corresponding amounts and nestedAssetData
+ * @param assetData Hex encoded assetData string to decode
+ * @return An object containing the decoded amounts and nestedAssetData
+ */
+ decodeMultiAssetData(assetData: string): MultiAssetData {
+ assetDataUtils.assertIsMultiAssetData(assetData);
+ const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
+ const abiEncoder = new AbiEncoder.Method(constants.MULTI_ASSET_METHOD_ABI);
+ const decodedAssetData = abiEncoder.decode(assetData, decodingRules);
+ // TODO(abandeali1): fix return types for `AbiEncoder.Method.decode` so that we can remove type assertion
+ const amounts = (decodedAssetData as any).amounts;
+ const nestedAssetData = (decodedAssetData as any).nestedAssetData;
+ if (amounts.length !== nestedAssetData.length) {
throw new Error(
- `Could not decode ERC721 Asset Data. Expected Asset Proxy Id to be ERC721 (${
- AssetProxyId.ERC721
- }), but got ${assetProxyId}`,
+ `Invalid MultiAsset assetData. Expected length of 'amounts' (${
+ amounts.length
+ }) to equal length of 'nestedAssetData' (${nestedAssetData.length})`,
);
}
- const [tokenAddress, tokenId] = ethAbi.rawDecode(['address', 'uint256'], data.slice(constants.SELECTOR_LENGTH));
return {
assetProxyId,
- tokenAddress: ethUtil.addHexPrefix(tokenAddress),
- tokenId: new BigNumber(tokenId.toString()),
+ amounts,
+ nestedAssetData,
+ };
+ },
+ /**
+ * Decodes a MultiAsset assetData hex string into it's corresponding amounts and decoded nestedAssetData elements (all nested elements are flattened)
+ * @param assetData Hex encoded assetData string to decode
+ * @return An object containing the decoded amounts and nestedAssetData
+ */
+ decodeMultiAssetDataRecursively(assetData: string): MultiAssetDataWithRecursiveDecoding {
+ const decodedAssetData = assetDataUtils.decodeMultiAssetData(assetData);
+ const amounts: any[] = [];
+ const decodedNestedAssetData = _.map(
+ decodedAssetData.nestedAssetData as string[],
+ (nestedAssetDataElement, index) => {
+ const decodedNestedAssetDataElement = assetDataUtils.decodeAssetDataOrThrow(nestedAssetDataElement);
+ if (decodedNestedAssetDataElement.assetProxyId === AssetProxyId.MultiAsset) {
+ const recursivelyDecodedAssetData = assetDataUtils.decodeMultiAssetDataRecursively(
+ nestedAssetDataElement,
+ );
+ amounts.push(
+ _.map(recursivelyDecodedAssetData.amounts, amountElement =>
+ amountElement.times(decodedAssetData.amounts[index]),
+ ),
+ );
+ return recursivelyDecodedAssetData.nestedAssetData;
+ } else {
+ amounts.push(decodedAssetData.amounts[index]);
+ return decodedNestedAssetDataElement as SingleAssetData;
+ }
+ },
+ );
+ const flattenedAmounts = _.flattenDeep(amounts);
+ const flattenedDecodedNestedAssetData = _.flattenDeep(decodedNestedAssetData);
+ return {
+ assetProxyId: decodedAssetData.assetProxyId,
+ amounts: flattenedAmounts,
+ // tslint:disable-next-line:no-unnecessary-type-assertion
+ nestedAssetData: flattenedDecodedNestedAssetData as SingleAssetData[],
};
},
/**
@@ -95,24 +163,133 @@ export const assetDataUtils = {
* @return The assetProxyId
*/
decodeAssetProxyId(assetData: string): AssetProxyId {
- const encodedAssetData = ethUtil.toBuffer(assetData);
- if (encodedAssetData.byteLength < constants.SELECTOR_LENGTH) {
+ if (assetData.length < constants.SELECTOR_CHAR_LENGTH_WITH_PREFIX) {
throw new Error(
- `Could not decode assetData. Expected length of encoded data to be at least 4. Got ${
- encodedAssetData.byteLength
+ `Could not decode assetData. Expected length of encoded data to be at least 10. Got ${
+ assetData.length
}`,
);
}
- const encodedAssetProxyId = encodedAssetData.slice(0, constants.SELECTOR_LENGTH);
- const assetProxyId = decodeAssetProxyId(encodedAssetProxyId);
+ const assetProxyId = assetData.slice(0, constants.SELECTOR_CHAR_LENGTH_WITH_PREFIX);
+ if (
+ assetProxyId !== AssetProxyId.ERC20 &&
+ assetProxyId !== AssetProxyId.ERC721 &&
+ assetProxyId !== AssetProxyId.MultiAsset
+ ) {
+ throw new Error(`Invalid assetProxyId: ${assetProxyId}`);
+ }
return assetProxyId;
},
/**
+ * Checks if the decoded asset data is valid ERC20 data
+ * @param decodedAssetData The decoded asset data to check
+ */
+ isERC20AssetData(decodedAssetData: SingleAssetData | MultiAssetData): decodedAssetData is ERC20AssetData {
+ return decodedAssetData.assetProxyId === AssetProxyId.ERC20;
+ },
+ /**
+ * Checks if the decoded asset data is valid ERC721 data
+ * @param decodedAssetData The decoded asset data to check
+ */
+ isERC721AssetData(decodedAssetData: SingleAssetData | MultiAssetData): decodedAssetData is ERC721AssetData {
+ return decodedAssetData.assetProxyId === AssetProxyId.ERC721;
+ },
+ /**
+ * Checks if the decoded asset data is valid MultiAsset data
+ * @param decodedAssetData The decoded asset data to check
+ */
+ isMultiAssetData(decodedAssetData: SingleAssetData | MultiAssetData): decodedAssetData is MultiAssetData {
+ return decodedAssetData.assetProxyId === AssetProxyId.MultiAsset;
+ },
+ /**
+ * Throws if the length or assetProxyId are invalid for the ERC20Proxy.
+ * @param assetData Hex encoded assetData string
+ */
+ assertIsERC20AssetData(assetData: string): void {
+ if (assetData.length < constants.ERC20_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX) {
+ throw new Error(
+ `Could not decode ERC20 Proxy Data. Expected length of encoded data to be at least ${
+ constants.ERC20_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX
+ }. Got ${assetData.length}`,
+ );
+ }
+ const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
+ if (assetProxyId !== AssetProxyId.ERC20) {
+ throw new Error(
+ `Could not decode ERC20 assetData. Expected assetProxyId to be ERC20 (${
+ AssetProxyId.ERC20
+ }), but got ${assetProxyId}`,
+ );
+ }
+ },
+ /**
+ * Throws if the length or assetProxyId are invalid for the ERC721Proxy.
+ * @param assetData Hex encoded assetData string
+ */
+ assertIsERC721AssetData(assetData: string): void {
+ if (assetData.length < constants.ERC721_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX) {
+ throw new Error(
+ `Could not decode ERC721 assetData. Expected length of encoded data to be at least ${
+ constants.ERC721_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX
+ }. Got ${assetData.length}`,
+ );
+ }
+ const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
+ if (assetProxyId !== AssetProxyId.ERC721) {
+ throw new Error(
+ `Could not decode ERC721 assetData. Expected assetProxyId to be ERC721 (${
+ AssetProxyId.ERC721
+ }), but got ${assetProxyId}`,
+ );
+ }
+ },
+ /**
+ * Throws if the length or assetProxyId are invalid for the MultiAssetProxy.
+ * @param assetData Hex encoded assetData string
+ */
+ assertIsMultiAssetData(assetData: string): void {
+ if (assetData.length < constants.MULTI_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX) {
+ throw new Error(
+ `Could not decode MultiAsset assetData. Expected length of encoded data to be at least ${
+ constants.MULTI_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX
+ }. Got ${assetData.length}`,
+ );
+ }
+ const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
+ if (assetProxyId !== AssetProxyId.MultiAsset) {
+ throw new Error(
+ `Could not decode MultiAsset assetData. Expected assetProxyId to be MultiAsset (${
+ AssetProxyId.MultiAsset
+ }), but got ${assetProxyId}`,
+ );
+ }
+ },
+ /**
+ * Throws if the length or assetProxyId are invalid for the corresponding AssetProxy.
+ * @param assetData Hex encoded assetData string
+ */
+ validateAssetDataOrThrow(assetData: string): void {
+ const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
+ switch (assetProxyId) {
+ case AssetProxyId.ERC20:
+ assetDataUtils.assertIsERC20AssetData(assetData);
+ break;
+ case AssetProxyId.ERC721:
+ assetDataUtils.assertIsERC721AssetData(assetData);
+ break;
+ case AssetProxyId.MultiAsset:
+ assetDataUtils.assertIsMultiAssetData(assetData);
+ break;
+ default:
+ throw new Error(`Unrecognized asset proxy id: ${assetProxyId}`);
+ }
+ },
+ /**
* Decode any assetData into it's corresponding assetData object
* @param assetData Hex encoded assetData string to decode
* @return Either a ERC20 or ERC721 assetData object
*/
- decodeAssetDataOrThrow(assetData: string): AssetData {
+ decodeAssetDataOrThrow(assetData: string): SingleAssetData | MultiAssetData {
const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
switch (assetProxyId) {
case AssetProxyId.ERC20:
@@ -121,19 +298,11 @@ export const assetDataUtils = {
case AssetProxyId.ERC721:
const erc721AssetData = assetDataUtils.decodeERC721AssetData(assetData);
return erc721AssetData;
+ case AssetProxyId.MultiAsset:
+ const multiAssetData = assetDataUtils.decodeMultiAssetData(assetData);
+ return multiAssetData;
default:
throw new Error(`Unrecognized asset proxy id: ${assetProxyId}`);
}
},
};
-
-function decodeAssetProxyId(encodedAssetProxyId: Buffer): AssetProxyId {
- const hexString = ethUtil.bufferToHex(encodedAssetProxyId);
- if (hexString === AssetProxyId.ERC20) {
- return AssetProxyId.ERC20;
- }
- if (hexString === AssetProxyId.ERC721) {
- return AssetProxyId.ERC721;
- }
- throw new Error(`Invalid ProxyId: ${hexString}`);
-}
diff --git a/packages/order-utils/src/constants.ts b/packages/order-utils/src/constants.ts
index 10029dcc3..a9a687719 100644
--- a/packages/order-utils/src/constants.ts
+++ b/packages/order-utils/src/constants.ts
@@ -1,16 +1,71 @@
import { BigNumber } from '@0x/utils';
+import { MethodAbi } from 'ethereum-types';
+
+const ERC20_METHOD_ABI: MethodAbi = {
+ constant: false,
+ inputs: [
+ {
+ name: 'tokenContract',
+ type: 'address',
+ },
+ ],
+ name: 'ERC20Token',
+ outputs: [],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function',
+};
+
+const ERC721_METHOD_ABI: MethodAbi = {
+ constant: false,
+ inputs: [
+ {
+ name: 'tokenContract',
+ type: 'address',
+ },
+ {
+ name: 'tokenId',
+ type: 'uint256',
+ },
+ ],
+ name: 'ERC721Token',
+ outputs: [],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function',
+};
+
+const MULTI_ASSET_METHOD_ABI: MethodAbi = {
+ constant: false,
+ inputs: [
+ {
+ name: 'amounts',
+ type: 'uint256[]',
+ },
+ {
+ name: 'nestedAssetData',
+ type: 'bytes[]',
+ },
+ ],
+ name: 'MultiAsset',
+ outputs: [],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function',
+};
export const constants = {
NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
NULL_BYTES: '0x',
+ NULL_ERC20_ASSET_DATA: '0xf47261b00000000000000000000000000000000000000000000000000000000000000000',
// tslint:disable-next-line:custom-no-magic-numbers
UNLIMITED_ALLOWANCE_IN_BASE_UNITS: new BigNumber(2).pow(256).minus(1),
TESTRPC_NETWORK_ID: 50,
ADDRESS_LENGTH: 20,
- ERC20_ASSET_DATA_BYTE_LENGTH: 36,
- ERC721_ASSET_DATA_MINIMUM_BYTE_LENGTH: 53,
- SELECTOR_LENGTH: 4,
- BASE_16: 16,
+ ERC20_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX: 74,
+ ERC721_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX: 136,
+ MULTI_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX: 266,
+ SELECTOR_CHAR_LENGTH_WITH_PREFIX: 10,
INFINITE_TIMESTAMP_SEC: new BigNumber(2524604400), // Close to infinite
ZERO_AMOUNT: new BigNumber(0),
EIP712_DOMAIN_NAME: '0x Protocol',
@@ -48,4 +103,7 @@ export const constants = {
{ name: 'data', type: 'bytes' },
],
},
+ ERC20_METHOD_ABI,
+ ERC721_METHOD_ABI,
+ MULTI_ASSET_METHOD_ABI,
};
diff --git a/packages/order-utils/src/exchange_transfer_simulator.ts b/packages/order-utils/src/exchange_transfer_simulator.ts
index 7a38b35df..06621fd9e 100644
--- a/packages/order-utils/src/exchange_transfer_simulator.ts
+++ b/packages/order-utils/src/exchange_transfer_simulator.ts
@@ -1,7 +1,8 @@
-import { ExchangeContractErrs } from '@0x/types';
+import { AssetProxyId, ExchangeContractErrs } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { AbstractBalanceAndProxyAllowanceLazyStore } from './abstract/abstract_balance_and_proxy_allowance_lazy_store';
+import { assetDataUtils } from './asset_data_utils';
import { constants } from './constants';
import { TradeSide, TransferType } from './types';
@@ -74,24 +75,51 @@ export class ExchangeTransferSimulator {
tradeSide: TradeSide,
transferType: TransferType,
): Promise<void> {
- // HACK: When simulating an open order (e.g taker is NULL_ADDRESS), we don't want to adjust balances/
- // allowances for the taker. We do however, want to increase the balance of the maker since the maker
- // might be relying on those funds to fill subsequent orders or pay the order's fees.
- if (from === constants.NULL_ADDRESS && tradeSide === TradeSide.Taker) {
- await this._increaseBalanceAsync(assetData, to, amountInBaseUnits);
- return;
+ const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
+ switch (assetProxyId) {
+ case AssetProxyId.ERC20:
+ case AssetProxyId.ERC721:
+ // HACK: When simulating an open order (e.g taker is NULL_ADDRESS), we don't want to adjust balances/
+ // allowances for the taker. We do however, want to increase the balance of the maker since the maker
+ // might be relying on those funds to fill subsequent orders or pay the order's fees.
+ if (from === constants.NULL_ADDRESS && tradeSide === TradeSide.Taker) {
+ await this._increaseBalanceAsync(assetData, to, amountInBaseUnits);
+ return;
+ }
+ const balance = await this._store.getBalanceAsync(assetData, from);
+ const proxyAllowance = await this._store.getProxyAllowanceAsync(assetData, from);
+ if (proxyAllowance.lessThan(amountInBaseUnits)) {
+ ExchangeTransferSimulator._throwValidationError(
+ FailureReason.ProxyAllowance,
+ tradeSide,
+ transferType,
+ );
+ }
+ if (balance.lessThan(amountInBaseUnits)) {
+ ExchangeTransferSimulator._throwValidationError(FailureReason.Balance, tradeSide, transferType);
+ }
+ await this._decreaseProxyAllowanceAsync(assetData, from, amountInBaseUnits);
+ await this._decreaseBalanceAsync(assetData, from, amountInBaseUnits);
+ await this._increaseBalanceAsync(assetData, to, amountInBaseUnits);
+ break;
+ case AssetProxyId.MultiAsset:
+ const decodedAssetData = assetDataUtils.decodeMultiAssetData(assetData);
+ for (const [index, nestedAssetDataElement] of decodedAssetData.nestedAssetData.entries()) {
+ const amountsElement = decodedAssetData.amounts[index];
+ const totalAmount = amountInBaseUnits.times(amountsElement);
+ await this.transferFromAsync(
+ nestedAssetDataElement,
+ from,
+ to,
+ totalAmount,
+ tradeSide,
+ transferType,
+ );
+ }
+ break;
+ default:
+ break;
}
- const balance = await this._store.getBalanceAsync(assetData, from);
- const proxyAllowance = await this._store.getProxyAllowanceAsync(assetData, from);
- if (proxyAllowance.lessThan(amountInBaseUnits)) {
- ExchangeTransferSimulator._throwValidationError(FailureReason.ProxyAllowance, tradeSide, transferType);
- }
- if (balance.lessThan(amountInBaseUnits)) {
- ExchangeTransferSimulator._throwValidationError(FailureReason.Balance, tradeSide, transferType);
- }
- await this._decreaseProxyAllowanceAsync(assetData, from, amountInBaseUnits);
- await this._decreaseBalanceAsync(assetData, from, amountInBaseUnits);
- await this._increaseBalanceAsync(assetData, to, amountInBaseUnits);
}
private async _decreaseProxyAllowanceAsync(
assetData: string,
diff --git a/packages/order-utils/src/index.ts b/packages/order-utils/src/index.ts
index e70d43efb..2150a02e4 100644
--- a/packages/order-utils/src/index.ts
+++ b/packages/order-utils/src/index.ts
@@ -34,11 +34,14 @@ export {
OrderRelevantState,
OrderState,
ECSignature,
- AssetData,
+ SingleAssetData,
ERC20AssetData,
ERC721AssetData,
+ MultiAssetData,
+ MultiAssetDataWithRecursiveDecoding,
AssetProxyId,
SignatureType,
+ ObjectMap,
OrderStateValid,
OrderStateInvalid,
ExchangeContractErrs,
diff --git a/packages/order-utils/src/order_state_utils.ts b/packages/order-utils/src/order_state_utils.ts
index fe0d6c773..389419587 100644
--- a/packages/order-utils/src/order_state_utils.ts
+++ b/packages/order-utils/src/order_state_utils.ts
@@ -1,5 +1,6 @@
import {
ExchangeContractErrs,
+ ObjectMap,
OrderRelevantState,
OrderState,
OrderStateInvalid,
@@ -7,9 +8,11 @@ import {
SignedOrder,
} from '@0x/types';
import { BigNumber } from '@0x/utils';
+import * as _ from 'lodash';
import { AbstractBalanceAndProxyAllowanceFetcher } from './abstract/abstract_balance_and_proxy_allowance_fetcher';
import { AbstractOrderFilledCancelledFetcher } from './abstract/abstract_order_filled_cancelled_fetcher';
+import { assetDataUtils } from './asset_data_utils';
import { orderHashUtils } from './order_hash';
import { OrderValidationUtils } from './order_validation_utils';
import { RemainingFillableCalculator } from './remaining_fillable_calculator';
@@ -18,7 +21,9 @@ import { utils } from './utils';
interface SidedOrderRelevantState {
isMakerSide: boolean;
traderBalance: BigNumber;
+ traderIndividualBalances: ObjectMap<BigNumber>;
traderProxyAllowance: BigNumber;
+ traderIndividualProxyAllowances: ObjectMap<BigNumber>;
traderFeeBalance: BigNumber;
traderFeeProxyAllowance: BigNumber;
filledTakerAssetAmount: BigNumber;
@@ -121,7 +126,9 @@ export class OrderStateUtils {
const sidedOrderRelevantState = {
isMakerSide: true,
traderBalance: orderRelevantState.makerBalance,
+ traderIndividualBalances: orderRelevantState.makerIndividualBalances,
traderProxyAllowance: orderRelevantState.makerProxyAllowance,
+ traderIndividualProxyAllowances: orderRelevantState.makerIndividualProxyAllowances,
traderFeeBalance: orderRelevantState.makerFeeBalance,
traderFeeProxyAllowance: orderRelevantState.makerFeeProxyAllowance,
filledTakerAssetAmount: orderRelevantState.filledTakerAssetAmount,
@@ -165,7 +172,9 @@ export class OrderStateUtils {
const orderRelevantState = {
makerBalance: sidedOrderRelevantState.traderBalance,
+ makerIndividualBalances: sidedOrderRelevantState.traderIndividualBalances,
makerProxyAllowance: sidedOrderRelevantState.traderProxyAllowance,
+ makerIndividualProxyAllowances: sidedOrderRelevantState.traderIndividualProxyAllowances,
makerFeeBalance: sidedOrderRelevantState.traderFeeBalance,
makerFeeProxyAllowance: sidedOrderRelevantState.traderFeeProxyAllowance,
filledTakerAssetAmount: sidedOrderRelevantState.filledTakerAssetAmount,
@@ -236,10 +245,12 @@ export class OrderStateUtils {
const isAssetZRX = assetData === zrxAssetData;
const traderBalance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync(assetData, traderAddress);
+ const traderIndividualBalances = await this._getAssetBalancesAsync(assetData, traderAddress);
const traderProxyAllowance = await this._balanceAndProxyAllowanceFetcher.getProxyAllowanceAsync(
assetData,
traderAddress,
);
+ const traderIndividualProxyAllowances = await this._getAssetProxyAllowancesAsync(assetData, traderAddress);
const traderFeeBalance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync(
zrxAssetData,
traderAddress,
@@ -278,7 +289,9 @@ export class OrderStateUtils {
const sidedOrderRelevantState = {
isMakerSide,
traderBalance,
+ traderIndividualBalances,
traderProxyAllowance,
+ traderIndividualProxyAllowances,
traderFeeBalance,
traderFeeProxyAllowance,
filledTakerAssetAmount,
@@ -287,4 +300,47 @@ export class OrderStateUtils {
};
return sidedOrderRelevantState;
}
+ private async _getAssetBalancesAsync(
+ assetData: string,
+ traderAddress: string,
+ initialBalances: ObjectMap<BigNumber> = {},
+ ): Promise<ObjectMap<BigNumber>> {
+ const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
+ let balances: ObjectMap<BigNumber> = { ...initialBalances };
+ if (assetDataUtils.isERC20AssetData(decodedAssetData) || assetDataUtils.isERC721AssetData(decodedAssetData)) {
+ const balance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync(assetData, traderAddress);
+ const tokenAddress = decodedAssetData.tokenAddress;
+ balances[tokenAddress] = _.isUndefined(initialBalances[tokenAddress])
+ ? balance
+ : balances[tokenAddress].add(balance);
+ } else if (assetDataUtils.isMultiAssetData(decodedAssetData)) {
+ for (const assetDataElement of decodedAssetData.nestedAssetData) {
+ balances = await this._getAssetBalancesAsync(assetDataElement, traderAddress, balances);
+ }
+ }
+ return balances;
+ }
+ private async _getAssetProxyAllowancesAsync(
+ assetData: string,
+ traderAddress: string,
+ initialAllowances: ObjectMap<BigNumber> = {},
+ ): Promise<ObjectMap<BigNumber>> {
+ const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
+ let allowances: ObjectMap<BigNumber> = { ...initialAllowances };
+ if (assetDataUtils.isERC20AssetData(decodedAssetData) || assetDataUtils.isERC721AssetData(decodedAssetData)) {
+ const allowance = await this._balanceAndProxyAllowanceFetcher.getProxyAllowanceAsync(
+ assetData,
+ traderAddress,
+ );
+ const tokenAddress = decodedAssetData.tokenAddress;
+ allowances[tokenAddress] = _.isUndefined(initialAllowances[tokenAddress])
+ ? allowance
+ : allowances[tokenAddress].add(allowance);
+ } else if (assetDataUtils.isMultiAssetData(decodedAssetData)) {
+ for (const assetDataElement of decodedAssetData.nestedAssetData) {
+ allowances = await this._getAssetBalancesAsync(assetDataElement, traderAddress, allowances);
+ }
+ }
+ return allowances;
+ }
}
diff --git a/packages/order-utils/src/store/balance_and_proxy_allowance_lazy_store.ts b/packages/order-utils/src/store/balance_and_proxy_allowance_lazy_store.ts
index f42a76d0c..ae3e36238 100644
--- a/packages/order-utils/src/store/balance_and_proxy_allowance_lazy_store.ts
+++ b/packages/order-utils/src/store/balance_and_proxy_allowance_lazy_store.ts
@@ -119,7 +119,7 @@ export class BalanceAndProxyAllowanceLazyStore implements AbstractBalanceAndProx
public deleteAllERC721ProxyAllowance(tokenAddress: string, userAddress: string): void {
for (const assetData in this._proxyAllowance) {
if (this._proxyAllowance.hasOwnProperty(assetData)) {
- const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
+ const decodedAssetData = assetDataUtils.decodeERC721AssetData(assetData);
if (
decodedAssetData.assetProxyId === AssetProxyId.ERC721 &&
decodedAssetData.tokenAddress === tokenAddress &&
diff --git a/packages/order-utils/test/asset_data_utils_test.ts b/packages/order-utils/test/asset_data_utils_test.ts
index f175b7a38..c498c5a00 100644
--- a/packages/order-utils/test/asset_data_utils_test.ts
+++ b/packages/order-utils/test/asset_data_utils_test.ts
@@ -1,6 +1,6 @@
import * as chai from 'chai';
-import { ERC20AssetData, ERC721AssetData } from '@0x/types';
+import { AssetProxyId, ERC721AssetData } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { assetDataUtils } from '../src/asset_data_utils';
@@ -10,41 +10,101 @@ import { chaiSetup } from './utils/chai_setup';
chaiSetup.configure();
const expect = chai.expect;
-const KNOWN_ENCODINGS = [
- {
- address: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48',
- assetData: '0xf47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48',
- },
- {
- address: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48',
- tokenId: new BigNumber(1),
- assetData:
- '0x025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001',
- },
-];
-
-const ERC20_ASSET_PROXY_ID = '0xf47261b0';
-const ERC721_ASSET_PROXY_ID = '0x02571792';
+const KNOWN_ERC20_ENCODING = {
+ address: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48',
+ assetData: '0xf47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48',
+};
+const KNOWN_ERC721_ENCODING = {
+ address: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48',
+ tokenId: new BigNumber(1),
+ assetData:
+ '0x025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001',
+};
+const KNOWN_MULTI_ASSET_ENCODING = {
+ amounts: [new BigNumber(1), new BigNumber(1)],
+ nestedAssetData: [KNOWN_ERC20_ENCODING.assetData, KNOWN_ERC721_ENCODING.assetData],
+ assetData:
+ '0x94cfcdd7000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000024f47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000',
+};
describe('assetDataUtils', () => {
it('should encode ERC20', () => {
- const assetData = assetDataUtils.encodeERC20AssetData(KNOWN_ENCODINGS[0].address);
- expect(assetData).to.equal(KNOWN_ENCODINGS[0].assetData);
+ const assetData = assetDataUtils.encodeERC20AssetData(KNOWN_ERC20_ENCODING.address);
+ expect(assetData).to.equal(KNOWN_ERC20_ENCODING.assetData);
});
it('should decode ERC20', () => {
- const assetData: ERC20AssetData = assetDataUtils.decodeERC20AssetData(KNOWN_ENCODINGS[0].assetData);
- expect(assetData.tokenAddress).to.equal(KNOWN_ENCODINGS[0].address);
- expect(assetData.assetProxyId).to.equal(ERC20_ASSET_PROXY_ID);
+ const decodedAssetData = assetDataUtils.decodeERC20AssetData(KNOWN_ERC20_ENCODING.assetData);
+ expect(decodedAssetData.tokenAddress).to.equal(KNOWN_ERC20_ENCODING.address);
+ expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.ERC20);
});
it('should encode ERC721', () => {
- const assetData = assetDataUtils.encodeERC721AssetData(KNOWN_ENCODINGS[1].address, KNOWN_ENCODINGS[1]
- .tokenId as BigNumber);
- expect(assetData).to.equal(KNOWN_ENCODINGS[1].assetData);
+ const assetData = assetDataUtils.encodeERC721AssetData(
+ KNOWN_ERC721_ENCODING.address,
+ KNOWN_ERC721_ENCODING.tokenId,
+ );
+ expect(assetData).to.equal(KNOWN_ERC721_ENCODING.assetData);
});
it('should decode ERC721', () => {
- const assetData: ERC721AssetData = assetDataUtils.decodeERC721AssetData(KNOWN_ENCODINGS[1].assetData);
- expect(assetData.tokenAddress).to.equal(KNOWN_ENCODINGS[1].address);
- expect(assetData.assetProxyId).to.equal(ERC721_ASSET_PROXY_ID);
- expect(assetData.tokenId).to.be.bignumber.equal(KNOWN_ENCODINGS[1].tokenId);
+ const decodedAssetData = assetDataUtils.decodeERC721AssetData(KNOWN_ERC721_ENCODING.assetData);
+ expect(decodedAssetData.tokenAddress).to.equal(KNOWN_ERC721_ENCODING.address);
+ expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.ERC721);
+ expect(decodedAssetData.tokenId).to.be.bignumber.equal(KNOWN_ERC721_ENCODING.tokenId);
+ });
+ it('should encode ERC20 and ERC721 multiAssetData', () => {
+ const assetData = assetDataUtils.encodeMultiAssetData(
+ KNOWN_MULTI_ASSET_ENCODING.amounts,
+ KNOWN_MULTI_ASSET_ENCODING.nestedAssetData,
+ );
+ expect(assetData).to.equal(KNOWN_MULTI_ASSET_ENCODING.assetData);
+ });
+ it('should decode ERC20 and ERC721 multiAssetData', () => {
+ const decodedAssetData = assetDataUtils.decodeMultiAssetData(KNOWN_MULTI_ASSET_ENCODING.assetData);
+ expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.MultiAsset);
+ expect(decodedAssetData.amounts).to.deep.equal(KNOWN_MULTI_ASSET_ENCODING.amounts);
+ expect(decodedAssetData.nestedAssetData).to.deep.equal(KNOWN_MULTI_ASSET_ENCODING.nestedAssetData);
+ });
+ it('should recursively decode ERC20 and ERC721 multiAssetData', () => {
+ const decodedAssetData = assetDataUtils.decodeMultiAssetDataRecursively(KNOWN_MULTI_ASSET_ENCODING.assetData);
+ expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.MultiAsset);
+ expect(decodedAssetData.amounts).to.deep.equal(KNOWN_MULTI_ASSET_ENCODING.amounts);
+ const decodedErc20AssetData = decodedAssetData.nestedAssetData[0];
+ // tslint:disable-next-line:no-unnecessary-type-assertion
+ const decodedErc721AssetData = decodedAssetData.nestedAssetData[1] as ERC721AssetData;
+ expect(decodedErc20AssetData.tokenAddress).to.equal(KNOWN_ERC20_ENCODING.address);
+ expect(decodedErc20AssetData.assetProxyId).to.equal(AssetProxyId.ERC20);
+ expect(decodedErc721AssetData.tokenAddress).to.equal(KNOWN_ERC721_ENCODING.address);
+ expect(decodedErc721AssetData.assetProxyId).to.equal(AssetProxyId.ERC721);
+ expect(decodedErc721AssetData.tokenId).to.be.bignumber.equal(KNOWN_ERC721_ENCODING.tokenId);
+ });
+ it('should recursively decode nested assetData within multiAssetData', () => {
+ const amounts = [new BigNumber(1), new BigNumber(1), new BigNumber(2)];
+ const nestedAssetData = [
+ KNOWN_ERC20_ENCODING.assetData,
+ KNOWN_ERC721_ENCODING.assetData,
+ KNOWN_MULTI_ASSET_ENCODING.assetData,
+ ];
+ const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData);
+ const decodedAssetData = assetDataUtils.decodeMultiAssetDataRecursively(assetData);
+ expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.MultiAsset);
+ const expectedAmounts = [new BigNumber(1), new BigNumber(1), new BigNumber(2), new BigNumber(2)];
+ expect(decodedAssetData.amounts).to.deep.equal(expectedAmounts);
+ const expectedLength = 4;
+ expect(decodedAssetData.nestedAssetData.length).to.be.equal(expectedLength);
+ const decodedErc20AssetData1 = decodedAssetData.nestedAssetData[0];
+ // tslint:disable-next-line:no-unnecessary-type-assertion
+ const decodedErc721AssetData1 = decodedAssetData.nestedAssetData[1] as ERC721AssetData;
+ const decodedErc20AssetData2 = decodedAssetData.nestedAssetData[2];
+ // tslint:disable-next-line:no-unnecessary-type-assertion
+ const decodedErc721AssetData2 = decodedAssetData.nestedAssetData[3] as ERC721AssetData;
+ expect(decodedErc20AssetData1.tokenAddress).to.equal(KNOWN_ERC20_ENCODING.address);
+ expect(decodedErc20AssetData1.assetProxyId).to.equal(AssetProxyId.ERC20);
+ expect(decodedErc721AssetData1.tokenAddress).to.equal(KNOWN_ERC721_ENCODING.address);
+ expect(decodedErc721AssetData1.assetProxyId).to.equal(AssetProxyId.ERC721);
+ expect(decodedErc721AssetData1.tokenId).to.be.bignumber.equal(KNOWN_ERC721_ENCODING.tokenId);
+ expect(decodedErc20AssetData2.tokenAddress).to.equal(KNOWN_ERC20_ENCODING.address);
+ expect(decodedErc20AssetData2.assetProxyId).to.equal(AssetProxyId.ERC20);
+ expect(decodedErc721AssetData2.tokenAddress).to.equal(KNOWN_ERC721_ENCODING.address);
+ expect(decodedErc721AssetData2.assetProxyId).to.equal(AssetProxyId.ERC721);
+ expect(decodedErc721AssetData2.tokenId).to.be.bignumber.equal(KNOWN_ERC721_ENCODING.tokenId);
});
});
diff --git a/packages/order-utils/test/utils/test_order_factory.ts b/packages/order-utils/test/utils/test_order_factory.ts
index 145332674..4efe0b38e 100644
--- a/packages/order-utils/test/utils/test_order_factory.ts
+++ b/packages/order-utils/test/utils/test_order_factory.ts
@@ -7,9 +7,9 @@ import { orderFactory } from '../../src/order_factory';
const BASE_TEST_ORDER: Order = orderFactory.createOrder(
constants.NULL_ADDRESS,
constants.ZERO_AMOUNT,
- constants.NULL_ADDRESS,
+ constants.NULL_ERC20_ASSET_DATA,
constants.ZERO_AMOUNT,
- constants.NULL_ADDRESS,
+ constants.NULL_ERC20_ASSET_DATA,
constants.NULL_ADDRESS,
);
const BASE_TEST_SIGNED_ORDER: SignedOrder = {
diff --git a/packages/order-watcher/CHANGELOG.json b/packages/order-watcher/CHANGELOG.json
index c1fd8d4a9..4cfecd034 100644
--- a/packages/order-watcher/CHANGELOG.json
+++ b/packages/order-watcher/CHANGELOG.json
@@ -1,5 +1,24 @@
[
{
+ "version": "2.4.0",
+ "changes": [
+ {
+ "note": "Add support for `MultiAssetProxy`",
+ "pr": 1363
+ }
+ ]
+ },
+ {
+ "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..1f4e5eff1 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 {
@@ -6,6 +7,7 @@ export {
OrderStateInvalid,
OrderState,
ExchangeContractErrs,
+ ObjectMap,
OrderRelevantState,
Stats,
} from '@0x/types';
diff --git a/packages/order-watcher/src/order_watcher/dependent_order_hashes_tracker.ts b/packages/order-watcher/src/order_watcher/dependent_order_hashes_tracker.ts
index a956a94db..d1085014c 100644
--- a/packages/order-watcher/src/order_watcher/dependent_order_hashes_tracker.ts
+++ b/packages/order-watcher/src/order_watcher/dependent_order_hashes_tracker.ts
@@ -1,6 +1,5 @@
-// tslint:disable:no-unnecessary-type-assertion
import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
-import { AssetProxyId, ERC20AssetData, ERC721AssetData, SignedOrder } from '@0x/types';
+import { AssetProxyId, SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
import * as _ from 'lodash';
@@ -62,35 +61,18 @@ export class DependentOrderHashesTracker {
return dependentOrderHashes;
}
public addToDependentOrderHashes(signedOrder: SignedOrder): void {
- const decodedMakerAssetData = assetDataUtils.decodeAssetDataOrThrow(signedOrder.makerAssetData);
- if (decodedMakerAssetData.assetProxyId === AssetProxyId.ERC20) {
- this._addToERC20DependentOrderHashes(signedOrder, (decodedMakerAssetData as ERC20AssetData).tokenAddress);
- } else {
- this._addToERC721DependentOrderHashes(
- signedOrder,
- (decodedMakerAssetData as ERC721AssetData).tokenAddress,
- (decodedMakerAssetData as ERC721AssetData).tokenId,
- );
- }
+ this._addAssetDataToDependentOrderHashes(signedOrder, signedOrder.makerAssetData);
this._addToERC20DependentOrderHashes(signedOrder, this._zrxTokenAddress);
this._addToMakerDependentOrderHashes(signedOrder);
}
public removeFromDependentOrderHashes(signedOrder: SignedOrder): void {
- const decodedMakerAssetData = assetDataUtils.decodeAssetDataOrThrow(signedOrder.makerAssetData);
- if (decodedMakerAssetData.assetProxyId === AssetProxyId.ERC20) {
- this._removeFromERC20DependentOrderhashes(
- signedOrder,
- (decodedMakerAssetData as ERC20AssetData).tokenAddress,
- );
- } else {
- this._removeFromERC721DependentOrderhashes(
- signedOrder,
- (decodedMakerAssetData as ERC721AssetData).tokenAddress,
- (decodedMakerAssetData as ERC721AssetData).tokenId,
- );
- }
+ this._removeAssetDataFromDependentOrderHashes(signedOrder, signedOrder.makerAssetData);
// If makerToken === ZRX then we already removed it and we don't need to remove it again.
- if ((decodedMakerAssetData as ERC20AssetData).tokenAddress !== this._zrxTokenAddress) {
+ const decodedMakerAssetData = assetDataUtils.decodeAssetDataOrThrow(signedOrder.makerAssetData);
+ if (
+ assetDataUtils.isERC20AssetData(decodedMakerAssetData) &&
+ decodedMakerAssetData.tokenAddress !== this._zrxTokenAddress
+ ) {
this._removeFromERC20DependentOrderhashes(signedOrder, this._zrxTokenAddress);
}
this._removeFromMakerDependentOrderhashes(signedOrder);
@@ -167,6 +149,18 @@ export class DependentOrderHashesTracker {
tokenId.toString()
].add(orderHash);
}
+ private _addAssetDataToDependentOrderHashes(signedOrder: SignedOrder, assetData: string): void {
+ const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
+ if (assetDataUtils.isERC20AssetData(decodedAssetData)) {
+ this._addToERC20DependentOrderHashes(signedOrder, decodedAssetData.tokenAddress);
+ } else if (assetDataUtils.isERC721AssetData(decodedAssetData)) {
+ this._addToERC721DependentOrderHashes(signedOrder, decodedAssetData.tokenAddress, decodedAssetData.tokenId);
+ } else if (assetDataUtils.isMultiAssetData(decodedAssetData)) {
+ _.each(decodedAssetData.nestedAssetData, nestedAssetDataElement =>
+ this._addAssetDataToDependentOrderHashes(signedOrder, nestedAssetDataElement),
+ );
+ }
+ }
private _addToMakerDependentOrderHashes(signedOrder: SignedOrder): void {
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
if (_.isUndefined(this._orderHashesByMakerAddress[signedOrder.makerAddress])) {
@@ -230,4 +224,20 @@ export class DependentOrderHashesTracker {
delete this._orderHashesByMakerAddress[signedOrder.makerAddress];
}
}
+ private _removeAssetDataFromDependentOrderHashes(signedOrder: SignedOrder, assetData: string): void {
+ const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
+ if (assetDataUtils.isERC20AssetData(decodedAssetData)) {
+ this._removeFromERC20DependentOrderhashes(signedOrder, decodedAssetData.tokenAddress);
+ } else if (assetDataUtils.isERC721AssetData(decodedAssetData)) {
+ this._removeFromERC721DependentOrderhashes(
+ signedOrder,
+ decodedAssetData.tokenAddress,
+ decodedAssetData.tokenId,
+ );
+ } else if (assetDataUtils.isMultiAssetData(decodedAssetData)) {
+ _.each(decodedAssetData.nestedAssetData, nestedAssetDataElement =>
+ this._removeAssetDataFromDependentOrderHashes(signedOrder, nestedAssetDataElement),
+ );
+ }
+ }
}
diff --git a/packages/order-watcher/src/order_watcher/order_watcher.ts b/packages/order-watcher/src/order_watcher/order_watcher.ts
index 96c5ca7b4..a06fd0cfe 100644
--- a/packages/order-watcher/src/order_watcher/order_watcher.ts
+++ b/packages/order-watcher/src/order_watcher/order_watcher.ts
@@ -161,14 +161,7 @@ export class OrderWatcher {
this._dependentOrderHashesTracker.addToDependentOrderHashes(signedOrder);
const orderAssetDatas = [signedOrder.makerAssetData, signedOrder.takerAssetData];
- _.each(orderAssetDatas, assetData => {
- const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
- if (decodedAssetData.assetProxyId === AssetProxyId.ERC20) {
- this._collisionResistantAbiDecoder.addERC20Token(decodedAssetData.tokenAddress);
- } else if (decodedAssetData.assetProxyId === AssetProxyId.ERC721) {
- this._collisionResistantAbiDecoder.addERC721Token(decodedAssetData.tokenAddress);
- }
- });
+ _.each(orderAssetDatas, assetData => this._addAssetDataToAbiDecoder(assetData));
}
/**
* Removes an order from the orderWatcher
@@ -236,31 +229,71 @@ export class OrderWatcher {
await this._emitRevalidateOrdersAsync([orderHash]);
}
}
+ private _addAssetDataToAbiDecoder(assetData: string): void {
+ const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
+ if (assetDataUtils.isERC20AssetData(decodedAssetData)) {
+ this._collisionResistantAbiDecoder.addERC20Token(decodedAssetData.tokenAddress);
+ } else if (assetDataUtils.isERC721AssetData(decodedAssetData)) {
+ this._collisionResistantAbiDecoder.addERC721Token(decodedAssetData.tokenAddress);
+ } else if (assetDataUtils.isMultiAssetData(decodedAssetData)) {
+ _.each(decodedAssetData.nestedAssetData, nestedAssetDataElement =>
+ this._addAssetDataToAbiDecoder(nestedAssetDataElement),
+ );
+ }
+ }
+ private _deleteLazyStoreBalance(assetData: string, userAddress: string): void {
+ const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
+ switch (assetProxyId) {
+ case AssetProxyId.ERC20:
+ case AssetProxyId.ERC721:
+ this._balanceAndProxyAllowanceLazyStore.deleteBalance(assetData, userAddress);
+ break;
+ case AssetProxyId.MultiAsset:
+ const decodedAssetData = assetDataUtils.decodeMultiAssetData(assetData);
+ _.each(decodedAssetData.nestedAssetData, nestedAssetDataElement =>
+ this._deleteLazyStoreBalance(nestedAssetDataElement, userAddress),
+ );
+ break;
+ default:
+ break;
+ }
+ }
+ private _deleteLazyStoreProxyAllowance(assetData: string, userAddress: string): void {
+ const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
+ switch (assetProxyId) {
+ case AssetProxyId.ERC20:
+ case AssetProxyId.ERC721:
+ this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(assetData, userAddress);
+ break;
+ case AssetProxyId.MultiAsset:
+ const decodedAssetData = assetDataUtils.decodeMultiAssetData(assetData);
+ _.each(decodedAssetData.nestedAssetData, nestedAssetDataElement =>
+ this._deleteLazyStoreProxyAllowance(nestedAssetDataElement, userAddress),
+ );
+ break;
+ default:
+ break;
+ }
+ }
private _cleanupOrderRelatedState(orderHash: string): void {
const signedOrder = this._orderByOrderHash[orderHash];
this._orderFilledCancelledLazyStore.deleteFilledTakerAmount(orderHash);
this._orderFilledCancelledLazyStore.deleteIsCancelled(orderHash);
- this._balanceAndProxyAllowanceLazyStore.deleteBalance(signedOrder.makerAssetData, signedOrder.makerAddress);
- this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(
- signedOrder.makerAssetData,
- signedOrder.makerAddress,
- );
- this._balanceAndProxyAllowanceLazyStore.deleteBalance(signedOrder.takerAssetData, signedOrder.takerAddress);
- this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(
- signedOrder.takerAssetData,
- signedOrder.takerAddress,
- );
+ this._deleteLazyStoreBalance(signedOrder.makerAssetData, signedOrder.makerAddress);
+ this._deleteLazyStoreProxyAllowance(signedOrder.makerAssetData, signedOrder.makerAddress);
+ this._deleteLazyStoreBalance(signedOrder.takerAssetData, signedOrder.takerAddress);
+ this._deleteLazyStoreProxyAllowance(signedOrder.takerAssetData, signedOrder.takerAddress);
const zrxAssetData = this._orderFilledCancelledLazyStore.getZRXAssetData();
if (!signedOrder.makerFee.isZero()) {
- this._balanceAndProxyAllowanceLazyStore.deleteBalance(zrxAssetData, signedOrder.makerAddress);
- this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(zrxAssetData, signedOrder.makerAddress);
+ this._deleteLazyStoreBalance(zrxAssetData, signedOrder.makerAddress);
+ this._deleteLazyStoreProxyAllowance(zrxAssetData, signedOrder.makerAddress);
}
if (!signedOrder.takerFee.isZero()) {
- this._balanceAndProxyAllowanceLazyStore.deleteBalance(zrxAssetData, signedOrder.takerAddress);
- this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(zrxAssetData, signedOrder.takerAddress);
+ this._deleteLazyStoreBalance(zrxAssetData, signedOrder.takerAddress);
+ this._deleteLazyStoreProxyAllowance(zrxAssetData, signedOrder.takerAddress);
}
}
private _onOrderExpired(orderHash: string): void {
@@ -302,7 +335,7 @@ export class OrderWatcher {
// Invalidate cache
const args = decodedLog.args as ERC20TokenApprovalEventArgs;
const tokenAssetData = assetDataUtils.encodeERC20AssetData(decodedLog.address);
- this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(tokenAssetData, args._owner);
+ this._deleteLazyStoreProxyAllowance(tokenAssetData, args._owner);
// Revalidate orders
const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
args._owner,
@@ -315,7 +348,7 @@ export class OrderWatcher {
// Invalidate cache
const args = decodedLog.args as ERC721TokenApprovalEventArgs;
const tokenAssetData = assetDataUtils.encodeERC721AssetData(decodedLog.address, args._tokenId);
- this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(tokenAssetData, args._owner);
+ this._deleteLazyStoreProxyAllowance(tokenAssetData, args._owner);
// Revalidate orders
const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
args._owner,
@@ -333,8 +366,8 @@ export class OrderWatcher {
// Invalidate cache
const args = decodedLog.args as ERC20TokenTransferEventArgs;
const tokenAssetData = assetDataUtils.encodeERC20AssetData(decodedLog.address);
- this._balanceAndProxyAllowanceLazyStore.deleteBalance(tokenAssetData, args._from);
- this._balanceAndProxyAllowanceLazyStore.deleteBalance(tokenAssetData, args._to);
+ this._deleteLazyStoreBalance(tokenAssetData, args._from);
+ this._deleteLazyStoreBalance(tokenAssetData, args._to);
// Revalidate orders
const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
args._from,
@@ -347,8 +380,8 @@ export class OrderWatcher {
// Invalidate cache
const args = decodedLog.args as ERC721TokenTransferEventArgs;
const tokenAssetData = assetDataUtils.encodeERC721AssetData(decodedLog.address, args._tokenId);
- this._balanceAndProxyAllowanceLazyStore.deleteBalance(tokenAssetData, args._from);
- this._balanceAndProxyAllowanceLazyStore.deleteBalance(tokenAssetData, args._to);
+ this._deleteLazyStoreBalance(tokenAssetData, args._from);
+ this._deleteLazyStoreBalance(tokenAssetData, args._to);
// Revalidate orders
const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
args._from,
@@ -375,7 +408,7 @@ export class OrderWatcher {
// Invalidate cache
const args = decodedLog.args as WETH9DepositEventArgs;
const tokenAssetData = assetDataUtils.encodeERC20AssetData(decodedLog.address);
- this._balanceAndProxyAllowanceLazyStore.deleteBalance(tokenAssetData, args._owner);
+ this._deleteLazyStoreBalance(tokenAssetData, args._owner);
// Revalidate orders
const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
args._owner,
@@ -388,7 +421,7 @@ export class OrderWatcher {
// Invalidate cache
const args = decodedLog.args as WETH9WithdrawalEventArgs;
const tokenAssetData = assetDataUtils.encodeERC20AssetData(decodedLog.address);
- this._balanceAndProxyAllowanceLazyStore.deleteBalance(tokenAssetData, args._owner);
+ this._deleteLazyStoreBalance(tokenAssetData, args._owner);
// Revalidate orders
const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
args._owner,
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_test.ts b/packages/order-watcher/test/order_watcher_test.ts
index 271e5dec5..41dc884d5 100644
--- a/packages/order-watcher/test/order_watcher_test.ts
+++ b/packages/order-watcher/test/order_watcher_test.ts
@@ -675,5 +675,213 @@ describe('OrderWatcher', () => {
})().catch(done);
});
});
+ describe('multiAsset', async () => {
+ const tokenId = new BigNumber(42);
+ const [makerErc721TokenAddress] = tokenUtils.getDummyERC721TokenAddresses();
+ const makerErc721AssetData = assetDataUtils.encodeERC721AssetData(makerErc721TokenAddress, tokenId);
+ const fillableErc721Amount = new BigNumber(1);
+ const [makerErc20TokenAddress] = tokenUtils.getDummyERC20TokenAddresses();
+ const makerErc20AssetData = assetDataUtils.encodeERC20AssetData(makerErc20TokenAddress);
+ const fillableErc20Amount = new BigNumber(2);
+ const multiAssetAmounts = [fillableErc721Amount, fillableErc20Amount];
+ const nestedAssetData = [makerErc721AssetData, makerErc20AssetData];
+ const makerMultiAssetData = assetDataUtils.encodeMultiAssetData(multiAssetAmounts, nestedAssetData);
+ it('should emit orderStateInvalid when maker allowance of ERC721 token set to 0 for watched order', (done: DoneCallback) => {
+ (async () => {
+ signedOrder = await fillScenarios.createFillableSignedOrderAsync(
+ makerMultiAssetData,
+ takerAssetData,
+ makerAddress,
+ takerAddress,
+ fillableErc721Amount,
+ );
+ const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
+ await orderWatcher.addOrderAsync(signedOrder);
+ const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
+ expect(orderState.isValid).to.be.false();
+ const invalidOrderState = orderState as OrderStateInvalid;
+ expect(invalidOrderState.orderHash).to.be.equal(orderHash);
+ expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerAllowance);
+ });
+ orderWatcher.subscribe(callback);
+ await contractWrappers.erc721Token.setApprovalAsync(
+ makerErc721TokenAddress,
+ constants.NULL_ADDRESS,
+ tokenId,
+ );
+ })().catch(done);
+ });
+ it('should emit orderStateInvalid when maker allowance for all of ERC721 token set to 0 for watched order', (done: DoneCallback) => {
+ (async () => {
+ signedOrder = await fillScenarios.createFillableSignedOrderAsync(
+ makerMultiAssetData,
+ takerAssetData,
+ makerAddress,
+ takerAddress,
+ fillableErc721Amount,
+ );
+ await contractWrappers.erc721Token.setApprovalAsync(
+ makerErc721TokenAddress,
+ constants.NULL_ADDRESS,
+ tokenId,
+ );
+ let isApproved = true;
+ await contractWrappers.erc721Token.setProxyApprovalForAllAsync(
+ makerErc721TokenAddress,
+ makerAddress,
+ isApproved,
+ );
+ const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
+ await orderWatcher.addOrderAsync(signedOrder);
+ const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
+ expect(orderState.isValid).to.be.false();
+ const invalidOrderState = orderState as OrderStateInvalid;
+ expect(invalidOrderState.orderHash).to.be.equal(orderHash);
+ expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerAllowance);
+ });
+ orderWatcher.subscribe(callback);
+ isApproved = false;
+ await contractWrappers.erc721Token.setProxyApprovalForAllAsync(
+ makerErc721TokenAddress,
+ makerAddress,
+ isApproved,
+ );
+ })().catch(done);
+ });
+ it('should emit orderStateInvalid when maker moves ERC721 backing watched order', (done: DoneCallback) => {
+ (async () => {
+ signedOrder = await fillScenarios.createFillableSignedOrderAsync(
+ makerMultiAssetData,
+ takerAssetData,
+ makerAddress,
+ takerAddress,
+ fillableErc721Amount,
+ );
+ const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
+ await orderWatcher.addOrderAsync(signedOrder);
+ const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
+ expect(orderState.isValid).to.be.false();
+ const invalidOrderState = orderState as OrderStateInvalid;
+ expect(invalidOrderState.orderHash).to.be.equal(orderHash);
+ expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerBalance);
+ });
+ orderWatcher.subscribe(callback);
+ await contractWrappers.erc721Token.transferFromAsync(
+ makerErc721TokenAddress,
+ coinbase,
+ makerAddress,
+ tokenId,
+ );
+ })().catch(done);
+ });
+ it('should emit orderStateInvalid when maker allowance of ERC20 token set to 0 for watched order', (done: DoneCallback) => {
+ (async () => {
+ signedOrder = await fillScenarios.createFillableSignedOrderAsync(
+ makerMultiAssetData,
+ takerAssetData,
+ makerAddress,
+ takerAddress,
+ fillableErc721Amount,
+ );
+ const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
+ await orderWatcher.addOrderAsync(signedOrder);
+ const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
+ expect(orderState.isValid).to.be.false();
+ const invalidOrderState = orderState as OrderStateInvalid;
+ expect(invalidOrderState.orderHash).to.be.equal(orderHash);
+ expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerAllowance);
+ });
+ orderWatcher.subscribe(callback);
+ await contractWrappers.erc20Token.setProxyAllowanceAsync(
+ makerErc20TokenAddress,
+ makerAddress,
+ new BigNumber(0),
+ );
+ })().catch(done);
+ });
+ it('should not emit an orderState event when irrelevant ERC20 Transfer event received', (done: DoneCallback) => {
+ (async () => {
+ signedOrder = await fillScenarios.createFillableSignedOrderAsync(
+ makerMultiAssetData,
+ takerAssetData,
+ makerAddress,
+ takerAddress,
+ fillableAmount,
+ );
+ await orderWatcher.addOrderAsync(signedOrder);
+ const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((_orderState: OrderState) => {
+ throw new Error('OrderState callback fired for irrelevant order');
+ });
+ orderWatcher.subscribe(callback);
+ const notTheMaker = userAddresses[0];
+ const anyRecipient = takerAddress;
+ const transferAmount = new BigNumber(2);
+ await contractWrappers.erc20Token.transferAsync(
+ makerTokenAddress,
+ notTheMaker,
+ anyRecipient,
+ transferAmount,
+ );
+ setTimeout(() => {
+ done();
+ }, TIMEOUT_MS);
+ })().catch(done);
+ });
+ it('should emit orderStateInvalid when makerAddress moves ERC20 balance backing watched order', (done: DoneCallback) => {
+ (async () => {
+ signedOrder = await fillScenarios.createFillableSignedOrderAsync(
+ makerMultiAssetData,
+ takerAssetData,
+ makerAddress,
+ takerAddress,
+ fillableAmount,
+ );
+ const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
+ await orderWatcher.addOrderAsync(signedOrder);
+ const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
+ expect(orderState.isValid).to.be.false();
+ const invalidOrderState = orderState as OrderStateInvalid;
+ expect(invalidOrderState.orderHash).to.be.equal(orderHash);
+ expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerBalance);
+ });
+ orderWatcher.subscribe(callback);
+ const anyRecipient = takerAddress;
+ const makerBalance = await contractWrappers.erc20Token.getBalanceAsync(
+ makerTokenAddress,
+ makerAddress,
+ );
+ await contractWrappers.erc20Token.transferAsync(
+ makerTokenAddress,
+ makerAddress,
+ anyRecipient,
+ makerBalance,
+ );
+ })().catch(done);
+ });
+ // TODO(abandeali1): The following test will fail until the MAP has been deployed and activated.
+ it.skip('should emit orderStateInvalid when watched order fully filled', (done: DoneCallback) => {
+ (async () => {
+ signedOrder = await fillScenarios.createFillableSignedOrderAsync(
+ makerMultiAssetData,
+ takerAssetData,
+ makerAddress,
+ takerAddress,
+ fillableAmount,
+ );
+ const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
+ await orderWatcher.addOrderAsync(signedOrder);
+
+ const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
+ expect(orderState.isValid).to.be.false();
+ const invalidOrderState = orderState as OrderStateInvalid;
+ expect(invalidOrderState.orderHash).to.be.equal(orderHash);
+ expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderRemainingFillAmountZero);
+ });
+ orderWatcher.subscribe(callback);
+
+ await contractWrappers.exchange.fillOrderAsync(signedOrder, fillableAmount, takerAddress);
+ })().catch(done);
+ });
+ });
});
}); // tslint:disable:max-file-line-count
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..6894f42fb
--- /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('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/migrations/1545440485644-CreateCopperTables.ts b/packages/pipeline/migrations/1545440485644-CreateCopperTables.ts
new file mode 100644
index 000000000..64bf70af4
--- /dev/null
+++ b/packages/pipeline/migrations/1545440485644-CreateCopperTables.ts
@@ -0,0 +1,103 @@
+import { MigrationInterface, QueryRunner, Table } from 'typeorm';
+
+const leads = new Table({
+ name: 'raw.copper_leads',
+ columns: [
+ { name: 'id', type: 'bigint', isPrimary: true },
+ { name: 'name', type: 'varchar', isNullable: true },
+ { name: 'first_name', type: 'varchar', isNullable: true },
+ { name: 'last_name', type: 'varchar', isNullable: true },
+ { name: 'middle_name', type: 'varchar', isNullable: true },
+ { name: 'assignee_id', type: 'bigint', isNullable: true },
+ { name: 'company_name', type: 'varchar', isNullable: true },
+ { name: 'customer_source_id', type: 'bigint', isNullable: true },
+ { name: 'monetary_value', type: 'integer', isNullable: true },
+ { name: 'status', type: 'varchar' },
+ { name: 'status_id', type: 'bigint' },
+ { name: 'title', type: 'varchar', isNullable: true },
+ { name: 'date_created', type: 'bigint' },
+ { name: 'date_modified', type: 'bigint', isPrimary: true },
+ ],
+});
+const activities = new Table({
+ name: 'raw.copper_activities',
+ columns: [
+ { name: 'id', type: 'bigint', isPrimary: true },
+ { name: 'parent_id', type: 'bigint' },
+ { name: 'parent_type', type: 'varchar' },
+ { name: 'type_id', type: 'bigint' },
+ { name: 'type_category', type: 'varchar' },
+ { name: 'type_name', type: 'varchar', isNullable: true },
+ { name: 'user_id', type: 'bigint' },
+ { name: 'old_value_id', type: 'bigint', isNullable: true },
+ { name: 'old_value_name', type: 'varchar', isNullable: true },
+ { name: 'new_value_id', type: 'bigint', isNullable: true },
+ { name: 'new_value_name', type: 'varchar', isNullable: true },
+ { name: 'date_created', type: 'bigint' },
+ { name: 'date_modified', type: 'bigint', isPrimary: true },
+ ],
+});
+
+const opportunities = new Table({
+ name: 'raw.copper_opportunities',
+ columns: [
+ { name: 'id', type: 'bigint', isPrimary: true },
+ { name: 'name', type: 'varchar' },
+ { name: 'assignee_id', isNullable: true, type: 'bigint' },
+ { name: 'close_date', isNullable: true, type: 'varchar' },
+ { name: 'company_id', isNullable: true, type: 'bigint' },
+ { name: 'company_name', isNullable: true, type: 'varchar' },
+ { name: 'customer_source_id', isNullable: true, type: 'bigint' },
+ { name: 'loss_reason_id', isNullable: true, type: 'bigint' },
+ { name: 'pipeline_id', type: 'bigint' },
+ { name: 'pipeline_stage_id', type: 'bigint' },
+ { name: 'primary_contact_id', isNullable: true, type: 'bigint' },
+ { name: 'priority', isNullable: true, type: 'varchar' },
+ { name: 'status', type: 'varchar' },
+ { name: 'interaction_count', type: 'bigint' },
+ { name: 'monetary_value', isNullable: true, type: 'integer' },
+ { name: 'win_probability', isNullable: true, type: 'integer' },
+ { name: 'date_created', type: 'bigint' },
+ { name: 'date_modified', type: 'bigint', isPrimary: true },
+ { name: 'custom_fields', type: 'jsonb' },
+ ],
+});
+
+const activityTypes = new Table({
+ name: 'raw.copper_activity_types',
+ columns: [
+ { name: 'id', type: 'bigint', isPrimary: true },
+ { name: 'category', type: 'varchar' },
+ { name: 'name', type: 'varchar' },
+ { name: 'is_disabled', type: 'boolean', isNullable: true },
+ { name: 'count_as_interaction', type: 'boolean', isNullable: true },
+ ],
+});
+
+const customFields = new Table({
+ name: 'raw.copper_custom_fields',
+ columns: [
+ { name: 'id', type: 'bigint', isPrimary: true },
+ { name: 'name', type: 'varchar' },
+ { name: 'data_type', type: 'varchar' },
+ { name: 'field_type', type: 'varchar', isNullable: true },
+ ],
+});
+
+export class CreateCopperTables1544055699284 implements MigrationInterface {
+ public async up(queryRunner: QueryRunner): Promise<any> {
+ await queryRunner.createTable(leads);
+ await queryRunner.createTable(activities);
+ await queryRunner.createTable(opportunities);
+ await queryRunner.createTable(activityTypes);
+ await queryRunner.createTable(customFields);
+ }
+
+ public async down(queryRunner: QueryRunner): Promise<any> {
+ await queryRunner.dropTable(leads.name);
+ await queryRunner.dropTable(activities.name);
+ await queryRunner.dropTable(opportunities.name);
+ await queryRunner.dropTable(activityTypes.name);
+ await queryRunner.dropTable(customFields.name);
+ }
+}
diff --git a/packages/pipeline/package.json b/packages/pipeline/package.json
index a40f3d21c..cb3763362 100644
--- a/packages/pipeline/package.json
+++ b/packages/pipeline/package.json
@@ -16,7 +16,7 @@
"test:coverage": "nyc npm run test:all --all && yarn coverage:report:lcov",
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
"clean": "shx rm -rf lib",
- "lint": "tslint --project . --format stylish --exclude ./migrations/**/*",
+ "lint": "tslint --project . --format stylish --exclude ./migrations/**/* --exclude ./test/fixtures/**/**/*.json",
"migrate:run": "yarn typeorm migration:run --config ./lib/src/ormconfig",
"migrate:revert": "yarn typeorm migration:revert --config ./lib/src/ormconfig",
"migrate:create": "yarn typeorm migration:create --config ./lib/src/ormconfig --dir migrations"
@@ -44,7 +44,7 @@
"@0x/contract-artifacts": "^1.0.1",
"@0x/contract-wrappers": "^3.0.0",
"@0x/dev-utils": "^1.0.21",
- "@0x/order-utils": "^2.0.0",
+ "@0x/order-utils": "^3.0.7",
"@0x/subproviders": "^2.1.8",
"@0x/types": "^1.4.1",
"@0x/utils": "^2.0.8",
diff --git a/packages/pipeline/src/data_sources/copper/index.ts b/packages/pipeline/src/data_sources/copper/index.ts
new file mode 100644
index 000000000..15df2fd7d
--- /dev/null
+++ b/packages/pipeline/src/data_sources/copper/index.ts
@@ -0,0 +1,126 @@
+import { fetchAsync } from '@0x/utils';
+import Bottleneck from 'bottleneck';
+
+import {
+ CopperActivityTypeCategory,
+ CopperActivityTypeResponse,
+ CopperCustomFieldResponse,
+ CopperSearchResponse,
+} from '../../parsers/copper';
+
+const HTTP_OK_STATUS = 200;
+const COPPER_URI = 'https://api.prosperworks.com/developer_api/v1';
+
+const DEFAULT_PAGINATION_PARAMS = {
+ page_size: 200,
+ sort_by: 'date_modified',
+ sort_direction: 'desc',
+};
+
+export type CopperSearchParams = CopperLeadSearchParams | CopperActivitySearchParams | CopperOpportunitySearchParams;
+export interface CopperLeadSearchParams {
+ page_number?: number;
+}
+
+export interface CopperActivitySearchParams {
+ minimum_activity_date: number;
+ page_number?: number;
+}
+
+export interface CopperOpportunitySearchParams {
+ sort_by: string; // must override the default 'date_modified' for this endpoint
+ page_number?: number;
+}
+export enum CopperEndpoint {
+ Leads = '/leads/search',
+ Opportunities = '/opportunities/search',
+ Activities = '/activities/search',
+}
+const ONE_SECOND = 1000;
+
+function httpErrorCheck(response: Response): void {
+ if (response.status !== HTTP_OK_STATUS) {
+ throw new Error(`HTTP error while scraping Copper: [${JSON.stringify(response)}]`);
+ }
+}
+export class CopperSource {
+ private readonly _accessToken: string;
+ private readonly _userEmail: string;
+ private readonly _defaultHeaders: any;
+ private readonly _limiter: Bottleneck;
+
+ constructor(maxConcurrentRequests: number, accessToken: string, userEmail: string) {
+ this._accessToken = accessToken;
+ this._userEmail = userEmail;
+ this._defaultHeaders = {
+ 'Content-Type': 'application/json',
+ 'X-PW-AccessToken': this._accessToken,
+ 'X-PW-Application': 'developer_api',
+ 'X-PW-UserEmail': this._userEmail,
+ };
+ this._limiter = new Bottleneck({
+ minTime: ONE_SECOND / maxConcurrentRequests,
+ reservoir: 30,
+ reservoirRefreshAmount: 30,
+ reservoirRefreshInterval: maxConcurrentRequests,
+ });
+ }
+
+ public async fetchNumberOfPagesAsync(endpoint: CopperEndpoint, searchParams?: CopperSearchParams): Promise<number> {
+ const resp = await this._limiter.schedule(() =>
+ fetchAsync(COPPER_URI + endpoint, {
+ method: 'POST',
+ body: JSON.stringify({ ...DEFAULT_PAGINATION_PARAMS, ...searchParams }),
+ headers: this._defaultHeaders,
+ }),
+ );
+
+ httpErrorCheck(resp);
+
+ // total number of records that match the request parameters
+ if (resp.headers.has('X-Pw-Total')) {
+ const totalRecords: number = parseInt(resp.headers.get('X-Pw-Total') as string, 10); // tslint:disable-line:custom-no-magic-numbers
+ return Math.ceil(totalRecords / DEFAULT_PAGINATION_PARAMS.page_size);
+ } else {
+ return 1;
+ }
+ }
+ public async fetchSearchResultsAsync<T extends CopperSearchResponse>(
+ endpoint: CopperEndpoint,
+ searchParams?: CopperSearchParams,
+ ): Promise<T[]> {
+ const request = { ...DEFAULT_PAGINATION_PARAMS, ...searchParams };
+ const response = await this._limiter.schedule(() =>
+ fetchAsync(COPPER_URI + endpoint, {
+ method: 'POST',
+ body: JSON.stringify(request),
+ headers: this._defaultHeaders,
+ }),
+ );
+ httpErrorCheck(response);
+ const json: T[] = await response.json();
+ return json;
+ }
+
+ public async fetchActivityTypesAsync(): Promise<Map<CopperActivityTypeCategory, CopperActivityTypeResponse[]>> {
+ const response = await this._limiter.schedule(() =>
+ fetchAsync(`${COPPER_URI}/activity_types`, {
+ method: 'GET',
+ headers: this._defaultHeaders,
+ }),
+ );
+ httpErrorCheck(response);
+ return response.json();
+ }
+
+ public async fetchCustomFieldsAsync(): Promise<CopperCustomFieldResponse[]> {
+ const response = await this._limiter.schedule(() =>
+ fetchAsync(`${COPPER_URI}/custom_field_definitions`, {
+ method: 'GET',
+ headers: this._defaultHeaders,
+ }),
+ );
+ httpErrorCheck(response);
+ return response.json();
+ }
+}
diff --git a/packages/pipeline/src/entities/copper_activity.ts b/packages/pipeline/src/entities/copper_activity.ts
new file mode 100644
index 000000000..cbc034285
--- /dev/null
+++ b/packages/pipeline/src/entities/copper_activity.ts
@@ -0,0 +1,41 @@
+import { Column, Entity, Index, PrimaryColumn } from 'typeorm';
+
+import { numberToBigIntTransformer } from '../utils';
+
+@Entity({ name: 'copper_activities', schema: 'raw' })
+export class CopperActivity {
+ @PrimaryColumn({ type: 'bigint', transformer: numberToBigIntTransformer })
+ public id!: number;
+
+ @Index()
+ @Column({ name: 'parent_id', type: 'bigint', transformer: numberToBigIntTransformer })
+ public parentId!: number;
+ @Column({ name: 'parent_type', type: 'varchar' })
+ public parentType!: string;
+
+ // join with CopperActivityType
+ @Index()
+ @Column({ name: 'type_id', type: 'bigint', transformer: numberToBigIntTransformer })
+ public typeId!: number;
+ @Column({ name: 'type_category', type: 'varchar' })
+ public typeCategory!: string;
+ @Column({ name: 'type_name', type: 'varchar', nullable: true })
+ public typeName?: string;
+
+ @Column({ name: 'user_id', type: 'bigint', transformer: numberToBigIntTransformer })
+ public userId!: number;
+ @Column({ name: 'old_value_id', type: 'bigint', nullable: true, transformer: numberToBigIntTransformer })
+ public oldValueId?: number;
+ @Column({ name: 'old_value_name', type: 'varchar', nullable: true })
+ public oldValueName?: string;
+ @Column({ name: 'new_value_id', type: 'bigint', nullable: true, transformer: numberToBigIntTransformer })
+ public newValueId?: number;
+ @Column({ name: 'new_value_name', type: 'varchar', nullable: true })
+ public newValueName?: string;
+
+ @Index()
+ @Column({ name: 'date_created', type: 'bigint', transformer: numberToBigIntTransformer })
+ public dateCreated!: number;
+ @PrimaryColumn({ name: 'date_modified', type: 'bigint', transformer: numberToBigIntTransformer })
+ public dateModified!: number;
+}
diff --git a/packages/pipeline/src/entities/copper_activity_type.ts b/packages/pipeline/src/entities/copper_activity_type.ts
new file mode 100644
index 000000000..8fb2dcf70
--- /dev/null
+++ b/packages/pipeline/src/entities/copper_activity_type.ts
@@ -0,0 +1,17 @@
+import { Column, Entity, PrimaryColumn } from 'typeorm';
+
+import { numberToBigIntTransformer } from '../utils';
+
+@Entity({ name: 'copper_activity_types', schema: 'raw' })
+export class CopperActivityType {
+ @PrimaryColumn({ type: 'bigint', transformer: numberToBigIntTransformer })
+ public id!: number;
+ @Column({ name: 'category', type: 'varchar' })
+ public category!: string;
+ @Column({ name: 'name', type: 'varchar' })
+ public name!: string;
+ @Column({ name: 'is_disabled', type: 'boolean', nullable: true })
+ public isDisabled?: boolean;
+ @Column({ name: 'count_as_interaction', type: 'boolean', nullable: true })
+ public countAsInteraction?: boolean;
+}
diff --git a/packages/pipeline/src/entities/copper_custom_field.ts b/packages/pipeline/src/entities/copper_custom_field.ts
new file mode 100644
index 000000000..f23f6ab22
--- /dev/null
+++ b/packages/pipeline/src/entities/copper_custom_field.ts
@@ -0,0 +1,15 @@
+import { Column, Entity, PrimaryColumn } from 'typeorm';
+
+import { numberToBigIntTransformer } from '../utils';
+
+@Entity({ name: 'copper_custom_fields', schema: 'raw' })
+export class CopperCustomField {
+ @PrimaryColumn({ type: 'bigint', transformer: numberToBigIntTransformer })
+ public id!: number;
+ @Column({ name: 'data_type', type: 'varchar' })
+ public dataType!: string;
+ @Column({ name: 'field_type', type: 'varchar', nullable: true })
+ public fieldType?: string;
+ @Column({ name: 'name', type: 'varchar' })
+ public name!: string;
+}
diff --git a/packages/pipeline/src/entities/copper_lead.ts b/packages/pipeline/src/entities/copper_lead.ts
new file mode 100644
index 000000000..c51ccd761
--- /dev/null
+++ b/packages/pipeline/src/entities/copper_lead.ts
@@ -0,0 +1,38 @@
+import { Column, Entity, Index, PrimaryColumn } from 'typeorm';
+
+import { numberToBigIntTransformer } from '../utils';
+
+@Entity({ name: 'copper_leads', schema: 'raw' })
+export class CopperLead {
+ @PrimaryColumn({ type: 'bigint', transformer: numberToBigIntTransformer })
+ public id!: number;
+
+ @Column({ name: 'name', type: 'varchar', nullable: true })
+ public name?: string;
+ @Column({ name: 'first_name', type: 'varchar', nullable: true })
+ public firstName?: string;
+ @Column({ name: 'last_name', type: 'varchar', nullable: true })
+ public lastName?: string;
+ @Column({ name: 'middle_name', type: 'varchar', nullable: true })
+ public middleName?: string;
+ @Column({ name: 'assignee_id', type: 'bigint', transformer: numberToBigIntTransformer, nullable: true })
+ public assigneeId?: number;
+ @Column({ name: 'company_name', type: 'varchar', nullable: true })
+ public companyName?: string;
+ @Column({ name: 'customer_source_id', type: 'bigint', transformer: numberToBigIntTransformer, nullable: true })
+ public customerSourceId?: number;
+ @Column({ name: 'monetary_value', type: 'integer', nullable: true })
+ public monetaryValue?: number;
+ @Column({ name: 'status', type: 'varchar' })
+ public status!: string;
+ @Column({ name: 'status_id', type: 'bigint', transformer: numberToBigIntTransformer })
+ public statusId!: number;
+ @Column({ name: 'title', type: 'varchar', nullable: true })
+ public title?: string;
+
+ @Index()
+ @Column({ name: 'date_created', type: 'bigint', transformer: numberToBigIntTransformer })
+ public dateCreated!: number;
+ @PrimaryColumn({ name: 'date_modified', type: 'bigint', transformer: numberToBigIntTransformer })
+ public dateModified!: number;
+}
diff --git a/packages/pipeline/src/entities/copper_opportunity.ts b/packages/pipeline/src/entities/copper_opportunity.ts
new file mode 100644
index 000000000..e12bd69ce
--- /dev/null
+++ b/packages/pipeline/src/entities/copper_opportunity.ts
@@ -0,0 +1,45 @@
+import { Column, Entity, PrimaryColumn } from 'typeorm';
+
+import { numberToBigIntTransformer } from '../utils';
+
+@Entity({ name: 'copper_opportunities', schema: 'raw' })
+export class CopperOpportunity {
+ @PrimaryColumn({ name: 'id', type: 'bigint', transformer: numberToBigIntTransformer })
+ public id!: number;
+ @Column({ name: 'name', type: 'varchar' })
+ public name!: string;
+ @Column({ name: 'assignee_id', nullable: true, type: 'bigint', transformer: numberToBigIntTransformer })
+ public assigneeId?: number;
+ @Column({ name: 'close_date', nullable: true, type: 'varchar' })
+ public closeDate?: string;
+ @Column({ name: 'company_id', nullable: true, type: 'bigint', transformer: numberToBigIntTransformer })
+ public companyId?: number;
+ @Column({ name: 'company_name', nullable: true, type: 'varchar' })
+ public companyName?: string;
+ @Column({ name: 'customer_source_id', nullable: true, type: 'bigint', transformer: numberToBigIntTransformer })
+ public customerSourceId?: number;
+ @Column({ name: 'loss_reason_id', nullable: true, type: 'bigint', transformer: numberToBigIntTransformer })
+ public lossReasonId?: number;
+ @Column({ name: 'pipeline_id', type: 'bigint', transformer: numberToBigIntTransformer })
+ public pipelineId!: number;
+ @Column({ name: 'pipeline_stage_id', type: 'bigint', transformer: numberToBigIntTransformer })
+ public pipelineStageId!: number;
+ @Column({ name: 'primary_contact_id', nullable: true, type: 'bigint', transformer: numberToBigIntTransformer })
+ public primaryContactId?: number;
+ @Column({ name: 'priority', nullable: true, type: 'varchar' })
+ public priority?: string;
+ @Column({ name: 'status', type: 'varchar' })
+ public status!: string;
+ @Column({ name: 'interaction_count', type: 'bigint', transformer: numberToBigIntTransformer })
+ public interactionCount!: number;
+ @Column({ name: 'monetary_value', nullable: true, type: 'integer' })
+ public monetaryValue?: number;
+ @Column({ name: 'win_probability', nullable: true, type: 'integer' })
+ public winProbability?: number;
+ @Column({ name: 'date_created', type: 'bigint', transformer: numberToBigIntTransformer })
+ public dateCreated!: number;
+ @PrimaryColumn({ name: 'date_modified', type: 'bigint', transformer: numberToBigIntTransformer })
+ public dateModified!: number;
+ @Column({ name: 'custom_fields', type: 'jsonb' })
+ public customFields!: { [key: number]: number };
+}
diff --git a/packages/pipeline/src/entities/index.ts b/packages/pipeline/src/entities/index.ts
index cc3de78bb..27c153c07 100644
--- a/packages/pipeline/src/entities/index.ts
+++ b/packages/pipeline/src/entities/index.ts
@@ -16,4 +16,10 @@ export { TokenOrderbookSnapshot } from './token_order';
export { Transaction } from './transaction';
export { ERC20ApprovalEvent } from './erc20_approval_event';
+export { CopperLead } from './copper_lead';
+export { CopperActivity } from './copper_activity';
+export { CopperOpportunity } from './copper_opportunity';
+export { CopperActivityType } from './copper_activity_type';
+export { CopperCustomField } from './copper_custom_field';
+
export type ExchangeEvent = ExchangeFillEvent | ExchangeCancelEvent | ExchangeCancelUpToEvent;
diff --git a/packages/pipeline/src/entities/token_order.ts b/packages/pipeline/src/entities/token_order.ts
index 4b8f0abc3..2709747cb 100644
--- a/packages/pipeline/src/entities/token_order.ts
+++ b/packages/pipeline/src/entities/token_order.ts
@@ -1,7 +1,6 @@
import { BigNumber } from '@0x/utils';
import { Column, Entity, PrimaryColumn } from 'typeorm';
-import { OrderType } from '../types';
import { bigNumberTransformer, numberToBigIntTransformer } from '../utils';
@Entity({ name: 'token_orderbook_snapshots', schema: 'raw' })
@@ -11,7 +10,7 @@ export class TokenOrderbookSnapshot {
@PrimaryColumn({ name: 'source' })
public source!: string;
@PrimaryColumn({ name: 'order_type' })
- public orderType!: OrderType;
+ public orderType!: string;
@PrimaryColumn({ name: 'price', type: 'numeric', transformer: bigNumberTransformer })
public price!: BigNumber;
@PrimaryColumn({ name: 'base_asset_symbol' })
diff --git a/packages/pipeline/src/ormconfig.ts b/packages/pipeline/src/ormconfig.ts
index fe11d81d5..2700714cd 100644
--- a/packages/pipeline/src/ormconfig.ts
+++ b/packages/pipeline/src/ormconfig.ts
@@ -2,6 +2,11 @@ import { ConnectionOptions } from 'typeorm';
import {
Block,
+ CopperActivity,
+ CopperActivityType,
+ CopperCustomField,
+ CopperLead,
+ CopperOpportunity,
DexTrade,
ERC20ApprovalEvent,
ExchangeCancelEvent,
@@ -18,6 +23,11 @@ import {
const entities = [
Block,
+ CopperOpportunity,
+ CopperActivity,
+ CopperActivityType,
+ CopperCustomField,
+ CopperLead,
DexTrade,
ExchangeCancelEvent,
ExchangeCancelUpToEvent,
diff --git a/packages/pipeline/src/parsers/copper/index.ts b/packages/pipeline/src/parsers/copper/index.ts
new file mode 100644
index 000000000..6c0c5abd5
--- /dev/null
+++ b/packages/pipeline/src/parsers/copper/index.ts
@@ -0,0 +1,259 @@
+import * as R from 'ramda';
+
+import { CopperActivity, CopperActivityType, CopperCustomField, CopperLead, CopperOpportunity } from '../../entities';
+
+const ONE_SECOND = 1000;
+export type CopperSearchResponse = CopperLeadResponse | CopperActivityResponse | CopperOpportunityResponse;
+export interface CopperLeadResponse {
+ id: number;
+ name?: string;
+ first_name?: string;
+ last_name?: string;
+ middle_name?: string;
+ assignee_id?: number;
+ company_name?: string;
+ customer_source_id?: number;
+ monetary_value?: number;
+ status: string;
+ status_id: number;
+ title?: string;
+ date_created: number; // in seconds
+ date_modified: number; // in seconds
+}
+
+export interface CopperActivityResponse {
+ id: number;
+ parent: CopperActivityParentResponse;
+ type: CopperActivityTypeResponse;
+ user_id: number;
+ activity_date: number;
+ old_value: CopperActivityValueResponse;
+ new_value: CopperActivityValueResponse;
+ date_created: number; // in seconds
+ date_modified: number; // in seconds
+}
+
+export interface CopperActivityValueResponse {
+ id: number;
+ name: string;
+}
+export interface CopperActivityParentResponse {
+ id: number;
+ type: string;
+}
+
+// custom activity types
+export enum CopperActivityTypeCategory {
+ user = 'user',
+ system = 'system',
+}
+export interface CopperActivityTypeResponse {
+ id: number;
+ category: CopperActivityTypeCategory;
+ name: string;
+ is_disabled?: boolean;
+ count_as_interaction?: boolean;
+}
+
+export interface CopperOpportunityResponse {
+ id: number;
+ name: string;
+ assignee_id?: number;
+ close_date?: string;
+ company_id?: number;
+ company_name?: string;
+ customer_source_id?: number;
+ loss_reason_id?: number;
+ pipeline_id: number;
+ pipeline_stage_id: number;
+ primary_contact_id?: number;
+ priority?: string;
+ status: string;
+ tags: string[];
+ interaction_count: number;
+ monetary_value?: number;
+ win_probability?: number;
+ date_created: number; // in seconds
+ date_modified: number; // in seconds
+ custom_fields: CopperNestedCustomFieldResponse[];
+}
+interface CopperNestedCustomFieldResponse {
+ custom_field_definition_id: number;
+ value: number | number[] | null;
+}
+// custom fields
+export enum CopperCustomFieldType {
+ String = 'String',
+ Text = 'Text',
+ Dropdown = 'Dropdown',
+ MultiSelect = 'MultiSelect', // not in API documentation but shows up in results
+ Date = 'Date',
+ Checkbox = 'Checkbox',
+ Float = 'Float',
+ URL = 'URL',
+ Percentage = 'Percentage',
+ Currency = 'Currency',
+ Connect = 'Connect',
+}
+export interface CopperCustomFieldOptionResponse {
+ id: number;
+ name: string;
+}
+export interface CopperCustomFieldResponse {
+ id: number;
+ name: string;
+ data_type: CopperCustomFieldType;
+ options?: CopperCustomFieldOptionResponse[];
+}
+/**
+ * Parse response from Copper API /search/leads/
+ *
+ * @param leads - The array of leads returned from the API
+ * @returns Returns an array of Copper Lead entities
+ */
+export function parseLeads(leads: CopperLeadResponse[]): CopperLead[] {
+ return leads.map(lead => {
+ const entity = new CopperLead();
+ entity.id = lead.id;
+ entity.name = lead.name || undefined;
+ entity.firstName = lead.first_name || undefined;
+ entity.lastName = lead.last_name || undefined;
+ entity.middleName = lead.middle_name || undefined;
+ entity.assigneeId = lead.assignee_id || undefined;
+ entity.companyName = lead.company_name || undefined;
+ entity.customerSourceId = lead.customer_source_id || undefined;
+ entity.monetaryValue = lead.monetary_value || undefined;
+ entity.status = lead.status;
+ entity.statusId = lead.status_id;
+ entity.title = lead.title || undefined;
+ entity.dateCreated = lead.date_created * ONE_SECOND;
+ entity.dateModified = lead.date_modified * ONE_SECOND;
+ return entity;
+ });
+}
+
+/**
+ * Parse response from Copper API /search/activities/
+ *
+ * @param activities - The array of activities returned from the API
+ * @returns Returns an array of Copper Activity entities
+ */
+export function parseActivities(activities: CopperActivityResponse[]): CopperActivity[] {
+ return activities.map(activity => {
+ const entity = new CopperActivity();
+ entity.id = activity.id;
+
+ entity.parentId = activity.parent.id;
+ entity.parentType = activity.parent.type;
+
+ entity.typeId = activity.type.id;
+ entity.typeCategory = activity.type.category.toString();
+ entity.typeName = activity.type.name;
+
+ entity.userId = activity.user_id;
+ entity.dateCreated = activity.date_created * ONE_SECOND;
+ entity.dateModified = activity.date_modified * ONE_SECOND;
+
+ // nested nullable fields
+ entity.oldValueId = R.path(['old_value', 'id'], activity);
+ entity.oldValueName = R.path(['old_value', 'name'], activity);
+ entity.newValueId = R.path(['new_value', 'id'], activity);
+ entity.newValueName = R.path(['new_value', 'name'], activity);
+
+ return entity;
+ });
+}
+
+/**
+ * Parse response from Copper API /search/opportunities/
+ *
+ * @param opportunities - The array of opportunities returned from the API
+ * @returns Returns an array of Copper Opportunity entities
+ */
+export function parseOpportunities(opportunities: CopperOpportunityResponse[]): CopperOpportunity[] {
+ return opportunities.map(opp => {
+ const customFields: { [key: number]: number } = opp.custom_fields
+ .filter(f => f.value !== null)
+ .map(f => ({
+ ...f,
+ value: ([] as number[]).concat(f.value || []), // normalise all values to number[]
+ }))
+ .map(f => f.value.map(val => [f.custom_field_definition_id, val] as [number, number])) // pair each value with the custom_field_definition_id
+ .reduce((acc, pair) => acc.concat(pair)) // flatten
+ .reduce<{ [key: number]: number }>((obj, [key, value]) => {
+ // transform into object literal
+ obj[key] = value;
+ return obj;
+ }, {});
+
+ const entity = new CopperOpportunity();
+ entity.id = opp.id;
+ entity.name = opp.name;
+ entity.assigneeId = opp.assignee_id || undefined;
+ entity.closeDate = opp.close_date || undefined;
+ entity.companyId = opp.company_id || undefined;
+ entity.companyName = opp.company_name || undefined;
+ entity.customerSourceId = opp.customer_source_id || undefined;
+ entity.lossReasonId = opp.loss_reason_id || undefined;
+ entity.pipelineId = opp.pipeline_id;
+ entity.pipelineStageId = opp.pipeline_stage_id;
+ entity.primaryContactId = opp.primary_contact_id || undefined;
+ entity.priority = opp.priority || undefined;
+ entity.status = opp.status;
+ entity.interactionCount = opp.interaction_count;
+ entity.monetaryValue = opp.monetary_value || undefined;
+ entity.winProbability = opp.win_probability === null ? undefined : opp.win_probability;
+ entity.dateCreated = opp.date_created * ONE_SECOND;
+ entity.dateModified = opp.date_modified * ONE_SECOND;
+ entity.customFields = customFields;
+ return entity;
+ });
+}
+
+/**
+ * Parse response from Copper API /activity_types/
+ *
+ * @param activityTypeResponse - Activity Types response from the API, keyed by "user" or "system"
+ * @returns Returns an array of Copper Activity Type entities
+ */
+export function parseActivityTypes(
+ activityTypeResponse: Map<CopperActivityTypeCategory, CopperActivityTypeResponse[]>,
+): CopperActivityType[] {
+ const values: CopperActivityTypeResponse[] = R.flatten(Object.values(activityTypeResponse));
+ return values.map(activityType => ({
+ id: activityType.id,
+ name: activityType.name,
+ category: activityType.category.toString(),
+ isDisabled: activityType.is_disabled,
+ countAsInteraction: activityType.count_as_interaction,
+ }));
+}
+
+/**
+ * Parse response from Copper API /custom_field_definitions/
+ *
+ * @param customFieldResponse - array of custom field definitions returned from the API, consisting of top-level fields and nested fields
+ * @returns Returns an array of Copper Custom Field entities
+ */
+export function parseCustomFields(customFieldResponse: CopperCustomFieldResponse[]): CopperCustomField[] {
+ function parseTopLevelField(field: CopperCustomFieldResponse): CopperCustomField[] {
+ const topLevelField: CopperCustomField = {
+ id: field.id,
+ name: field.name,
+ dataType: field.data_type.toString(),
+ };
+
+ if (field.options !== undefined) {
+ const nestedFields: CopperCustomField[] = field.options.map(option => ({
+ id: option.id,
+ name: option.name,
+ dataType: field.name,
+ fieldType: 'option',
+ }));
+ return nestedFields.concat(topLevelField);
+ } else {
+ return [topLevelField];
+ }
+ }
+ return R.chain(parseTopLevelField, customFieldResponse);
+}
diff --git a/packages/pipeline/src/parsers/ddex_orders/index.ts b/packages/pipeline/src/parsers/ddex_orders/index.ts
index d7b97efbe..eeb9c9d5b 100644
--- a/packages/pipeline/src/parsers/ddex_orders/index.ts
+++ b/packages/pipeline/src/parsers/ddex_orders/index.ts
@@ -23,8 +23,12 @@ export function parseDdexOrders(
): TokenOrder[] {
const aggregatedBids = aggregateOrders(ddexOrderbook.bids);
const aggregatedAsks = aggregateOrders(ddexOrderbook.asks);
- const parsedBids = aggregatedBids.map(order => parseDdexOrder(ddexMarket, observedTimestamp, 'bid', source, order));
- const parsedAsks = aggregatedAsks.map(order => parseDdexOrder(ddexMarket, observedTimestamp, 'ask', source, order));
+ const parsedBids = aggregatedBids.map(order =>
+ parseDdexOrder(ddexMarket, observedTimestamp, OrderType.Bid, source, order),
+ );
+ const parsedAsks = aggregatedAsks.map(order =>
+ parseDdexOrder(ddexMarket, observedTimestamp, OrderType.Ask, source, order),
+ );
return parsedBids.concat(parsedAsks);
}
diff --git a/packages/pipeline/src/parsers/events/exchange_events.ts b/packages/pipeline/src/parsers/events/exchange_events.ts
index e18106c75..9c4a5f89a 100644
--- a/packages/pipeline/src/parsers/events/exchange_events.ts
+++ b/packages/pipeline/src/parsers/events/exchange_events.ts
@@ -5,7 +5,7 @@ import { LogWithDecodedArgs } from 'ethereum-types';
import * as R from 'ramda';
import { ExchangeCancelEvent, ExchangeCancelUpToEvent, ExchangeFillEvent } from '../../entities';
-import { bigNumbertoStringOrNull } from '../../utils';
+import { bigNumbertoStringOrNull, convertAssetProxyIdToType } from '../../utils';
/**
* Parses raw event logs for a fill event and returns an array of
@@ -40,9 +40,7 @@ export const parseExchangeCancelUpToEvents: (
*/
export function _convertToExchangeFillEvent(eventLog: LogWithDecodedArgs<ExchangeFillEventArgs>): ExchangeFillEvent {
const makerAssetData = assetDataUtils.decodeAssetDataOrThrow(eventLog.args.makerAssetData);
- const makerAssetType = makerAssetData.assetProxyId === AssetProxyId.ERC20 ? 'erc20' : 'erc721';
const takerAssetData = assetDataUtils.decodeAssetDataOrThrow(eventLog.args.takerAssetData);
- const takerAssetType = takerAssetData.assetProxyId === AssetProxyId.ERC20 ? 'erc20' : 'erc721';
const exchangeFillEvent = new ExchangeFillEvent();
exchangeFillEvent.contractAddress = eventLog.address as string;
exchangeFillEvent.blockNumber = eventLog.blockNumber as number;
@@ -59,16 +57,24 @@ export function _convertToExchangeFillEvent(eventLog: LogWithDecodedArgs<Exchang
exchangeFillEvent.takerFeePaid = eventLog.args.takerFeePaid;
exchangeFillEvent.orderHash = eventLog.args.orderHash;
exchangeFillEvent.rawMakerAssetData = eventLog.args.makerAssetData;
- exchangeFillEvent.makerAssetType = makerAssetType;
+ // tslint:disable-next-line:no-unnecessary-type-assertion
+ exchangeFillEvent.makerAssetType = convertAssetProxyIdToType(makerAssetData.assetProxyId as AssetProxyId);
exchangeFillEvent.makerAssetProxyId = makerAssetData.assetProxyId;
- exchangeFillEvent.makerTokenAddress = makerAssetData.tokenAddress;
+ // HACK(abandeali1): this event schema currently does not support multiple maker/taker assets, so we store the first token address from the MultiAssetProxy assetData
+ exchangeFillEvent.makerTokenAddress = assetDataUtils.isMultiAssetData(makerAssetData)
+ ? assetDataUtils.decodeMultiAssetDataRecursively(eventLog.args.makerAssetData).nestedAssetData[0].tokenAddress
+ : makerAssetData.tokenAddress;
// tslint has a false positive here. Type assertion is required.
// tslint:disable-next-line:no-unnecessary-type-assertion
exchangeFillEvent.makerTokenId = bigNumbertoStringOrNull((makerAssetData as ERC721AssetData).tokenId);
exchangeFillEvent.rawTakerAssetData = eventLog.args.takerAssetData;
- exchangeFillEvent.takerAssetType = takerAssetType;
+ // tslint:disable-next-line:no-unnecessary-type-assertion
+ exchangeFillEvent.takerAssetType = convertAssetProxyIdToType(takerAssetData.assetProxyId as AssetProxyId);
exchangeFillEvent.takerAssetProxyId = takerAssetData.assetProxyId;
- exchangeFillEvent.takerTokenAddress = takerAssetData.tokenAddress;
+ // HACK(abandeali1): this event schema currently does not support multiple maker/taker assets, so we store the first token address from the MultiAssetProxy assetData
+ exchangeFillEvent.takerTokenAddress = assetDataUtils.isMultiAssetData(takerAssetData)
+ ? assetDataUtils.decodeMultiAssetDataRecursively(eventLog.args.takerAssetData).nestedAssetData[0].tokenAddress
+ : takerAssetData.tokenAddress;
// tslint:disable-next-line:no-unnecessary-type-assertion
exchangeFillEvent.takerTokenId = bigNumbertoStringOrNull((takerAssetData as ERC721AssetData).tokenId);
return exchangeFillEvent;
@@ -83,9 +89,7 @@ export function _convertToExchangeCancelEvent(
eventLog: LogWithDecodedArgs<ExchangeCancelEventArgs>,
): ExchangeCancelEvent {
const makerAssetData = assetDataUtils.decodeAssetDataOrThrow(eventLog.args.makerAssetData);
- const makerAssetType = makerAssetData.assetProxyId === AssetProxyId.ERC20 ? 'erc20' : 'erc721';
const takerAssetData = assetDataUtils.decodeAssetDataOrThrow(eventLog.args.takerAssetData);
- const takerAssetType = takerAssetData.assetProxyId === AssetProxyId.ERC20 ? 'erc20' : 'erc721';
const exchangeCancelEvent = new ExchangeCancelEvent();
exchangeCancelEvent.contractAddress = eventLog.address as string;
exchangeCancelEvent.blockNumber = eventLog.blockNumber as number;
@@ -98,15 +102,23 @@ export function _convertToExchangeCancelEvent(
exchangeCancelEvent.senderAddress = eventLog.args.senderAddress;
exchangeCancelEvent.orderHash = eventLog.args.orderHash;
exchangeCancelEvent.rawMakerAssetData = eventLog.args.makerAssetData;
- exchangeCancelEvent.makerAssetType = makerAssetType;
+ // tslint:disable-next-line:no-unnecessary-type-assertion
+ exchangeCancelEvent.makerAssetType = convertAssetProxyIdToType(makerAssetData.assetProxyId as AssetProxyId);
exchangeCancelEvent.makerAssetProxyId = makerAssetData.assetProxyId;
- exchangeCancelEvent.makerTokenAddress = makerAssetData.tokenAddress;
+ // HACK(abandeali1): this event schema currently does not support multiple maker/taker assets, so we store the first token address from the MultiAssetProxy assetData
+ exchangeCancelEvent.makerTokenAddress = assetDataUtils.isMultiAssetData(makerAssetData)
+ ? assetDataUtils.decodeMultiAssetDataRecursively(eventLog.args.makerAssetData).nestedAssetData[0].tokenAddress
+ : makerAssetData.tokenAddress;
// tslint:disable-next-line:no-unnecessary-type-assertion
exchangeCancelEvent.makerTokenId = bigNumbertoStringOrNull((makerAssetData as ERC721AssetData).tokenId);
exchangeCancelEvent.rawTakerAssetData = eventLog.args.takerAssetData;
- exchangeCancelEvent.takerAssetType = takerAssetType;
+ // tslint:disable-next-line:no-unnecessary-type-assertion
+ exchangeCancelEvent.takerAssetType = convertAssetProxyIdToType(takerAssetData.assetProxyId as AssetProxyId);
exchangeCancelEvent.takerAssetProxyId = takerAssetData.assetProxyId;
- exchangeCancelEvent.takerTokenAddress = takerAssetData.tokenAddress;
+ // HACK(abandeali1): this event schema currently does not support multiple maker/taker assets, so we store the first token address from the MultiAssetProxy assetData
+ exchangeCancelEvent.takerTokenAddress = assetDataUtils.isMultiAssetData(takerAssetData)
+ ? assetDataUtils.decodeMultiAssetDataRecursively(eventLog.args.takerAssetData).nestedAssetData[0].tokenAddress
+ : takerAssetData.tokenAddress;
// tslint:disable-next-line:no-unnecessary-type-assertion
exchangeCancelEvent.takerTokenId = bigNumbertoStringOrNull((takerAssetData as ERC721AssetData).tokenId);
return exchangeCancelEvent;
diff --git a/packages/pipeline/src/parsers/idex_orders/index.ts b/packages/pipeline/src/parsers/idex_orders/index.ts
index dfe27455c..14b871195 100644
--- a/packages/pipeline/src/parsers/idex_orders/index.ts
+++ b/packages/pipeline/src/parsers/idex_orders/index.ts
@@ -2,7 +2,7 @@ import { BigNumber } from '@0x/utils';
import { aggregateOrders } from '../utils';
-import { IdexOrder, IdexOrderbook, IdexOrderParam } from '../../data_sources/idex';
+import { IdexOrderbook, IdexOrderParam } from '../../data_sources/idex';
import { TokenOrderbookSnapshot as TokenOrder } from '../../entities';
import { OrderType } from '../../types';
@@ -21,7 +21,9 @@ export function parseIdexOrders(idexOrderbook: IdexOrderbook, observedTimestamp:
const idexBidOrder = idexOrderbook.bids[0];
const parsedBids =
aggregatedBids.length > 0
- ? aggregatedBids.map(order => parseIdexOrder(idexBidOrder.params, observedTimestamp, 'bid', source, order))
+ ? aggregatedBids.map(order =>
+ parseIdexOrder(idexBidOrder.params, observedTimestamp, OrderType.Bid, source, order),
+ )
: [];
const aggregatedAsks = aggregateOrders(idexOrderbook.asks);
@@ -29,7 +31,9 @@ export function parseIdexOrders(idexOrderbook: IdexOrderbook, observedTimestamp:
const idexAskOrder = idexOrderbook.asks[0];
const parsedAsks =
aggregatedAsks.length > 0
- ? aggregatedAsks.map(order => parseIdexOrder(idexAskOrder.params, observedTimestamp, 'ask', source, order))
+ ? aggregatedAsks.map(order =>
+ parseIdexOrder(idexAskOrder.params, observedTimestamp, OrderType.Ask, source, order),
+ )
: [];
return parsedBids.concat(parsedAsks);
}
@@ -62,7 +66,7 @@ export function parseIdexOrder(
tokenOrder.baseVolume = amount;
tokenOrder.quoteVolume = price.times(amount);
- if (orderType === 'bid') {
+ if (orderType === OrderType.Bid) {
tokenOrder.baseAssetSymbol = idexOrderParam.buySymbol;
tokenOrder.baseAssetAddress = idexOrderParam.tokenBuy;
tokenOrder.quoteAssetSymbol = idexOrderParam.sellSymbol;
diff --git a/packages/pipeline/src/parsers/oasis_orders/index.ts b/packages/pipeline/src/parsers/oasis_orders/index.ts
index 13997f31b..b71fb65b9 100644
--- a/packages/pipeline/src/parsers/oasis_orders/index.ts
+++ b/packages/pipeline/src/parsers/oasis_orders/index.ts
@@ -23,13 +23,13 @@ export function parseOasisOrders(
observedTimestamp: number,
source: string,
): TokenOrder[] {
- const aggregatedBids = aggregateOrders(R.filter(R.propEq('act', 'bid'), oasisOrderbook));
- const aggregatedAsks = aggregateOrders(R.filter(R.propEq('act', 'ask'), oasisOrderbook));
+ const aggregatedBids = aggregateOrders(R.filter(R.propEq('act', OrderType.Bid), oasisOrderbook));
+ const aggregatedAsks = aggregateOrders(R.filter(R.propEq('act', OrderType.Ask), oasisOrderbook));
const parsedBids = aggregatedBids.map(order =>
- parseOasisOrder(oasisMarket, observedTimestamp, 'bid', source, order),
+ parseOasisOrder(oasisMarket, observedTimestamp, OrderType.Bid, source, order),
);
const parsedAsks = aggregatedAsks.map(order =>
- parseOasisOrder(oasisMarket, observedTimestamp, 'ask', source, order),
+ parseOasisOrder(oasisMarket, observedTimestamp, OrderType.Ask, source, order),
);
return parsedBids.concat(parsedAsks);
}
diff --git a/packages/pipeline/src/parsers/paradex_orders/index.ts b/packages/pipeline/src/parsers/paradex_orders/index.ts
index 5ceeb64a4..85990dae4 100644
--- a/packages/pipeline/src/parsers/paradex_orders/index.ts
+++ b/packages/pipeline/src/parsers/paradex_orders/index.ts
@@ -21,10 +21,10 @@ export function parseParadexOrders(
source: string,
): TokenOrder[] {
const parsedBids = paradexOrderbookResponse.bids.map(order =>
- parseParadexOrder(paradexMarket, observedTimestamp, 'bid', source, order),
+ parseParadexOrder(paradexMarket, observedTimestamp, OrderType.Bid, source, order),
);
const parsedAsks = paradexOrderbookResponse.asks.map(order =>
- parseParadexOrder(paradexMarket, observedTimestamp, 'ask', source, order),
+ parseParadexOrder(paradexMarket, observedTimestamp, OrderType.Ask, source, order),
);
return parsedBids.concat(parsedAsks);
}
diff --git a/packages/pipeline/src/parsers/sra_orders/index.ts b/packages/pipeline/src/parsers/sra_orders/index.ts
index ef8901e40..13fe632a4 100644
--- a/packages/pipeline/src/parsers/sra_orders/index.ts
+++ b/packages/pipeline/src/parsers/sra_orders/index.ts
@@ -4,7 +4,7 @@ import { AssetProxyId, ERC721AssetData } from '@0x/types';
import * as R from 'ramda';
import { SraOrder } from '../../entities';
-import { bigNumbertoStringOrNull } from '../../utils';
+import { bigNumbertoStringOrNull, convertAssetProxyIdToType } from '../../utils';
/**
* Parses a raw order response from an SRA endpoint and returns an array of
@@ -22,9 +22,7 @@ export function parseSraOrders(rawOrdersResponse: OrdersResponse): SraOrder[] {
export function _convertToEntity(apiOrder: APIOrder): SraOrder {
// TODO(albrow): refactor out common asset data decoding code.
const makerAssetData = assetDataUtils.decodeAssetDataOrThrow(apiOrder.order.makerAssetData);
- const makerAssetType = makerAssetData.assetProxyId === AssetProxyId.ERC20 ? 'erc20' : 'erc721';
const takerAssetData = assetDataUtils.decodeAssetDataOrThrow(apiOrder.order.takerAssetData);
- const takerAssetType = takerAssetData.assetProxyId === AssetProxyId.ERC20 ? 'erc20' : 'erc721';
const sraOrder = new SraOrder();
sraOrder.exchangeAddress = apiOrder.order.exchangeAddress;
@@ -43,16 +41,24 @@ export function _convertToEntity(apiOrder: APIOrder): SraOrder {
sraOrder.signature = apiOrder.order.signature;
sraOrder.rawMakerAssetData = apiOrder.order.makerAssetData;
- sraOrder.makerAssetType = makerAssetType;
+ // tslint:disable-next-line:no-unnecessary-type-assertion
+ sraOrder.makerAssetType = convertAssetProxyIdToType(makerAssetData.assetProxyId as AssetProxyId);
sraOrder.makerAssetProxyId = makerAssetData.assetProxyId;
- sraOrder.makerTokenAddress = makerAssetData.tokenAddress;
+ // HACK(abandeali1): this event schema currently does not support multiple maker/taker assets, so we store the first token address from the MultiAssetProxy assetData
+ sraOrder.makerTokenAddress = assetDataUtils.isMultiAssetData(makerAssetData)
+ ? assetDataUtils.decodeMultiAssetDataRecursively(apiOrder.order.makerAssetData).nestedAssetData[0].tokenAddress
+ : makerAssetData.tokenAddress;
// tslint has a false positive here. Type assertion is required.
// tslint:disable-next-line:no-unnecessary-type-assertion
sraOrder.makerTokenId = bigNumbertoStringOrNull((makerAssetData as ERC721AssetData).tokenId);
sraOrder.rawTakerAssetData = apiOrder.order.takerAssetData;
- sraOrder.takerAssetType = takerAssetType;
+ // tslint:disable-next-line:no-unnecessary-type-assertion
+ sraOrder.takerAssetType = convertAssetProxyIdToType(takerAssetData.assetProxyId as AssetProxyId);
sraOrder.takerAssetProxyId = takerAssetData.assetProxyId;
- sraOrder.takerTokenAddress = takerAssetData.tokenAddress;
+ // HACK(abandeali1): this event schema currently does not support multiple maker/taker assets, so we store the first token address from the MultiAssetProxy assetData
+ sraOrder.takerTokenAddress = assetDataUtils.isMultiAssetData(takerAssetData)
+ ? assetDataUtils.decodeMultiAssetDataRecursively(apiOrder.order.takerAssetData).nestedAssetData[0].tokenAddress
+ : takerAssetData.tokenAddress;
// tslint:disable-next-line:no-unnecessary-type-assertion
sraOrder.takerTokenId = bigNumbertoStringOrNull((takerAssetData as ERC721AssetData).tokenId);
diff --git a/packages/pipeline/src/scripts/pull_copper.ts b/packages/pipeline/src/scripts/pull_copper.ts
new file mode 100644
index 000000000..69814f209
--- /dev/null
+++ b/packages/pipeline/src/scripts/pull_copper.ts
@@ -0,0 +1,129 @@
+// tslint:disable:no-console
+import * as R from 'ramda';
+import { Connection, ConnectionOptions, createConnection, Repository } from 'typeorm';
+
+import { CopperEndpoint, CopperSearchParams, CopperSource } from '../data_sources/copper';
+import { CopperActivity, CopperActivityType, CopperCustomField, CopperLead, CopperOpportunity } from '../entities';
+import * as ormConfig from '../ormconfig';
+import {
+ CopperSearchResponse,
+ parseActivities,
+ parseActivityTypes,
+ parseCustomFields,
+ parseLeads,
+ parseOpportunities,
+} from '../parsers/copper';
+import { handleError } from '../utils';
+const ONE_SECOND = 1000;
+const COPPER_RATE_LIMIT = 10;
+let connection: Connection;
+
+(async () => {
+ connection = await createConnection(ormConfig as ConnectionOptions);
+
+ const accessToken = process.env.COPPER_ACCESS_TOKEN;
+ const userEmail = process.env.COPPER_USER_EMAIL;
+ if (accessToken === undefined || userEmail === undefined) {
+ throw new Error('Missing required env var: COPPER_ACCESS_TOKEN and/or COPPER_USER_EMAIL');
+ }
+ const source = new CopperSource(COPPER_RATE_LIMIT, accessToken, userEmail);
+
+ const fetchPromises = [
+ fetchAndSaveLeadsAsync(source),
+ fetchAndSaveOpportunitiesAsync(source),
+ fetchAndSaveActivitiesAsync(source),
+ fetchAndSaveCustomFieldsAsync(source),
+ fetchAndSaveActivityTypesAsync(source),
+ ];
+ fetchPromises.forEach(async fn => {
+ await fn;
+ });
+})().catch(handleError);
+
+async function fetchAndSaveLeadsAsync(source: CopperSource): Promise<void> {
+ const repository = connection.getRepository(CopperLead);
+ const startTime = await getMaxAsync(connection, 'date_modified', 'raw.copper_leads');
+ console.log(`Fetching Copper leads starting from ${startTime}...`);
+ await fetchAndSaveAsync(CopperEndpoint.Leads, source, startTime, {}, parseLeads, repository);
+}
+
+async function fetchAndSaveOpportunitiesAsync(source: CopperSource): Promise<void> {
+ const repository = connection.getRepository(CopperOpportunity);
+ const startTime = await getMaxAsync(connection, 'date_modified', 'raw.copper_opportunities');
+ console.log(`Fetching Copper opportunities starting from ${startTime}...`);
+ await fetchAndSaveAsync(
+ CopperEndpoint.Opportunities,
+ source,
+ startTime,
+ { sort_by: 'name' },
+ parseOpportunities,
+ repository,
+ );
+}
+
+async function fetchAndSaveActivitiesAsync(source: CopperSource): Promise<void> {
+ const repository = connection.getRepository(CopperActivity);
+ const startTime = await getMaxAsync(connection, 'date_modified', 'raw.copper_activities');
+ const searchParams = {
+ minimum_activity_date: Math.floor(startTime / ONE_SECOND),
+ };
+ console.log(`Fetching Copper activities starting from ${startTime}...`);
+ await fetchAndSaveAsync(CopperEndpoint.Activities, source, startTime, searchParams, parseActivities, repository);
+}
+
+async function getMaxAsync(conn: Connection, sortColumn: string, tableName: string): Promise<number> {
+ const queryResult = await conn.query(`SELECT MAX(${sortColumn}) as _max from ${tableName};`);
+ if (R.isEmpty(queryResult)) {
+ return 0;
+ } else {
+ return queryResult[0]._max;
+ }
+}
+
+// (Xianny): Copper API doesn't allow queries to filter by date. To ensure that we are filling in ascending chronological
+// order and not missing any records, we are scraping all available pages. If Copper data gets larger,
+// it would make sense to search for and start filling from the first page that contains a new record.
+// This search would increase our network calls and is not efficient to implement with our current small volume
+// of Copper records.
+async function fetchAndSaveAsync<T extends CopperSearchResponse, E>(
+ endpoint: CopperEndpoint,
+ source: CopperSource,
+ startTime: number,
+ searchParams: CopperSearchParams,
+ parseFn: (recs: T[]) => E[],
+ repository: Repository<E>,
+): Promise<void> {
+ let saved = 0;
+ const numPages = await source.fetchNumberOfPagesAsync(endpoint);
+ try {
+ for (let i = numPages; i > 0; i--) {
+ console.log(`Fetching page ${i}/${numPages} of ${endpoint}...`);
+ const raw = await source.fetchSearchResultsAsync<T>(endpoint, {
+ ...searchParams,
+ page_number: i,
+ });
+ const newRecords = raw.filter(rec => rec.date_modified * ONE_SECOND > startTime);
+ const parsed = parseFn(newRecords);
+ await repository.save<any>(parsed);
+ saved += newRecords.length;
+ }
+ } catch (err) {
+ console.log(`Error fetching ${endpoint}, stopping: ${err.stack}`);
+ } finally {
+ console.log(`Saved ${saved} items from ${endpoint}, done.`);
+ }
+}
+
+async function fetchAndSaveActivityTypesAsync(source: CopperSource): Promise<void> {
+ console.log(`Fetching Copper activity types...`);
+ const activityTypes = await source.fetchActivityTypesAsync();
+ const repository = connection.getRepository(CopperActivityType);
+ await repository.save(parseActivityTypes(activityTypes));
+}
+
+async function fetchAndSaveCustomFieldsAsync(source: CopperSource): Promise<void> {
+ console.log(`Fetching Copper custom fields...`);
+ const customFields = await source.fetchCustomFieldsAsync();
+ const repository = connection.getRepository(CopperCustomField);
+ await repository.save(parseCustomFields(customFields));
+}
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..ced9d99eb 100644
--- a/packages/pipeline/src/scripts/pull_missing_blocks.ts
+++ b/packages/pipeline/src/scripts/pull_missing_blocks.ts
@@ -9,25 +9,34 @@ 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;
// Maximum number of requests to send at once.
-const MAX_CONCURRENCY = 10;
+const MAX_CONCURRENCY = 20;
// Maximum number of blocks to query for at once. This is also the maximum
// number of blocks we will hold in memory prior to being saved to the database.
const MAX_BLOCKS_PER_QUERY = 1000;
let connection: Connection;
+const tablesWithMissingBlocks = [
+ 'raw.exchange_fill_events',
+ 'raw.exchange_cancel_events',
+ 'raw.exchange_cancel_up_to_events',
+ 'raw.erc20_approval_events',
+];
+
(async () => {
connection = await createConnection(ormConfig as ConnectionOptions);
const provider = web3Factory.getRpcProvider({
rpcUrl: INFURA_ROOT_URL,
});
const web3Source = new Web3Source(provider);
- await getAllMissingBlocksAsync(web3Source);
+ for (const tableName of tablesWithMissingBlocks) {
+ await getAllMissingBlocksAsync(web3Source, tableName);
+ }
process.exit(0);
})().catch(handleError);
@@ -35,44 +44,31 @@ interface MissingBlocksResponse {
block_number: string;
}
-async function getAllMissingBlocksAsync(web3Source: Web3Source): Promise<void> {
+async function getAllMissingBlocksAsync(web3Source: Web3Source, tableName: string): Promise<void> {
const blocksRepository = connection.getRepository(Block);
- let fromBlock = EXCHANGE_START_BLOCK;
while (true) {
- const blockNumbers = await getMissingBlockNumbersAsync(fromBlock);
+ console.log(`Checking for missing blocks in ${tableName}...`);
+ const blockNumbers = await getMissingBlockNumbersAsync(tableName);
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.`);
+ console.log(`Done saving blocks for ${tableName}. There are now ${totalBlocks} total blocks.`);
}
-async function getMissingBlockNumbersAsync(fromBlock: number): Promise<number[]> {
- console.log(`Checking for missing blocks starting at ${fromBlock}...`);
- // 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
- // getting the blocks for one type of event at a time.
+async function getMissingBlockNumbersAsync(tableName: string): Promise<number[]> {
+ // This query returns up to `MAX_BLOCKS_PER_QUERY` distinct block numbers
+ // which are present in `tableName` but not in `raw.blocks`.
const response = (await connection.query(
- `WITH all_events AS (
- SELECT block_number FROM raw.exchange_fill_events
- UNION SELECT block_number FROM raw.exchange_cancel_events
- UNION SELECT block_number FROM raw.exchange_cancel_up_to_events
- UNION SELECT block_number FROM raw.erc20_approval_events
- )
- 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],
+ `SELECT DISTINCT(block_number) FROM ${tableName} LEFT JOIN raw.blocks ON ${tableName}.block_number = raw.blocks.number WHERE number IS NULL 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;
}
@@ -90,4 +86,5 @@ async function getAndSaveBlocksAsync(
const blocks = R.map(parseBlock, rawBlocks);
console.log(`Saving ${blocks.length} blocks...`);
await blocksRepository.save(blocks, { chunk: Math.ceil(blocks.length / BATCH_SAVE_SIZE) });
+ console.log('Done saving this batch of blocks');
}
diff --git a/packages/pipeline/src/types.ts b/packages/pipeline/src/types.ts
index e02b42a40..5f2121807 100644
--- a/packages/pipeline/src/types.ts
+++ b/packages/pipeline/src/types.ts
@@ -1,2 +1,9 @@
-export type AssetType = 'erc20' | 'erc721';
-export type OrderType = 'bid' | 'ask';
+export enum AssetType {
+ ERC20 = 'erc20',
+ ERC721 = 'erc721',
+ MultiAsset = 'multiAsset',
+}
+export enum OrderType {
+ Bid = 'bid',
+ Ask = 'ask',
+}
diff --git a/packages/pipeline/src/utils/transformers/asset_proxy_id_types.ts b/packages/pipeline/src/utils/transformers/asset_proxy_id_types.ts
new file mode 100644
index 000000000..2cd05a616
--- /dev/null
+++ b/packages/pipeline/src/utils/transformers/asset_proxy_id_types.ts
@@ -0,0 +1,20 @@
+import { AssetProxyId } from '@0x/types';
+
+import { AssetType } from '../../types';
+
+/**
+ * Converts an assetProxyId to its string equivalent
+ * @param assetProxyId Id of AssetProxy
+ */
+export function convertAssetProxyIdToType(assetProxyId: AssetProxyId): AssetType {
+ switch (assetProxyId) {
+ case AssetProxyId.ERC20:
+ return AssetType.ERC20;
+ case AssetProxyId.ERC721:
+ return AssetType.ERC721;
+ case AssetProxyId.MultiAsset:
+ return AssetType.MultiAsset;
+ default:
+ throw new Error(`${assetProxyId} not a supported assetProxyId`);
+ }
+}
diff --git a/packages/pipeline/src/utils/transformers/index.ts b/packages/pipeline/src/utils/transformers/index.ts
index 232c1c5de..31a4c9223 100644
--- a/packages/pipeline/src/utils/transformers/index.ts
+++ b/packages/pipeline/src/utils/transformers/index.ts
@@ -1,2 +1,3 @@
export * from './big_number';
export * from './number_to_bigint';
+export * from './asset_proxy_id_types';
diff --git a/packages/pipeline/src/utils/transformers/number_to_bigint.ts b/packages/pipeline/src/utils/transformers/number_to_bigint.ts
index 85560c1f0..9736d7c18 100644
--- a/packages/pipeline/src/utils/transformers/number_to_bigint.ts
+++ b/packages/pipeline/src/utils/transformers/number_to_bigint.ts
@@ -9,8 +9,12 @@ const decimalRadix = 10;
// https://github.com/typeorm/typeorm/issues/2400 for more information.
export class NumberToBigIntTransformer implements ValueTransformer {
// tslint:disable-next-line:prefer-function-over-method
- public to(value: number): string {
- return value.toString();
+ public to(value: number): string | null {
+ if (value === null || value === undefined) {
+ return null;
+ } else {
+ return value.toString();
+ }
}
// tslint:disable-next-line:prefer-function-over-method
diff --git a/packages/pipeline/test/entities/copper_test.ts b/packages/pipeline/test/entities/copper_test.ts
new file mode 100644
index 000000000..2543364e6
--- /dev/null
+++ b/packages/pipeline/test/entities/copper_test.ts
@@ -0,0 +1,54 @@
+import 'mocha';
+import 'reflect-metadata';
+
+import {
+ CopperActivity,
+ CopperActivityType,
+ CopperCustomField,
+ CopperLead,
+ CopperOpportunity,
+} from '../../src/entities';
+import { createDbConnectionOnceAsync } from '../db_setup';
+import {
+ ParsedActivities,
+ ParsedActivityTypes,
+ ParsedCustomFields,
+ ParsedLeads,
+ ParsedOpportunities,
+} from '../fixtures/copper/parsed_entities';
+import { chaiSetup } from '../utils/chai_setup';
+
+import { testSaveAndFindEntityAsync } from './util';
+
+chaiSetup.configure();
+
+describe('Copper entities', () => {
+ describe('save and find', async () => {
+ it('Copper lead', async () => {
+ const connection = await createDbConnectionOnceAsync();
+ const repository = connection.getRepository(CopperLead);
+ ParsedLeads.forEach(async entity => testSaveAndFindEntityAsync(repository, entity));
+ });
+ it('Copper activity', async () => {
+ const connection = await createDbConnectionOnceAsync();
+ const repository = connection.getRepository(CopperActivity);
+ ParsedActivities.forEach(async entity => testSaveAndFindEntityAsync(repository, entity));
+ });
+ // searching on jsonb fields is broken in typeorm
+ it.skip('Copper opportunity', async () => {
+ const connection = await createDbConnectionOnceAsync();
+ const repository = connection.getRepository(CopperOpportunity);
+ ParsedOpportunities.forEach(async entity => testSaveAndFindEntityAsync(repository, entity));
+ });
+ it('Copper activity type', async () => {
+ const connection = await createDbConnectionOnceAsync();
+ const repository = connection.getRepository(CopperActivityType);
+ ParsedActivityTypes.forEach(async entity => testSaveAndFindEntityAsync(repository, entity));
+ });
+ it('Copper custom field', async () => {
+ const connection = await createDbConnectionOnceAsync();
+ const repository = connection.getRepository(CopperCustomField);
+ ParsedCustomFields.forEach(async entity => testSaveAndFindEntityAsync(repository, entity));
+ });
+ });
+});
diff --git a/packages/pipeline/test/entities/util.ts b/packages/pipeline/test/entities/util.ts
index 043a3b15d..42df23a4a 100644
--- a/packages/pipeline/test/entities/util.ts
+++ b/packages/pipeline/test/entities/util.ts
@@ -15,9 +15,9 @@ const expect = chai.expect;
* @param entity An instance of a TypeORM entity which will be saved/retrieved from the database.
*/
export async function testSaveAndFindEntityAsync<T>(repository: Repository<T>, entity: T): Promise<void> {
- // Note(albrow): We are forced to use an 'as any' hack here because
+ // Note(albrow): We are forced to use an 'any' hack here because
// TypeScript complains about stack depth when checking the types.
- await repository.save(entity as any);
+ await repository.save<any>(entity);
const gotEntity = await repository.findOneOrFail({
where: entity,
});
diff --git a/packages/pipeline/test/fixtures/copper/api_v1_activity_types.json b/packages/pipeline/test/fixtures/copper/api_v1_activity_types.json
new file mode 100644
index 000000000..dbd39c31b
--- /dev/null
+++ b/packages/pipeline/test/fixtures/copper/api_v1_activity_types.json
@@ -0,0 +1,24 @@
+{
+ "user": [
+ { "id": 0, "category": "user", "name": "Note", "is_disabled": false, "count_as_interaction": false },
+ { "id": 660496, "category": "user", "name": "To Do", "is_disabled": false, "count_as_interaction": false },
+ { "id": 660495, "category": "user", "name": "Meeting", "is_disabled": false, "count_as_interaction": true },
+ { "id": 660494, "category": "user", "name": "Phone Call", "is_disabled": false, "count_as_interaction": true }
+ ],
+ "system": [
+ {
+ "id": 1,
+ "category": "system",
+ "name": "Property Changed",
+ "is_disabled": false,
+ "count_as_interaction": false
+ },
+ {
+ "id": 3,
+ "category": "system",
+ "name": "Pipeline Stage Changed",
+ "is_disabled": false,
+ "count_as_interaction": false
+ }
+ ]
+}
diff --git a/packages/pipeline/test/fixtures/copper/api_v1_activity_types.ts b/packages/pipeline/test/fixtures/copper/api_v1_activity_types.ts
new file mode 100644
index 000000000..fd2d62a6c
--- /dev/null
+++ b/packages/pipeline/test/fixtures/copper/api_v1_activity_types.ts
@@ -0,0 +1,16 @@
+import { CopperActivityType } from '../../../src/entities';
+const ParsedActivityTypes: CopperActivityType[] = [
+ { id: 0, name: 'Note', category: 'user', isDisabled: false, countAsInteraction: false },
+ { id: 660496, name: 'To Do', category: 'user', isDisabled: false, countAsInteraction: false },
+ { id: 660495, name: 'Meeting', category: 'user', isDisabled: false, countAsInteraction: true },
+ { id: 660494, name: 'Phone Call', category: 'user', isDisabled: false, countAsInteraction: true },
+ { id: 1, name: 'Property Changed', category: 'system', isDisabled: false, countAsInteraction: false },
+ {
+ id: 3,
+ name: 'Pipeline Stage Changed',
+ category: 'system',
+ isDisabled: false,
+ countAsInteraction: false,
+ },
+];
+export { ParsedActivityTypes };
diff --git a/packages/pipeline/test/fixtures/copper/api_v1_custom_field_definitions.json b/packages/pipeline/test/fixtures/copper/api_v1_custom_field_definitions.json
new file mode 100644
index 000000000..c6665cb0f
--- /dev/null
+++ b/packages/pipeline/test/fixtures/copper/api_v1_custom_field_definitions.json
@@ -0,0 +1,38 @@
+[
+ {
+ "id": 261066,
+ "name": "Integration Type",
+ "canonical_name": null,
+ "data_type": "MultiSelect",
+ "available_on": ["opportunity", "company", "person"],
+ "options": [
+ { "id": 394020, "name": "Strategic Relationship", "rank": 7 },
+ { "id": 394013, "name": "ERC-20 Exchange", "rank": 0 },
+ { "id": 394014, "name": "ERC-721 Marketplace", "rank": 1 },
+ { "id": 394015, "name": "Trade Widget", "rank": 2 },
+ { "id": 394016, "name": "Prediction Market Exchange", "rank": 3 },
+ { "id": 394017, "name": "Security Token Exchange", "rank": 4 },
+ { "id": 394018, "name": "Complementary Company", "rank": 5 },
+ { "id": 394019, "name": "Service Provider", "rank": 6 }
+ ]
+ },
+ {
+ "id": 261067,
+ "name": "Company Type",
+ "canonical_name": null,
+ "data_type": "Dropdown",
+ "available_on": ["company", "opportunity", "person"],
+ "options": [
+ { "id": 394129, "name": "Market Maker", "rank": 6 },
+ { "id": 394130, "name": "Events", "rank": 2 },
+ { "id": 394023, "name": "Exchange", "rank": 3 },
+ { "id": 394024, "name": "Investor", "rank": 5 },
+ { "id": 394026, "name": "Service Provider", "rank": 8 },
+ { "id": 394027, "name": "Wallet", "rank": 9 },
+ { "id": 394134, "name": "Game", "rank": 4 },
+ { "id": 394025, "name": "OTC", "rank": 7 },
+ { "id": 394021, "name": "Blockchain/Protocol", "rank": 0 },
+ { "id": 394022, "name": "dApp", "rank": 1 }
+ ]
+ }
+]
diff --git a/packages/pipeline/test/fixtures/copper/api_v1_custom_field_definitions.ts b/packages/pipeline/test/fixtures/copper/api_v1_custom_field_definitions.ts
new file mode 100644
index 000000000..a44bbd2c3
--- /dev/null
+++ b/packages/pipeline/test/fixtures/copper/api_v1_custom_field_definitions.ts
@@ -0,0 +1,39 @@
+import { CopperCustomField } from '../../../src/entities';
+const ParsedCustomFields: CopperCustomField[] = [
+ {
+ id: 394020,
+ name: 'Strategic Relationship',
+ dataType: 'Integration Type',
+ fieldType: 'option',
+ },
+ { id: 394013, name: 'ERC-20 Exchange', dataType: 'Integration Type', fieldType: 'option' },
+ { id: 394014, name: 'ERC-721 Marketplace', dataType: 'Integration Type', fieldType: 'option' },
+ { id: 394015, name: 'Trade Widget', dataType: 'Integration Type', fieldType: 'option' },
+ {
+ id: 394016,
+ name: 'Prediction Market Exchange',
+ dataType: 'Integration Type',
+ fieldType: 'option',
+ },
+ {
+ id: 394017,
+ name: 'Security Token Exchange',
+ dataType: 'Integration Type',
+ fieldType: 'option',
+ },
+ { id: 394018, name: 'Complementary Company', dataType: 'Integration Type', fieldType: 'option' },
+ { id: 394019, name: 'Service Provider', dataType: 'Integration Type', fieldType: 'option' },
+ { id: 261066, name: 'Integration Type', dataType: 'MultiSelect' },
+ { id: 394129, name: 'Market Maker', dataType: 'Company Type', fieldType: 'option' },
+ { id: 394130, name: 'Events', dataType: 'Company Type', fieldType: 'option' },
+ { id: 394023, name: 'Exchange', dataType: 'Company Type', fieldType: 'option' },
+ { id: 394024, name: 'Investor', dataType: 'Company Type', fieldType: 'option' },
+ { id: 394026, name: 'Service Provider', dataType: 'Company Type', fieldType: 'option' },
+ { id: 394027, name: 'Wallet', dataType: 'Company Type', fieldType: 'option' },
+ { id: 394134, name: 'Game', dataType: 'Company Type', fieldType: 'option' },
+ { id: 394025, name: 'OTC', dataType: 'Company Type', fieldType: 'option' },
+ { id: 394021, name: 'Blockchain/Protocol', dataType: 'Company Type', fieldType: 'option' },
+ { id: 394022, name: 'dApp', dataType: 'Company Type', fieldType: 'option' },
+ { id: 261067, name: 'Company Type', dataType: 'Dropdown' },
+];
+export { ParsedCustomFields };
diff --git a/packages/pipeline/test/fixtures/copper/api_v1_list_activities.json b/packages/pipeline/test/fixtures/copper/api_v1_list_activities.json
new file mode 100644
index 000000000..a726111ac
--- /dev/null
+++ b/packages/pipeline/test/fixtures/copper/api_v1_list_activities.json
@@ -0,0 +1,242 @@
+[
+ {
+ "id": 5015299552,
+ "parent": { "id": 14667512, "type": "opportunity" },
+ "type": { "id": 3, "category": "system", "name": "Stage Change" },
+ "user_id": 680302,
+ "details": "blah blah",
+ "activity_date": 1545329595,
+ "old_value": { "id": 2392929, "name": "Evaluation" },
+ "new_value": { "id": 2392931, "name": "Integration Started" },
+ "date_created": 1545329595,
+ "date_modified": 1545329595
+ },
+ {
+ "id": 5010214065,
+ "parent": { "id": 14978865, "type": "opportunity" },
+ "type": { "id": 3, "category": "system", "name": "Stage Change" },
+ "user_id": 680302,
+ "details": "blah blah",
+ "activity_date": 1545245706,
+ "old_value": { "id": 2392928, "name": "Intro" },
+ "new_value": { "id": 2392929, "name": "Evaluation" },
+ "date_created": 1545245706,
+ "date_modified": 1545245706
+ },
+ {
+ "id": 5006149111,
+ "parent": { "id": 70430977, "type": "person" },
+ "type": { "id": 660495, "category": "user" },
+ "user_id": 680302,
+ "details": "blah blah",
+ "activity_date": 1545166908,
+ "old_value": null,
+ "new_value": null,
+ "date_created": 1545168280,
+ "date_modified": 1545166908
+ },
+ {
+ "id": 5005314622,
+ "parent": { "id": 27778968, "type": "company" },
+ "type": { "id": 660495, "category": "user" },
+ "user_id": 680302,
+ "details": "blah blah",
+ "activity_date": 1545080504,
+ "old_value": null,
+ "new_value": null,
+ "date_created": 1545160479,
+ "date_modified": 1545080504
+ },
+ {
+ "id": 5000006802,
+ "parent": { "id": 14956518, "type": "opportunity" },
+ "type": { "id": 660495, "category": "user" },
+ "user_id": 680302,
+ "details": "blah blah",
+ "activity_date": 1545071374,
+ "old_value": null,
+ "new_value": null,
+ "date_created": 1545071500,
+ "date_modified": 1545071374
+ },
+ {
+ "id": 4985504199,
+ "parent": { "id": 14912790, "type": "opportunity" },
+ "type": { "id": 660495, "category": "user" },
+ "user_id": 680302,
+ "details": "blah blah",
+ "activity_date": 1544644058,
+ "old_value": null,
+ "new_value": null,
+ "date_created": 1544644661,
+ "date_modified": 1544644058
+ },
+ {
+ "id": 4985456147,
+ "parent": { "id": 14912790, "type": "opportunity" },
+ "type": { "id": 660495, "category": "user" },
+ "user_id": 680302,
+ "details": "blah blah",
+ "activity_date": 1544644048,
+ "old_value": null,
+ "new_value": null,
+ "date_created": 1544644053,
+ "date_modified": 1544644048
+ },
+ {
+ "id": 4980975996,
+ "parent": { "id": 14902828, "type": "opportunity" },
+ "type": { "id": 660495, "category": "user" },
+ "user_id": 680302,
+ "details": "blah blah",
+ "activity_date": 1544563171,
+ "old_value": null,
+ "new_value": null,
+ "date_created": 1544563224,
+ "date_modified": 1544563171
+ },
+ {
+ "id": 4980910331,
+ "parent": { "id": 14902828, "type": "opportunity" },
+ "type": { "id": 3, "category": "system", "name": "Stage Change" },
+ "user_id": 680302,
+ "details": "blah blah",
+ "activity_date": 1544562495,
+ "old_value": { "id": 2392928, "name": "Intro" },
+ "new_value": { "id": 2392931, "name": "Integration Started" },
+ "date_created": 1544562495,
+ "date_modified": 1544562495
+ },
+ {
+ "id": 4980872220,
+ "parent": { "id": 14888910, "type": "opportunity" },
+ "type": { "id": 660495, "category": "user" },
+ "user_id": 680302,
+ "details": "blah blah",
+ "activity_date": 1544559279,
+ "old_value": null,
+ "new_value": null,
+ "date_created": 1544562118,
+ "date_modified": 1544559279
+ },
+ {
+ "id": 4980508097,
+ "parent": { "id": 14050167, "type": "opportunity" },
+ "type": { "id": 1, "category": "system", "name": "Status Change" },
+ "user_id": 680302,
+ "details": "blah blah",
+ "activity_date": 1544558077,
+ "old_value": "Open",
+ "new_value": "Won",
+ "date_created": 1544558077,
+ "date_modified": 1544558077
+ },
+ {
+ "id": 4980508095,
+ "parent": { "id": 66538237, "type": "person" },
+ "type": { "id": 1, "category": "system" },
+ "user_id": 680302,
+ "details": "blah blah",
+ "activity_date": 1544558077,
+ "old_value": null,
+ "new_value": null,
+ "date_created": 1544558077,
+ "date_modified": 1544558077
+ },
+ {
+ "id": 4980508092,
+ "parent": { "id": 27779020, "type": "company" },
+ "type": { "id": 1, "category": "system" },
+ "user_id": 680302,
+ "details": "blah blah",
+ "activity_date": 1544558077,
+ "old_value": null,
+ "new_value": null,
+ "date_created": 1544558077,
+ "date_modified": 1544558077
+ },
+ {
+ "id": 4980507507,
+ "parent": { "id": 14050167, "type": "opportunity" },
+ "type": { "id": 3, "category": "system", "name": "Stage Change" },
+ "user_id": 680302,
+ "details": "blah blah",
+ "activity_date": 1544558071,
+ "old_value": { "id": 2392931, "name": "Integration Started" },
+ "new_value": { "id": 2405442, "name": "Integration Complete" },
+ "date_created": 1544558071,
+ "date_modified": 1544558071
+ },
+ {
+ "id": 4980479684,
+ "parent": { "id": 14901232, "type": "opportunity" },
+ "type": { "id": 3, "category": "system", "name": "Stage Change" },
+ "user_id": 680302,
+ "details": "blah blah",
+ "activity_date": 1544557777,
+ "old_value": { "id": 2392928, "name": "Intro" },
+ "new_value": { "id": 2392929, "name": "Evaluation" },
+ "date_created": 1544557777,
+ "date_modified": 1544557777
+ },
+ {
+ "id": 4980327164,
+ "parent": { "id": 14901232, "type": "opportunity" },
+ "type": { "id": 660495, "category": "user" },
+ "user_id": 680302,
+ "details": "blah blah",
+ "activity_date": 1544554864,
+ "old_value": null,
+ "new_value": null,
+ "date_created": 1544556132,
+ "date_modified": 1544554864
+ },
+ {
+ "id": 4975270470,
+ "parent": { "id": 14888744, "type": "opportunity" },
+ "type": { "id": 3, "category": "system", "name": "Stage Change" },
+ "user_id": 680302,
+ "details": "blah blah",
+ "activity_date": 1544469501,
+ "old_value": { "id": 2392928, "name": "Intro" },
+ "new_value": { "id": 2392931, "name": "Integration Started" },
+ "date_created": 1544469501,
+ "date_modified": 1544469501
+ },
+ {
+ "id": 4975255523,
+ "parent": { "id": 64713448, "type": "person" },
+ "type": { "id": 1, "category": "system" },
+ "user_id": 680302,
+ "details": "blah blah",
+ "activity_date": 1544469389,
+ "old_value": null,
+ "new_value": null,
+ "date_created": 1544469389,
+ "date_modified": 1544469389
+ },
+ {
+ "id": 4975255519,
+ "parent": { "id": 13735617, "type": "opportunity" },
+ "type": { "id": 1, "category": "system", "name": "Status Change" },
+ "user_id": 680302,
+ "details": "blah blah",
+ "activity_date": 1544469388,
+ "old_value": "Open",
+ "new_value": "Won",
+ "date_created": 1544469388,
+ "date_modified": 1544469388
+ },
+ {
+ "id": 4975255514,
+ "parent": { "id": 27778968, "type": "company" },
+ "type": { "id": 1, "category": "system" },
+ "user_id": 680302,
+ "details": "blah blah",
+ "activity_date": 1544469388,
+ "old_value": null,
+ "new_value": null,
+ "date_created": 1544469388,
+ "date_modified": 1544469388
+ }
+]
diff --git a/packages/pipeline/test/fixtures/copper/api_v1_list_activities.ts b/packages/pipeline/test/fixtures/copper/api_v1_list_activities.ts
new file mode 100644
index 000000000..51ee9ced3
--- /dev/null
+++ b/packages/pipeline/test/fixtures/copper/api_v1_list_activities.ts
@@ -0,0 +1,305 @@
+import { CopperActivity } from '../../../src/entities';
+
+const ParsedActivities: CopperActivity[] = [
+ {
+ id: 5015299552,
+ parentId: 14667512,
+ parentType: 'opportunity',
+ typeId: 3,
+ typeCategory: 'system',
+ typeName: 'Stage Change',
+ userId: 680302,
+ dateCreated: 1545329595000,
+ dateModified: 1545329595000,
+ oldValueId: 2392929,
+ oldValueName: 'Evaluation',
+ newValueId: 2392931,
+ newValueName: 'Integration Started',
+ },
+ {
+ id: 5010214065,
+ parentId: 14978865,
+ parentType: 'opportunity',
+ typeId: 3,
+ typeCategory: 'system',
+ typeName: 'Stage Change',
+ userId: 680302,
+ dateCreated: 1545245706000,
+ dateModified: 1545245706000,
+ oldValueId: 2392928,
+ oldValueName: 'Intro',
+ newValueId: 2392929,
+ newValueName: 'Evaluation',
+ },
+ {
+ id: 5006149111,
+ parentId: 70430977,
+ parentType: 'person',
+ typeId: 660495,
+ typeCategory: 'user',
+ typeName: undefined,
+ userId: 680302,
+ dateCreated: 1545168280000,
+ dateModified: 1545166908000,
+ oldValueId: undefined,
+ oldValueName: undefined,
+ newValueId: undefined,
+ newValueName: undefined,
+ },
+ {
+ id: 5005314622,
+ parentId: 27778968,
+ parentType: 'company',
+ typeId: 660495,
+ typeCategory: 'user',
+ typeName: undefined,
+ userId: 680302,
+ dateCreated: 1545160479000,
+ dateModified: 1545080504000,
+ oldValueId: undefined,
+ oldValueName: undefined,
+ newValueId: undefined,
+ newValueName: undefined,
+ },
+ {
+ id: 5000006802,
+ parentId: 14956518,
+ parentType: 'opportunity',
+ typeId: 660495,
+ typeCategory: 'user',
+ typeName: undefined,
+ userId: 680302,
+ dateCreated: 1545071500000,
+ dateModified: 1545071374000,
+ oldValueId: undefined,
+ oldValueName: undefined,
+ newValueId: undefined,
+ newValueName: undefined,
+ },
+ {
+ id: 4985504199,
+ parentId: 14912790,
+ parentType: 'opportunity',
+ typeId: 660495,
+ typeCategory: 'user',
+ typeName: undefined,
+ userId: 680302,
+ dateCreated: 1544644661000,
+ dateModified: 1544644058000,
+ oldValueId: undefined,
+ oldValueName: undefined,
+ newValueId: undefined,
+ newValueName: undefined,
+ },
+ {
+ id: 4985456147,
+ parentId: 14912790,
+ parentType: 'opportunity',
+ typeId: 660495,
+ typeCategory: 'user',
+ typeName: undefined,
+ userId: 680302,
+ dateCreated: 1544644053000,
+ dateModified: 1544644048000,
+ oldValueId: undefined,
+ oldValueName: undefined,
+ newValueId: undefined,
+ newValueName: undefined,
+ },
+ {
+ id: 4980975996,
+ parentId: 14902828,
+ parentType: 'opportunity',
+ typeId: 660495,
+ typeCategory: 'user',
+ typeName: undefined,
+ userId: 680302,
+ dateCreated: 1544563224000,
+ dateModified: 1544563171000,
+ oldValueId: undefined,
+ oldValueName: undefined,
+ newValueId: undefined,
+ newValueName: undefined,
+ },
+ {
+ id: 4980910331,
+ parentId: 14902828,
+ parentType: 'opportunity',
+ typeId: 3,
+ typeCategory: 'system',
+ typeName: 'Stage Change',
+ userId: 680302,
+ dateCreated: 1544562495000,
+ dateModified: 1544562495000,
+ oldValueId: 2392928,
+ oldValueName: 'Intro',
+ newValueId: 2392931,
+ newValueName: 'Integration Started',
+ },
+ {
+ id: 4980872220,
+ parentId: 14888910,
+ parentType: 'opportunity',
+ typeId: 660495,
+ typeCategory: 'user',
+ typeName: undefined,
+ userId: 680302,
+ dateCreated: 1544562118000,
+ dateModified: 1544559279000,
+ oldValueId: undefined,
+ oldValueName: undefined,
+ newValueId: undefined,
+ newValueName: undefined,
+ },
+ {
+ id: 4980508097,
+ parentId: 14050167,
+ parentType: 'opportunity',
+ typeId: 1,
+ typeCategory: 'system',
+ typeName: 'Status Change',
+ userId: 680302,
+ dateCreated: 1544558077000,
+ dateModified: 1544558077000,
+ oldValueId: undefined,
+ oldValueName: undefined,
+ newValueId: undefined,
+ newValueName: undefined,
+ },
+ {
+ id: 4980508095,
+ parentId: 66538237,
+ parentType: 'person',
+ typeId: 1,
+ typeCategory: 'system',
+ typeName: undefined,
+ userId: 680302,
+ dateCreated: 1544558077000,
+ dateModified: 1544558077000,
+ oldValueId: undefined,
+ oldValueName: undefined,
+ newValueId: undefined,
+ newValueName: undefined,
+ },
+ {
+ id: 4980508092,
+ parentId: 27779020,
+ parentType: 'company',
+ typeId: 1,
+ typeCategory: 'system',
+ typeName: undefined,
+ userId: 680302,
+ dateCreated: 1544558077000,
+ dateModified: 1544558077000,
+ oldValueId: undefined,
+ oldValueName: undefined,
+ newValueId: undefined,
+ newValueName: undefined,
+ },
+ {
+ id: 4980507507,
+ parentId: 14050167,
+ parentType: 'opportunity',
+ typeId: 3,
+ typeCategory: 'system',
+ typeName: 'Stage Change',
+ userId: 680302,
+ dateCreated: 1544558071000,
+ dateModified: 1544558071000,
+ oldValueId: 2392931,
+ oldValueName: 'Integration Started',
+ newValueId: 2405442,
+ newValueName: 'Integration Complete',
+ },
+ {
+ id: 4980479684,
+ parentId: 14901232,
+ parentType: 'opportunity',
+ typeId: 3,
+ typeCategory: 'system',
+ typeName: 'Stage Change',
+ userId: 680302,
+ dateCreated: 1544557777000,
+ dateModified: 1544557777000,
+ oldValueId: 2392928,
+ oldValueName: 'Intro',
+ newValueId: 2392929,
+ newValueName: 'Evaluation',
+ },
+ {
+ id: 4980327164,
+ parentId: 14901232,
+ parentType: 'opportunity',
+ typeId: 660495,
+ typeCategory: 'user',
+ typeName: undefined,
+ userId: 680302,
+ dateCreated: 1544556132000,
+ dateModified: 1544554864000,
+ oldValueId: undefined,
+ oldValueName: undefined,
+ newValueId: undefined,
+ newValueName: undefined,
+ },
+ {
+ id: 4975270470,
+ parentId: 14888744,
+ parentType: 'opportunity',
+ typeId: 3,
+ typeCategory: 'system',
+ typeName: 'Stage Change',
+ userId: 680302,
+ dateCreated: 1544469501000,
+ dateModified: 1544469501000,
+ oldValueId: 2392928,
+ oldValueName: 'Intro',
+ newValueId: 2392931,
+ newValueName: 'Integration Started',
+ },
+ {
+ id: 4975255523,
+ parentId: 64713448,
+ parentType: 'person',
+ typeId: 1,
+ typeCategory: 'system',
+ typeName: undefined,
+ userId: 680302,
+ dateCreated: 1544469389000,
+ dateModified: 1544469389000,
+ oldValueId: undefined,
+ oldValueName: undefined,
+ newValueId: undefined,
+ newValueName: undefined,
+ },
+ {
+ id: 4975255519,
+ parentId: 13735617,
+ parentType: 'opportunity',
+ typeId: 1,
+ typeCategory: 'system',
+ typeName: 'Status Change',
+ userId: 680302,
+ dateCreated: 1544469388000,
+ dateModified: 1544469388000,
+ oldValueId: undefined,
+ oldValueName: undefined,
+ newValueId: undefined,
+ newValueName: undefined,
+ },
+ {
+ id: 4975255514,
+ parentId: 27778968,
+ parentType: 'company',
+ typeId: 1,
+ typeCategory: 'system',
+ typeName: undefined,
+ userId: 680302,
+ dateCreated: 1544469388000,
+ dateModified: 1544469388000,
+ oldValueId: undefined,
+ oldValueName: undefined,
+ newValueId: undefined,
+ newValueName: undefined,
+ },
+];
+export { ParsedActivities };
diff --git a/packages/pipeline/test/fixtures/copper/api_v1_list_leads.json b/packages/pipeline/test/fixtures/copper/api_v1_list_leads.json
new file mode 100644
index 000000000..5223976f9
--- /dev/null
+++ b/packages/pipeline/test/fixtures/copper/api_v1_list_leads.json
@@ -0,0 +1,583 @@
+[
+ {
+ "id": 9150547,
+ "name": "My Contact",
+ "prefix": null,
+ "first_name": "My",
+ "last_name": "Contact",
+ "middle_name": null,
+ "suffix": null,
+ "address": null,
+ "assignee_id": null,
+ "company_name": null,
+ "customer_source_id": null,
+ "details": null,
+ "email": {
+ "email": "mycontact@noemail.com",
+ "category": "work"
+ },
+ "interaction_count": 0,
+ "monetary_value": null,
+ "socials": [],
+ "status": "New",
+ "status_id": 208231,
+ "tags": [],
+ "title": null,
+ "websites": [],
+ "phone_numbers": [],
+ "custom_fields": [
+ {
+ "custom_field_definition_id": 100764,
+ "value": null
+ },
+ {
+ "custom_field_definition_id": 103481,
+ "value": null
+ }
+ ],
+ "date_created": 1490045162,
+ "date_modified": 1490045162
+ },
+ {
+ "id": 9150552,
+ "name": "My Contact",
+ "prefix": null,
+ "first_name": "My",
+ "last_name": "Contact",
+ "middle_name": null,
+ "suffix": null,
+ "address": null,
+ "assignee_id": null,
+ "company_name": null,
+ "customer_source_id": null,
+ "details": null,
+ "email": null,
+ "interaction_count": 0,
+ "monetary_value": null,
+ "socials": [],
+ "status": "New",
+ "status_id": 208231,
+ "tags": [],
+ "title": null,
+ "websites": [],
+ "phone_numbers": [
+ {
+ "number": "415-123-45678",
+ "category": "mobile"
+ }
+ ],
+ "custom_fields": [
+ {
+ "custom_field_definition_id": 100764,
+ "value": null
+ },
+ {
+ "custom_field_definition_id": 103481,
+ "value": null
+ }
+ ],
+ "date_created": 1490045237,
+ "date_modified": 1490045237
+ },
+ {
+ "id": 9150578,
+ "name": "My Contact",
+ "prefix": null,
+ "first_name": "My",
+ "last_name": "Contact",
+ "middle_name": null,
+ "suffix": null,
+ "address": null,
+ "assignee_id": null,
+ "company_name": null,
+ "customer_source_id": null,
+ "details": null,
+ "email": null,
+ "interaction_count": 0,
+ "monetary_value": null,
+ "socials": [],
+ "status": "New",
+ "status_id": 208231,
+ "tags": [],
+ "title": null,
+ "websites": [],
+ "phone_numbers": [
+ {
+ "number": "415-123-45678",
+ "category": "mobile"
+ }
+ ],
+ "custom_fields": [
+ {
+ "custom_field_definition_id": 100764,
+ "value": null
+ },
+ {
+ "custom_field_definition_id": 103481,
+ "value": null
+ }
+ ],
+ "date_created": 1490045279,
+ "date_modified": 1490045279
+ },
+ {
+ "id": 8982554,
+ "name": "My Lead",
+ "prefix": null,
+ "first_name": "My",
+ "last_name": "Lead",
+ "middle_name": null,
+ "suffix": null,
+ "address": null,
+ "assignee_id": null,
+ "company_name": null,
+ "customer_source_id": null,
+ "details": null,
+ "email": {
+ "email": "mylead@noemail.com",
+ "category": "work"
+ },
+ "interaction_count": 0,
+ "monetary_value": null,
+ "socials": [],
+ "status": "New",
+ "status_id": 208231,
+ "tags": [],
+ "title": null,
+ "websites": [],
+ "phone_numbers": [],
+ "custom_fields": [
+ {
+ "custom_field_definition_id": 100764,
+ "value": null
+ },
+ {
+ "custom_field_definition_id": 103481,
+ "value": null
+ }
+ ],
+ "date_created": 1489528899,
+ "date_modified": 1489528899
+ },
+ {
+ "id": 8982702,
+ "name": "My Lead",
+ "prefix": null,
+ "first_name": "My",
+ "last_name": "Lead",
+ "middle_name": null,
+ "suffix": null,
+ "address": null,
+ "assignee_id": null,
+ "company_name": null,
+ "customer_source_id": null,
+ "details": null,
+ "email": {
+ "email": "mylead@gmail.test",
+ "category": "work"
+ },
+ "interaction_count": 0,
+ "monetary_value": null,
+ "socials": [],
+ "status": "New",
+ "status_id": 208231,
+ "tags": [],
+ "title": null,
+ "websites": [],
+ "phone_numbers": [],
+ "custom_fields": [
+ {
+ "custom_field_definition_id": 100764,
+ "value": null
+ },
+ {
+ "custom_field_definition_id": 103481,
+ "value": null
+ }
+ ],
+ "date_created": 1489531171,
+ "date_modified": 1489531171
+ },
+ {
+ "id": 9094361,
+ "name": "My Lead",
+ "prefix": null,
+ "first_name": "My",
+ "last_name": "Lead",
+ "middle_name": null,
+ "suffix": null,
+ "address": null,
+ "assignee_id": null,
+ "company_name": null,
+ "customer_source_id": null,
+ "details": null,
+ "email": {
+ "email": "mylead@noemail.com",
+ "category": "work"
+ },
+ "interaction_count": 0,
+ "monetary_value": null,
+ "socials": [],
+ "status": "New",
+ "status_id": 208231,
+ "tags": [],
+ "title": null,
+ "websites": [],
+ "phone_numbers": [],
+ "custom_fields": [
+ {
+ "custom_field_definition_id": 100764,
+ "value": null
+ },
+ {
+ "custom_field_definition_id": 103481,
+ "value": null
+ }
+ ],
+ "date_created": 1489791225,
+ "date_modified": 1489791225
+ },
+ {
+ "id": 9094364,
+ "name": "My Lead",
+ "prefix": null,
+ "first_name": "My",
+ "last_name": "Lead",
+ "middle_name": null,
+ "suffix": null,
+ "address": null,
+ "assignee_id": null,
+ "company_name": null,
+ "customer_source_id": null,
+ "details": null,
+ "email": {
+ "email": "mylead@noemail.com",
+ "category": "work"
+ },
+ "interaction_count": 0,
+ "monetary_value": null,
+ "socials": [],
+ "status": "New",
+ "status_id": 208231,
+ "tags": [],
+ "title": null,
+ "websites": [],
+ "phone_numbers": [],
+ "custom_fields": [
+ {
+ "custom_field_definition_id": 100764,
+ "value": "123456789012345678901234567890"
+ },
+ {
+ "custom_field_definition_id": 103481,
+ "value": "123456789012345678901234567890"
+ }
+ ],
+ "date_created": 1489791283,
+ "date_modified": 1489791283
+ },
+ {
+ "id": 9094371,
+ "name": "My Lead",
+ "prefix": null,
+ "first_name": "My",
+ "last_name": "Lead",
+ "middle_name": null,
+ "suffix": null,
+ "address": null,
+ "assignee_id": null,
+ "company_name": null,
+ "customer_source_id": null,
+ "details": null,
+ "email": {
+ "email": "mylead@noemail.com",
+ "category": "work"
+ },
+ "interaction_count": 0,
+ "monetary_value": null,
+ "socials": [],
+ "status": "New",
+ "status_id": 208231,
+ "tags": [],
+ "title": null,
+ "websites": [],
+ "phone_numbers": [],
+ "custom_fields": [
+ {
+ "custom_field_definition_id": 100764,
+ "value":
+ "|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------"
+ },
+ {
+ "custom_field_definition_id": 103481,
+ "value": "123456789012345678901234567890"
+ }
+ ],
+ "date_created": 1489791417,
+ "date_modified": 1489791417
+ },
+ {
+ "id": 9094372,
+ "name": "My Lead",
+ "prefix": null,
+ "first_name": "My",
+ "last_name": "Lead",
+ "middle_name": null,
+ "suffix": null,
+ "address": null,
+ "assignee_id": null,
+ "company_name": null,
+ "customer_source_id": null,
+ "details": null,
+ "email": {
+ "email": "mylead@noemail.com",
+ "category": "work"
+ },
+ "interaction_count": 0,
+ "monetary_value": null,
+ "socials": [],
+ "status": "New",
+ "status_id": 208231,
+ "tags": [],
+ "title": null,
+ "websites": [],
+ "phone_numbers": [],
+ "custom_fields": [
+ {
+ "custom_field_definition_id": 100764,
+ "value":
+ "|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------|--------1---------2---------3---------4---------5-----"
+ },
+ {
+ "custom_field_definition_id": 103481,
+ "value": "123456789012345678901234567890"
+ }
+ ],
+ "date_created": 1489791453,
+ "date_modified": 1489791453
+ },
+ {
+ "id": 9094373,
+ "name": "My Lead",
+ "prefix": null,
+ "first_name": "My",
+ "last_name": "Lead",
+ "middle_name": null,
+ "suffix": null,
+ "address": null,
+ "assignee_id": null,
+ "company_name": null,
+ "customer_source_id": null,
+ "details": null,
+ "email": {
+ "email": "mylead@noemail.com",
+ "category": "work"
+ },
+ "interaction_count": 0,
+ "monetary_value": null,
+ "socials": [],
+ "status": "New",
+ "status_id": 208231,
+ "tags": [],
+ "title": null,
+ "websites": [],
+ "phone_numbers": [],
+ "custom_fields": [
+ {
+ "custom_field_definition_id": 100764,
+ "value":
+ "|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------|--------1---------2---------3---------4---------5-----"
+ },
+ {
+ "custom_field_definition_id": 103481,
+ "value":
+ "|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------"
+ }
+ ],
+ "date_created": 1489791470,
+ "date_modified": 1489791470
+ },
+ {
+ "id": 9094383,
+ "name": "My Lead",
+ "prefix": null,
+ "first_name": "My",
+ "last_name": "Lead",
+ "middle_name": null,
+ "suffix": null,
+ "address": null,
+ "assignee_id": null,
+ "company_name": null,
+ "customer_source_id": null,
+ "details": null,
+ "email": {
+ "email": "mylead@noemail.com",
+ "category": "work"
+ },
+ "interaction_count": 0,
+ "monetary_value": null,
+ "socials": [],
+ "status": "New",
+ "status_id": 208231,
+ "tags": [],
+ "title": null,
+ "websites": [],
+ "phone_numbers": [],
+ "custom_fields": [
+ {
+ "custom_field_definition_id": 100764,
+ "value":
+ "|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------|--------1---------2---------3---------4---------5-----"
+ },
+ {
+ "custom_field_definition_id": 103481,
+ "value":
+ "|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------"
+ }
+ ],
+ "date_created": 1489791672,
+ "date_modified": 1489791672
+ },
+ {
+ "id": 9174441,
+ "name": "My Lead",
+ "prefix": null,
+ "first_name": "My",
+ "last_name": "Lead",
+ "middle_name": null,
+ "suffix": null,
+ "address": null,
+ "assignee_id": null,
+ "company_name": null,
+ "customer_source_id": null,
+ "details": null,
+ "email": {
+ "email": "mylead@noemail.com",
+ "category": "work"
+ },
+ "interaction_count": 0,
+ "monetary_value": null,
+ "socials": [],
+ "status": "New",
+ "status_id": 208231,
+ "tags": [],
+ "title": null,
+ "websites": [],
+ "phone_numbers": [],
+ "custom_fields": [
+ {
+ "custom_field_definition_id": 100764,
+ "value": "Text fields are 255 chars or less!"
+ },
+ {
+ "custom_field_definition_id": 103481,
+ "value": "text \n text"
+ }
+ ],
+ "date_created": 1490112942,
+ "date_modified": 1490112942
+ },
+ {
+ "id": 9174443,
+ "name": "My Lead",
+ "prefix": null,
+ "first_name": "My",
+ "last_name": "Lead",
+ "middle_name": null,
+ "suffix": null,
+ "address": null,
+ "assignee_id": null,
+ "company_name": null,
+ "customer_source_id": null,
+ "details": null,
+ "email": {
+ "email": "mylead@noemail.com",
+ "category": "work"
+ },
+ "interaction_count": 0,
+ "monetary_value": null,
+ "socials": [],
+ "status": "New",
+ "status_id": 208231,
+ "tags": [],
+ "title": null,
+ "websites": [],
+ "phone_numbers": [],
+ "custom_fields": [
+ {
+ "custom_field_definition_id": 100764,
+ "value": "Text fields are 255 chars or less!"
+ },
+ {
+ "custom_field_definition_id": 103481,
+ "value": "text /n text"
+ }
+ ],
+ "date_created": 1490112953,
+ "date_modified": 1490112953
+ },
+ {
+ "id": 8894157,
+ "name": "Test Lead",
+ "prefix": null,
+ "first_name": "Test",
+ "last_name": "Lead",
+ "middle_name": null,
+ "suffix": null,
+ "address": {
+ "street": "301 Howard St Ste 600",
+ "city": "San Francisco",
+ "state": "CA",
+ "postal_code": "94105",
+ "country": "US"
+ },
+ "assignee_id": 137658,
+ "company_name": "Lead's Company",
+ "customer_source_id": 331241,
+ "details": "This is an update",
+ "email": {
+ "email": "address@workemail.com",
+ "category": "work"
+ },
+ "interaction_count": 0,
+ "monetary_value": 100,
+ "socials": [
+ {
+ "url": "facebook.com/test_lead",
+ "category": "facebook"
+ }
+ ],
+ "status": "New",
+ "status_id": 208231,
+ "tags": ["tag 1", "tag 2"],
+ "title": "Title",
+ "websites": [
+ {
+ "url": "www.workwebsite.com",
+ "category": "work"
+ }
+ ],
+ "phone_numbers": [
+ {
+ "number": "415-999-4321",
+ "category": "mobile"
+ },
+ {
+ "number": "415-555-1234",
+ "category": "work"
+ }
+ ],
+ "custom_fields": [
+ {
+ "custom_field_definition_id": 100764,
+ "value": null
+ },
+ {
+ "custom_field_definition_id": 103481,
+ "value": null
+ }
+ ],
+ "date_created": 1489018784,
+ "date_modified": 1496692911
+ }
+]
diff --git a/packages/pipeline/test/fixtures/copper/api_v1_list_leads.ts b/packages/pipeline/test/fixtures/copper/api_v1_list_leads.ts
new file mode 100644
index 000000000..b1f00cba7
--- /dev/null
+++ b/packages/pipeline/test/fixtures/copper/api_v1_list_leads.ts
@@ -0,0 +1,229 @@
+import { CopperLead } from '../../../src/entities';
+const ParsedLeads: CopperLead[] = [
+ {
+ id: 9150547,
+ name: 'My Contact',
+ firstName: 'My',
+ lastName: 'Contact',
+ middleName: undefined,
+ assigneeId: undefined,
+ companyName: undefined,
+ customerSourceId: undefined,
+ monetaryValue: undefined,
+ status: 'New',
+ statusId: 208231,
+ title: undefined,
+ dateCreated: 1490045162000,
+ dateModified: 1490045162000,
+ },
+ {
+ id: 9150552,
+ name: 'My Contact',
+ firstName: 'My',
+ lastName: 'Contact',
+ middleName: undefined,
+ assigneeId: undefined,
+ companyName: undefined,
+ customerSourceId: undefined,
+ monetaryValue: undefined,
+ status: 'New',
+ statusId: 208231,
+ title: undefined,
+ dateCreated: 1490045237000,
+ dateModified: 1490045237000,
+ },
+ {
+ id: 9150578,
+ name: 'My Contact',
+ firstName: 'My',
+ lastName: 'Contact',
+ middleName: undefined,
+ assigneeId: undefined,
+ companyName: undefined,
+ customerSourceId: undefined,
+ monetaryValue: undefined,
+ status: 'New',
+ statusId: 208231,
+ title: undefined,
+ dateCreated: 1490045279000,
+ dateModified: 1490045279000,
+ },
+ {
+ id: 8982554,
+ name: 'My Lead',
+ firstName: 'My',
+ lastName: 'Lead',
+ middleName: undefined,
+ assigneeId: undefined,
+ companyName: undefined,
+ customerSourceId: undefined,
+ monetaryValue: undefined,
+ status: 'New',
+ statusId: 208231,
+ title: undefined,
+ dateCreated: 1489528899000,
+ dateModified: 1489528899000,
+ },
+ {
+ id: 8982702,
+ name: 'My Lead',
+ firstName: 'My',
+ lastName: 'Lead',
+ middleName: undefined,
+ assigneeId: undefined,
+ companyName: undefined,
+ customerSourceId: undefined,
+ monetaryValue: undefined,
+ status: 'New',
+ statusId: 208231,
+ title: undefined,
+ dateCreated: 1489531171000,
+ dateModified: 1489531171000,
+ },
+ {
+ id: 9094361,
+ name: 'My Lead',
+ firstName: 'My',
+ lastName: 'Lead',
+ middleName: undefined,
+ assigneeId: undefined,
+ companyName: undefined,
+ customerSourceId: undefined,
+ monetaryValue: undefined,
+ status: 'New',
+ statusId: 208231,
+ title: undefined,
+ dateCreated: 1489791225000,
+ dateModified: 1489791225000,
+ },
+ {
+ id: 9094364,
+ name: 'My Lead',
+ firstName: 'My',
+ lastName: 'Lead',
+ middleName: undefined,
+ assigneeId: undefined,
+ companyName: undefined,
+ customerSourceId: undefined,
+ monetaryValue: undefined,
+ status: 'New',
+ statusId: 208231,
+ title: undefined,
+ dateCreated: 1489791283000,
+ dateModified: 1489791283000,
+ },
+ {
+ id: 9094371,
+ name: 'My Lead',
+ firstName: 'My',
+ lastName: 'Lead',
+ middleName: undefined,
+ assigneeId: undefined,
+ companyName: undefined,
+ customerSourceId: undefined,
+ monetaryValue: undefined,
+ status: 'New',
+ statusId: 208231,
+ title: undefined,
+ dateCreated: 1489791417000,
+ dateModified: 1489791417000,
+ },
+ {
+ id: 9094372,
+ name: 'My Lead',
+ firstName: 'My',
+ lastName: 'Lead',
+ middleName: undefined,
+ assigneeId: undefined,
+ companyName: undefined,
+ customerSourceId: undefined,
+ monetaryValue: undefined,
+ status: 'New',
+ statusId: 208231,
+ title: undefined,
+ dateCreated: 1489791453000,
+ dateModified: 1489791453000,
+ },
+ {
+ id: 9094373,
+ name: 'My Lead',
+ firstName: 'My',
+ lastName: 'Lead',
+ middleName: undefined,
+ assigneeId: undefined,
+ companyName: undefined,
+ customerSourceId: undefined,
+ monetaryValue: undefined,
+ status: 'New',
+ statusId: 208231,
+ title: undefined,
+ dateCreated: 1489791470000,
+ dateModified: 1489791470000,
+ },
+ {
+ id: 9094383,
+ name: 'My Lead',
+ firstName: 'My',
+ lastName: 'Lead',
+ middleName: undefined,
+ assigneeId: undefined,
+ companyName: undefined,
+ customerSourceId: undefined,
+ monetaryValue: undefined,
+ status: 'New',
+ statusId: 208231,
+ title: undefined,
+ dateCreated: 1489791672000,
+ dateModified: 1489791672000,
+ },
+ {
+ id: 9174441,
+ name: 'My Lead',
+ firstName: 'My',
+ lastName: 'Lead',
+ middleName: undefined,
+ assigneeId: undefined,
+ companyName: undefined,
+ customerSourceId: undefined,
+ monetaryValue: undefined,
+ status: 'New',
+ statusId: 208231,
+ title: undefined,
+ dateCreated: 1490112942000,
+ dateModified: 1490112942000,
+ },
+ {
+ id: 9174443,
+ name: 'My Lead',
+ firstName: 'My',
+ lastName: 'Lead',
+ middleName: undefined,
+ assigneeId: undefined,
+ companyName: undefined,
+ customerSourceId: undefined,
+ monetaryValue: undefined,
+ status: 'New',
+ statusId: 208231,
+ title: undefined,
+ dateCreated: 1490112953000,
+ dateModified: 1490112953000,
+ },
+ {
+ id: 8894157,
+ name: 'Test Lead',
+ firstName: 'Test',
+ lastName: 'Lead',
+ middleName: undefined,
+ assigneeId: 137658,
+ companyName: "Lead's Company",
+ customerSourceId: 331241,
+ monetaryValue: 100,
+ status: 'New',
+ statusId: 208231,
+ title: 'Title',
+ dateCreated: 1489018784000,
+ dateModified: 1496692911000,
+ },
+];
+
+export { ParsedLeads };
diff --git a/packages/pipeline/test/fixtures/copper/api_v1_list_opportunities.json b/packages/pipeline/test/fixtures/copper/api_v1_list_opportunities.json
new file mode 100644
index 000000000..34ac58c30
--- /dev/null
+++ b/packages/pipeline/test/fixtures/copper/api_v1_list_opportunities.json
@@ -0,0 +1,662 @@
+[
+ {
+ "id": 14050269,
+ "name": "8Base RaaS",
+ "assignee_id": 680302,
+ "close_date": "11/19/2018",
+ "company_id": 27778962,
+ "company_name": "8base",
+ "customer_source_id": null,
+ "details": "blah blah",
+ "loss_reason_id": null,
+ "pipeline_id": 512676,
+ "pipeline_stage_id": 2405442,
+ "primary_contact_id": 66088850,
+ "priority": "None",
+ "status": "Won",
+ "tags": [],
+ "interaction_count": 81,
+ "monetary_unit": null,
+ "monetary_value": null,
+ "converted_unit": null,
+ "converted_value": null,
+ "win_probability": 0,
+ "date_stage_changed": 1542653860,
+ "date_last_contacted": 1544757550,
+ "leads_converted_from": [],
+ "date_lead_created": null,
+ "date_created": 1538414159,
+ "date_modified": 1544769562,
+ "custom_fields": [
+ { "custom_field_definition_id": 261066, "value": [394013, 394018] },
+ { "custom_field_definition_id": 261067, "value": 394026 }
+ ]
+ },
+ {
+ "id": 14631430,
+ "name": "Alice.si TW + ERC 20 Marketplace",
+ "assignee_id": 680302,
+ "close_date": "12/15/2018",
+ "company_id": 30238847,
+ "company_name": "Alice SI",
+ "customer_source_id": null,
+ "details": "blah blah",
+ "loss_reason_id": null,
+ "pipeline_id": 512676,
+ "pipeline_stage_id": 2392929,
+ "primary_contact_id": 69354024,
+ "priority": "None",
+ "status": "Open",
+ "tags": [],
+ "interaction_count": 4,
+ "monetary_unit": null,
+ "monetary_value": null,
+ "converted_unit": null,
+ "converted_value": null,
+ "win_probability": 0,
+ "date_stage_changed": 1542304481,
+ "date_last_contacted": 1542304800,
+ "leads_converted_from": [],
+ "date_lead_created": null,
+ "date_created": 1542304481,
+ "date_modified": 1542304943,
+ "custom_fields": [
+ { "custom_field_definition_id": 261066, "value": [394013, 394015] },
+ { "custom_field_definition_id": 261067, "value": 394023 }
+ ]
+ },
+ {
+ "id": 14632057,
+ "name": "Altcoin.io Relayer",
+ "assignee_id": 680302,
+ "close_date": "12/15/2018",
+ "company_id": 29936486,
+ "company_name": "Altcoin.io",
+ "customer_source_id": null,
+ "details": "blah blah",
+ "loss_reason_id": null,
+ "pipeline_id": 512676,
+ "pipeline_stage_id": 2392929,
+ "primary_contact_id": 68724646,
+ "priority": "None",
+ "status": "Open",
+ "tags": [],
+ "interaction_count": 22,
+ "monetary_unit": null,
+ "monetary_value": null,
+ "converted_unit": null,
+ "converted_value": null,
+ "win_probability": 0,
+ "date_stage_changed": 1542310909,
+ "date_last_contacted": 1543864597,
+ "leads_converted_from": [],
+ "date_lead_created": null,
+ "date_created": 1542306827,
+ "date_modified": 1543864667,
+ "custom_fields": [
+ { "custom_field_definition_id": 261066, "value": [394013, 394017] },
+ { "custom_field_definition_id": 261067, "value": 394023 }
+ ]
+ },
+ {
+ "id": 14667523,
+ "name": "Altcoin.io Relayer",
+ "assignee_id": 680302,
+ "close_date": "12/19/2018",
+ "company_id": 29936486,
+ "company_name": "Altcoin.io",
+ "customer_source_id": null,
+ "details": "blah blah",
+ "loss_reason_id": null,
+ "pipeline_id": 512676,
+ "pipeline_stage_id": 2392929,
+ "primary_contact_id": 68724646,
+ "priority": "None",
+ "status": "Open",
+ "tags": [],
+ "interaction_count": 21,
+ "monetary_unit": null,
+ "monetary_value": null,
+ "converted_unit": null,
+ "converted_value": null,
+ "win_probability": 0,
+ "date_stage_changed": 1542657437,
+ "date_last_contacted": 1543864597,
+ "leads_converted_from": [],
+ "date_lead_created": null,
+ "date_created": 1542657437,
+ "date_modified": 1543864667,
+ "custom_fields": [
+ { "custom_field_definition_id": 261066, "value": [394013, 394017] },
+ { "custom_field_definition_id": 261067, "value": 394023 }
+ ]
+ },
+ {
+ "id": 14666706,
+ "name": "Amadeus Relayer",
+ "assignee_id": 680302,
+ "close_date": "11/19/2018",
+ "company_id": 29243209,
+ "company_name": "Amadeus",
+ "customer_source_id": null,
+ "details": "blah blah",
+ "loss_reason_id": null,
+ "pipeline_id": 512676,
+ "pipeline_stage_id": 2405442,
+ "primary_contact_id": 66912020,
+ "priority": "None",
+ "status": "Won",
+ "tags": [],
+ "interaction_count": 11,
+ "monetary_unit": null,
+ "monetary_value": null,
+ "converted_unit": null,
+ "converted_value": null,
+ "win_probability": 0,
+ "date_stage_changed": 1542654284,
+ "date_last_contacted": 1543264254,
+ "leads_converted_from": [],
+ "date_lead_created": null,
+ "date_created": 1542654284,
+ "date_modified": 1543277520,
+ "custom_fields": [
+ { "custom_field_definition_id": 261066, "value": [394013] },
+ { "custom_field_definition_id": 261067, "value": 394023 }
+ ]
+ },
+ {
+ "id": 14666718,
+ "name": "Ambo Relayer",
+ "assignee_id": 680302,
+ "close_date": "11/19/2018",
+ "company_id": 29249190,
+ "company_name": "Ambo",
+ "customer_source_id": null,
+ "details": "blah blah",
+ "loss_reason_id": null,
+ "pipeline_id": 512676,
+ "pipeline_stage_id": 2405442,
+ "primary_contact_id": 66927869,
+ "priority": "None",
+ "status": "Won",
+ "tags": [],
+ "interaction_count": 126,
+ "monetary_unit": null,
+ "monetary_value": null,
+ "converted_unit": null,
+ "converted_value": null,
+ "win_probability": 0,
+ "date_stage_changed": 1542654352,
+ "date_last_contacted": 1545252349,
+ "leads_converted_from": [],
+ "date_lead_created": null,
+ "date_created": 1542654352,
+ "date_modified": 1545253761,
+ "custom_fields": [
+ { "custom_field_definition_id": 261066, "value": [394013] },
+ { "custom_field_definition_id": 261067, "value": 394023 }
+ ]
+ },
+ {
+ "id": 14164318,
+ "name": "Augur TW",
+ "assignee_id": 680302,
+ "close_date": "12/10/2018",
+ "company_id": 27778967,
+ "company_name": "Augur",
+ "customer_source_id": null,
+ "details": "blah blah",
+ "loss_reason_id": null,
+ "pipeline_id": 512676,
+ "pipeline_stage_id": 2405442,
+ "primary_contact_id": 67248692,
+ "priority": "None",
+ "status": "Won",
+ "tags": [],
+ "interaction_count": 22,
+ "monetary_unit": null,
+ "monetary_value": null,
+ "converted_unit": null,
+ "converted_value": null,
+ "win_probability": 0,
+ "date_stage_changed": 1544469362,
+ "date_last_contacted": 1544491567,
+ "leads_converted_from": [],
+ "date_lead_created": null,
+ "date_created": 1539204858,
+ "date_modified": 1544653867,
+ "custom_fields": [
+ { "custom_field_definition_id": 261066, "value": [394015] },
+ { "custom_field_definition_id": 261067, "value": 394021 }
+ ]
+ },
+ {
+ "id": 14666626,
+ "name": "Autonio",
+ "assignee_id": 680302,
+ "close_date": "12/19/2018",
+ "company_id": 27920701,
+ "company_name": "Auton",
+ "customer_source_id": null,
+ "details": "blah blah",
+ "loss_reason_id": null,
+ "pipeline_id": 512676,
+ "pipeline_stage_id": 2392931,
+ "primary_contact_id": 64742640,
+ "priority": "None",
+ "status": "Open",
+ "tags": [],
+ "interaction_count": 54,
+ "monetary_unit": null,
+ "monetary_value": null,
+ "converted_unit": null,
+ "converted_value": null,
+ "win_probability": 0,
+ "date_stage_changed": 1542653834,
+ "date_last_contacted": 1542658568,
+ "leads_converted_from": [],
+ "date_lead_created": null,
+ "date_created": 1542653834,
+ "date_modified": 1542658808,
+ "custom_fields": [
+ { "custom_field_definition_id": 261066, "value": [394013, 394019] },
+ { "custom_field_definition_id": 261067, "value": 394023 }
+ ]
+ },
+ {
+ "id": 14050921,
+ "name": "Axie Infinity 721 Marketplace",
+ "assignee_id": 680302,
+ "close_date": "11/1/2018",
+ "company_id": 27779033,
+ "company_name": "Axie Infinity",
+ "customer_source_id": null,
+ "details": "blah blah",
+ "loss_reason_id": null,
+ "pipeline_id": 512676,
+ "pipeline_stage_id": 2392931,
+ "primary_contact_id": 66499254,
+ "priority": "None",
+ "status": "Open",
+ "tags": [],
+ "interaction_count": 4,
+ "monetary_unit": null,
+ "monetary_value": null,
+ "converted_unit": null,
+ "converted_value": null,
+ "win_probability": 0,
+ "date_stage_changed": 1543861025,
+ "date_last_contacted": 1539024738,
+ "leads_converted_from": [],
+ "date_lead_created": null,
+ "date_created": 1538416687,
+ "date_modified": 1543861025,
+ "custom_fields": [
+ { "custom_field_definition_id": 261066, "value": [394014] },
+ { "custom_field_definition_id": 261067, "value": 394134 }
+ ]
+ },
+ {
+ "id": 13735617,
+ "name": "Balance TW",
+ "assignee_id": 680302,
+ "close_date": "12/10/2018",
+ "company_id": 27778968,
+ "company_name": "Balance",
+ "customer_source_id": null,
+ "details": "blah blah",
+ "loss_reason_id": null,
+ "pipeline_id": 512676,
+ "pipeline_stage_id": 2405442,
+ "primary_contact_id": 64713448,
+ "priority": "None",
+ "status": "Won",
+ "tags": [],
+ "interaction_count": 34,
+ "monetary_unit": null,
+ "monetary_value": null,
+ "converted_unit": null,
+ "converted_value": null,
+ "win_probability": 0,
+ "date_stage_changed": 1544469382,
+ "date_last_contacted": 1545082200,
+ "leads_converted_from": [],
+ "date_lead_created": null,
+ "date_created": 1535668009,
+ "date_modified": 1545082454,
+ "custom_fields": [
+ { "custom_field_definition_id": 261066, "value": [394015] },
+ { "custom_field_definition_id": 261067, "value": 394027 }
+ ]
+ },
+ {
+ "id": 14667112,
+ "name": "Bamboo Relayer",
+ "assignee_id": 680302,
+ "close_date": "11/19/2018",
+ "company_id": 29243795,
+ "company_name": "Bamboo Relay",
+ "customer_source_id": null,
+ "details": "blah blah",
+ "loss_reason_id": null,
+ "pipeline_id": 512676,
+ "pipeline_stage_id": 2405442,
+ "primary_contact_id": 66914687,
+ "priority": "None",
+ "status": "Won",
+ "tags": [],
+ "interaction_count": 46,
+ "monetary_unit": null,
+ "monetary_value": null,
+ "converted_unit": null,
+ "converted_value": null,
+ "win_probability": 0,
+ "date_stage_changed": 1542655143,
+ "date_last_contacted": 1545252349,
+ "leads_converted_from": [],
+ "date_lead_created": null,
+ "date_created": 1542655143,
+ "date_modified": 1545253761,
+ "custom_fields": [
+ { "custom_field_definition_id": 261066, "value": [394013] },
+ { "custom_field_definition_id": 261067, "value": 394023 }
+ ]
+ },
+ {
+ "id": 13627309,
+ "name": "Ben TW",
+ "assignee_id": 680302,
+ "close_date": "1/1/2019",
+ "company_id": 27702348,
+ "company_name": "Ben",
+ "customer_source_id": null,
+ "details": "blah blah",
+ "loss_reason_id": null,
+ "pipeline_id": 512676,
+ "pipeline_stage_id": 2392929,
+ "primary_contact_id": 64262622,
+ "priority": "None",
+ "status": "Open",
+ "tags": [],
+ "interaction_count": 64,
+ "monetary_unit": null,
+ "monetary_value": null,
+ "converted_unit": null,
+ "converted_value": null,
+ "win_probability": 0,
+ "date_stage_changed": 1541527279,
+ "date_last_contacted": 1541639882,
+ "leads_converted_from": [],
+ "date_lead_created": null,
+ "date_created": 1534887789,
+ "date_modified": 1541651395,
+ "custom_fields": [
+ { "custom_field_definition_id": 261066, "value": [394015] },
+ { "custom_field_definition_id": 261067, "value": 394027 }
+ ]
+ },
+ {
+ "id": 14808512,
+ "name": "Bit2Me Relayer",
+ "assignee_id": 680302,
+ "close_date": "12/3/2018",
+ "company_id": 30793050,
+ "company_name": "Bit2Me",
+ "customer_source_id": null,
+ "details": "blah blah",
+ "loss_reason_id": null,
+ "pipeline_id": 512676,
+ "pipeline_stage_id": 2405442,
+ "primary_contact_id": 70267217,
+ "priority": "None",
+ "status": "Won",
+ "tags": [],
+ "interaction_count": 0,
+ "monetary_unit": null,
+ "monetary_value": null,
+ "converted_unit": null,
+ "converted_value": null,
+ "win_probability": 0,
+ "date_stage_changed": 1543861167,
+ "date_last_contacted": null,
+ "leads_converted_from": [],
+ "date_lead_created": null,
+ "date_created": 1543861167,
+ "date_modified": 1543861189,
+ "custom_fields": [
+ { "custom_field_definition_id": 261066, "value": [394013] },
+ { "custom_field_definition_id": 261067, "value": 394023 }
+ ]
+ },
+ {
+ "id": 14050312,
+ "name": "Bitcoin.tax Reporting Integration",
+ "assignee_id": 680302,
+ "close_date": "11/1/2018",
+ "company_id": 27957614,
+ "company_name": "Bitcoin",
+ "customer_source_id": null,
+ "details": "blah blah",
+ "loss_reason_id": null,
+ "pipeline_id": 512676,
+ "pipeline_stage_id": 2392928,
+ "primary_contact_id": 66539479,
+ "priority": "None",
+ "status": "Open",
+ "tags": [],
+ "interaction_count": 5,
+ "monetary_unit": null,
+ "monetary_value": null,
+ "converted_unit": null,
+ "converted_value": null,
+ "win_probability": 0,
+ "date_stage_changed": 1538414308,
+ "date_last_contacted": 1536766098,
+ "leads_converted_from": [],
+ "date_lead_created": null,
+ "date_created": 1538414308,
+ "date_modified": 1538414314,
+ "custom_fields": [
+ { "custom_field_definition_id": 261066, "value": [394019] },
+ { "custom_field_definition_id": 261067, "value": 394026 }
+ ]
+ },
+ {
+ "id": 14331463,
+ "name": "Bitpie TW",
+ "assignee_id": 680302,
+ "close_date": "11/19/2018",
+ "company_id": 27779026,
+ "company_name": "Bitpie",
+ "customer_source_id": null,
+ "details": "blah blah",
+ "loss_reason_id": null,
+ "pipeline_id": 512676,
+ "pipeline_stage_id": 2392929,
+ "primary_contact_id": 67700943,
+ "priority": "None",
+ "status": "Open",
+ "tags": [],
+ "interaction_count": 9,
+ "monetary_unit": null,
+ "monetary_value": null,
+ "converted_unit": null,
+ "converted_value": null,
+ "win_probability": 0,
+ "date_stage_changed": 1539984566,
+ "date_last_contacted": 1541529947,
+ "leads_converted_from": [],
+ "date_lead_created": null,
+ "date_created": 1539984566,
+ "date_modified": 1541530233,
+ "custom_fields": [
+ { "custom_field_definition_id": 261066, "value": [394015] },
+ { "custom_field_definition_id": 261067, "value": 394027 }
+ ]
+ },
+ {
+ "id": 14331481,
+ "name": "Bitski Wallet SDK TW",
+ "assignee_id": 680302,
+ "close_date": "11/19/2018",
+ "company_id": 29489300,
+ "company_name": "Bitski",
+ "customer_source_id": null,
+ "details": "blah blah",
+ "loss_reason_id": null,
+ "pipeline_id": 512676,
+ "pipeline_stage_id": 2392929,
+ "primary_contact_id": 67697528,
+ "priority": "None",
+ "status": "Open",
+ "tags": [],
+ "interaction_count": 23,
+ "monetary_unit": null,
+ "monetary_value": null,
+ "converted_unit": null,
+ "converted_value": null,
+ "win_probability": 0,
+ "date_stage_changed": 1539984735,
+ "date_last_contacted": 1544811399,
+ "leads_converted_from": [],
+ "date_lead_created": null,
+ "date_created": 1539984735,
+ "date_modified": 1544818605,
+ "custom_fields": [
+ { "custom_field_definition_id": 261066, "value": [394015] },
+ { "custom_field_definition_id": 261067, "value": 394026 }
+ ]
+ },
+ {
+ "id": 14531554,
+ "name": "BitUniverse TW",
+ "assignee_id": 680302,
+ "close_date": "12/6/2018",
+ "company_id": 29901805,
+ "company_name": "BitUniverse Co., Ltd (Cryptocurrency Portfolio)",
+ "customer_source_id": null,
+ "details": "blah blah",
+ "loss_reason_id": null,
+ "pipeline_id": 512676,
+ "pipeline_stage_id": 2392929,
+ "primary_contact_id": 68692107,
+ "priority": "None",
+ "status": "Open",
+ "tags": [],
+ "interaction_count": 15,
+ "monetary_unit": null,
+ "monetary_value": null,
+ "converted_unit": null,
+ "converted_value": null,
+ "win_probability": 0,
+ "date_stage_changed": 1543861104,
+ "date_last_contacted": 1544803276,
+ "leads_converted_from": [],
+ "date_lead_created": null,
+ "date_created": 1541527110,
+ "date_modified": 1544812979,
+ "custom_fields": [
+ { "custom_field_definition_id": 261066, "value": [394015] },
+ { "custom_field_definition_id": 261067, "value": 394026 }
+ ]
+ },
+ {
+ "id": 14050895,
+ "name": "BlitzPredict PMR",
+ "assignee_id": 680302,
+ "close_date": "11/1/2018",
+ "company_id": 28758258,
+ "company_name": "BlitzPredict",
+ "customer_source_id": null,
+ "details": "blah blah",
+ "loss_reason_id": null,
+ "pipeline_id": 512676,
+ "pipeline_stage_id": 2392929,
+ "primary_contact_id": 66378659,
+ "priority": "None",
+ "status": "Open",
+ "tags": [],
+ "interaction_count": 32,
+ "monetary_unit": null,
+ "monetary_value": null,
+ "converted_unit": null,
+ "converted_value": null,
+ "win_probability": 0,
+ "date_stage_changed": 1539985501,
+ "date_last_contacted": 1544830560,
+ "leads_converted_from": [],
+ "date_lead_created": null,
+ "date_created": 1538416597,
+ "date_modified": 1544830709,
+ "custom_fields": [
+ { "custom_field_definition_id": 261066, "value": [394016] },
+ { "custom_field_definition_id": 261067, "value": 394023 }
+ ]
+ },
+ {
+ "id": 14209841,
+ "name": "Blockfolio TW",
+ "assignee_id": 680302,
+ "close_date": "11/15/2018",
+ "company_id": 29332516,
+ "company_name": "Blockfolio",
+ "customer_source_id": null,
+ "details": "blah blah",
+ "loss_reason_id": null,
+ "pipeline_id": 512676,
+ "pipeline_stage_id": 2405443,
+ "primary_contact_id": 67247027,
+ "priority": "None",
+ "status": "Open",
+ "tags": [],
+ "interaction_count": 20,
+ "monetary_unit": null,
+ "monetary_value": null,
+ "converted_unit": null,
+ "converted_value": null,
+ "win_probability": 0,
+ "date_stage_changed": 1539984098,
+ "date_last_contacted": 1539977661,
+ "leads_converted_from": [],
+ "date_lead_created": null,
+ "date_created": 1539624801,
+ "date_modified": 1539984098,
+ "custom_fields": [
+ { "custom_field_definition_id": 261066, "value": [394015] },
+ { "custom_field_definition_id": 261067, "value": 394026 }
+ ]
+ },
+ {
+ "id": 14633220,
+ "name": "BlockSwap 721 / 1155 Conversational Marketplace",
+ "assignee_id": 680302,
+ "close_date": "12/15/2018",
+ "company_id": 30210921,
+ "company_name": "BlockSwap",
+ "customer_source_id": null,
+ "details": "blah blah",
+ "loss_reason_id": null,
+ "pipeline_id": 512676,
+ "pipeline_stage_id": 2392929,
+ "primary_contact_id": 69296220,
+ "priority": "None",
+ "status": "Open",
+ "tags": [],
+ "interaction_count": 82,
+ "monetary_unit": null,
+ "monetary_value": null,
+ "converted_unit": null,
+ "converted_value": null,
+ "win_probability": 0,
+ "date_stage_changed": 1542311056,
+ "date_last_contacted": 1543536442,
+ "leads_converted_from": [],
+ "date_lead_created": null,
+ "date_created": 1542311056,
+ "date_modified": 1543557877,
+ "custom_fields": [
+ { "custom_field_definition_id": 261066, "value": [394014] },
+ { "custom_field_definition_id": 261067, "value": 394023 }
+ ]
+ }
+]
diff --git a/packages/pipeline/test/fixtures/copper/api_v1_list_opportunities.ts b/packages/pipeline/test/fixtures/copper/api_v1_list_opportunities.ts
new file mode 100644
index 000000000..3c2d4ae5e
--- /dev/null
+++ b/packages/pipeline/test/fixtures/copper/api_v1_list_opportunities.ts
@@ -0,0 +1,425 @@
+// tslint:disable:custom-no-magic-numbers
+import { CopperOpportunity } from '../../../src/entities';
+const ParsedOpportunities: CopperOpportunity[] = [
+ {
+ id: 14050269,
+ name: '8Base RaaS',
+ assigneeId: 680302,
+ closeDate: '11/19/2018',
+ companyId: 27778962,
+ companyName: '8base',
+ customerSourceId: undefined,
+ lossReasonId: undefined,
+ pipelineId: 512676,
+ pipelineStageId: 2405442,
+ primaryContactId: 66088850,
+ priority: 'None',
+ status: 'Won',
+ interactionCount: 81,
+ monetaryValue: undefined,
+ winProbability: 0,
+ dateCreated: 1538414159000,
+ dateModified: 1544769562000,
+ customFields: { '261066': 394018, '261067': 394026 },
+ },
+ {
+ id: 14631430,
+ name: 'Alice.si TW + ERC 20 Marketplace',
+ assigneeId: 680302,
+ closeDate: '12/15/2018',
+ companyId: 30238847,
+ companyName: 'Alice SI',
+ customerSourceId: undefined,
+ lossReasonId: undefined,
+ pipelineId: 512676,
+ pipelineStageId: 2392929,
+ primaryContactId: 69354024,
+ priority: 'None',
+ status: 'Open',
+ interactionCount: 4,
+ monetaryValue: undefined,
+ winProbability: 0,
+ dateCreated: 1542304481000,
+ dateModified: 1542304943000,
+ customFields: { '261066': 394015, '261067': 394023 },
+ },
+ {
+ id: 14632057,
+ name: 'Altcoin.io Relayer',
+ assigneeId: 680302,
+ closeDate: '12/15/2018',
+ companyId: 29936486,
+ companyName: 'Altcoin.io',
+ customerSourceId: undefined,
+ lossReasonId: undefined,
+ pipelineId: 512676,
+ pipelineStageId: 2392929,
+ primaryContactId: 68724646,
+ priority: 'None',
+ status: 'Open',
+ interactionCount: 22,
+ monetaryValue: undefined,
+ winProbability: 0,
+ dateCreated: 1542306827000,
+ dateModified: 1543864667000,
+ customFields: { '261066': 394017, '261067': 394023 },
+ },
+ {
+ id: 14667523,
+ name: 'Altcoin.io Relayer',
+ assigneeId: 680302,
+ closeDate: '12/19/2018',
+ companyId: 29936486,
+ companyName: 'Altcoin.io',
+ customerSourceId: undefined,
+ lossReasonId: undefined,
+ pipelineId: 512676,
+ pipelineStageId: 2392929,
+ primaryContactId: 68724646,
+ priority: 'None',
+ status: 'Open',
+ interactionCount: 21,
+ monetaryValue: undefined,
+ winProbability: 0,
+ dateCreated: 1542657437000,
+ dateModified: 1543864667000,
+ customFields: { '261066': 394017, '261067': 394023 },
+ },
+ {
+ id: 14666706,
+ name: 'Amadeus Relayer',
+ assigneeId: 680302,
+ closeDate: '11/19/2018',
+ companyId: 29243209,
+ companyName: 'Amadeus',
+ customerSourceId: undefined,
+ lossReasonId: undefined,
+ pipelineId: 512676,
+ pipelineStageId: 2405442,
+ primaryContactId: 66912020,
+ priority: 'None',
+ status: 'Won',
+ interactionCount: 11,
+ monetaryValue: undefined,
+ winProbability: 0,
+ dateCreated: 1542654284000,
+ dateModified: 1543277520000,
+ customFields: { '261066': 394013, '261067': 394023 },
+ },
+ {
+ id: 14666718,
+ name: 'Ambo Relayer',
+ assigneeId: 680302,
+ closeDate: '11/19/2018',
+ companyId: 29249190,
+ companyName: 'Ambo',
+ customerSourceId: undefined,
+ lossReasonId: undefined,
+ pipelineId: 512676,
+ pipelineStageId: 2405442,
+ primaryContactId: 66927869,
+ priority: 'None',
+ status: 'Won',
+ interactionCount: 126,
+ monetaryValue: undefined,
+ winProbability: 0,
+ dateCreated: 1542654352000,
+ dateModified: 1545253761000,
+ customFields: { '261066': 394013, '261067': 394023 },
+ },
+ {
+ id: 14164318,
+ name: 'Augur TW',
+ assigneeId: 680302,
+ closeDate: '12/10/2018',
+ companyId: 27778967,
+ companyName: 'Augur',
+ customerSourceId: undefined,
+ lossReasonId: undefined,
+ pipelineId: 512676,
+ pipelineStageId: 2405442,
+ primaryContactId: 67248692,
+ priority: 'None',
+ status: 'Won',
+ interactionCount: 22,
+ monetaryValue: undefined,
+ winProbability: 0,
+ dateCreated: 1539204858000,
+ dateModified: 1544653867000,
+ customFields: { '261066': 394015, '261067': 394021 },
+ },
+ {
+ id: 14666626,
+ name: 'Autonio',
+ assigneeId: 680302,
+ closeDate: '12/19/2018',
+ companyId: 27920701,
+ companyName: 'Auton',
+ customerSourceId: undefined,
+ lossReasonId: undefined,
+ pipelineId: 512676,
+ pipelineStageId: 2392931,
+ primaryContactId: 64742640,
+ priority: 'None',
+ status: 'Open',
+ interactionCount: 54,
+ monetaryValue: undefined,
+ winProbability: 0,
+ dateCreated: 1542653834000,
+ dateModified: 1542658808000,
+ customFields: { '261066': 394019, '261067': 394023 },
+ },
+ {
+ id: 14050921,
+ name: 'Axie Infinity 721 Marketplace',
+ assigneeId: 680302,
+ closeDate: '11/1/2018',
+ companyId: 27779033,
+ companyName: 'Axie Infinity',
+ customerSourceId: undefined,
+ lossReasonId: undefined,
+ pipelineId: 512676,
+ pipelineStageId: 2392931,
+ primaryContactId: 66499254,
+ priority: 'None',
+ status: 'Open',
+ interactionCount: 4,
+ monetaryValue: undefined,
+ winProbability: 0,
+ dateCreated: 1538416687000,
+ dateModified: 1543861025000,
+ customFields: { '261066': 394014, '261067': 394134 },
+ },
+ {
+ id: 13735617,
+ name: 'Balance TW',
+ assigneeId: 680302,
+ closeDate: '12/10/2018',
+ companyId: 27778968,
+ companyName: 'Balance',
+ customerSourceId: undefined,
+ lossReasonId: undefined,
+ pipelineId: 512676,
+ pipelineStageId: 2405442,
+ primaryContactId: 64713448,
+ priority: 'None',
+ status: 'Won',
+ interactionCount: 34,
+ monetaryValue: undefined,
+ winProbability: 0,
+ dateCreated: 1535668009000,
+ dateModified: 1545082454000,
+ customFields: { '261066': 394015, '261067': 394027 },
+ },
+ {
+ id: 14667112,
+ name: 'Bamboo Relayer',
+ assigneeId: 680302,
+ closeDate: '11/19/2018',
+ companyId: 29243795,
+ companyName: 'Bamboo Relay',
+ customerSourceId: undefined,
+ lossReasonId: undefined,
+ pipelineId: 512676,
+ pipelineStageId: 2405442,
+ primaryContactId: 66914687,
+ priority: 'None',
+ status: 'Won',
+ interactionCount: 46,
+ monetaryValue: undefined,
+ winProbability: 0,
+ dateCreated: 1542655143000,
+ dateModified: 1545253761000,
+ customFields: { '261066': 394013, '261067': 394023 },
+ },
+ {
+ id: 13627309,
+ name: 'Ben TW',
+ assigneeId: 680302,
+ closeDate: '1/1/2019',
+ companyId: 27702348,
+ companyName: 'Ben',
+ customerSourceId: undefined,
+ lossReasonId: undefined,
+ pipelineId: 512676,
+ pipelineStageId: 2392929,
+ primaryContactId: 64262622,
+ priority: 'None',
+ status: 'Open',
+ interactionCount: 64,
+ monetaryValue: undefined,
+ winProbability: 0,
+ dateCreated: 1534887789000,
+ dateModified: 1541651395000,
+ customFields: { '261066': 394015, '261067': 394027 },
+ },
+ {
+ id: 14808512,
+ name: 'Bit2Me Relayer',
+ assigneeId: 680302,
+ closeDate: '12/3/2018',
+ companyId: 30793050,
+ companyName: 'Bit2Me',
+ customerSourceId: undefined,
+ lossReasonId: undefined,
+ pipelineId: 512676,
+ pipelineStageId: 2405442,
+ primaryContactId: 70267217,
+ priority: 'None',
+ status: 'Won',
+ interactionCount: 0,
+ monetaryValue: undefined,
+ winProbability: 0,
+ dateCreated: 1543861167000,
+ dateModified: 1543861189000,
+ customFields: { '261066': 394013, '261067': 394023 },
+ },
+ {
+ id: 14050312,
+ name: 'Bitcoin.tax Reporting Integration',
+ assigneeId: 680302,
+ closeDate: '11/1/2018',
+ companyId: 27957614,
+ companyName: 'Bitcoin',
+ customerSourceId: undefined,
+ lossReasonId: undefined,
+ pipelineId: 512676,
+ pipelineStageId: 2392928,
+ primaryContactId: 66539479,
+ priority: 'None',
+ status: 'Open',
+ interactionCount: 5,
+ monetaryValue: undefined,
+ winProbability: 0,
+ dateCreated: 1538414308000,
+ dateModified: 1538414314000,
+ customFields: { '261066': 394019, '261067': 394026 },
+ },
+ {
+ id: 14331463,
+ name: 'Bitpie TW',
+ assigneeId: 680302,
+ closeDate: '11/19/2018',
+ companyId: 27779026,
+ companyName: 'Bitpie',
+ customerSourceId: undefined,
+ lossReasonId: undefined,
+ pipelineId: 512676,
+ pipelineStageId: 2392929,
+ primaryContactId: 67700943,
+ priority: 'None',
+ status: 'Open',
+ interactionCount: 9,
+ monetaryValue: undefined,
+ winProbability: 0,
+ dateCreated: 1539984566000,
+ dateModified: 1541530233000,
+ customFields: { '261066': 394015, '261067': 394027 },
+ },
+ {
+ id: 14331481,
+ name: 'Bitski Wallet SDK TW',
+ assigneeId: 680302,
+ closeDate: '11/19/2018',
+ companyId: 29489300,
+ companyName: 'Bitski',
+ customerSourceId: undefined,
+ lossReasonId: undefined,
+ pipelineId: 512676,
+ pipelineStageId: 2392929,
+ primaryContactId: 67697528,
+ priority: 'None',
+ status: 'Open',
+ interactionCount: 23,
+ monetaryValue: undefined,
+ winProbability: 0,
+ dateCreated: 1539984735000,
+ dateModified: 1544818605000,
+ customFields: { '261066': 394015, '261067': 394026 },
+ },
+ {
+ id: 14531554,
+ name: 'BitUniverse TW',
+ assigneeId: 680302,
+ closeDate: '12/6/2018',
+ companyId: 29901805,
+ companyName: 'BitUniverse Co., Ltd (Cryptocurrency Portfolio)',
+ customerSourceId: undefined,
+ lossReasonId: undefined,
+ pipelineId: 512676,
+ pipelineStageId: 2392929,
+ primaryContactId: 68692107,
+ priority: 'None',
+ status: 'Open',
+ interactionCount: 15,
+ monetaryValue: undefined,
+ winProbability: 0,
+ dateCreated: 1541527110000,
+ dateModified: 1544812979000,
+ customFields: { '261066': 394015, '261067': 394026 },
+ },
+ {
+ id: 14050895,
+ name: 'BlitzPredict PMR',
+ assigneeId: 680302,
+ closeDate: '11/1/2018',
+ companyId: 28758258,
+ companyName: 'BlitzPredict',
+ customerSourceId: undefined,
+ lossReasonId: undefined,
+ pipelineId: 512676,
+ pipelineStageId: 2392929,
+ primaryContactId: 66378659,
+ priority: 'None',
+ status: 'Open',
+ interactionCount: 32,
+ monetaryValue: undefined,
+ winProbability: 0,
+ dateCreated: 1538416597000,
+ dateModified: 1544830709000,
+ customFields: { '261066': 394016, '261067': 394023 },
+ },
+ {
+ id: 14209841,
+ name: 'Blockfolio TW',
+ assigneeId: 680302,
+ closeDate: '11/15/2018',
+ companyId: 29332516,
+ companyName: 'Blockfolio',
+ customerSourceId: undefined,
+ lossReasonId: undefined,
+ pipelineId: 512676,
+ pipelineStageId: 2405443,
+ primaryContactId: 67247027,
+ priority: 'None',
+ status: 'Open',
+ interactionCount: 20,
+ monetaryValue: undefined,
+ winProbability: 0,
+ dateCreated: 1539624801000,
+ dateModified: 1539984098000,
+ customFields: { '261066': 394015, '261067': 394026 },
+ },
+ {
+ id: 14633220,
+ name: 'BlockSwap 721 / 1155 Conversational Marketplace',
+ assigneeId: 680302,
+ closeDate: '12/15/2018',
+ companyId: 30210921,
+ companyName: 'BlockSwap',
+ customerSourceId: undefined,
+ lossReasonId: undefined,
+ pipelineId: 512676,
+ pipelineStageId: 2392929,
+ primaryContactId: 69296220,
+ priority: 'None',
+ status: 'Open',
+ interactionCount: 82,
+ monetaryValue: undefined,
+ winProbability: 0,
+ dateCreated: 1542311056000,
+ dateModified: 1543557877000,
+ customFields: { '261066': 394014, '261067': 394023 },
+ },
+];
+export { ParsedOpportunities };
diff --git a/packages/pipeline/test/fixtures/copper/parsed_entities.ts b/packages/pipeline/test/fixtures/copper/parsed_entities.ts
new file mode 100644
index 000000000..1f49d38ed
--- /dev/null
+++ b/packages/pipeline/test/fixtures/copper/parsed_entities.ts
@@ -0,0 +1,5 @@
+export { ParsedActivityTypes } from './api_v1_activity_types';
+export { ParsedCustomFields } from './api_v1_custom_field_definitions';
+export { ParsedActivities } from './api_v1_list_activities';
+export { ParsedLeads } from './api_v1_list_leads';
+export { ParsedOpportunities } from './api_v1_list_opportunities';
diff --git a/packages/pipeline/test/parsers/copper/index_test.ts b/packages/pipeline/test/parsers/copper/index_test.ts
new file mode 100644
index 000000000..bb8e70da1
--- /dev/null
+++ b/packages/pipeline/test/parsers/copper/index_test.ts
@@ -0,0 +1,87 @@
+import * as chai from 'chai';
+import 'mocha';
+
+import {
+ CopperActivity,
+ CopperActivityType,
+ CopperCustomField,
+ CopperLead,
+ CopperOpportunity,
+} from '../../../src/entities';
+import {
+ CopperActivityResponse,
+ CopperActivityTypeCategory,
+ CopperActivityTypeResponse,
+ CopperCustomFieldResponse,
+ CopperSearchResponse,
+ parseActivities,
+ parseActivityTypes,
+ parseCustomFields,
+ parseLeads,
+ parseOpportunities,
+} from '../../../src/parsers/copper';
+import { chaiSetup } from '../../utils/chai_setup';
+
+chaiSetup.configure();
+const expect = chai.expect;
+
+type CopperResponse = CopperSearchResponse | CopperCustomFieldResponse;
+type CopperEntity = CopperLead | CopperActivity | CopperOpportunity | CopperActivityType | CopperCustomField;
+
+import * as activityTypesApiResponse from '../../fixtures/copper/api_v1_activity_types.json';
+import * as customFieldsApiResponse from '../../fixtures/copper/api_v1_custom_field_definitions.json';
+import * as listActivitiesApiResponse from '../../fixtures/copper/api_v1_list_activities.json';
+import * as listLeadsApiResponse from '../../fixtures/copper/api_v1_list_leads.json';
+import * as listOpportunitiesApiResponse from '../../fixtures/copper/api_v1_list_opportunities.json';
+import {
+ ParsedActivities,
+ ParsedActivityTypes,
+ ParsedCustomFields,
+ ParsedLeads,
+ ParsedOpportunities,
+} from '../../fixtures/copper/parsed_entities';
+
+interface TestCase {
+ input: CopperResponse[];
+ expected: CopperEntity[];
+ parseFn(input: CopperResponse[]): CopperEntity[];
+}
+const testCases: TestCase[] = [
+ {
+ input: listLeadsApiResponse,
+ expected: ParsedLeads,
+ parseFn: parseLeads,
+ },
+ {
+ input: (listActivitiesApiResponse as unknown) as CopperActivityResponse[],
+ expected: ParsedActivities,
+ parseFn: parseActivities,
+ },
+ {
+ input: listOpportunitiesApiResponse,
+ expected: ParsedOpportunities,
+ parseFn: parseOpportunities,
+ },
+ {
+ input: customFieldsApiResponse,
+ expected: ParsedCustomFields,
+ parseFn: parseCustomFields,
+ },
+];
+describe('Copper parser', () => {
+ it('parses API responses', () => {
+ testCases.forEach(testCase => {
+ const actual: CopperEntity[] = testCase.parseFn(testCase.input);
+ expect(actual).deep.equal(testCase.expected);
+ });
+ });
+
+ // special case because the API response is not an array
+ it('parses activity types API response', () => {
+ const actual: CopperActivityType[] = parseActivityTypes((activityTypesApiResponse as unknown) as Map<
+ CopperActivityTypeCategory,
+ CopperActivityTypeResponse[]
+ >);
+ expect(actual).deep.equal(ParsedActivityTypes);
+ });
+});
diff --git a/packages/pipeline/test/parsers/ddex_orders/index_test.ts b/packages/pipeline/test/parsers/ddex_orders/index_test.ts
index 4a4a86bf8..f30e86b02 100644
--- a/packages/pipeline/test/parsers/ddex_orders/index_test.ts
+++ b/packages/pipeline/test/parsers/ddex_orders/index_test.ts
@@ -31,13 +31,13 @@ describe('ddex_orders', () => {
amountDecimals: 0,
};
const observedTimestamp: number = Date.now();
- const orderType: OrderType = 'bid';
+ const orderType: OrderType = OrderType.Bid;
const source: string = 'ddex';
const expected = new TokenOrder();
expected.source = 'ddex';
expected.observedTimestamp = observedTimestamp;
- expected.orderType = 'bid';
+ expected.orderType = OrderType.Bid;
expected.price = new BigNumber(0.5);
// ddex currently confuses base and quote assets.
// Switch them to maintain our internal consistency.
diff --git a/packages/pipeline/test/parsers/events/exchange_events_test.ts b/packages/pipeline/test/parsers/events/exchange_events_test.ts
index 5d4b185a5..956ad9ef8 100644
--- a/packages/pipeline/test/parsers/events/exchange_events_test.ts
+++ b/packages/pipeline/test/parsers/events/exchange_events_test.ts
@@ -6,6 +6,7 @@ import 'mocha';
import { ExchangeFillEvent } from '../../../src/entities';
import { _convertToExchangeFillEvent } from '../../../src/parsers/events/exchange_events';
+import { AssetType } from '../../../src/types';
import { chaiSetup } from '../../utils/chai_setup';
chaiSetup.configure();
@@ -62,12 +63,12 @@ describe('exchange_events', () => {
expected.takerFeePaid = new BigNumber('12345');
expected.orderHash = '0xab12ed2cbaa5615ab690b9da75a46e53ddfcf3f1a68655b5fe0d94c75a1aac4a';
expected.rawMakerAssetData = '0xf47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
- expected.makerAssetType = 'erc20';
+ expected.makerAssetType = AssetType.ERC20;
expected.makerAssetProxyId = '0xf47261b0';
expected.makerTokenAddress = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
expected.makerTokenId = null;
expected.rawTakerAssetData = '0xf47261b0000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498';
- expected.takerAssetType = 'erc20';
+ expected.takerAssetType = AssetType.ERC20;
expected.takerAssetProxyId = '0xf47261b0';
expected.takerTokenAddress = '0xe41d2489571d322189246dafa5ebde1f4699f498';
expected.takerTokenId = null;
diff --git a/packages/pipeline/test/parsers/idex_orders/index_test.ts b/packages/pipeline/test/parsers/idex_orders/index_test.ts
index d54ecb9a8..48b019732 100644
--- a/packages/pipeline/test/parsers/idex_orders/index_test.ts
+++ b/packages/pipeline/test/parsers/idex_orders/index_test.ts
@@ -31,13 +31,13 @@ describe('idex_orders', () => {
user: '0x212345667543456435324564345643453453333',
};
const observedTimestamp: number = Date.now();
- const orderType: OrderType = 'bid';
+ const orderType: OrderType = OrderType.Bid;
const source: string = 'idex';
const expected = new TokenOrder();
expected.source = 'idex';
expected.observedTimestamp = observedTimestamp;
- expected.orderType = 'bid';
+ expected.orderType = OrderType.Bid;
expected.price = new BigNumber(0.5);
expected.baseAssetSymbol = 'ABC';
expected.baseAssetAddress = '0x0000000000000000000000000000000000000000';
@@ -65,13 +65,13 @@ describe('idex_orders', () => {
user: '0x212345667543456435324564345643453453333',
};
const observedTimestamp: number = Date.now();
- const orderType: OrderType = 'ask';
+ const orderType: OrderType = OrderType.Ask;
const source: string = 'idex';
const expected = new TokenOrder();
expected.source = 'idex';
expected.observedTimestamp = observedTimestamp;
- expected.orderType = 'ask';
+ expected.orderType = OrderType.Ask;
expected.price = new BigNumber(0.5);
expected.baseAssetSymbol = 'ABC';
expected.baseAssetAddress = '0x0000000000000000000000000000000000000000';
diff --git a/packages/pipeline/test/parsers/oasis_orders/index_test.ts b/packages/pipeline/test/parsers/oasis_orders/index_test.ts
index 433bfb665..401fedff8 100644
--- a/packages/pipeline/test/parsers/oasis_orders/index_test.ts
+++ b/packages/pipeline/test/parsers/oasis_orders/index_test.ts
@@ -27,13 +27,13 @@ describe('oasis_orders', () => {
low: 0,
};
const observedTimestamp: number = Date.now();
- const orderType: OrderType = 'bid';
+ const orderType: OrderType = OrderType.Bid;
const source: string = 'oasis';
const expected = new TokenOrder();
expected.source = 'oasis';
expected.observedTimestamp = observedTimestamp;
- expected.orderType = 'bid';
+ expected.orderType = OrderType.Bid;
expected.price = new BigNumber(0.5);
expected.baseAssetSymbol = 'DEF';
expected.baseAssetAddress = null;
diff --git a/packages/pipeline/test/parsers/paradex_orders/index_test.ts b/packages/pipeline/test/parsers/paradex_orders/index_test.ts
index 6b811b90d..c5dd8751b 100644
--- a/packages/pipeline/test/parsers/paradex_orders/index_test.ts
+++ b/packages/pipeline/test/parsers/paradex_orders/index_test.ts
@@ -32,13 +32,13 @@ describe('paradex_orders', () => {
quoteTokenAddress: '0x0000000000000000000000000000000000000000',
};
const observedTimestamp: number = Date.now();
- const orderType: OrderType = 'bid';
+ const orderType: OrderType = OrderType.Bid;
const source: string = 'paradex';
const expected = new TokenOrder();
expected.source = 'paradex';
expected.observedTimestamp = observedTimestamp;
- expected.orderType = 'bid';
+ expected.orderType = OrderType.Bid;
expected.price = new BigNumber(0.1245);
expected.baseAssetSymbol = 'DEF';
expected.baseAssetAddress = '0xb45df06e38540a675fdb5b598abf2c0dbe9d6b81';
diff --git a/packages/pipeline/test/parsers/sra_orders/index_test.ts b/packages/pipeline/test/parsers/sra_orders/index_test.ts
index ee2842ef3..838171a72 100644
--- a/packages/pipeline/test/parsers/sra_orders/index_test.ts
+++ b/packages/pipeline/test/parsers/sra_orders/index_test.ts
@@ -5,6 +5,7 @@ import 'mocha';
import { SraOrder } from '../../../src/entities';
import { _convertToEntity } from '../../../src/parsers/sra_orders';
+import { AssetType } from '../../../src/types';
import { chaiSetup } from '../../utils/chai_setup';
chaiSetup.configure();
@@ -50,12 +51,12 @@ describe('sra_orders', () => {
expected.signature =
'0x1b5a5d672b0d647b5797387ccbb89d822d5d2e873346b014f4ff816ff0783f2a7a0d2824d2d7042ec8ea375bc7f870963e1cb8248f1db03ddf125e27b5963aa11f03';
expected.rawMakerAssetData = '0xf47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
- expected.makerAssetType = 'erc20';
+ expected.makerAssetType = AssetType.ERC20;
expected.makerAssetProxyId = '0xf47261b0';
expected.makerTokenAddress = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
expected.makerTokenId = null;
expected.rawTakerAssetData = '0xf47261b000000000000000000000000042d6622dece394b54999fbd73d108123806f6a18';
- expected.takerAssetType = 'erc20';
+ expected.takerAssetType = AssetType.ERC20;
expected.takerAssetProxyId = '0xf47261b0';
expected.takerTokenAddress = '0x42d6622dece394b54999fbd73d108123806f6a18';
expected.takerTokenId = null;
diff --git a/packages/pipeline/tsconfig.json b/packages/pipeline/tsconfig.json
index 6f138f260..45e07374c 100644
--- a/packages/pipeline/tsconfig.json
+++ b/packages/pipeline/tsconfig.json
@@ -4,7 +4,15 @@
"outDir": "lib",
"rootDir": ".",
"emitDecoratorMetadata": true,
- "experimentalDecorators": true
+ "experimentalDecorators": true,
+ "resolveJsonModule": true
},
- "include": ["./src/**/*", "./test/**/*", "./migrations/**/*"]
+ "include": ["./src/**/*", "./test/**/*", "./migrations/**/*"],
+ "files": [
+ "./test/fixtures/copper/api_v1_activity_types.json",
+ "./test/fixtures/copper/api_v1_custom_field_definitions.json",
+ "./test/fixtures/copper/api_v1_list_activities.json",
+ "./test/fixtures/copper/api_v1_list_leads.json",
+ "./test/fixtures/copper/api_v1_list_opportunities.json"
+ ]
}
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/sra-spec/public/index.html b/packages/sra-spec/public/index.html
index e75ae7f04..5271b50c6 100644
--- a/packages/sra-spec/public/index.html
+++ b/packages/sra-spec/public/index.html
@@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
- <title>ReDoc</title>
+ <title>0x Standard Relayer API</title>
<!-- needed for adaptive design -->
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
@@ -21,4 +21,4 @@
<redoc spec-url='http://sra-spec.s3-website-us-east-1.amazonaws.com/api.json'></redoc>
<script src="https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js"> </script>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/packages/types/CHANGELOG.json b/packages/types/CHANGELOG.json
index f1cd2f18e..7094953cb 100644
--- a/packages/types/CHANGELOG.json
+++ b/packages/types/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "1.5.0",
+ "changes": [
+ {
+ "note": "Added types for Dutch Auction contract",
+ "pr": 1465
+ }
+ ]
+ },
+ {
"version": "1.4.1",
"changes": [
{
@@ -18,6 +27,10 @@
{
"note": "Add RevertReasons for DutchAuction contract",
"pr": 1225
+ },
+ {
+ "note": "Add MultiAsset types",
+ "pr": 1363
}
],
"timestamp": 1544570656
diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts
index 6b728af71..49f788fb0 100644
--- a/packages/types/src/index.ts
+++ b/packages/types/src/index.ts
@@ -110,7 +110,9 @@ export type DoneCallback = (err?: Error) => void;
export interface OrderRelevantState {
makerBalance: BigNumber;
+ makerIndividualBalances: ObjectMap<BigNumber>;
makerProxyAllowance: BigNumber;
+ makerIndividualProxyAllowances: ObjectMap<BigNumber>;
makerFeeBalance: BigNumber;
makerFeeProxyAllowance: BigNumber;
filledTakerAssetAmount: BigNumber;
@@ -155,6 +157,7 @@ export enum SignatureType {
export enum AssetProxyId {
ERC20 = '0xf47261b0',
ERC721 = '0x02571792',
+ MultiAsset = '0x94cfcdd7',
}
export interface ERC20AssetData {
@@ -168,7 +171,21 @@ export interface ERC721AssetData {
tokenId: BigNumber;
}
-export type AssetData = ERC20AssetData | ERC721AssetData;
+export type SingleAssetData = ERC20AssetData | ERC721AssetData;
+
+export interface MultiAssetData {
+ assetProxyId: string;
+ amounts: BigNumber[];
+ nestedAssetData: string[];
+}
+
+export interface MultiAssetDataWithRecursiveDecoding {
+ assetProxyId: string;
+ amounts: BigNumber[];
+ nestedAssetData: SingleAssetData[];
+}
+
+export type AssetData = SingleAssetData | MultiAssetData | MultiAssetDataWithRecursiveDecoding;
// TODO: DRY. These should be extracted from contract code.
export enum RevertReason {
@@ -243,6 +260,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 {
@@ -655,3 +676,12 @@ export interface SimpleEvmOutput {
export interface SimpleEvmBytecodeOutput {
object: string;
}
+
+export interface DutchAuctionDetails {
+ beginTimeSeconds: BigNumber;
+ endTimeSeconds: BigNumber;
+ beginAmount: BigNumber;
+ endAmount: BigNumber;
+ currentAmount: BigNumber;
+ currentTimeSeconds: BigNumber;
+}
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..eb94da8d6 100644
--- a/packages/utils/CHANGELOG.json
+++ b/packages/utils/CHANGELOG.json
@@ -1,5 +1,23 @@
[
{
+ "version": "2.1.1",
+ "changes": [
+ {
+ "note": "Add `should` prefix to names of properties in EncodingRules and DecodingRules",
+ "pr": 1363
+ }
+ ]
+ },
+ {
+ "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/abi_encoder/abstract_data_types/types/set.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
index 089d04659..00059a4b6 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
@@ -62,7 +62,7 @@ export abstract class AbstractSetDataType extends DataType {
// Create a new scope in the calldata, before descending into the members of this set.
calldata.startScope();
let value: any[] | object;
- if (rules.structsAsObjects && !this._isArray) {
+ if (rules.shouldConvertStructsToObjects && !this._isArray) {
// Construct an object with values for each member of the set.
value = {};
_.each(this._memberIndexByName, (idx: number, key: string) => {
diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts
index 5f3eee94a..b08fb71ce 100644
--- a/packages/utils/src/abi_encoder/calldata/calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata/calldata.ts
@@ -49,7 +49,7 @@ export class Calldata {
throw new Error('expected root');
}
// Optimize, if flag set
- if (this._rules.optimize) {
+ if (this._rules.shouldOptimize) {
this._optimize();
}
// Set offsets
@@ -60,7 +60,9 @@ export class Calldata {
offset += block.getSizeInBytes();
}
// Generate hex string
- const hexString = this._rules.annotate ? this._toHumanReadableCallData() : this._toEvmCompatibeCallDataHex();
+ const hexString = this._rules.shouldAnnotate
+ ? this._toHumanReadableCallData()
+ : this._toEvmCompatibeCallDataHex();
return hexString;
}
/**
diff --git a/packages/utils/src/abi_encoder/utils/constants.ts b/packages/utils/src/abi_encoder/utils/constants.ts
index 2f43ba04d..36de2dd4f 100644
--- a/packages/utils/src/abi_encoder/utils/constants.ts
+++ b/packages/utils/src/abi_encoder/utils/constants.ts
@@ -11,7 +11,7 @@ export const constants = {
HEX_SELECTOR_BYTE_OFFSET_IN_CALLDATA: 0,
// Disable no-object-literal-type-assertion so we can enforce cast
/* tslint:disable no-object-literal-type-assertion */
- DEFAULT_DECODING_RULES: { structsAsObjects: false } as DecodingRules,
- DEFAULT_ENCODING_RULES: { optimize: true, annotate: false } as EncodingRules,
+ DEFAULT_DECODING_RULES: { shouldConvertStructsToObjects: false } as DecodingRules,
+ DEFAULT_ENCODING_RULES: { shouldOptimize: true, shouldAnnotate: false } as EncodingRules,
/* tslint:enable no-object-literal-type-assertion */
};
diff --git a/packages/utils/src/abi_encoder/utils/rules.ts b/packages/utils/src/abi_encoder/utils/rules.ts
index 31471e97a..c8d83c3ba 100644
--- a/packages/utils/src/abi_encoder/utils/rules.ts
+++ b/packages/utils/src/abi_encoder/utils/rules.ts
@@ -1,8 +1,8 @@
export interface DecodingRules {
- structsAsObjects: boolean;
+ shouldConvertStructsToObjects: boolean;
}
export interface EncodingRules {
- optimize?: boolean;
- annotate?: boolean;
+ shouldOptimize?: boolean;
+ shouldAnnotate?: boolean;
}
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/utils/test/abi_encoder/evm_data_types_test.ts b/packages/utils/test/abi_encoder/evm_data_types_test.ts
index 7185851a8..55d582d10 100644
--- a/packages/utils/test/abi_encoder/evm_data_types_test.ts
+++ b/packages/utils/test/abi_encoder/evm_data_types_test.ts
@@ -10,7 +10,7 @@ chaiSetup.configure();
const expect = chai.expect;
describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
- const encodingRules: AbiEncoder.EncodingRules = { optimize: false }; // optimizer is tested separately.
+ const encodingRules: AbiEncoder.EncodingRules = { shouldOptimize: false }; // optimizer is tested separately.
describe('Array', () => {
it('Fixed size; Static elements', async () => {
// Create DataType object
@@ -194,7 +194,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
'0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0000000000000000000000000000000000000000000000000000000000000001';
expect(encodedArgs).to.be.equal(expectedEncodedArgs);
// Decode Encoded Args and validate result
- const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
+ const decodingRules: AbiEncoder.DecodingRules = { shouldConvertStructsToObjects: true };
const decodedArgs = dataType.decode(encodedArgs, decodingRules);
expect(decodedArgs).to.be.deep.equal(args);
});
@@ -214,7 +214,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
'0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c6421000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008abcdef0123456789000000000000000000000000000000000000000000000000';
expect(encodedArgs).to.be.equal(expectedEncodedArgs);
// Decode Encoded Args and validate result
- const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
+ const decodingRules: AbiEncoder.DecodingRules = { shouldConvertStructsToObjects: true };
const decodedArgs = dataType.decode(encodedArgs, decodingRules);
expect(decodedArgs).to.be.deep.equal(args);
});
@@ -234,7 +234,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
'0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002';
expect(encodedArgs).to.be.equal(expectedEncodedArgs);
// Decode Encoded Args and validate result
- const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
+ const decodingRules: AbiEncoder.DecodingRules = { shouldConvertStructsToObjects: true };
const decodedArgs = dataType.decode(encodedArgs, decodingRules);
expect(decodedArgs).to.be.deep.equal(args);
});
@@ -254,7 +254,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
'0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002';
expect(encodedArgs).to.be.equal(expectedEncodedArgs);
// Decode Encoded Args and validate result
- const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
+ const decodingRules: AbiEncoder.DecodingRules = { shouldConvertStructsToObjects: true };
const decodedArgs = dataType.decode(encodedArgs, decodingRules);
expect(decodedArgs).to.be.deep.equal(args);
});
@@ -276,7 +276,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
'0x0102030400000000000000000000000000000000000000000000000000000000050607080000000000000000000000000000000000000000000000000000000009101112000000000000000000000000000000000000000000000000000000001314151600000000000000000000000000000000000000000000000000000000';
expect(encodedArgs).to.be.equal(expectedEncodedArgs);
// Decode Encoded Args and validate result
- const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
+ const decodingRules: AbiEncoder.DecodingRules = { shouldConvertStructsToObjects: true };
const decodedArgs = dataType.decode(encodedArgs, decodingRules);
expect(decodedArgs).to.be.deep.equal(args);
});
@@ -298,7 +298,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
'0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004010203040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040506070800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004091011120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041314151600000000000000000000000000000000000000000000000000000000';
expect(encodedArgs).to.be.equal(expectedEncodedArgs);
// Decode Encoded Args and validate result
- const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
+ const decodingRules: AbiEncoder.DecodingRules = { shouldConvertStructsToObjects: true };
const decodedArgs = dataType.decode(encodedArgs, decodingRules);
expect(decodedArgs).to.be.deep.equal(args);
});
@@ -328,7 +328,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
'0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c6421000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008abcdef0123456789000000000000000000000000000000000000000000000000';
expect(encodedArgs).to.be.equal(expectedEncodedArgs);
// Decode Encoded Args and validate result
- const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
+ const decodingRules: AbiEncoder.DecodingRules = { shouldConvertStructsToObjects: true };
const decodedArgs = dataType.decode(encodedArgs, decodingRules);
expect(decodedArgs).to.be.deep.equal(args);
});
diff --git a/packages/utils/test/abi_encoder/methods_test.ts b/packages/utils/test/abi_encoder/methods_test.ts
index 837020883..a0525967e 100644
--- a/packages/utils/test/abi_encoder/methods_test.ts
+++ b/packages/utils/test/abi_encoder/methods_test.ts
@@ -10,7 +10,7 @@ chaiSetup.configure();
const expect = chai.expect;
describe('ABI Encoder: Method Encoding / Decoding', () => {
- const encodingRules: AbiEncoder.EncodingRules = { optimize: false }; // optimizer is tested separately.
+ const encodingRules: AbiEncoder.EncodingRules = { shouldOptimize: false }; // optimizer is tested separately.
it('Types with default widths', async () => {
// Generate calldata
const method = new AbiEncoder.Method(AbiSamples.typesWithDefaultWidthsAbi);
@@ -360,7 +360,7 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
'0x4b49031c000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009800000000000000000000000000000000000000000000000000000000000000ae0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000163874563783498732482743928742389723894723984700000000000000000000000000000000000000000000000000000000000000000000000000000000006e72834723982374239847239847298472489274987489742847289472394874987498478743294237434923473298472398423748923748923748923472389472894789474893742894728947389427498237432987423894723894732894723894372498237498237428934723980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027283473298473248923749238742398742398472894729843278942374982374892374892743982000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000b736f6d6520737472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013736f6d6520616e6f7468657220737472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024746865726520617265206a75737420746f6f206d616e7920737472696e6773757020696e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002079616c6c2067686f6e6e61206d616b65206d65206c6f7365206d79206d696e640000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0ac511500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003d69d500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000000000000004e616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002829384723894723843743289742389472398473289472348927489274894738427428947389facdea0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000089b51500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000746dafa5ebde1f4699f4981d3221892e41d24895000000000000000000000000000000000000000000000000000000000000004e6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002829384723894398473289472348927489272384374328974238947274894738427428947389facde100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fa3150000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000089571d322189e415ebde1f4699f498d24246dafa000000000000000000000000000000000000000000000000000000000000004e73646873616a6b646873616a6b646861646a6b617368646a616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b6b73616468616a6b646873616a6b64687361646a6b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002838947238437432829384729742389472398473289472348927489274894738427428947389facdef000000000000000000000000000000000000000000000000';
expect(calldata).to.be.equal(expectedCalldata);
// Validate decoding
- const decodedValue = method.decode(calldata, { structsAsObjects: true });
+ const decodedValue = method.decode(calldata, { shouldConvertStructsToObjects: true });
expect(decodedValue).to.be.deep.equal(args);
});
});
diff --git a/packages/utils/test/abi_encoder/optimizer_test.ts b/packages/utils/test/abi_encoder/optimizer_test.ts
index 18aa6549a..ee0654ec3 100644
--- a/packages/utils/test/abi_encoder/optimizer_test.ts
+++ b/packages/utils/test/abi_encoder/optimizer_test.ts
@@ -10,7 +10,7 @@ chaiSetup.configure();
const expect = chai.expect;
describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
- const encodingRules: AbiEncoder.EncodingRules = { optimize: true };
+ const encodingRules: AbiEncoder.EncodingRules = { shouldOptimize: true };
it('Duplicate Dynamic Arrays with Static Elements', async () => {
// Generate calldata
const method = new AbiEncoder.Method(OptimizedAbis.duplicateDynamicArraysWithStaticElements);
@@ -206,7 +206,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
const twoDimArray2 = twoDimArray1;
const args = [twoDimArray1, twoDimArray2];
// Validata calldata
- const optimizedCalldata = method.encode(args, { optimize: false });
+ const optimizedCalldata = method.encode(args, { shouldOptimize: false });
const expectedOptimizedCalldata =
'0x0d28c4f9000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000003466f6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003426172000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035a61610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000003466f6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003426172000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035a61610000000000000000000000000000000000000000000000000000000000';
expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
diff --git a/packages/utils/test/abi_encoder/return_values_test.ts b/packages/utils/test/abi_encoder/return_values_test.ts
index a8cdd6ca3..104c7f5db 100644
--- a/packages/utils/test/abi_encoder/return_values_test.ts
+++ b/packages/utils/test/abi_encoder/return_values_test.ts
@@ -10,7 +10,7 @@ chaiSetup.configure();
const expect = chai.expect;
describe('ABI Encoder: Return Value Encoding/Decoding', () => {
- const encodingRules: AbiEncoder.EncodingRules = { optimize: false }; // optimizer is tested separately.
+ const encodingRules: AbiEncoder.EncodingRules = { shouldOptimize: false }; // optimizer is tested separately.
it('No Return Value', async () => {
// Decode return value
const method = new AbiEncoder.Method(ReturnValueAbis.noReturnValues);
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
new file mode 100644
index 000000000..79c774b40
--- /dev/null
+++ b/packages/website/public/fonts/Formular-Light.woff
Binary files differ
diff --git a/packages/website/public/fonts/Formular-Light.woff2 b/packages/website/public/fonts/Formular-Light.woff2
new file mode 100644
index 000000000..6502d5da1
--- /dev/null
+++ b/packages/website/public/fonts/Formular-Light.woff2
Binary files differ
diff --git a/packages/website/public/fonts/Formular-Regular.woff b/packages/website/public/fonts/Formular-Regular.woff
new file mode 100644
index 000000000..651364b9b
--- /dev/null
+++ b/packages/website/public/fonts/Formular-Regular.woff
Binary files differ
diff --git a/packages/website/public/fonts/Formular-Regular.woff2 b/packages/website/public/fonts/Formular-Regular.woff2
new file mode 100644
index 000000000..91cdbf29f
--- /dev/null
+++ b/packages/website/public/fonts/Formular-Regular.woff2
Binary files differ
diff --git a/packages/website/public/images/0x-instant/0x-instant-widgets.png b/packages/website/public/images/0x-instant/0x-instant-widgets.png
new file mode 100644
index 000000000..707f0eccc
--- /dev/null
+++ b/packages/website/public/images/0x-instant/0x-instant-widgets.png
Binary files differ
diff --git a/packages/website/public/images/0x-instant/0x-instant-widgets@2x.png b/packages/website/public/images/0x-instant/0x-instant-widgets@2x.png
new file mode 100644
index 000000000..35d51387c
--- /dev/null
+++ b/packages/website/public/images/0x-instant/0x-instant-widgets@2x.png
Binary files differ
diff --git a/packages/website/public/images/0x-instant/widget-1.png b/packages/website/public/images/0x-instant/widget-1.png
new file mode 100755
index 000000000..622c1f42c
--- /dev/null
+++ b/packages/website/public/images/0x-instant/widget-1.png
Binary files differ
diff --git a/packages/website/public/images/0x-instant/widget-2.png b/packages/website/public/images/0x-instant/widget-2.png
new file mode 100755
index 000000000..7fec16cfb
--- /dev/null
+++ b/packages/website/public/images/0x-instant/widget-2.png
Binary files differ
diff --git a/packages/website/public/images/0x-instant/widget-3.png b/packages/website/public/images/0x-instant/widget-3.png
new file mode 100755
index 000000000..91ac7d36a
--- /dev/null
+++ b/packages/website/public/images/0x-instant/widget-3.png
Binary files differ
diff --git a/packages/website/public/images/0x-instant/widget-4.png b/packages/website/public/images/0x-instant/widget-4.png
new file mode 100755
index 000000000..3db35e068
--- /dev/null
+++ b/packages/website/public/images/0x-instant/widget-4.png
Binary files differ
diff --git a/packages/website/public/images/0x-instant/widget-5.png b/packages/website/public/images/0x-instant/widget-5.png
new file mode 100755
index 000000000..05cebf28b
--- /dev/null
+++ b/packages/website/public/images/0x-instant/widget-5.png
Binary files differ
diff --git a/packages/website/public/images/0x-instant/widget-6.png b/packages/website/public/images/0x-instant/widget-6.png
new file mode 100755
index 000000000..33def6e04
--- /dev/null
+++ b/packages/website/public/images/0x-instant/widget-6.png
Binary files differ
diff --git a/packages/website/public/images/about/about-office.png b/packages/website/public/images/about/about-office.png
new file mode 100755
index 000000000..432d18a8b
--- /dev/null
+++ b/packages/website/public/images/about/about-office.png
Binary files differ
diff --git a/packages/website/public/images/advisors/david.png b/packages/website/public/images/advisors/david.png
deleted file mode 100644
index 0f87d8935..000000000
--- a/packages/website/public/images/advisors/david.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/advisors/fred.jpg b/packages/website/public/images/advisors/fred.jpg
deleted file mode 100644
index f3b37e2d9..000000000
--- a/packages/website/public/images/advisors/fred.jpg
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/advisors/joey.jpg b/packages/website/public/images/advisors/joey.jpg
deleted file mode 100644
index daccc9b55..000000000
--- a/packages/website/public/images/advisors/joey.jpg
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/advisors/linda.jpg b/packages/website/public/images/advisors/linda.jpg
deleted file mode 100644
index 1ee59d301..000000000
--- a/packages/website/public/images/advisors/linda.jpg
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/advisors/olaf.png b/packages/website/public/images/advisors/olaf.png
deleted file mode 100644
index d1715081f..000000000
--- a/packages/website/public/images/advisors/olaf.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/banner/bottomofcta.png b/packages/website/public/images/banner/bottomofcta.png
new file mode 100644
index 000000000..910022a28
--- /dev/null
+++ b/packages/website/public/images/banner/bottomofcta.png
Binary files differ
diff --git a/packages/website/public/images/banner/topofcta.png b/packages/website/public/images/banner/topofcta.png
new file mode 100644
index 000000000..710c390ab
--- /dev/null
+++ b/packages/website/public/images/banner/topofcta.png
Binary files differ
diff --git a/packages/website/public/images/clients/bamboo.svg b/packages/website/public/images/clients/bamboo.svg
new file mode 100644
index 000000000..702b7d5aa
--- /dev/null
+++ b/packages/website/public/images/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/clients/emoon.svg b/packages/website/public/images/clients/emoon.svg
new file mode 100644
index 000000000..1b14c41b0
--- /dev/null
+++ b/packages/website/public/images/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/clients/ercdex.svg b/packages/website/public/images/clients/ercdex.svg
new file mode 100644
index 000000000..41a0ff3b0
--- /dev/null
+++ b/packages/website/public/images/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/clients/godsUnchained.svg b/packages/website/public/images/clients/godsUnchained.svg
new file mode 100644
index 000000000..f039b00f9
--- /dev/null
+++ b/packages/website/public/images/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/clients/instex.svg b/packages/website/public/images/clients/instex.svg
new file mode 100644
index 000000000..c92033b93
--- /dev/null
+++ b/packages/website/public/images/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/clients/laketrade.svg b/packages/website/public/images/clients/laketrade.svg
new file mode 100644
index 000000000..6ab08bcec
--- /dev/null
+++ b/packages/website/public/images/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/clients/ledgerdex.svg b/packages/website/public/images/clients/ledgerdex.svg
new file mode 100644
index 000000000..44126012e
--- /dev/null
+++ b/packages/website/public/images/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/clients/openrelay.svg b/packages/website/public/images/clients/openrelay.svg
new file mode 100644
index 000000000..21e32cc18
--- /dev/null
+++ b/packages/website/public/images/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/clients/paradex.svg b/packages/website/public/images/clients/paradex.svg
new file mode 100644
index 000000000..e3bdf48b1
--- /dev/null
+++ b/packages/website/public/images/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/clients/radar-relay.svg b/packages/website/public/images/clients/radar-relay.svg
new file mode 100644
index 000000000..ecc759fab
--- /dev/null
+++ b/packages/website/public/images/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/clients/sharkrelay.svg b/packages/website/public/images/clients/sharkrelay.svg
new file mode 100644
index 000000000..41d5376de
--- /dev/null
+++ b/packages/website/public/images/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/clients/starbitex.svg b/packages/website/public/images/clients/starbitex.svg
new file mode 100644
index 000000000..eee21b3fc
--- /dev/null
+++ b/packages/website/public/images/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/clients/tokenjar.svg b/packages/website/public/images/clients/tokenjar.svg
new file mode 100644
index 000000000..f36a6c6aa
--- /dev/null
+++ b/packages/website/public/images/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/clients/veil.svg b/packages/website/public/images/clients/veil.svg
new file mode 100644
index 000000000..b4b36ce57
--- /dev/null
+++ b/packages/website/public/images/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/events/berlin.jpg b/packages/website/public/images/events/berlin.jpg
new file mode 100644
index 000000000..0bcc0fa63
--- /dev/null
+++ b/packages/website/public/images/events/berlin.jpg
Binary files differ
diff --git a/packages/website/public/images/events/event-sample.jpg b/packages/website/public/images/events/event-sample.jpg
new file mode 100644
index 000000000..f7a832a5c
--- /dev/null
+++ b/packages/website/public/images/events/event-sample.jpg
Binary files differ
diff --git a/packages/website/public/images/events/london.jpg b/packages/website/public/images/events/london.jpg
new file mode 100644
index 000000000..4b6b7ef06
--- /dev/null
+++ b/packages/website/public/images/events/london.jpg
Binary files differ
diff --git a/packages/website/public/images/events/sf.jpg b/packages/website/public/images/events/sf.jpg
new file mode 100644
index 000000000..efd7f7c29
--- /dev/null
+++ b/packages/website/public/images/events/sf.jpg
Binary files differ
diff --git a/packages/website/public/images/instant/dai_screenshot.png b/packages/website/public/images/instant/dai_screenshot.png
deleted file mode 100644
index 02aefc909..000000000
--- a/packages/website/public/images/instant/dai_screenshot.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/instant/feature_1.svg b/packages/website/public/images/instant/feature_1.svg
deleted file mode 100644
index cca58d9b9..000000000
--- a/packages/website/public/images/instant/feature_1.svg
+++ /dev/null
@@ -1,33 +0,0 @@
-<svg width="343" height="127" viewBox="0 0 343 127" fill="none" xmlns="http://www.w3.org/2000/svg">
-<circle cx="22" cy="101" r="22" fill="#0057FF"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M15.9276 102.3C16.7747 102.3 17.5795 102.47 18.3419 102.81C19.0873 103.133 19.7396 103.576 20.2986 104.137C20.8577 104.698 21.2982 105.353 21.6201 106.101C21.959 106.867 22.1284 107.675 22.1284 108.525C22.1284 109.392 21.9675 110.2 21.6455 110.949C21.3067 111.697 20.8577 112.356 20.2986 112.926C19.7395 113.496 19.0873 113.942 18.3419 114.265C17.5795 114.588 16.7747 114.75 15.9276 114.75C15.0635 114.75 14.2589 114.588 13.5133 114.265C12.7679 113.942 12.1114 113.496 11.5438 112.926C10.9763 112.356 10.5315 111.697 10.2096 110.949C9.88772 110.2 9.72677 109.392 9.72677 108.525C9.72677 107.675 9.88772 106.867 10.2096 106.101C10.5315 105.353 10.9763 104.698 11.5438 104.137C12.1114 103.576 12.7679 103.125 13.5133 102.785C14.2588 102.462 15.0635 102.3 15.9276 102.3ZM15.9276 112.582C17.0289 112.582 17.9734 112.186 18.7612 111.395C19.549 110.604 19.9429 109.648 19.9429 108.525C19.9429 107.42 19.549 106.471 18.7612 105.68C17.9734 104.89 17.0288 104.494 15.9276 104.494C14.8094 104.494 13.8564 104.89 13.0686 105.68C12.2807 106.471 11.8868 107.42 11.8868 108.525C11.8868 109.648 12.2807 110.604 13.0686 111.395C13.8564 112.186 14.8093 112.582 15.9276 112.582ZM29.5492 88.625C30.4132 88.625 31.2179 88.7866 31.9634 89.1097C32.7089 89.4329 33.3654 89.8794 33.9329 90.4491C34.5005 91.0189 34.9452 91.678 35.2671 92.4263C35.5891 93.1747 35.75 93.9826 35.75 94.85C35.75 95.7004 35.5891 96.5084 35.2671 97.2737C34.9452 98.0221 34.5005 98.6769 33.9329 99.2381C33.3654 99.7994 32.7089 100.25 31.9634 100.59C31.218 100.913 30.4132 101.075 29.5492 101.075C28.7021 101.075 27.8973 100.913 27.1349 100.59C26.3894 100.25 25.7372 99.7994 25.1781 99.2381C24.6191 98.6768 24.1701 98.022 23.8312 97.2737C23.5093 96.5083 23.3484 95.7004 23.3484 94.85C23.3484 93.9826 23.5093 93.1748 23.8312 92.4263C24.1701 91.678 24.619 91.0189 25.1781 90.4491C25.7372 89.8794 26.3895 89.4329 27.1349 89.1097C27.8973 88.7866 28.7021 88.625 29.5492 88.625ZM29.5492 98.881C30.6674 98.881 31.6204 98.4856 32.4082 97.6947C33.1961 96.9038 33.59 95.9555 33.59 94.85C33.59 93.7275 33.1961 92.7707 32.4082 91.9798C31.6204 91.189 30.6675 90.7935 29.5492 90.7935C28.4479 90.7935 27.5034 91.1889 26.7156 91.9798C25.9278 92.7707 25.5339 93.7274 25.5339 94.85C25.5339 95.9556 25.9278 96.9038 26.7156 97.6947C27.5034 98.4856 28.448 98.881 29.5492 98.881ZM15.1398 88.625H22.2046V90.7936H20.629C21.0864 91.3379 21.4465 91.9502 21.7091 92.6305C21.9717 93.3108 22.103 94.0337 22.103 94.7991V94.8502C22.103 95.7176 21.9336 96.5254 21.5947 97.2738C21.2728 98.0392 20.8281 98.7068 20.2605 99.2766C19.6929 99.8464 19.0364 100.293 18.291 100.616C17.5286 100.939 16.7154 101.101 15.8513 101.101C14.9872 101.101 14.1825 100.939 13.437 100.616C12.6746 100.293 12.0139 99.8464 11.4548 99.2766C10.8957 98.7068 10.4467 98.0392 10.1079 97.2738C9.78595 96.5255 9.625 95.7176 9.625 94.8502C9.625 94.0337 9.78595 93.2684 10.1079 92.554C10.4298 91.8396 10.8491 91.2061 11.3658 90.6534C11.8826 90.1006 12.4713 89.6456 13.132 89.2885C13.7928 88.9313 14.462 88.7187 15.1397 88.6506L15.1398 88.625ZM19.9429 94.8501C19.9429 93.7276 19.549 92.7708 18.7611 91.9799C17.9733 91.189 17.0287 90.7936 15.9275 90.7936C14.8093 90.7936 13.8563 91.189 13.0685 91.9799C12.2807 92.7708 11.8868 93.7274 11.8868 94.8501C11.8868 95.9557 12.2807 96.9038 13.0685 97.6947C13.8563 98.4856 14.8092 98.8811 15.9275 98.8811C17.0288 98.8811 17.9733 98.4856 18.7611 97.6947C19.5489 96.9039 19.9429 95.9556 19.9429 94.8501Z" fill="white"/>
-<circle cx="75.5" cy="25.5" r="22.5" fill="#F08839"/>
-<path d="M56.8066 31.7309C61.6528 31.5578 71.2413 31.7309 72.9028 33.8078C74.9797 36.404 62.5182 39.5193 72.9028 40.5578C80.4452 41.312 83.4605 43.327 83.8066 44.1924" stroke="white" stroke-width="1.73077"/>
-<circle cx="75.4997" cy="25.5002" r="19.9038" stroke="white" stroke-width="1.73077"/>
-<circle cx="72.039" cy="13.3847" r="4.32692" stroke="white" stroke-width="1.73077"/>
-<path d="M56.2891 26.0186C56.6352 26.3647 57.4314 26.7455 57.8468 25.4993C58.2621 24.2532 60.0968 21.5186 60.9621 20.307H64.0775L66.1544 26.0186C67.1929 25.8455 69.3737 25.4993 69.7891 25.4993C70.3083 25.4993 71.3468 26.0186 71.866 26.0186M71.866 26.0186C72.3852 26.0186 73.9429 23.9416 74.9814 23.9416C76.0198 23.9416 79.1352 26.0186 79.1352 25.4993C79.1352 24.9801 81.7314 22.3839 82.2506 21.3455C82.666 20.5147 83.8083 19.9609 84.3275 19.7878C84.8468 19.9609 85.8852 20.2032 85.8852 19.7878C85.8852 19.2686 86.4044 18.7493 87.4429 20.307C88.4814 21.8647 90.0391 23.9416 90.5583 23.9416C91.0775 23.9416 91.5968 23.9416 92.116 24.4609C92.5314 24.8762 94.0198 26.3647 94.7121 27.057L95.5 28M71.866 26.0186L70.3083 29.1339" stroke="white" stroke-width="1.73077"/>
-<path d="M85.885 33.9376C85.885 35.2995 84.9901 35.7159 83.7215 35.8374C83.3207 35.8758 82.8825 35.8847 82.4235 35.8847C81.9644 35.8847 81.5262 35.8758 81.1254 35.8374C79.8568 35.7159 78.9619 35.2995 78.9619 33.9376C78.9619 32.1453 80.5117 30.6924 82.4235 30.6924C84.3352 30.6924 85.885 32.1453 85.885 33.9376Z" stroke="white" stroke-width="1.73077"/>
-<path d="M91.0771 36.3173C91.0771 37.2252 90.4059 37.5028 89.4545 37.5838C89.1538 37.6094 88.8252 37.6153 88.4809 37.6153C88.1366 37.6153 87.808 37.6094 87.5074 37.5838C86.5559 37.5028 85.8848 37.2252 85.8848 36.3173C85.8848 35.1224 87.0471 34.1538 88.4809 34.1538C89.9147 34.1538 91.0771 35.1224 91.0771 36.3173Z" stroke="white" stroke-width="1.73077"/>
-<circle cx="322.5" cy="98.5" r="20.5" fill="#F2B350"/>
-<rect x="322.499" y="88.1144" width="14.6871" height="14.6871" transform="rotate(45 322.499 88.1144)" stroke="white" stroke-width="3.15385"/>
-<rect x="322.499" y="94.2949" width="5.94697" height="5.94697" transform="rotate(45 322.499 94.2949)" fill="white"/>
-<path d="M335.115 98.4998L322.499 111.115L309.884 98.4998H335.115Z" fill="white"/>
-<circle cx="274" cy="26" r="21" fill="#9E19A0"/>
-<path d="M268.973 27.3501C268.829 25.8594 270.406 23.8901 272.06 23.1905C273.715 22.4909 274.124 20.8111 274.124 20.8111L273.999 12.269" stroke="white" stroke-width="1.61538" stroke-miterlimit="10" stroke-linecap="round"/>
-<path d="M274.125 40.027V36.6055C274.125 36.6055 273.637 34.5659 275.292 33.8663C276.253 33.4599 277.23 33.8663 278.547 31.6665" stroke="white" stroke-width="1.61538" stroke-miterlimit="10" stroke-linecap="round"/>
-<path d="M262.567 32.8566L265.863 30.707C265.863 30.707 268.146 29.9997 269.476 31.197C270.368 32.0011 270.625 32.9673 272.061 33.1987" stroke="white" stroke-width="1.61538" stroke-miterlimit="10" stroke-linecap="round"/>
-<path d="M285.929 32.3543C285.929 32.3543 282.656 31.2176 281.559 30.5071C280.461 29.7966 279.769 29.6631 279.169 27.1944C278.751 25.4729 277.422 24.0452 275.938 23.9409" stroke="white" stroke-width="1.61538" stroke-miterlimit="10" stroke-linecap="round"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M275.494 12.3748C274.88 11.2696 273.293 11.2649 272.673 12.3664L261.859 31.589C261.426 32.3596 261.692 33.3356 262.457 33.7788L273.307 40.0648C273.812 40.3574 274.436 40.3548 274.939 40.0579L285.57 33.7788C286.323 33.3338 286.585 32.3696 286.161 31.6043L275.494 12.3748Z" stroke="white" stroke-width="1.61538" stroke-miterlimit="10" stroke-linecap="round"/>
-<circle cx="119.5" cy="102.5" r="19.5" fill="#68CCBB"/>
-<path d="M131.499 109.423V96.4901C131.499 95.8739 130.797 95.5206 130.302 95.8878L122.469 101.698C122.278 101.84 122.166 102.063 122.166 102.301V110" stroke="white" stroke-width="2.25" stroke-linecap="round"/>
-<path d="M107.501 109.423V96.4901C107.501 95.8739 108.203 95.5206 108.698 95.8878L116.531 101.698C116.722 101.84 116.834 102.063 116.834 102.301V110" stroke="white" stroke-width="2.25" stroke-linecap="round"/>
-<path d="M222.5 125.557C224.047 126.45 225.953 126.45 227.5 125.557L245.883 114.943C247.43 114.05 248.383 112.4 248.383 110.613V89.3867C248.383 87.6004 247.43 85.9498 245.883 85.0566L227.5 74.4434C225.953 73.5502 224.047 73.5502 222.5 74.4434L204.117 85.0566C202.57 85.9498 201.617 87.6004 201.617 89.3867V110.613C201.617 112.4 202.57 114.05 204.117 114.943L222.5 125.557Z" fill="#FF5D3A"/>
-<path d="M213.397 96.7922L213.829 88L219.337 91.1811C223.063 89.3156 227.01 89.296 230.751 91.132L236.195 88V96.4241C236.985 97.9655 237.397 99.669 237.397 101.402C237.378 107.828 231.781 113.037 224.874 113.037C217.967 113.037 212.371 107.813 212.371 101.402C212.371 99.8064 212.719 98.2355 213.397 96.7922Z" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
-<path d="M232.003 99.3155C231.551 98.1177 229.632 98.2993 229.151 99.3155" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
-<path d="M221.738 99.3155C221.287 98.1177 219.367 98.2993 218.886 99.3155" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
-<path d="M226.951 103.307H223.942" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
-<path d="M225.443 103.307V104.809" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
-<path d="M226.734 108.471C226.327 108.746 225.34 109.203 223.941 108.52" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
-<path d="M174.169 1.04473C172.798 0.384526 171.202 0.384527 169.831 1.04473L153.06 9.12104C151.689 9.78124 150.693 11.0298 150.355 12.5133L146.213 30.6606C145.874 32.144 146.23 33.701 147.178 34.8906L158.784 49.4436C159.733 50.6333 161.171 51.3262 162.693 51.3262L181.307 51.3262C182.829 51.3262 184.267 50.6333 185.216 49.4436L196.822 34.8906C197.77 33.701 198.126 32.144 197.787 30.6606L193.645 12.5133C193.307 11.0298 192.311 9.78125 190.94 9.12104L174.169 1.04473Z" fill="#3AC4FF"/>
-<path d="M161 22.12V37H169.186M161 22.12H183M161 22.12L171.744 13L183 22.12M183 22.12V37H175.326M175.326 37V29.32H169.186V37M175.326 37H169.186" stroke="white" stroke-width="2"/>
-</svg>
diff --git a/packages/website/public/images/instant/feature_2.svg b/packages/website/public/images/instant/feature_2.svg
deleted file mode 100644
index a313872b2..000000000
--- a/packages/website/public/images/instant/feature_2.svg
+++ /dev/null
@@ -1,15 +0,0 @@
-<svg width="209" height="112" viewBox="0 0 209 112" fill="none" xmlns="http://www.w3.org/2000/svg">
-<rect x="2" y="32" width="178.035" height="77.5613" rx="3.29952" fill="#8397DE" stroke="#5265AA" stroke-width="4"/>
-<path d="M121.491 69.9311C121.491 88.7841 107.718 103.915 90.9058 103.915C74.0938 103.915 60.3203 88.7841 60.3203 69.9311C60.3203 51.0782 74.0938 35.9473 90.9058 35.9473C107.718 35.9473 121.491 51.0782 121.491 69.9311Z" fill="#6E80BF" stroke="#6E80BF" stroke-width="1.69919"/>
-<path d="M172.468 50.39C172.468 55.6225 168.596 59.7356 163.972 59.7356C159.347 59.7356 155.476 55.6225 155.476 50.39C155.476 45.1575 159.347 41.0444 163.972 41.0444C168.596 41.0444 172.468 45.1575 172.468 50.39Z" fill="#6E80C0" stroke="#8397DE" stroke-width="1.69919"/>
-<path d="M172.468 93.1903C172.468 98.4228 168.596 102.536 163.972 102.536C159.347 102.536 155.476 98.4228 155.476 93.1903C155.476 87.9578 159.347 83.8447 163.972 83.8447C168.596 83.8447 172.468 87.9578 172.468 93.1903Z" fill="#6E80C0" stroke="#8397DE" stroke-width="1.69919"/>
-<path d="M26.3171 49.4691C26.3171 54.7016 22.4453 58.8147 17.8212 58.8147C13.197 58.8147 9.32518 54.7016 9.32518 49.4691C9.32518 44.2366 13.197 40.1235 17.8212 40.1235C22.4453 40.1235 26.3171 44.2366 26.3171 49.4691Z" fill="#6E80C0" stroke="#8397DE" stroke-width="1.69919"/>
-<path d="M26.3367 92.87C26.3367 98.1025 22.4648 102.216 17.8407 102.216C13.2166 102.216 9.34471 98.1025 9.34471 92.87C9.34471 87.6375 13.2166 83.5244 17.8407 83.5244C22.4648 83.5244 26.3367 87.6375 26.3367 92.87Z" fill="#6E80C0" stroke="#8397DE" stroke-width="1.69919"/>
-<path d="M105.329 70.7255L105.329 70.7256L93.111 77.9472L93.1106 77.9474C92.199 78.4868 91.0649 78.4871 90.1516 77.9472L90.1515 77.9471L77.9287 70.7256C76.537 69.903 76.0828 68.1043 76.9171 66.721L76.9172 66.7208L89.1402 46.4409L89.1402 46.4408C90.2706 44.5646 92.9907 44.5646 94.1211 46.4408L106.339 66.7207L106.339 66.7208C107.174 68.1058 106.719 69.9044 105.329 70.7255Z" fill="#5265AA" stroke="#5265AA" stroke-width="1.69919"/>
-<path d="M93.4911 93.863L93.4911 93.863C92.5828 95.1423 90.6834 95.1423 89.7751 93.863L77.2355 76.1985L90.7948 84.2098C90.7952 84.21 90.7955 84.2102 90.7959 84.2104C91.3117 84.5159 91.9534 84.5158 92.4693 84.2103C92.4696 84.2101 92.4699 84.2099 92.4702 84.2098L106.035 76.1981L93.4911 93.863Z" fill="#5265AA" stroke="#5265AA" stroke-width="1.69919"/>
-<circle cx="177" cy="32" r="32" fill="#9AA7D7"/>
-<g opacity="0.7">
-<line x1="195.064" y1="32.5152" x2="158.935" y2="32.5152" stroke="white" stroke-width="5.16129" stroke-linecap="round"/>
-<line x1="177.516" y1="50.0644" x2="177.516" y2="13.9353" stroke="white" stroke-width="5.16129" stroke-linecap="round"/>
-</g>
-</svg>
diff --git a/packages/website/public/images/instant/feature_3.svg b/packages/website/public/images/instant/feature_3.svg
deleted file mode 100644
index 83aa259c6..000000000
--- a/packages/website/public/images/instant/feature_3.svg
+++ /dev/null
@@ -1,195 +0,0 @@
-<svg width="312" height="238" viewBox="0 0 312 238" fill="none" xmlns="http://www.w3.org/2000/svg">
-<g clip-path="url(#clip0)">
-<path d="M4.54049 64.6748L115.492 0.617544C117.998 -0.826333 120.032 0.345114 120.032 3.24195V162.804C120.032 165.701 117.998 169.215 115.492 170.668L4.54049 234.716C2.03414 236.16 0 234.989 0 232.092V72.539C0 69.6421 2.03414 66.1278 4.54049 64.6748Z" fill="#363636"/>
-<path d="M4.54049 64.6748L115.492 0.617544C117.998 -0.826333 120.032 0.345114 120.032 3.24195V43.6342L0 112.931V72.539C0 69.6421 2.03414 66.1278 4.54049 64.6748Z" fill="#363636"/>
-<path d="M14.8197 76.8164L13.5393 77.552C13.4667 77.7064 12.9854 79.577 11.4053 80.4851V81.8745C12.4768 81.257 13.2124 80.3943 13.3668 79.9675L13.4394 79.9221V88.6126L14.8106 87.8226V76.8164H14.8197ZM24.0551 78.9414L22.7111 79.7133V72.2578L21.2037 73.1295L17.0627 83.3366V84.4354L21.4034 81.929V84.0176L22.7111 83.2639V81.1753L24.0551 80.4034V78.9414ZM18.7245 82.0198L21.2037 75.763L21.4034 75.1001V80.467L18.7245 82.0198ZM31.7104 71.84C31.7104 68.6526 30.5026 67.6174 28.4775 68.7797C26.4343 69.9603 25.2175 72.4031 25.2175 75.5905V76.8891C25.2175 80.1401 26.4525 81.2661 28.4957 80.0856C30.5208 78.9141 31.7194 76.3896 31.7194 73.1386V71.84H31.7104ZM30.2483 74.2465C30.2483 76.2352 29.6399 77.9606 28.4866 78.6326C27.3061 79.3137 26.6704 78.3057 26.6704 76.317V74.4826C26.6704 72.5393 27.297 70.9138 28.4775 70.2327C29.6399 69.5607 30.2574 70.4597 30.2574 72.4121V74.2465H30.2483ZM33.8353 76.9526C34.3529 76.653 34.7797 75.9265 34.7797 75.3181C34.7797 74.7278 34.3529 74.4917 33.8353 74.7914C33.3268 75.082 32.8909 75.7993 32.8909 76.4078C32.9 77.0162 33.3177 77.2614 33.8353 76.9526ZM42.3079 65.7195C42.3079 62.532 41.1001 61.4968 39.075 62.6592C37.0318 63.8397 35.815 66.2825 35.815 69.4699V70.7685C35.815 74.0195 37.05 75.1455 39.0932 73.965C41.1183 72.7935 42.317 70.269 42.317 67.018V65.7195H42.3079ZM40.8549 68.1259C40.8549 70.1146 40.2465 71.84 39.0932 72.512C37.9127 73.1931 37.277 72.1851 37.277 70.1964V68.362C37.277 66.4187 37.9036 64.7932 39.0841 64.1121C40.2465 63.4401 40.864 64.3391 40.864 66.2916V68.1259H40.8549ZM50.1811 61.1699C50.1811 57.9825 48.9733 56.9472 46.9483 58.1096C44.905 59.2901 43.6882 61.7329 43.6882 64.9203V66.2189C43.6882 69.4699 44.9232 70.5959 46.9664 69.4154C48.9915 68.244 50.1902 65.7195 50.1902 62.4685V61.1699H50.1811ZM48.7281 63.5763C48.7281 65.5651 48.1197 67.2905 46.9664 67.9625C45.7859 68.6435 45.1502 67.6355 45.1502 65.6468V63.8124C45.1502 61.8691 45.7768 60.2436 46.9573 59.5625C48.1197 58.8905 48.7372 59.7896 48.7372 61.742V63.5763H48.7281ZM62.0772 59.0812L57.0826 61.969L62.0409 50.6813V49.5553L55.2574 53.4692V54.9312L60.2519 52.0526L55.2937 63.3402V64.4663L62.0772 60.5524V59.0812ZM69.1059 56.4841L70.7768 55.5215L68.7517 52.1434C69.7869 51.0082 70.4226 49.637 70.4226 48.1205C70.4226 46.1862 69.4146 45.3054 67.1535 46.6131L63.8116 48.5382V59.5535L65.2919 58.6998V54.4863L67.2806 53.3421L69.1059 56.4841ZM65.2828 49.1466L67.1444 48.0751C68.5428 47.2669 68.9606 47.9752 68.9606 48.9832C68.9606 50.1274 68.443 51.1808 67.0536 51.9799L65.2828 53.0061V49.1466ZM73.2105 43.1078L71.5033 44.0885L74.4818 47.8753L71.4851 55.1129L73.2014 54.123L75.4353 48.62L75.508 48.5745L77.7419 51.4986L79.4582 50.5088L76.5069 46.7039L79.44 39.5117L77.7328 40.4925L75.508 46.041L75.4353 46.0864L73.2105 43.1078Z" fill="#363636"/>
-<path d="M10.724 199.291L109.716 142.145C110.833 141.5 111.732 142.027 111.732 143.307V160.443C111.732 161.732 110.833 163.294 109.716 163.939L10.724 221.086C9.60703 221.73 8.70801 221.204 8.70801 219.923V202.788C8.70801 201.498 9.61611 199.936 10.724 199.291Z" fill="#363636"/>
-<path opacity="0.2" d="M10.5881 121.159L109.435 64.0936C109.989 63.7758 110.443 64.0301 110.443 64.6748V78.6505C110.443 79.2952 109.989 80.0762 109.435 80.394L10.5881 137.468C10.0341 137.786 9.58008 137.532 9.58008 136.887V122.911C9.58008 122.266 10.0341 121.485 10.5881 121.159Z" fill="#363636"/>
-<path opacity="0.2" d="M9.7168 183.272L107.583 126.771" stroke="white" stroke-width="2.16763" stroke-linecap="round"/>
-<path opacity="0.2" d="M9.7168 167.835L107.583 111.333" stroke="white" stroke-width="2.16763" stroke-linecap="round"/>
-<path opacity="0.2" d="M9.7168 153.305L107.583 96.8032" stroke="white" stroke-width="2.16763" stroke-linecap="round"/>
-<path d="M6.56588 66.4912L117.517 2.43395C120.024 0.990073 122.058 2.16152 122.058 5.05836V164.62C122.058 167.517 120.024 171.032 117.517 172.485L6.56588 236.533C4.05953 237.977 2.02539 236.805 2.02539 233.908V74.3554C2.02539 71.4585 4.05953 67.9442 6.56588 66.4912Z" fill="#424242"/>
-<path d="M85.7878 33.0822C85.7878 35.1708 85.1159 36.7237 83.9081 37.4229C82.7003 38.1222 82.0283 37.3503 82.0283 35.2526C82.0283 33.1549 82.7003 31.602 83.9081 30.9028C85.1159 30.2035 85.7878 30.9845 85.7878 33.0822ZM84.8888 32.2377C84.7254 31.5929 84.3894 31.4022 83.9081 31.6837C83.1816 32.1015 82.7911 33.1912 82.7911 34.8167C82.7911 35.0074 82.7911 35.1799 82.8093 35.3434L84.8888 32.2377ZM82.9183 36.1153C83.0908 36.7509 83.4177 36.9416 83.9081 36.6601C84.6346 36.2424 85.016 35.1527 85.016 33.5272C85.016 33.3365 85.016 33.1549 84.9978 32.9914L82.9183 36.1153Z" fill="#FF602E"/>
-<path d="M87.9219 34.1629C87.9219 33.6998 88.2397 33.1277 88.6393 32.9006C89.0388 32.6736 89.3567 32.8643 89.3567 33.3365C89.3567 33.7997 89.0388 34.3718 88.6393 34.5988C88.2397 34.8258 87.9219 34.626 87.9219 34.1629Z" fill="#FF602E"/>
-<path d="M93.4165 31.9291C92.3086 32.5738 91.5186 32.1289 91.5186 30.8485C91.5186 30.1129 91.7365 29.3138 92.2632 28.1423C92.3449 27.9425 93.3802 25.6905 93.4528 25.5452L94.3427 25.0366L92.9079 28.1332C92.7445 28.4965 92.7445 28.5056 92.7082 28.6054L92.7717 28.5964C92.9443 28.2513 93.3166 27.8608 93.6617 27.661C94.6243 27.1071 95.3326 27.543 95.3326 28.6781C95.3144 29.9131 94.5153 31.2934 93.4165 31.9291ZM94.5516 29.1594C94.5516 28.3966 94.0612 28.106 93.4165 28.4783C92.7717 28.8506 92.2814 29.7133 92.2814 30.4761C92.2814 31.2389 92.7717 31.5295 93.4165 31.1572C94.0612 30.7758 94.5516 29.9131 94.5516 29.1594Z" fill="#FF602E"/>
-<path d="M100.017 24.8641C100.017 26.9527 99.3453 28.5056 98.1376 29.2048C96.9298 29.904 96.2578 29.1321 96.2578 27.0344C96.2578 24.9367 96.9298 23.3839 98.1376 22.6846C99.3453 21.9945 100.017 22.7664 100.017 24.8641ZM99.1183 24.0195C98.9549 23.3748 98.6189 23.1841 98.1285 23.4656C97.402 23.8833 97.0115 24.973 97.0115 26.5985C97.0115 26.7892 97.0115 26.9618 97.0297 27.1252L99.1183 24.0195ZM97.1478 27.8971C97.3203 28.5328 97.6472 28.7235 98.1376 28.442C98.8641 28.0243 99.2455 26.9345 99.2455 25.309C99.2455 25.1183 99.2455 24.9367 99.2273 24.7733L97.1478 27.8971Z" fill="#FF602E"/>
-<path d="M85.7878 44.3337C85.7878 46.4223 85.1159 47.9751 83.9081 48.6744C82.7003 49.3736 82.0283 48.6017 82.0283 46.504C82.0283 44.4063 82.7003 42.8535 83.9081 42.1542C85.1159 41.455 85.7878 42.236 85.7878 44.3337ZM84.8888 43.4801C84.7254 42.8353 84.3894 42.6446 83.9081 42.9261C83.1816 43.3438 82.7911 44.4336 82.7911 46.0591C82.7911 46.2498 82.7911 46.4223 82.8093 46.5858L84.8888 43.4801ZM82.9183 47.3576C83.0908 47.9933 83.4177 48.184 83.9081 47.9025C84.6346 47.4848 85.016 46.3951 85.016 44.7696C85.016 44.5789 85.016 44.3972 84.9978 44.2338L82.9183 47.3576Z" fill="#FF602E"/>
-<path d="M87.9219 45.4051C87.9219 44.942 88.2397 44.3699 88.6393 44.1428C89.0388 43.9158 89.3567 44.1065 89.3567 44.5787C89.3567 45.0419 89.0388 45.614 88.6393 45.841C88.2397 46.068 87.9219 45.8682 87.9219 45.4051Z" fill="#FF602E"/>
-<path d="M91.5273 42.4452L92.272 42.0093C92.3356 42.5814 92.7805 42.7448 93.3799 42.3997C94.0428 42.0183 94.4877 41.2283 94.4877 40.4201C94.4877 39.6119 94.0428 39.3213 93.3799 39.7027C92.9258 39.966 92.5535 40.4201 92.3446 40.965L91.6 41.3918L91.8633 37.6958L94.9145 35.9341V36.715L92.4808 38.1226L92.3356 40.1386L92.3991 40.1023C92.6534 39.5756 93.0439 39.1578 93.5252 38.8763C94.5241 38.2951 95.2233 38.7492 95.2233 39.9751C95.2233 41.2555 94.4605 42.5632 93.3345 43.217C92.3083 43.8073 91.5727 43.4985 91.5273 42.4452Z" fill="#FF602E"/>
-<path d="M98.1284 33.9542C99.2363 33.3094 100.026 33.7544 100.026 35.0348C100.026 35.7522 99.8084 36.5514 99.2726 37.75C99.1818 37.9589 98.1466 40.211 98.083 40.3472L97.1931 40.8557L98.6278 37.7591C98.755 37.4776 98.7913 37.3868 98.8276 37.296L98.7641 37.3051C98.5915 37.6502 98.2283 38.0316 97.8923 38.2313C96.9297 38.7853 96.2305 38.3585 96.2305 37.2052C96.2305 35.9611 97.0296 34.5899 98.1284 33.9542ZM96.9933 36.7239C96.9933 37.4867 97.4836 37.7773 98.1284 37.405C98.7731 37.0326 99.2635 36.17 99.2635 35.4071C99.2635 34.6443 98.7731 34.3538 98.1284 34.7261C97.4836 35.0984 96.9933 35.9611 96.9933 36.7239Z" fill="#FF602E"/>
-<path d="M85.7878 56.5112C85.7878 58.5998 85.1159 60.1527 83.9081 60.8519C82.7003 61.5511 82.0283 60.7793 82.0283 58.6816C82.0283 56.5838 82.7003 55.031 83.9081 54.3318C85.1159 53.6325 85.7878 54.4226 85.7878 56.5112ZM84.8888 55.6667C84.7254 55.0219 84.3894 54.8312 83.9081 55.1127C83.1816 55.5304 82.7911 56.6202 82.7911 58.2457C82.7911 58.4364 82.7911 58.6089 82.8093 58.7724L84.8888 55.6667ZM82.9183 59.5442C83.0908 60.1799 83.4177 60.3706 83.9081 60.0891C84.6346 59.6714 85.016 58.5817 85.016 56.9562C85.016 56.7655 85.016 56.5838 84.9978 56.4204L82.9183 59.5442Z" fill="#FF602E"/>
-<path d="M87.9219 57.5916C87.9219 57.1285 88.2397 56.5564 88.6393 56.3294C89.0388 56.1023 89.3567 56.293 89.3567 56.7652C89.3567 57.2284 89.0388 57.8005 88.6393 58.0275C88.2397 58.2545 87.9219 58.0547 87.9219 57.5916Z" fill="#FF602E"/>
-<path d="M91.5273 54.6317L92.272 54.1958C92.3356 54.7679 92.7805 54.9313 93.3799 54.5863C94.0428 54.2049 94.4877 53.4148 94.4877 52.6066C94.4877 51.7984 94.0428 51.5078 93.3799 51.8892C92.9258 52.1526 92.5535 52.6066 92.3446 53.1515L91.6091 53.5783L91.8724 49.8823L94.9236 48.1206V48.9016L92.4899 50.3091L92.3446 52.3251L92.4082 52.2888C92.6625 51.7621 93.0529 51.3444 93.5342 51.0628C94.5331 50.4817 95.2324 50.9357 95.2324 52.1616C95.2324 53.4421 94.4696 54.7497 93.3435 55.4036C92.3083 55.9938 91.5727 55.6851 91.5273 54.6317Z" fill="#FF602E"/>
-<path d="M96.1768 51.9617C96.1768 51.1898 96.6126 50.3089 97.2937 49.7277V49.6551C96.7398 49.8004 96.3947 49.4644 96.3947 48.7924C96.3947 47.8116 97.1212 46.7038 98.1473 46.1135C99.1735 45.5232 99.9 45.7957 99.9 46.7673C99.9 47.4393 99.5549 48.1658 98.9919 48.6653V48.7379C99.6639 48.5109 100.118 48.9014 100.118 49.6732C100.118 50.7448 99.3097 51.9526 98.1473 52.6246C96.985 53.3056 96.1768 53.0332 96.1768 51.9617ZM99.3279 50.0728C99.3279 49.3917 98.8466 49.201 98.1564 49.6097C97.4663 50.0183 96.985 50.7539 96.985 51.435C96.985 52.116 97.4663 52.3067 98.1564 51.8981C98.8466 51.4894 99.3279 50.7448 99.3279 50.0728ZM99.1372 47.294C99.1372 46.6856 98.7376 46.5131 98.1473 46.8491C97.548 47.1941 97.1575 47.8298 97.1575 48.4291C97.1575 49.0376 97.548 49.2192 98.1473 48.8741C98.7376 48.5381 99.1372 47.9025 99.1372 47.294Z" fill="#FF602E"/>
-<path d="M85.7878 68.2712C85.7878 70.3598 85.1159 71.9126 83.9081 72.6119C82.7003 73.3111 82.0283 72.5392 82.0283 70.4415C82.0283 68.3438 82.7003 66.791 83.9081 66.0917C85.1159 65.3925 85.7878 66.1735 85.7878 68.2712ZM84.8888 67.4266C84.7254 66.7819 84.3894 66.5912 83.9081 66.8727C83.1816 67.2904 82.7911 68.3801 82.7911 70.0056C82.7911 70.1963 82.7911 70.3689 82.8093 70.5323L84.8888 67.4266ZM82.9183 71.2951C83.0908 71.9308 83.4177 72.1215 83.9081 71.84C84.6346 71.4223 85.016 70.3326 85.016 68.7071C85.016 68.5164 85.016 68.3347 84.9978 68.1713L82.9183 71.2951Z" fill="#FF602E"/>
-<path d="M87.9219 69.3519C87.9219 68.8887 88.2397 68.3166 88.6393 68.0896C89.0388 67.8626 89.3567 68.0533 89.3567 68.5255C89.3567 68.9886 89.0388 69.5607 88.6393 69.7878C88.2397 70.0148 87.9219 69.815 87.9219 69.3519Z" fill="#FF602E"/>
-<path d="M91.5273 66.3822L92.272 65.9463C92.3356 66.5184 92.7805 66.6818 93.3799 66.3368C94.0428 65.9554 94.4877 65.1653 94.4877 64.3571C94.4877 63.5489 94.0428 63.2583 93.3799 63.6397C92.9258 63.9031 92.5535 64.3571 92.3446 64.902L91.6 65.3288L91.8633 61.6328L94.9145 59.8711V60.6521L92.4808 62.0596L92.3356 64.0756L92.3991 64.0393C92.6534 63.5126 93.0439 63.0948 93.5252 62.8133C94.5241 62.2321 95.2233 62.6862 95.2233 63.9121C95.2233 65.1926 94.4605 66.5002 93.3345 67.154C92.3083 67.7443 91.5727 67.4356 91.5273 66.3822Z" fill="#FF602E"/>
-<path d="M99.2097 58.2366V58.173L96.3311 59.8348V59.0629L100.009 56.938V57.728L97.6206 64.5569L96.7942 65.0291L99.2097 58.2366Z" fill="#FF602E"/>
-<path d="M85.7878 79.5226C85.7878 81.6113 85.1159 83.1641 83.9081 83.8633C82.7003 84.5626 82.0283 83.7907 82.0283 81.693C82.0283 79.5953 82.7003 78.0424 83.9081 77.3432C85.1159 76.644 85.7878 77.4249 85.7878 79.5226ZM84.8888 78.669C84.7254 78.0243 84.3894 77.8336 83.9081 78.1151C83.1816 78.5328 82.7911 79.6225 82.7911 81.248C82.7911 81.4387 82.7911 81.6113 82.8093 81.7747L84.8888 78.669ZM82.9183 82.5466C83.0908 83.1823 83.4177 83.373 83.9081 83.0915C84.6346 82.6737 85.016 81.584 85.016 79.9585C85.016 79.7678 85.016 79.5862 84.9978 79.4227L82.9183 82.5466Z" fill="#FF602E"/>
-<path d="M87.9219 80.5936C87.9219 80.1304 88.2397 79.5583 88.6393 79.3313C89.0388 79.1043 89.3567 79.295 89.3567 79.7672C89.3567 80.2303 89.0388 80.8024 88.6393 81.0295C88.2397 81.2565 87.9219 81.0567 87.9219 80.5936Z" fill="#FF602E"/>
-<path d="M91.5273 77.6336L92.272 77.1977C92.3356 77.7698 92.7805 77.9333 93.3799 77.5882C94.0428 77.2068 94.4877 76.4168 94.4877 75.6086C94.4877 74.8004 94.0428 74.5098 93.3799 74.8912C92.9258 75.1545 92.5535 75.6086 92.3446 76.1534L91.6 76.5802L91.8633 72.8843L94.9145 71.1226V71.9035L92.4808 73.3111L92.3356 75.3271L92.3991 75.2907C92.6534 74.764 93.0439 74.3463 93.5252 74.0648C94.5241 73.4836 95.2233 73.9377 95.2233 75.1636C95.2233 76.444 94.4605 77.7517 93.3345 78.4055C92.3083 78.9958 91.5727 78.687 91.5273 77.6336Z" fill="#FF602E"/>
-<path d="M98.1645 75.6176C97.0566 76.2623 96.2666 75.8174 96.2666 74.5369C96.2666 73.8014 96.4845 73.0022 97.0112 71.8308C97.1021 71.631 98.1282 69.3789 98.2008 69.2336L99.0908 68.7251L97.656 71.8217C97.4925 72.185 97.4925 72.194 97.4562 72.2939L97.5198 72.2848C97.6923 71.9398 98.0646 71.5493 98.4097 71.3495C99.3723 70.7956 100.081 71.2315 100.081 72.3666C100.053 73.6107 99.2542 74.991 98.1645 75.6176ZM99.2906 72.8479C99.2906 72.0851 98.8002 71.7945 98.1554 72.1668C97.5107 72.5391 97.0203 73.4018 97.0203 74.1646C97.0203 74.9274 97.5107 75.218 98.1554 74.8457C98.8002 74.4734 99.2906 73.6107 99.2906 72.8479Z" fill="#FF602E"/>
-<path d="M85.7878 91.6999C85.7878 93.7885 85.1159 95.3414 83.9081 96.0406C82.7003 96.7398 82.0283 95.9679 82.0283 93.8702C82.0283 91.7725 82.7003 90.2197 83.9081 89.5204C85.1159 88.8212 85.7878 89.6022 85.7878 91.6999ZM84.8888 90.8553C84.7254 90.2106 84.3894 90.0199 83.9081 90.3014C83.1816 90.7191 82.7911 91.8088 82.7911 93.4343C82.7911 93.625 82.7911 93.7976 82.8093 93.961L84.8888 90.8553ZM82.9183 94.7329C83.0908 95.3686 83.4177 95.5593 83.9081 95.2778C84.6346 94.8601 85.016 93.7703 85.016 92.1448C85.016 91.9541 85.016 91.7725 84.9978 91.6091L82.9183 94.7329Z" fill="#FF602E"/>
-<path d="M87.9219 92.7806C87.9219 92.3174 88.2397 91.7453 88.6393 91.5183C89.0388 91.2913 89.3567 91.482 89.3567 91.9542C89.3567 92.4173 89.0388 92.9894 88.6393 93.2165C88.2397 93.4435 87.9219 93.2437 87.9219 92.7806Z" fill="#FF602E"/>
-<path d="M91.5273 89.8202L92.272 89.3843C92.3356 89.9564 92.7805 90.1198 93.3799 89.7747C94.0428 89.3933 94.4877 88.6033 94.4877 87.7951C94.4877 86.9869 94.0428 86.6963 93.3799 87.0777C92.9258 87.341 92.5535 87.7951 92.3446 88.34L91.6 88.7668L91.8633 85.0708L94.9145 83.3091V84.09L92.4808 85.4976L92.3356 87.5136L92.3991 87.4773C92.6534 86.9506 93.0439 86.5328 93.5252 86.2513C94.5241 85.6701 95.2233 86.1242 95.2233 87.3501C95.2233 88.6305 94.4605 89.9382 93.3345 90.592C92.3083 91.1823 91.5727 90.8736 91.5273 89.8202Z" fill="#FF602E"/>
-<path d="M96.2666 87.0775L97.0112 86.6416C97.0748 87.2137 97.5198 87.3771 98.1191 87.0321C98.782 86.6507 99.227 85.8606 99.227 85.0524C99.227 84.2442 98.782 83.9536 98.1191 84.335C97.6651 84.5984 97.2928 85.0524 97.0839 85.5973L96.3392 86.0241L96.6026 82.3281L99.6538 80.5664V81.3474L97.2201 82.7549L97.0748 84.7709L97.1384 84.7346C97.3926 84.2079 97.7831 83.7902 98.2644 83.5086C99.2633 82.9275 99.9626 83.3815 99.9626 84.6074C99.9626 85.8879 99.1998 87.1955 98.0737 87.8494C97.0476 88.4396 96.312 88.1309 96.2666 87.0775Z" fill="#FF602E"/>
-<path d="M85.7878 114.238C85.7878 116.327 85.1159 117.88 83.9081 118.579C82.7003 119.278 82.0283 118.507 82.0283 116.409C82.0283 114.311 82.7003 112.758 83.9081 112.059C85.1159 111.36 85.7878 112.141 85.7878 114.238ZM84.8888 113.394C84.7254 112.749 84.3894 112.558 83.9081 112.84C83.1816 113.258 82.7911 114.347 82.7911 115.973C82.7911 116.164 82.7911 116.336 82.8093 116.5L84.8888 113.394ZM82.9183 117.271C83.0908 117.907 83.4177 118.098 83.9081 117.816C84.6346 117.399 85.016 116.309 85.016 114.683C85.016 114.493 85.016 114.311 84.9978 114.148L82.9183 117.271Z" fill="#23C49E"/>
-<path d="M87.9219 115.319C87.9219 114.856 88.2397 114.284 88.6393 114.057C89.0388 113.83 89.3567 114.021 89.3567 114.493C89.3567 114.956 89.0388 115.528 88.6393 115.755C88.2397 115.982 87.9219 115.782 87.9219 115.319Z" fill="#23C49E"/>
-<path d="M91.5273 112.349L92.272 111.914C92.3356 112.486 92.7805 112.649 93.3799 112.304C94.0428 111.923 94.4877 111.133 94.4877 110.324C94.4877 109.516 94.0428 109.226 93.3799 109.607C92.9258 109.87 92.5535 110.324 92.3446 110.869L91.6 111.296L91.8633 107.6L94.9145 105.838V106.619L92.4808 108.027L92.3356 110.043L92.3991 110.007C92.6534 109.48 93.0439 109.062 93.5252 108.781C94.5241 108.199 95.2233 108.653 95.2233 109.879C95.2233 111.16 94.4605 112.467 93.3345 113.121C92.3083 113.721 91.5727 113.412 91.5273 112.349Z" fill="#23C49E"/>
-<path d="M98.7006 108.617L96.2578 110.025V109.307L98.0377 104.04L98.8277 103.586L97.0842 108.735V108.799L98.7278 107.854V106.129L99.4271 105.72V107.446L100.226 106.983V107.736L99.4362 108.19V109.471L98.7188 109.889V108.617H98.7006Z" fill="#23C49E"/>
-<path d="M85.7878 125.49C85.7878 127.579 85.1159 129.132 83.9081 129.831C82.7003 130.53 82.0283 129.758 82.0283 127.661C82.0283 125.563 82.7003 124.01 83.9081 123.311C85.1159 122.612 85.7878 123.393 85.7878 125.49ZM84.8888 124.646C84.7254 124.001 84.3894 123.81 83.9081 124.092C83.1816 124.51 82.7911 125.599 82.7911 127.225C82.7911 127.416 82.7911 127.588 82.8093 127.752L84.8888 124.646ZM82.9183 128.514C83.0908 129.15 83.4177 129.341 83.9081 129.059C84.6346 128.642 85.016 127.552 85.016 125.926C85.016 125.736 85.016 125.554 84.9978 125.391L82.9183 128.514Z" fill="#23C49E"/>
-<path d="M87.9219 126.571C87.9219 126.108 88.2397 125.536 88.6393 125.309C89.0388 125.082 89.3567 125.273 89.3567 125.745C89.3567 126.208 89.0388 126.78 88.6393 127.007C88.2397 127.234 87.9219 127.025 87.9219 126.571Z" fill="#23C49E"/>
-<path d="M91.5273 123.601L92.272 123.166C92.3356 123.738 92.7805 123.901 93.3799 123.556C94.0428 123.175 94.4877 122.385 94.4877 121.576C94.4877 120.768 94.0428 120.478 93.3799 120.859C92.9258 121.122 92.5535 121.576 92.3446 122.121L91.6 122.548L91.8633 118.852L94.9145 117.09V117.871L92.4808 119.279L92.3356 121.295L92.3991 121.259C92.6534 120.732 93.0439 120.314 93.5252 120.033C94.5241 119.451 95.2233 119.905 95.2233 121.131C95.2233 122.412 94.4605 123.719 93.3345 124.373C92.3083 124.964 91.5727 124.655 91.5273 123.601Z" fill="#23C49E"/>
-<path d="M97.4751 118.289L98.0745 117.944C98.6557 117.608 99.0643 116.945 99.0643 116.327C99.0643 115.719 98.6738 115.546 98.0836 115.892C97.4933 116.228 97.1119 116.845 97.0574 117.517L96.3309 117.935C96.3854 116.8 97.0665 115.719 98.1017 115.12C99.1097 114.538 99.809 114.802 99.809 115.764C99.809 116.509 99.4639 117.254 98.8736 117.744V117.817C99.6001 117.508 100.027 117.835 100.027 118.679C100.027 119.76 99.2369 120.968 98.1199 121.613C97.0211 122.248 96.2674 121.967 96.2129 120.886L96.9394 120.468C96.9939 121.077 97.4479 121.222 98.0927 120.841C98.801 120.432 99.2369 119.76 99.2369 119.097C99.2369 118.416 98.7828 118.244 98.0745 118.661L97.4479 119.024V118.289H97.4751Z" fill="#23C49E"/>
-<path d="M85.7878 137.677C85.7878 139.766 85.1159 141.319 83.9081 142.018C82.7003 142.717 82.0283 141.945 82.0283 139.848C82.0283 137.75 82.7003 136.197 83.9081 135.498C85.1159 134.799 85.7878 135.58 85.7878 137.677ZM84.8888 136.824C84.7254 136.179 84.3894 135.988 83.9081 136.27C83.1816 136.688 82.7911 137.777 82.7911 139.403C82.7911 139.593 82.7911 139.766 82.8093 139.929L84.8888 136.824ZM82.9183 140.701C83.0908 141.337 83.4177 141.528 83.9081 141.246C84.6346 140.829 85.016 139.739 85.016 138.113C85.016 137.923 85.016 137.741 84.9978 137.578L82.9183 140.701Z" fill="#23C49E"/>
-<path d="M87.9219 138.748C87.9219 138.285 88.2397 137.713 88.6393 137.486C89.0388 137.259 89.3567 137.45 89.3567 137.922C89.3567 138.385 89.0388 138.957 88.6393 139.184C88.2397 139.411 87.9219 139.211 87.9219 138.748Z" fill="#23C49E"/>
-<path d="M91.5273 135.788L92.272 135.353C92.3356 135.925 92.7805 136.088 93.3799 135.743C94.0428 135.362 94.4877 134.572 94.4877 133.763C94.4877 132.955 94.0428 132.665 93.3799 133.046C92.9258 133.309 92.5535 133.763 92.3446 134.308L91.6 134.735L91.8633 131.039L94.9145 129.277V130.058L92.4808 131.466L92.3356 133.482L92.3991 133.446C92.6534 132.919 93.0439 132.501 93.5252 132.22C94.5241 131.638 95.2233 132.092 95.2233 133.318C95.2233 134.599 94.4605 135.906 93.3345 136.56C92.3083 137.151 91.5727 136.842 91.5273 135.788Z" fill="#23C49E"/>
-<path d="M98.1016 127.307C99.1277 126.716 99.8269 127.025 99.8269 128.078C99.8269 128.732 99.5545 129.432 98.6737 131.003L97.4659 133.182V133.255L99.9087 131.847V132.637L96.3762 134.68V134.063L98.1833 130.757C98.8825 129.477 99.0551 129.05 99.0551 128.578C99.0551 127.933 98.6646 127.752 98.0743 128.088C97.475 128.433 97.0754 129.123 97.0754 129.822V129.849L96.3398 130.276V130.249C96.3489 129.123 97.0754 127.906 98.1016 127.307Z" fill="#23C49E"/>
-<path d="M85.7878 149.428C85.7878 151.517 85.1159 153.069 83.9081 153.769C82.7003 154.468 82.0283 153.696 82.0283 151.598C82.0283 149.501 82.7003 147.948 83.9081 147.248C85.1159 146.549 85.7878 147.33 85.7878 149.428ZM84.8888 148.583C84.7254 147.939 84.3894 147.748 83.9081 148.029C83.1816 148.447 82.7911 149.537 82.7911 151.162C82.7911 151.353 82.7911 151.526 82.8093 151.689L84.8888 148.583ZM82.9183 152.461C83.0908 153.097 83.4177 153.287 83.9081 153.006C84.6346 152.588 85.016 151.498 85.016 149.873C85.016 149.682 85.016 149.501 84.9978 149.337L82.9183 152.461Z" fill="#23C49E"/>
-<path d="M87.9219 150.509C87.9219 150.045 88.2397 149.473 88.6393 149.246C89.0388 149.019 89.3567 149.21 89.3567 149.682C89.3567 150.145 89.0388 150.717 88.6393 150.944C88.2397 151.172 87.9219 150.972 87.9219 150.509Z" fill="#23C49E"/>
-<path d="M91.5273 147.539L92.272 147.103C92.3356 147.675 92.7805 147.839 93.3799 147.493C94.0428 147.112 94.4877 146.322 94.4877 145.514C94.4877 144.706 94.0428 144.415 93.3799 144.796C92.9258 145.06 92.5535 145.514 92.3446 146.059L91.6 146.486L91.8633 142.79L94.9145 141.028V141.809L92.4808 143.216L92.3356 145.232L92.3991 145.196C92.6534 144.669 93.0439 144.252 93.5252 143.97C94.5241 143.389 95.2233 143.843 95.2233 145.069C95.2233 146.349 94.4605 147.657 93.3345 148.311C92.3083 148.91 91.5727 148.601 91.5273 147.539Z" fill="#23C49E"/>
-<path d="M100.19 143.462V144.224L96.3938 146.413V145.65L97.9467 144.751V140.247L97.8831 140.283L96.3848 142.281V141.373L97.9467 139.284L98.7095 138.839V144.315L100.19 143.462Z" fill="#23C49E"/>
-<path d="M85.7878 160.678C85.7878 162.767 85.1159 164.32 83.9081 165.019C82.7003 165.718 82.0283 164.946 82.0283 162.849C82.0283 160.751 82.7003 159.198 83.9081 158.499C85.1159 157.8 85.7878 158.581 85.7878 160.678ZM84.8888 159.825C84.7254 159.18 84.3894 158.989 83.9081 159.271C83.1816 159.689 82.7911 160.778 82.7911 162.404C82.7911 162.594 82.7911 162.767 82.8093 162.93L84.8888 159.825ZM82.9183 163.702C83.0908 164.338 83.4177 164.529 83.9081 164.247C84.6346 163.829 85.016 162.74 85.016 161.114C85.016 160.924 85.016 160.742 84.9978 160.579L82.9183 163.702Z" fill="#23C49E"/>
-<path d="M87.9219 161.75C87.9219 161.287 88.2397 160.715 88.6393 160.488C89.0388 160.261 89.3567 160.451 89.3567 160.923C89.3567 161.387 89.0388 161.959 88.6393 162.186C88.2397 162.413 87.9219 162.213 87.9219 161.75Z" fill="#23C49E"/>
-<path d="M91.5273 158.79L92.272 158.354C92.3356 158.926 92.7805 159.09 93.3799 158.744C94.0428 158.363 94.4877 157.573 94.4877 156.765C94.4877 155.957 94.0428 155.666 93.3799 156.047C92.9258 156.311 92.5535 156.765 92.3446 157.31L91.6 157.736L91.8633 154.041L94.9145 152.279V153.06L92.4808 154.467L92.3356 156.483L92.3991 156.447C92.6534 155.92 93.0439 155.503 93.5252 155.221C94.5241 154.64 95.2233 155.094 95.2233 156.32C95.2233 157.6 94.4605 158.908 93.3345 159.562C92.3083 160.152 91.5727 159.843 91.5273 158.79Z" fill="#23C49E"/>
-<path d="M100.017 152.46C100.017 154.549 99.3453 156.102 98.1376 156.801C96.9298 157.5 96.2578 156.728 96.2578 154.631C96.2578 152.533 96.9298 150.98 98.1376 150.281C99.3453 149.591 100.017 150.363 100.017 152.46ZM99.1183 151.607C98.9549 150.962 98.6189 150.771 98.1285 151.053C97.402 151.47 97.0115 152.56 97.0115 154.186C97.0115 154.376 97.0115 154.549 97.0297 154.712L99.1183 151.607ZM97.1478 155.484C97.3203 156.12 97.6472 156.311 98.1376 156.029C98.8641 155.611 99.2455 154.522 99.2455 152.896C99.2455 152.705 99.2455 152.524 99.2273 152.36L97.1478 155.484Z" fill="#23C49E"/>
-<path d="M85.7878 172.856C85.7878 174.945 85.1159 176.498 83.9081 177.197C82.7003 177.896 82.0283 177.124 82.0283 175.027C82.0283 172.929 82.7003 171.376 83.9081 170.677C85.1159 169.978 85.7878 170.768 85.7878 172.856ZM84.8888 172.012C84.7254 171.367 84.3894 171.176 83.9081 171.458C83.1816 171.876 82.7911 172.965 82.7911 174.591C82.7911 174.782 82.7911 174.954 82.8093 175.118L84.8888 172.012ZM82.9183 175.889C83.0908 176.525 83.4177 176.716 83.9081 176.434C84.6346 176.017 85.016 174.927 85.016 173.301C85.016 173.111 85.016 172.929 84.9978 172.766L82.9183 175.889Z" fill="#23C49E"/>
-<path d="M87.9219 173.937C87.9219 173.474 88.2397 172.902 88.6393 172.675C89.0388 172.448 89.3567 172.638 89.3567 173.11C89.3567 173.574 89.0388 174.146 88.6393 174.373C88.2397 174.6 87.9219 174.4 87.9219 173.937Z" fill="#23C49E"/>
-<path d="M93.9613 169.978L91.5186 171.385V170.668L93.2984 165.401L94.0885 164.947L92.3449 170.096V170.159L93.9886 169.215V167.489L94.6878 167.081V168.806L95.4869 168.343V169.097L94.6969 169.551V170.831L93.9704 171.249V169.978H93.9613Z" fill="#23C49E"/>
-<path d="M98.1284 162.486C99.2363 161.841 100.026 162.286 100.026 163.567C100.026 164.284 99.8084 165.083 99.2726 166.282C99.1818 166.491 98.1466 168.743 98.083 168.879L97.1931 169.387L98.6278 166.291C98.755 166.009 98.7913 165.919 98.8276 165.828L98.7641 165.837C98.5915 166.182 98.2283 166.563 97.8923 166.763C96.9297 167.317 96.2305 166.89 96.2305 165.737C96.2305 164.493 97.0296 163.113 98.1284 162.486ZM96.9933 165.256C96.9933 166.018 97.4836 166.309 98.1284 165.937C98.7731 165.564 99.2635 164.702 99.2635 163.939C99.2635 163.176 98.7731 162.885 98.1284 163.258C97.4836 163.63 96.9933 164.493 96.9933 165.256Z" fill="#23C49E"/>
-<g opacity="0.6">
-<g opacity="0.6">
-<path opacity="0.6" d="M25.6448 70.1598V70.9226L21.8489 73.1111V72.3483L23.4018 71.4493V66.9452L23.3382 66.9815L21.8398 68.9793V68.0712L23.4018 65.9826L24.1646 65.5376V71.0134L25.6448 70.1598Z" fill="white"/>
-<path opacity="0.6" d="M28.9047 67.7628L26.4619 69.1704V68.453L28.2418 63.186L29.0318 62.7319L27.2883 67.8809V67.9444L28.9229 67V65.2746L29.6221 64.866V66.5914L30.4212 66.1282V66.8819L29.6312 67.336V68.6164L28.9047 69.0341V67.7628Z" fill="white"/>
-<path opacity="0.6" d="M34.9617 62.4232C34.9617 64.5118 34.2897 66.0646 33.0819 66.7639C31.8741 67.4631 31.2021 66.6912 31.2021 64.5935C31.2021 62.4958 31.8741 60.943 33.0819 60.2437C34.2897 59.5536 34.9617 60.3255 34.9617 62.4232ZM34.0627 61.5786C33.8992 60.9339 33.5632 60.7432 33.0819 61.0247C32.3554 61.4424 31.965 62.5321 31.965 64.1576C31.965 64.3483 31.965 64.5209 31.9831 64.6843L34.0627 61.5786ZM32.0921 65.4562C32.2555 66.0919 32.5915 66.2826 33.0819 66.0011C33.8084 65.5833 34.1898 64.4936 34.1898 62.8681C34.1898 62.6774 34.1898 62.4958 34.1716 62.3324L32.0921 65.4562Z" fill="white"/>
-<path opacity="0.6" d="M37.1045 63.5037C37.1045 63.0406 37.4223 62.4685 37.8219 62.2415C38.2215 62.0144 38.5393 62.2051 38.5393 62.6774C38.5393 63.1405 38.2215 63.7126 37.8219 63.9396C37.4223 64.1666 37.1045 63.9669 37.1045 63.5037Z" fill="white"/>
-<path opacity="0.6" d="M44.4509 56.9476C44.4509 59.0362 43.7789 60.589 42.5712 61.2883C41.3634 61.9875 40.6914 61.2156 40.6914 59.1179C40.6914 57.0202 41.3634 55.4674 42.5712 54.7681C43.7789 54.078 44.4509 54.8499 44.4509 56.9476ZM43.5519 56.103C43.3885 55.4583 43.0525 55.2676 42.5712 55.5491C41.8447 55.9668 41.4542 57.0565 41.4542 58.682C41.4542 58.8727 41.4542 59.0453 41.4724 59.2087L43.5519 56.103ZM41.5813 59.9806C41.7539 60.6163 42.0808 60.807 42.5712 60.5255C43.2976 60.1078 43.679 59.018 43.679 57.3925C43.679 57.2018 43.67 57.0202 43.6609 56.8568L41.5813 59.9806Z" fill="white"/>
-<path opacity="0.6" d="M49.2009 54.2049C49.2009 56.2935 48.5289 57.8464 47.3212 58.5456C46.1134 59.2448 45.4414 58.473 45.4414 56.3753C45.4414 54.2775 46.1134 52.7247 47.3212 52.0255C48.5199 51.3353 49.2009 52.1072 49.2009 54.2049ZM48.3019 53.3604C48.1385 52.7156 47.8025 52.5249 47.3212 52.8064C46.5947 53.2241 46.2042 54.3139 46.2042 55.9394C46.2042 56.1301 46.2042 56.3026 46.2224 56.4661L48.3019 53.3604ZM46.3223 57.2379C46.4948 57.8736 46.8217 58.0643 47.3121 57.7828C48.0386 57.3651 48.42 56.2754 48.42 54.6499C48.42 54.4592 48.4109 54.2775 48.4018 54.1141L46.3223 57.2379Z" fill="white"/>
-</g>
-<g opacity="0.6">
-<path opacity="0.6" d="M30.1213 78.8234V79.5862L26.3255 81.7747V81.0119L27.8783 80.1129V75.6087L27.8148 75.6451L26.3164 77.6429V76.7348L27.8783 74.6461L28.6411 74.2012V79.677L30.1213 78.8234Z" fill="white"/>
-<path opacity="0.6" d="M32.7815 71.686C33.8077 71.0958 34.5069 71.4045 34.5069 72.4579C34.5069 73.1117 34.2345 73.811 33.3536 75.382L32.1459 77.5614V77.6341L34.5887 76.2265V77.0166L31.0561 79.0598V78.4423L32.8633 75.1368C33.5625 73.8564 33.735 73.4296 33.735 72.9573C33.735 72.3126 33.3446 72.131 32.7452 72.467C32.1459 72.8121 31.7463 73.5022 31.7463 74.2014V74.2287L31.0107 74.6555V74.6283C31.0198 73.4931 31.7463 72.2763 32.7815 71.686Z" fill="white"/>
-<path opacity="0.6" d="M36.832 74.9095C36.832 74.4464 37.1499 73.8743 37.5494 73.6472C37.949 73.4202 38.2668 73.6109 38.2668 74.0831C38.2668 74.5462 37.9399 75.1183 37.5494 75.3454C37.1589 75.5724 36.832 75.3726 36.832 74.9095Z" fill="white"/>
-<path opacity="0.6" d="M44.1882 68.3527C44.1882 70.4413 43.5162 71.9942 42.3085 72.6934C41.1007 73.3927 40.4287 72.6208 40.4287 70.5231C40.4287 68.4254 41.1007 66.8725 42.3085 66.1733C43.5162 65.474 44.1882 66.255 44.1882 68.3527ZM43.2892 67.4991C43.1258 66.8543 42.7898 66.6636 42.3085 66.9452C41.582 67.3629 41.1915 68.4526 41.1915 70.0781C41.1915 70.2688 41.1915 70.4413 41.2097 70.6048L43.2892 67.4991ZM41.3186 71.3767C41.4912 72.0123 41.8181 72.203 42.3085 71.9215C43.035 71.5038 43.4164 70.4141 43.4164 68.7886C43.4164 68.5979 43.4073 68.4163 43.3982 68.2528L41.3186 71.3767Z" fill="white"/>
-<path opacity="0.6" d="M48.9275 65.6107C48.9275 67.6993 48.2555 69.2521 47.0477 69.9514C45.84 70.6506 45.168 69.8787 45.168 67.781C45.168 65.6833 45.84 64.1305 47.0477 63.4312C48.2555 62.7411 48.9275 63.513 48.9275 65.6107ZM48.0285 64.7661C47.865 64.1214 47.529 63.9307 47.0477 64.2122C46.3213 64.6299 45.9308 65.7196 45.9308 67.3451C45.9308 67.5358 45.9308 67.7084 45.9489 67.8718L48.0285 64.7661ZM46.0579 68.6437C46.2304 69.2794 46.5574 69.4701 47.0477 69.1886C47.7742 68.7708 48.1556 67.6811 48.1556 66.0556C48.1556 65.8649 48.1465 65.6833 48.1374 65.5199L46.0579 68.6437Z" fill="white"/>
-</g>
-<g opacity="0.6">
-<path opacity="0.6" d="M25.6448 93.5895V94.3523L21.8489 96.5408V95.778L23.4018 94.879V90.3748L23.3382 90.4112L21.8398 92.409V91.5009L23.4018 89.4123L24.1646 88.9673V94.4431L25.6448 93.5895Z" fill="white"/>
-<path opacity="0.6" d="M27.6705 89.6209L28.2698 89.2759C28.851 88.9399 29.2596 88.277 29.2596 87.6594C29.2596 87.051 28.8692 86.8785 28.2789 87.2236C27.6886 87.5686 27.3072 88.1771 27.2527 88.8491L26.5263 89.2668C26.5807 88.1317 27.2618 87.051 28.297 86.4517C29.305 85.8705 30.0043 86.1338 30.0043 87.0964C30.0043 87.8411 29.6592 88.5857 29.0689 89.0761V89.1487C29.7954 88.84 30.2222 89.1669 30.2222 90.0114C30.2222 91.0921 29.4322 92.2998 28.3152 92.9446C27.2164 93.5802 26.4627 93.2987 26.4082 92.2181L27.1347 91.8004C27.1892 92.4088 27.6432 92.5541 28.288 92.1727C28.9872 91.7641 29.4322 91.0921 29.4322 90.4291C29.4322 89.7481 28.9781 89.5755 28.2698 89.9933L27.6432 90.3565V89.6209H27.6705Z" fill="white"/>
-<path opacity="0.6" d="M33.0452 83.7187C34.0714 83.1285 34.7706 83.4372 34.7706 84.4906C34.7706 85.1444 34.4982 85.8437 33.6173 87.4147L32.4095 89.5941V89.6668L34.8523 88.2592V89.0493L31.3198 91.0925V90.475L33.1269 87.1695C33.8262 85.8891 33.9987 85.4623 33.9987 84.9901C33.9987 84.3453 33.6082 84.1637 33.0089 84.4997C32.4095 84.8448 32.01 85.5349 32.01 86.2342V86.2614L31.2744 86.6882V86.661C31.2926 85.5258 32.0191 84.309 33.0452 83.7187Z" fill="white"/>
-<path opacity="0.6" d="M37.1045 86.9329C37.1045 86.4698 37.4223 85.8977 37.8219 85.6707C38.2215 85.4436 38.5393 85.6343 38.5393 86.1066C38.5393 86.5697 38.2215 87.1418 37.8219 87.3688C37.4223 87.5958 37.1045 87.3961 37.1045 86.9329Z" fill="white"/>
-<path opacity="0.6" d="M44.4509 80.3766C44.4509 82.4652 43.7789 84.018 42.5712 84.7173C41.3634 85.4165 40.6914 84.6446 40.6914 82.5469C40.6914 80.4492 41.3634 78.8964 42.5712 78.1971C43.7789 77.507 44.4509 78.2879 44.4509 80.3766ZM43.5519 79.532C43.3885 78.8873 43.0525 78.6966 42.5712 78.9781C41.8447 79.3958 41.4542 80.4855 41.4542 82.111C41.4542 82.3017 41.4542 82.4743 41.4724 82.6377L43.5519 79.532ZM41.5813 83.4096C41.7539 84.0453 42.0808 84.236 42.5712 83.9545C43.2976 83.5367 43.679 82.447 43.679 80.8215C43.679 80.6308 43.67 80.4492 43.6609 80.2858L41.5813 83.4096Z" fill="white"/>
-<path opacity="0.6" d="M49.2009 77.6434C49.2009 79.732 48.5289 81.2848 47.3212 81.9841C46.1134 82.6833 45.4414 81.9114 45.4414 79.8137C45.4414 77.716 46.1134 76.1632 47.3212 75.4639C48.5199 74.7738 49.2009 75.5457 49.2009 77.6434ZM48.3019 76.7898C48.1385 76.145 47.8025 75.9543 47.3212 76.2358C46.5947 76.6535 46.2042 77.7433 46.2042 79.3688C46.2042 79.5595 46.2042 79.732 46.2224 79.8955L48.3019 76.7898ZM46.3223 80.6673C46.4948 81.303 46.8217 81.4937 47.3121 81.2122C48.0386 80.7945 48.42 79.7048 48.42 78.0793C48.42 77.8886 48.4109 77.7069 48.4018 77.5435L46.3223 80.6673Z" fill="white"/>
-</g>
-<g opacity="0.6">
-<path opacity="0.6" d="M25.6448 105.349V106.112L21.8489 108.3V107.537L23.4018 106.638V102.134L23.3382 102.17L21.8398 104.168V103.26L23.4018 101.172L24.1646 100.727V106.202L25.6448 105.349Z" fill="white"/>
-<path opacity="0.6" d="M28.9047 102.952L26.4619 104.359V103.642L28.2418 98.3749L29.0318 97.9209L27.2883 103.07V103.133L28.9229 102.189V100.464L29.6221 100.055V101.78L30.4212 101.317V102.071L29.6312 102.525V103.805L28.9047 104.223V102.952Z" fill="white"/>
-<path opacity="0.6" d="M34.9617 97.6121C34.9617 99.7008 34.2897 101.254 33.0819 101.953C31.8741 102.652 31.2021 101.88 31.2021 99.7825C31.2021 97.6848 31.8741 96.1319 33.0819 95.4327C34.2897 94.7425 34.9617 95.5144 34.9617 97.6121ZM34.0627 96.7676C33.8992 96.1228 33.5632 95.9321 33.0819 96.2137C32.3554 96.6314 31.965 97.7211 31.965 99.3466C31.965 99.5373 31.965 99.7098 31.9831 99.8733L34.0627 96.7676ZM32.0921 100.645C32.2555 101.281 32.5915 101.472 33.0819 101.19C33.8084 100.772 34.1898 99.6826 34.1898 98.0571C34.1898 97.8664 34.1898 97.6848 34.1716 97.5213L32.0921 100.645Z" fill="white"/>
-<path opacity="0.6" d="M37.1045 98.6927C37.1045 98.2296 37.4223 97.6575 37.8219 97.4304C38.2215 97.2034 38.5393 97.3941 38.5393 97.8663C38.5393 98.3294 38.2215 98.9016 37.8219 99.1286C37.4223 99.3556 37.1045 99.1558 37.1045 98.6927Z" fill="white"/>
-<path opacity="0.6" d="M44.4509 92.1365C44.4509 94.2252 43.7789 95.778 42.5712 96.4772C41.3634 97.1765 40.6914 96.4046 40.6914 94.3069C40.6914 92.2092 41.3634 90.6563 42.5712 89.9571C43.7789 89.2669 44.4509 90.0388 44.4509 92.1365ZM43.5519 91.292C43.3885 90.6473 43.0525 90.4566 42.5712 90.7381C41.8447 91.1558 41.4542 92.2455 41.4542 93.871C41.4542 94.0617 41.4542 94.2342 41.4724 94.3977L43.5519 91.292ZM41.5813 95.1605C41.7539 95.7962 42.0808 95.9869 42.5712 95.7054C43.2976 95.2876 43.679 94.1979 43.679 92.5724C43.679 92.3817 43.67 92.2001 43.6609 92.0366L41.5813 95.1605Z" fill="white"/>
-<path opacity="0.6" d="M49.2009 89.3939C49.2009 91.4825 48.5289 93.0353 47.3212 93.7346C46.1134 94.4338 45.4414 93.6619 45.4414 91.5642C45.4414 89.4665 46.1134 87.9137 47.3212 87.2144C48.5199 86.5243 49.2009 87.2962 49.2009 89.3939ZM48.3019 88.5493C48.1385 87.9046 47.8025 87.7139 47.3212 87.9954C46.5947 88.4131 46.2042 89.5028 46.2042 91.1283C46.2042 91.319 46.2042 91.4916 46.2224 91.655L48.3019 88.5493ZM46.3223 92.4269C46.4948 93.0626 46.8217 93.2533 47.3121 92.9718C48.0386 92.554 48.42 91.4643 48.42 89.8388C48.42 89.6481 48.4109 89.4665 48.4018 89.303L46.3223 92.4269Z" fill="white"/>
-</g>
-<g opacity="0.6">
-<path opacity="0.6" d="M30.1213 114.012V114.775L26.3255 116.964V116.201L27.8783 115.302V110.798L27.8148 110.834L26.3164 112.832V111.924L27.8783 109.835L28.6411 109.39V114.866L30.1213 114.012Z" fill="white"/>
-<path opacity="0.6" d="M32.7815 106.875C33.8077 106.285 34.5069 106.593 34.5069 107.647C34.5069 108.301 34.2345 109 33.3536 110.571L32.1459 112.75V112.823L34.5887 111.415V112.206L31.0561 114.249V113.631L32.8633 110.326C33.5625 109.045 33.735 108.619 33.735 108.146C33.735 107.502 33.3446 107.32 32.7452 107.656C32.1459 108.001 31.7463 108.691 31.7463 109.39V109.418L31.0107 109.844V109.817C31.0198 108.682 31.7463 107.465 32.7815 106.875Z" fill="white"/>
-<path opacity="0.6" d="M36.832 110.089C36.832 109.626 37.1499 109.054 37.5494 108.827C37.949 108.6 38.2668 108.791 38.2668 109.263C38.2668 109.726 37.9399 110.298 37.5494 110.525C37.1589 110.752 36.832 110.552 36.832 110.089Z" fill="white"/>
-<path opacity="0.6" d="M44.1882 103.533C44.1882 105.621 43.5162 107.174 42.3085 107.874C41.1007 108.573 40.4287 107.801 40.4287 105.703C40.4287 103.605 41.1007 102.053 42.3085 101.353C43.5162 100.663 44.1882 101.444 44.1882 103.533ZM43.2892 102.688C43.1258 102.044 42.7898 101.853 42.3085 102.134C41.582 102.552 41.1915 103.642 41.1915 105.267C41.1915 105.458 41.1915 105.631 41.2097 105.794L43.2892 102.688ZM41.3186 106.566C41.4912 107.202 41.8181 107.392 42.3085 107.111C43.035 106.693 43.4164 105.603 43.4164 103.978C43.4164 103.787 43.4073 103.605 43.3982 103.442L41.3186 106.566Z" fill="white"/>
-<path opacity="0.6" d="M48.9275 100.8C48.9275 102.888 48.2555 104.441 47.0477 105.14C45.84 105.84 45.168 105.068 45.168 102.97C45.168 100.872 45.84 99.3194 47.0477 98.6202C48.2555 97.93 48.9275 98.7019 48.9275 100.8ZM48.0285 99.9551C47.865 99.3103 47.529 99.1196 47.0477 99.4012C46.3213 99.8189 45.9308 100.909 45.9308 102.534C45.9308 102.725 45.9308 102.897 45.9489 103.061L48.0285 99.9551ZM46.0579 103.824C46.2304 104.459 46.5574 104.65 47.0477 104.368C47.7742 103.951 48.1556 102.861 48.1556 101.236C48.1556 101.045 48.1465 100.863 48.1374 100.7L46.0579 103.824Z" fill="white"/>
-</g>
-<g opacity="0.6">
-<path opacity="0.6" d="M25.6448 128.777V129.54L21.8489 131.729V130.966L23.4018 130.067V125.563L23.3382 125.599L21.8398 127.597V126.689L23.4018 124.6L24.1646 124.155V129.631L25.6448 128.777Z" fill="white"/>
-<path opacity="0.6" d="M27.6705 124.809L28.2698 124.464C28.851 124.128 29.2596 123.465 29.2596 122.848C29.2596 122.239 28.8692 122.067 28.2789 122.412C27.6886 122.757 27.3072 123.366 27.2527 124.038L26.5263 124.455C26.5807 123.32 27.2618 122.239 28.297 121.64C29.305 121.059 30.0043 121.322 30.0043 122.285C30.0043 123.03 29.6592 123.774 29.0689 124.265V124.337C29.7954 124.028 30.2222 124.355 30.2222 125.2C30.2222 126.281 29.4322 127.488 28.3152 128.133C27.2164 128.769 26.4627 128.487 26.4082 127.407L27.1347 126.989C27.1892 127.597 27.6432 127.743 28.288 127.361C28.9872 126.953 29.4322 126.281 29.4322 125.618C29.4322 124.937 28.9781 124.764 28.2698 125.182L27.6432 125.545V124.809H27.6705Z" fill="white"/>
-<path opacity="0.6" d="M33.0452 118.898C34.0714 118.308 34.7706 118.616 34.7706 119.67C34.7706 120.324 34.4982 121.023 33.6173 122.594L32.4095 124.773V124.846L34.8523 123.438V124.228L31.3198 126.272V125.654L33.1269 122.349C33.8262 121.068 33.9987 120.641 33.9987 120.169C33.9987 119.525 33.6082 119.343 33.0089 119.679C32.4095 120.024 32.01 120.714 32.01 121.413V121.441L31.2744 121.867V121.84C31.2926 120.714 32.0191 119.497 33.0452 118.898Z" fill="white"/>
-<path opacity="0.6" d="M37.1045 122.121C37.1045 121.658 37.4223 121.086 37.8219 120.859C38.2215 120.632 38.5393 120.823 38.5393 121.295C38.5393 121.758 38.2215 122.33 37.8219 122.557C37.4223 122.784 37.1045 122.585 37.1045 122.121Z" fill="white"/>
-<path opacity="0.6" d="M44.4509 115.565C44.4509 117.654 43.7789 119.207 42.5712 119.906C41.3634 120.605 40.6914 119.833 40.6914 117.736C40.6914 115.638 41.3634 114.085 42.5712 113.386C43.7789 112.696 44.4509 113.468 44.4509 115.565ZM43.5519 114.721C43.3885 114.076 43.0525 113.885 42.5712 114.167C41.8447 114.585 41.4542 115.674 41.4542 117.3C41.4542 117.49 41.4542 117.663 41.4724 117.826L43.5519 114.721ZM41.5813 118.598C41.7539 119.234 42.0808 119.425 42.5712 119.143C43.2976 118.725 43.679 117.636 43.679 116.01C43.679 115.82 43.67 115.638 43.6609 115.474L41.5813 118.598Z" fill="white"/>
-<path opacity="0.6" d="M49.2009 112.832C49.2009 114.92 48.5289 116.473 47.3212 117.172C46.1134 117.872 45.4414 117.1 45.4414 115.002C45.4414 112.904 46.1134 111.352 47.3212 110.652C48.5199 109.953 49.2009 110.734 49.2009 112.832ZM48.3019 111.978C48.1385 111.333 47.8025 111.143 47.3212 111.424C46.5947 111.842 46.2042 112.932 46.2042 114.557C46.2042 114.748 46.2042 114.92 46.2224 115.084L48.3019 111.978ZM46.3223 115.856C46.4948 116.491 46.8217 116.682 47.3121 116.401C48.0386 115.983 48.42 114.893 48.42 113.268C48.42 113.077 48.4109 112.895 48.4018 112.732L46.3223 115.856Z" fill="white"/>
-</g>
-<g opacity="0.6">
-<path opacity="0.6" d="M25.6448 151.318V152.08L21.8489 154.269V153.506L23.4018 152.607V148.103L23.3382 148.139L21.8398 150.137V149.229L23.4018 147.14L24.1646 146.695V152.171L25.6448 151.318Z" fill="white"/>
-<path opacity="0.6" d="M28.9047 148.92L26.4619 150.327V149.61L28.2418 144.343L29.0318 143.889L27.2883 149.038V149.101L28.9229 148.157V146.431L29.6221 146.023V147.748L30.4212 147.285V148.039L29.6312 148.493V149.773L28.9047 150.191V148.92Z" fill="white"/>
-<path opacity="0.6" d="M34.9617 143.58C34.9617 145.669 34.2897 147.222 33.0819 147.921C31.8741 148.62 31.2021 147.848 31.2021 145.751C31.2021 143.653 31.8741 142.1 33.0819 141.401C34.2897 140.711 34.9617 141.492 34.9617 143.58ZM34.0627 142.736C33.8992 142.091 33.5632 141.9 33.0819 142.182C32.3554 142.599 31.965 143.689 31.965 145.315C31.965 145.505 31.965 145.678 31.9831 145.841L34.0627 142.736ZM32.0921 146.613C32.2555 147.249 32.5915 147.44 33.0819 147.158C33.8084 146.74 34.1898 145.651 34.1898 144.025C34.1898 143.834 34.1898 143.653 34.1716 143.489L32.0921 146.613Z" fill="white"/>
-<path opacity="0.6" d="M37.1045 144.661C37.1045 144.198 37.4223 143.626 37.8219 143.399C38.2215 143.172 38.5393 143.362 38.5393 143.835C38.5393 144.298 38.2215 144.87 37.8219 145.097C37.4223 145.324 37.1045 145.124 37.1045 144.661Z" fill="white"/>
-<path opacity="0.6" d="M44.4509 138.104C44.4509 140.193 43.7789 141.746 42.5712 142.445C41.3634 143.144 40.6914 142.372 40.6914 140.275C40.6914 138.177 41.3634 136.624 42.5712 135.925C43.7789 135.235 44.4509 136.007 44.4509 138.104ZM43.5519 137.26C43.3885 136.615 43.0525 136.424 42.5712 136.706C41.8447 137.124 41.4542 138.213 41.4542 139.839C41.4542 140.029 41.4542 140.202 41.4724 140.365L43.5519 137.26ZM41.5813 141.137C41.7539 141.773 42.0808 141.964 42.5712 141.682C43.2976 141.265 43.679 140.175 43.679 138.549C43.679 138.359 43.67 138.177 43.6609 138.014L41.5813 141.137Z" fill="white"/>
-<path opacity="0.6" d="M49.2009 135.362C49.2009 137.451 48.5289 139.003 47.3212 139.703C46.1134 140.402 45.4414 139.63 45.4414 137.532C45.4414 135.435 46.1134 133.882 47.3212 133.182C48.5199 132.492 49.2009 133.273 49.2009 135.362ZM48.3019 134.517C48.1385 133.873 47.8025 133.682 47.3212 133.963C46.5947 134.381 46.2042 135.471 46.2042 137.096C46.2042 137.287 46.2042 137.46 46.2224 137.623L48.3019 134.517ZM46.3223 138.395C46.4948 139.031 46.8217 139.221 47.3121 138.94C48.0386 138.522 48.42 137.432 48.42 135.807C48.42 135.616 48.4109 135.435 48.4018 135.271L46.3223 138.395Z" fill="white"/>
-</g>
-<g opacity="0.6">
-<path opacity="0.6" d="M30.1213 159.98V160.743L26.3255 162.931V162.169L27.8783 161.27V156.765L27.8148 156.802L26.3164 158.8V157.891L27.8783 155.803L28.6411 155.358V160.834L30.1213 159.98Z" fill="white"/>
-<path opacity="0.6" d="M32.7815 152.843C33.8077 152.252 34.5069 152.561 34.5069 153.615C34.5069 154.268 34.2345 154.968 33.3536 156.539L32.1459 158.718V158.791L34.5887 157.383V158.173L31.0561 160.217V159.599L32.8633 156.294C33.5625 155.013 33.735 154.586 33.735 154.114C33.735 153.469 33.3446 153.288 32.7452 153.624C32.1459 153.969 31.7463 154.659 31.7463 155.358V155.385L31.0107 155.812V155.785C31.0198 154.65 31.7463 153.433 32.7815 152.843Z" fill="white"/>
-<path opacity="0.6" d="M36.832 156.066C36.832 155.603 37.1499 155.031 37.5494 154.804C37.949 154.577 38.2668 154.768 38.2668 155.24C38.2668 155.703 37.9399 156.275 37.5494 156.502C37.1589 156.729 36.832 156.529 36.832 156.066Z" fill="white"/>
-<path opacity="0.6" d="M44.1882 149.51C44.1882 151.599 43.5162 153.152 42.3085 153.851C41.1007 154.55 40.4287 153.778 40.4287 151.68C40.4287 149.583 41.1007 148.03 42.3085 147.331C43.5162 146.64 44.1882 147.412 44.1882 149.51ZM43.2892 148.656C43.1258 148.012 42.7898 147.821 42.3085 148.103C41.582 148.52 41.1915 149.61 41.1915 151.235C41.1915 151.426 41.1915 151.599 41.2097 151.762L43.2892 148.656ZM41.3186 152.534C41.4912 153.17 41.8181 153.36 42.3085 153.079C43.035 152.661 43.4164 151.571 43.4164 149.946C43.4164 149.755 43.4073 149.574 43.3982 149.41L41.3186 152.534Z" fill="white"/>
-<path opacity="0.6" d="M48.9275 146.767C48.9275 148.856 48.2555 150.409 47.0477 151.108C45.84 151.807 45.168 151.035 45.168 148.938C45.168 146.84 45.84 145.287 47.0477 144.588C48.2555 143.898 48.9275 144.67 48.9275 146.767ZM48.0285 145.923C47.865 145.278 47.529 145.087 47.0477 145.369C46.3213 145.787 45.9308 146.876 45.9308 148.502C45.9308 148.693 45.9308 148.865 45.9489 149.029L48.0285 145.923ZM46.0579 149.8C46.2304 150.436 46.5574 150.627 47.0477 150.345C47.7742 149.928 48.1556 148.838 48.1556 147.212C48.1556 147.022 48.1465 146.84 48.1374 146.677L46.0579 149.8Z" fill="white"/>
-</g>
-<g opacity="0.6">
-<path opacity="0.6" d="M25.6448 174.746V175.509L21.8489 177.697V176.934L23.4018 176.035V171.531L23.3382 171.567L21.8398 173.565V172.657L23.4018 170.569L24.1646 170.124V175.599L25.6448 174.746Z" fill="white"/>
-<path opacity="0.6" d="M27.6705 170.777L28.2698 170.432C28.851 170.096 29.2596 169.433 29.2596 168.816C29.2596 168.207 28.8692 168.035 28.2789 168.38C27.6886 168.725 27.3072 169.333 27.2527 170.005L26.5263 170.423C26.5807 169.288 27.2618 168.207 28.297 167.608C29.305 167.027 30.0043 167.29 30.0043 168.253C30.0043 168.997 29.6592 169.742 29.0689 170.232V170.305C29.7954 169.996 30.2222 170.323 30.2222 171.168C30.2222 172.248 29.4322 173.456 28.3152 174.101C27.2164 174.736 26.4627 174.455 26.4082 173.374L27.1347 172.957C27.1892 173.565 27.6432 173.71 28.288 173.329C28.9872 172.92 29.4322 172.248 29.4322 171.585C29.4322 170.904 28.9781 170.732 28.2698 171.15L27.6432 171.513V170.777H27.6705Z" fill="white"/>
-<path opacity="0.6" d="M33.0452 164.875C34.0714 164.285 34.7706 164.593 34.7706 165.647C34.7706 166.301 34.4982 167 33.6173 168.571L32.4095 170.75V170.823L34.8523 169.415V170.206L31.3198 172.249V171.631L33.1269 168.326C33.8262 167.045 33.9987 166.619 33.9987 166.146C33.9987 165.502 33.6082 165.32 33.0089 165.656C32.4095 166.001 32.01 166.691 32.01 167.39V167.418L31.2744 167.844V167.817C31.2926 166.682 32.0191 165.465 33.0452 164.875Z" fill="white"/>
-<path opacity="0.6" d="M37.1045 168.098C37.1045 167.635 37.4223 167.063 37.8219 166.836C38.2215 166.609 38.5393 166.8 38.5393 167.272C38.5393 167.735 38.2215 168.307 37.8219 168.534C37.4223 168.752 37.1045 168.562 37.1045 168.098Z" fill="white"/>
-<path opacity="0.6" d="M44.4509 161.542C44.4509 163.63 43.7789 165.183 42.5712 165.882C41.3634 166.582 40.6914 165.81 40.6914 163.712C40.6914 161.614 41.3634 160.061 42.5712 159.362C43.7789 158.663 44.4509 159.444 44.4509 161.542ZM43.5519 160.688C43.3885 160.043 43.0525 159.853 42.5712 160.134C41.8447 160.552 41.4542 161.642 41.4542 163.267C41.4542 163.458 41.4542 163.63 41.4724 163.794L43.5519 160.688ZM41.5813 164.566C41.7539 165.201 42.0808 165.392 42.5712 165.111C43.2976 164.693 43.679 163.603 43.679 161.978C43.679 161.787 43.67 161.605 43.6609 161.442L41.5813 164.566Z" fill="white"/>
-<path opacity="0.6" d="M49.2009 158.8C49.2009 160.888 48.5289 162.441 47.3212 163.14C46.1134 163.84 45.4414 163.068 45.4414 160.97C45.4414 158.872 46.1134 157.319 47.3212 156.62C48.5199 155.93 49.2009 156.702 49.2009 158.8ZM48.3019 157.955C48.1385 157.31 47.8025 157.12 47.3212 157.401C46.5947 157.819 46.2042 158.909 46.2042 160.534C46.2042 160.725 46.2042 160.897 46.2224 161.061L48.3019 157.955ZM46.3223 161.824C46.4948 162.459 46.8217 162.65 47.3121 162.368C48.0386 161.951 48.42 160.861 48.42 159.236C48.42 159.045 48.4109 158.863 48.4018 158.7L46.3223 161.824Z" fill="white"/>
-</g>
-<g opacity="0.6">
-<path opacity="0.6" d="M25.6448 186.506V187.268L21.8489 189.457V188.694L23.4018 187.795V183.291L23.3382 183.327L21.8398 185.325V184.417L23.4018 182.328L24.1646 181.883V187.359L25.6448 186.506Z" fill="white"/>
-<path opacity="0.6" d="M28.9047 184.109L26.4619 185.516V184.799L28.2418 179.532L29.0318 179.078L27.2883 184.227V184.29L28.9229 183.346V181.62L29.6221 181.212V182.937L30.4212 182.474V183.228L29.6312 183.682V184.962L28.9047 185.38V184.109Z" fill="white"/>
-<path opacity="0.6" d="M34.9617 178.769C34.9617 180.857 34.2897 182.41 33.0819 183.11C31.8741 183.809 31.2021 183.037 31.2021 180.939C31.2021 178.842 31.8741 177.289 33.0819 176.589C34.2897 175.899 34.9617 176.671 34.9617 178.769ZM34.0627 177.924C33.8992 177.28 33.5632 177.089 33.0819 177.37C32.3554 177.788 31.965 178.878 31.965 180.503C31.965 180.694 31.965 180.867 31.9831 181.03L34.0627 177.924ZM32.0921 181.802C32.2555 182.438 32.5915 182.628 33.0819 182.347C33.8084 181.929 34.1898 180.839 34.1898 179.214C34.1898 179.023 34.1898 178.841 34.1716 178.678L32.0921 181.802Z" fill="white"/>
-<path opacity="0.6" d="M37.1045 179.849C37.1045 179.386 37.4223 178.814 37.8219 178.587C38.2215 178.36 38.5393 178.551 38.5393 179.023C38.5393 179.486 38.2215 180.058 37.8219 180.285C37.4223 180.512 37.1045 180.313 37.1045 179.849Z" fill="white"/>
-<path opacity="0.6" d="M44.4509 173.293C44.4509 175.382 43.7789 176.935 42.5712 177.634C41.3634 178.333 40.6914 177.561 40.6914 175.464C40.6914 173.366 41.3634 171.813 42.5712 171.114C43.7789 170.424 44.4509 171.196 44.4509 173.293ZM43.5519 172.449C43.3885 171.804 43.0525 171.613 42.5712 171.895C41.8447 172.313 41.4542 173.402 41.4542 175.028C41.4542 175.218 41.4542 175.391 41.4724 175.554L43.5519 172.449ZM41.5813 176.326C41.7539 176.962 42.0808 177.153 42.5712 176.871C43.2976 176.453 43.679 175.364 43.679 173.738C43.679 173.548 43.67 173.366 43.6609 173.202L41.5813 176.326Z" fill="white"/>
-<path opacity="0.6" d="M49.2009 170.551C49.2009 172.639 48.5289 174.192 47.3212 174.891C46.1134 175.591 45.4414 174.819 45.4414 172.721C45.4414 170.623 46.1134 169.07 47.3212 168.371C48.5199 167.681 49.2009 168.453 49.2009 170.551ZM48.3019 169.706C48.1385 169.061 47.8025 168.871 47.3212 169.152C46.5947 169.57 46.2042 170.66 46.2042 172.285C46.2042 172.476 46.2042 172.648 46.2224 172.812L48.3019 169.706ZM46.3223 173.584C46.4948 174.219 46.8217 174.41 47.3121 174.129C48.0386 173.711 48.42 172.621 48.42 170.996C48.42 170.805 48.4109 170.623 48.4018 170.46L46.3223 173.584Z" fill="white"/>
-</g>
-<g opacity="0.6">
-<path opacity="0.6" d="M30.1213 195.169V195.932L26.3255 198.12V197.358L27.8783 196.459V191.954L27.8148 191.991L26.3164 193.989V193.08L27.8783 190.992L28.6411 190.547V196.023L30.1213 195.169Z" fill="white"/>
-<path opacity="0.6" d="M32.7815 188.032C33.8077 187.441 34.5069 187.75 34.5069 188.804C34.5069 189.457 34.2345 190.157 33.3536 191.728L32.1459 193.907V193.98L34.5887 192.572V193.362L31.0561 195.405V194.788L32.8633 191.482C33.5625 190.202 33.735 189.775 33.735 189.303C33.735 188.658 33.3446 188.477 32.7452 188.813C32.1459 189.158 31.7463 189.848 31.7463 190.547V190.574L31.0107 191.001V190.974C31.0198 189.839 31.7463 188.622 32.7815 188.032Z" fill="white"/>
-<path opacity="0.6" d="M36.832 191.255C36.832 190.792 37.1499 190.22 37.5494 189.993C37.949 189.766 38.2668 189.957 38.2668 190.429C38.2668 190.892 37.9399 191.464 37.5494 191.691C37.1589 191.918 36.832 191.718 36.832 191.255Z" fill="white"/>
-<path opacity="0.6" d="M44.1882 184.699C44.1882 186.788 43.5162 188.341 42.3085 189.04C41.1007 189.739 40.4287 188.967 40.4287 186.869C40.4287 184.772 41.1007 183.219 42.3085 182.52C43.5162 181.829 44.1882 182.601 44.1882 184.699ZM43.2892 183.845C43.1258 183.201 42.7898 183.01 42.3085 183.291C41.582 183.709 41.1915 184.799 41.1915 186.424C41.1915 186.615 41.1915 186.788 41.2097 186.951L43.2892 183.845ZM41.3186 187.723C41.4912 188.359 41.8181 188.549 42.3085 188.268C43.035 187.85 43.4164 186.76 43.4164 185.135C43.4164 184.944 43.4073 184.763 43.3982 184.599L41.3186 187.723Z" fill="white"/>
-<path opacity="0.6" d="M48.9275 181.956C48.9275 184.045 48.2555 185.598 47.0477 186.297C45.84 186.996 45.168 186.224 45.168 184.127C45.168 182.029 45.84 180.476 47.0477 179.777C48.2555 179.087 48.9275 179.859 48.9275 181.956ZM48.0285 181.112C47.865 180.467 47.529 180.276 47.0477 180.558C46.3213 180.976 45.9308 182.065 45.9308 183.691C45.9308 183.882 45.9308 184.054 45.9489 184.218L48.0285 181.112ZM46.0579 184.989C46.2304 185.625 46.5574 185.816 47.0477 185.534C47.7742 185.117 48.1556 184.027 48.1556 182.401C48.1556 182.211 48.1465 182.029 48.1374 181.866L46.0579 184.989Z" fill="white"/>
-</g>
-<g opacity="0.6">
-<path opacity="0.6" d="M25.6448 209.935V210.698L21.8489 212.887V212.124L23.4018 211.225V206.721L23.3382 206.757L21.8398 208.755V207.847L23.4018 205.758L24.1646 205.313V210.789L25.6448 209.935Z" fill="white"/>
-<path opacity="0.6" d="M27.6705 205.967L28.2698 205.622C28.851 205.286 29.2596 204.623 29.2596 204.005C29.2596 203.397 28.8692 203.224 28.2789 203.569C27.6886 203.914 27.3072 204.523 27.2527 205.195L26.5263 205.612C26.5807 204.477 27.2618 203.397 28.297 202.797C29.305 202.216 30.0043 202.48 30.0043 203.442C30.0043 204.187 29.6592 204.931 29.0689 205.422V205.494C29.7954 205.186 30.2222 205.513 30.2222 206.357C30.2222 207.438 29.4322 208.646 28.3152 209.29C27.2164 209.926 26.4627 209.644 26.4082 208.564L27.1347 208.146C27.1892 208.755 27.6432 208.9 28.288 208.518C28.9872 208.11 29.4322 207.438 29.4322 206.775C29.4322 206.094 28.9781 205.921 28.2698 206.339L27.6432 206.702V205.967H27.6705Z" fill="white"/>
-<path opacity="0.6" d="M33.0452 200.064C34.0714 199.474 34.7706 199.783 34.7706 200.836C34.7706 201.49 34.4982 202.189 33.6173 203.76L32.4095 205.94V206.012L34.8523 204.605V205.395L31.3198 207.438V206.821L33.1269 203.515C33.8262 202.235 33.9987 201.808 33.9987 201.336C33.9987 200.691 33.6082 200.509 33.0089 200.845C32.4095 201.19 32.01 201.881 32.01 202.58V202.607L31.2744 203.034V203.007C31.2926 201.872 32.0191 200.655 33.0452 200.064Z" fill="white"/>
-<path opacity="0.6" d="M37.1045 203.279C37.1045 202.815 37.4223 202.243 37.8219 202.016C38.2215 201.789 38.5393 201.98 38.5393 202.452C38.5393 202.915 38.2215 203.487 37.8219 203.715C37.4223 203.942 37.1045 203.742 37.1045 203.279Z" fill="white"/>
-<path opacity="0.6" d="M44.4509 196.722C44.4509 198.811 43.7789 200.364 42.5712 201.063C41.3634 201.762 40.6914 200.99 40.6914 198.893C40.6914 196.795 41.3634 195.242 42.5712 194.543C43.7789 193.853 44.4509 194.634 44.4509 196.722ZM43.5519 195.878C43.3885 195.233 43.0525 195.042 42.5712 195.324C41.8447 195.742 41.4542 196.831 41.4542 198.457C41.4542 198.647 41.4542 198.82 41.4724 198.983L43.5519 195.878ZM41.5813 199.755C41.7539 200.391 42.0808 200.582 42.5712 200.3C43.2976 199.882 43.679 198.793 43.679 197.167C43.679 196.977 43.67 196.795 43.6609 196.631L41.5813 199.755Z" fill="white"/>
-<path opacity="0.6" d="M49.2009 193.989C49.2009 196.078 48.5289 197.631 47.3212 198.33C46.1134 199.029 45.4414 198.257 45.4414 196.159C45.4414 194.062 46.1134 192.509 47.3212 191.81C48.5199 191.119 49.2009 191.891 49.2009 193.989ZM48.3019 193.135C48.1385 192.491 47.8025 192.3 47.3212 192.582C46.5947 192.999 46.2042 194.089 46.2042 195.714C46.2042 195.905 46.2042 196.078 46.2224 196.241L48.3019 193.135ZM46.3223 197.013C46.4948 197.649 46.8217 197.839 47.3121 197.558C48.0386 197.14 48.42 196.05 48.42 194.425C48.42 194.234 48.4109 194.053 48.4018 193.889L46.3223 197.013Z" fill="white"/>
-</g>
-</g>
-<path d="M98.4106 64.6748L209.362 0.617544C211.868 -0.826333 213.903 0.345114 213.903 3.24195V162.804C213.903 165.701 211.868 169.215 209.362 170.668L98.4106 234.725C95.9043 236.169 93.8701 234.998 93.8701 232.101V72.539C93.8701 69.6421 95.9043 66.1278 98.4106 64.6748Z" fill="#363636"/>
-<path d="M104.604 199.291L203.596 142.145C204.713 141.5 205.612 142.027 205.612 143.307V160.443C205.612 161.732 204.713 163.294 203.596 163.939L104.604 221.086C103.487 221.73 102.588 221.204 102.588 219.923V202.788C102.588 201.498 103.487 199.936 104.604 199.291Z" fill="#424242"/>
-<path d="M100.444 66.4912L211.387 2.43395C213.893 0.990073 215.927 2.16152 215.927 5.05836V164.62C215.927 167.517 213.893 171.032 211.387 172.485L100.435 236.542C97.9287 237.986 95.8945 236.814 95.8945 233.917V74.3554C95.9036 71.4585 97.9378 67.9442 100.444 66.4912Z" fill="#424242"/>
-<path d="M100.444 66.4912L211.386 2.43395C213.893 0.990073 215.927 2.16152 215.927 5.05836V45.4506L95.9033 114.748V74.3554C95.9033 71.4585 97.9375 67.9442 100.444 66.4912Z" fill="#424242"/>
-<path d="M193.679 64.6748L304.631 0.617544C307.137 -0.826333 309.171 0.345114 309.171 3.24195V162.804C309.171 165.701 307.137 169.215 304.631 170.668L193.679 234.725C191.173 236.169 189.139 234.998 189.139 232.101V72.539C189.139 69.6421 191.173 66.1278 193.679 64.6748Z" fill="#424242"/>
-<path d="M193.679 64.6748L304.63 0.617544C307.137 -0.826333 309.171 0.345114 309.171 3.24195V43.6342L189.147 112.931V72.539C189.138 69.6421 191.173 66.1278 193.679 64.6748Z" fill="#424242"/>
-<path d="M203.968 76.8164L202.688 77.552C202.615 77.7064 202.134 79.577 200.554 80.4851V81.8745C201.625 81.257 202.361 80.3943 202.515 79.9675L202.588 79.9221V88.6126L203.959 87.8226V76.8164H203.968ZM213.194 78.9414L211.85 79.7133V72.2578L210.343 73.1295L206.202 83.3366V84.4354L210.543 81.929V84.0176L211.85 83.2639V81.1753L213.194 80.4034V78.9414ZM207.864 82.0198L210.343 75.763L210.543 75.1001V80.467L207.864 82.0198ZM220.85 71.84C220.85 68.6526 219.642 67.6174 217.617 68.7797C215.574 69.9603 214.357 72.4031 214.357 75.5905V76.8891C214.357 80.1401 215.592 81.2661 217.635 80.0856C219.66 78.9141 220.859 76.3896 220.859 73.1386V71.84H220.85ZM219.388 74.2465C219.388 76.2352 218.779 77.9606 217.626 78.6326C216.445 79.3137 215.81 78.3057 215.81 76.317V74.4826C215.81 72.5393 216.436 70.9138 217.617 70.2327C218.779 69.5607 219.397 70.4597 219.397 72.4121V74.2465H219.388ZM222.984 76.9526C223.501 76.653 223.928 75.9265 223.928 75.3181C223.928 74.7278 223.501 74.4917 222.984 74.7914C222.475 75.082 222.039 75.7993 222.039 76.4078C222.039 77.0162 222.457 77.2614 222.984 76.9526ZM231.447 65.7195C231.447 62.532 230.239 61.4968 228.214 62.6592C226.171 63.8397 224.954 66.2825 224.954 69.4699V70.7685C224.954 74.0195 226.189 75.1455 228.233 73.965C230.258 72.7935 231.456 70.269 231.456 67.018V65.7195H231.447ZM229.994 68.1259C229.994 70.1146 229.386 71.84 228.233 72.512C227.052 73.1931 226.416 72.1851 226.416 70.1964V68.362C226.416 66.4187 227.043 64.7932 228.223 64.1121C229.386 63.4401 230.003 64.3391 230.003 66.2916V68.1259H229.994ZM239.33 61.1699C239.33 57.9825 238.122 56.9472 236.097 58.1096C234.053 59.2901 232.837 61.7329 232.837 64.9203V66.2189C232.837 69.4699 234.072 70.5959 236.115 69.4154C238.14 68.244 239.339 65.7195 239.339 62.4685V61.1699H239.33ZM237.867 63.5763C237.867 65.5651 237.259 67.2905 236.106 67.9625C234.925 68.6435 234.29 67.6355 234.29 65.6468V63.8124C234.29 61.8691 234.916 60.2436 236.097 59.5625C237.259 58.8905 237.877 59.7896 237.877 61.742V63.5763H237.867ZM251.226 59.0812L246.231 61.969L251.189 50.6813V49.5553L244.406 53.4692V54.9312L249.4 52.0526L244.442 63.3402V64.4663L251.226 60.5524V59.0812ZM258.254 56.4841L259.925 55.5215L257.9 52.1434C258.935 51.0082 259.571 49.637 259.571 48.1205C259.571 46.1862 258.563 45.3054 256.302 46.6131L252.96 48.5382V59.5535L254.44 58.6998V54.4863L256.429 53.3421L258.254 56.4841ZM254.431 49.1466L256.293 48.0751C257.691 47.2669 258.109 47.9752 258.109 48.9832C258.109 50.1274 257.591 51.1808 256.202 51.9799L254.431 53.0061V49.1466ZM262.35 43.1078L260.643 44.0885L263.621 47.8753L260.624 55.1129L262.341 54.123L264.575 48.62L264.647 48.5745L266.881 51.4986L268.598 50.5088L265.646 46.7039L268.579 39.5117L266.872 40.4925L264.647 46.041L264.575 46.0864L262.35 43.1078Z" fill="#424242"/>
-<path d="M199.872 199.291L298.864 142.145C299.981 141.5 300.88 142.027 300.88 143.307V160.443C300.88 161.732 299.981 163.294 298.864 163.939L199.872 221.086C198.755 221.73 197.856 221.204 197.856 219.923V202.788C197.856 201.498 198.755 199.936 199.872 199.291Z" fill="#424242"/>
-<path opacity="0.2" d="M199.736 121.159L298.582 64.0936C299.136 63.7758 299.59 64.0301 299.59 64.6748V78.6505C299.59 79.2952 299.136 80.0762 298.582 80.394L199.736 137.459C199.182 137.777 198.728 137.522 198.728 136.878V122.902C198.728 122.266 199.173 121.485 199.736 121.159Z" fill="#424242"/>
-<path opacity="0.2" d="M198.864 183.272L296.721 126.771" stroke="white" stroke-width="2.16763" stroke-linecap="round"/>
-<path opacity="0.2" d="M198.864 167.835L296.721 111.333" stroke="white" stroke-width="2.16763" stroke-linecap="round"/>
-<path opacity="0.2" d="M198.864 153.305L296.721 96.8032" stroke="white" stroke-width="2.16763" stroke-linecap="round"/>
-<path d="M115.601 82.0923L112.804 83.7087L112.123 86.7781L110.897 87.4864L113.549 76.2351L114.902 75.4541L117.554 83.6452L116.264 84.3898L115.601 82.0923ZM115.32 81.1206L114.23 77.4065L114.194 77.4338L113.095 82.4101L115.32 81.1206Z" fill="white"/>
-<path d="M121.64 73.8013C123.03 73.0022 123.938 73.2383 124.047 74.4551L122.93 75.0999C122.821 74.5641 122.33 74.4733 121.631 74.8819C120.887 75.3087 120.396 75.9989 120.396 76.6073C120.396 77.134 120.705 77.243 121.45 77.0069L122.376 76.7072C123.629 76.3076 124.192 76.5982 124.192 77.6789C124.192 79.0773 123.193 80.5394 121.64 81.4384C120.142 82.3011 119.17 82.0922 119.07 80.8572L120.251 80.1761C120.378 80.7301 120.905 80.7846 121.677 80.3396C122.476 79.8765 122.993 79.1682 122.993 78.5325C122.993 77.9967 122.712 77.8786 121.94 78.1238L120.986 78.4235C119.824 78.7867 119.252 78.4508 119.252 77.3792C119.225 76.0534 120.178 74.6458 121.64 73.8013Z" fill="white"/>
-<path d="M129.023 69.5332C130.413 68.7341 131.321 68.9702 131.43 70.187L130.304 70.8318C130.195 70.296 129.704 70.2052 129.005 70.6139C128.261 71.0407 127.77 71.7308 127.77 72.3392C127.77 72.8659 128.079 72.9749 128.824 72.7388L129.75 72.4391C131.003 72.0396 131.566 72.3302 131.566 73.4108C131.566 74.8093 130.567 76.2713 129.014 77.1703C127.516 78.033 126.544 77.8242 126.444 76.5891L127.625 75.9081C127.752 76.462 128.279 76.5165 129.051 76.0715C129.85 75.6084 130.367 74.9001 130.367 74.2644C130.367 73.7286 130.086 73.6106 129.314 73.8558L128.36 74.1554C127.198 74.5187 126.626 74.1827 126.626 73.1111C126.617 71.7853 127.561 70.3777 129.023 69.5332Z" fill="white"/>
-<path d="M139.13 69.2515C138.958 70.5864 137.914 72.0394 136.542 72.8294C134.753 73.8646 133.736 73.2381 133.736 71.1494V70.0325C133.736 68.0982 134.826 66.2003 136.479 65.2468C138.141 64.2842 139.149 64.9744 139.149 67.063V67.8621L134.881 70.3231V70.65C134.881 71.8941 135.525 72.3118 136.533 71.7306C137.287 71.2947 137.85 70.5955 138.013 69.9053L139.13 69.2515ZM134.881 69.3605L137.995 67.5624C137.995 66.2548 137.423 65.8007 136.461 66.3547C135.48 66.9177 134.881 68.0437 134.881 69.3605Z" fill="white"/>
-<path d="M143.78 59.1538V61.2061L146.295 59.7532V60.861L143.798 62.3049V66.2733C143.798 66.9998 144.234 67.1451 145.042 66.6819C145.342 66.5094 146.114 66.0463 146.259 65.9464V67.0543C146.132 67.1542 145.206 67.7172 144.96 67.8534C143.335 68.7887 142.617 68.5345 142.617 66.9544V62.986L140.938 63.9577V62.8407L142.617 61.869V59.8167L143.78 59.1538Z" fill="white"/>
-<path d="M157.174 59.6169L157.065 59.6805V60.8429L155.885 61.5239V51.3078L157.083 50.6177V54.6496L157.202 54.5861C157.456 53.6144 158.128 52.7699 159.036 52.2341C160.498 51.3896 161.433 52.0525 161.433 53.9776V55.3125C161.433 57.2286 160.498 58.9813 159.036 59.8258C158.128 60.3434 157.474 60.2708 157.174 59.6169ZM160.253 55.8665V54.7677C160.253 53.5054 159.635 53.0605 158.654 53.6326C157.683 54.1956 157.056 55.3489 157.056 56.6202V57.719C157.056 58.9813 157.683 59.4171 158.654 58.8541C159.635 58.2729 160.253 57.1197 160.253 55.8665Z" fill="white"/>
-<path d="M168.607 54.1683L167.472 54.8221V53.5508L167.391 53.5962C167.055 54.695 166.337 55.6213 165.393 56.1661C164.013 56.9652 163.259 56.4385 163.259 54.6768V49.9093L164.43 49.2282V53.6598C164.43 54.9129 164.866 55.2489 165.811 54.7132C166.782 54.1501 167.436 52.9878 167.436 51.7982V47.4938L168.598 46.8218V54.1683H168.607Z" fill="white"/>
-<path d="M171.032 55.3849V54.2498C171.095 54.2226 171.286 54.1227 171.386 54.0682C171.994 53.714 172.33 53.2237 172.566 52.3156L172.666 51.8978L170.351 45.8408L171.631 45.0962L173.302 50.1361L173.384 50.0907L175.045 43.1256L176.29 42.4082L173.956 51.3257C173.402 53.4688 172.802 54.3951 171.513 55.1397C171.331 55.2306 171.104 55.3395 171.032 55.3849Z" fill="white"/>
-<path d="M183.446 43.6617C183.273 44.9966 182.229 46.4495 180.858 47.2396C179.069 48.2748 178.052 47.6482 178.052 45.5596V44.4426C178.052 42.5084 179.141 40.6105 180.794 39.657C182.456 38.6944 183.464 39.3845 183.464 41.4731V42.2723L179.196 44.7332V45.0601C179.196 46.3042 179.841 46.722 180.849 46.1408C181.602 45.7049 182.165 45.0057 182.329 44.3155L183.446 43.6617ZM179.196 43.7706L182.311 41.9726C182.311 40.6649 181.739 40.2109 180.776 40.7648C179.795 41.3369 179.196 42.463 179.196 43.7706Z" fill="white"/>
-<path d="M188.04 37.4773C188.294 35.9517 189.03 34.8438 190.256 34.1355C190.619 33.9266 190.964 33.7813 191.173 33.7632V35.2434C190.891 35.2888 190.474 35.4432 190.119 35.6429C188.685 36.4693 187.886 37.9677 187.886 39.7657V41.9996L189.82 40.8827V41.9179L185.488 44.4152V43.38L186.75 42.6535V37.3865L185.37 38.1856V37.1504L187.886 35.6974V37.5681L188.04 37.4773Z" fill="white"/>
-<path d="M161.914 168.47L164.348 164.248C165.419 162.386 165.565 160.352 164.693 159.426L162.323 156.892C163.24 154.531 163.948 152.161 164.42 149.836L168.48 146.667C169.987 145.514 171.086 143.371 171.095 141.609V137.586C171.086 135.824 169.987 134.962 168.48 135.543L164.42 137.059C163.948 135.288 163.24 133.736 162.323 132.428L164.693 127.206C165.565 125.272 165.419 123.401 164.348 122.784L161.914 121.376C160.843 120.759 159.153 121.567 157.909 123.283L154.531 127.969C152.942 127.824 151.244 127.996 149.473 128.469L148.756 124.191C148.501 122.602 147.203 122.076 145.686 122.947L142.199 124.954C140.674 125.844 139.375 127.86 139.13 129.749L138.412 134.843C136.642 136.415 134.944 138.213 133.354 140.183L130.022 139.375C128.778 139.084 127.088 140.229 126.017 142.09L123.583 146.313C122.521 148.174 122.385 150.199 123.265 151.126L125.636 153.659C124.718 156.02 124.01 158.39 123.538 160.715L119.479 163.884C117.971 165.038 116.872 167.181 116.863 168.943V172.965C116.872 174.727 117.971 175.59 119.479 175.009L123.538 173.492C124.01 175.263 124.718 176.816 125.636 178.123L123.265 183.345C122.394 185.279 122.539 187.15 123.61 187.767L126.044 189.175C127.116 189.793 128.805 188.984 130.049 187.268L133.427 182.582C135.016 182.728 136.714 182.555 138.485 182.083L139.203 186.36C139.457 187.949 140.755 188.476 142.272 187.604L145.759 185.597C147.285 184.707 148.583 182.691 148.828 180.802L149.546 175.708C151.317 174.137 153.015 172.339 154.604 170.368L157.909 171.158C159.144 171.458 160.833 170.332 161.914 168.47ZM198.946 76.0623C198.547 74.6002 197.166 74.2824 195.659 75.3085L191.963 77.8149C190.674 76.3165 189.012 75.3539 187.068 74.9907L187.386 70.541C187.522 68.7157 186.551 67.6714 185.08 68.0619L181.756 68.9791C180.285 69.3877 178.741 71.1222 178.115 73.0928L176.544 77.8149C174.219 79.3133 171.949 81.3292 169.869 83.7357L166.827 83.0274C165.583 82.7368 163.894 83.881 162.822 85.7426L160.388 89.9652C159.317 91.8268 159.172 93.861 160.043 94.7872L162.205 97.0484C161.16 100.054 160.552 103.024 160.416 105.793L157.019 109.607C155.63 111.133 154.894 113.331 155.276 114.82L156.148 118.162C156.538 119.633 157.928 119.951 159.435 118.925L163.131 116.418C164.42 117.917 166.082 118.879 168.026 119.242L167.708 123.692C167.599 125.499 168.58 126.516 170.042 126.108L173.365 125.19C174.836 124.782 176.38 123.047 177.007 121.077L178.578 116.282C180.911 114.793 183.2 112.786 185.289 110.388L188.331 111.124C189.575 111.415 191.264 110.27 192.335 108.409L194.769 104.186C195.841 102.324 195.986 100.29 195.114 99.3641L192.98 97.0847C194.024 94.0789 194.633 91.1094 194.769 88.3397L198.138 84.5802C199.528 83.0546 200.263 80.857 199.882 79.3677L198.946 76.0623ZM177.642 94.2151L171.894 100.554L177.642 101.153L183.391 93.9064L177.642 94.2151ZM171.894 100.554L177.642 101.153V86.2148L171.894 100.554ZM177.642 86.2148V101.162L183.391 93.9155L177.642 86.2148ZM171.894 101.816L177.642 107.855V102.424L171.894 101.816ZM177.642 102.415V107.846L183.4 95.1687L177.642 102.415Z" stroke="white" stroke-width="1.18552" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
-<path d="M137.731 171.949C139.275 172.094 141.037 171.731 142.935 170.777C145.559 169.461 148.038 167.218 150.1 164.511C151.126 163.167 152.043 161.696 152.824 160.171C152.179 159.508 151.489 158.827 150.763 158.155C150.563 157.973 150.363 157.791 150.163 157.61C149.382 159.49 148.256 161.279 146.93 162.759L144.896 161.633L137.731 171.949Z" stroke="white" stroke-width="1.42299" stroke-miterlimit="10"/>
-<path d="M133.381 155.757C132.501 158.028 131.947 160.361 131.829 162.595C131.656 165.719 132.355 168.189 133.681 169.806C134.335 170.605 135.143 171.195 136.069 171.567C136.968 170.296 137.904 168.961 138.848 167.572C139.102 167.199 139.357 166.818 139.62 166.437C138.385 166.246 137.404 165.519 136.787 164.348L138.794 160.825L133.381 155.757Z" stroke="white" stroke-width="1.42299" stroke-miterlimit="10"/>
-<path d="M149.681 141.3C148.138 141.155 146.376 141.518 144.469 142.472C141.845 143.789 139.365 146.032 137.304 148.747C136.287 150.091 135.37 151.544 134.589 153.069C135.234 153.732 135.924 154.413 136.65 155.085C136.85 155.267 137.05 155.449 137.25 155.63C138.031 153.76 139.157 151.971 140.482 150.49L142.399 151.544L149.681 141.3Z" stroke="white" stroke-width="1.42299" stroke-miterlimit="10"/>
-<path d="M154.05 157.419C154.913 155.176 155.458 152.87 155.576 150.654C155.748 147.53 155.049 145.069 153.732 143.453C153.078 142.644 152.27 142.054 151.335 141.691C150.436 142.962 149.5 144.297 148.556 145.677C148.302 146.05 148.048 146.431 147.784 146.813C149.019 147.003 150.009 147.739 150.627 148.91L150.636 148.938L148.71 152.361L154.05 157.419Z" stroke="white" stroke-width="1.42299" stroke-miterlimit="10"/>
-<path d="M195.713 66.4912L306.655 2.43395C309.161 0.990073 311.196 2.16152 311.196 5.05836V164.62C311.196 167.517 309.161 171.032 306.655 172.485L195.704 236.542C193.197 237.986 191.163 236.814 191.163 233.917V74.3554C191.172 71.4585 193.206 67.9442 195.713 66.4912Z" fill="#B0B0B0"/>
-<path d="M195.712 66.4912L306.655 2.43395C309.161 0.990073 311.195 2.16152 311.195 5.05836V45.4506L191.172 114.748V74.3554C191.172 71.4585 193.206 67.9442 195.712 66.4912Z" fill="#4F4F4F"/>
-<path opacity="0.3" d="M205.993 78.6323L204.712 79.3679C204.64 79.5223 204.158 81.393 202.578 82.3011V83.6905C203.65 83.0729 204.385 82.2102 204.54 81.7834L204.612 81.738V90.4285L205.983 89.6385V78.6323H205.993ZM215.219 80.7573L213.875 81.5292V74.0737L212.367 74.9455L208.227 85.1525V86.2513L212.567 83.7449V85.8336L213.875 85.0798V82.9912L215.219 82.2193V80.7573ZM209.888 83.8357L212.367 77.5789L212.567 76.916V82.2829L209.888 83.8357ZM222.874 73.656C222.874 70.4685 221.666 69.4333 219.641 70.5957C217.598 71.7762 216.381 74.219 216.381 77.4064V78.705C216.381 81.956 217.616 83.082 219.659 81.9015C221.685 80.73 222.883 78.2055 222.883 74.9545V73.656H222.874ZM221.421 76.0624C221.421 78.0512 220.813 79.7765 219.659 80.4485C218.479 81.1296 217.843 80.1216 217.843 78.1329V76.2985C217.843 74.3552 218.47 72.7297 219.65 72.0486C220.813 71.3766 221.43 72.2756 221.43 74.2281V76.0624H221.421ZM225.008 78.7686C225.526 78.4689 225.953 77.7424 225.953 77.134C225.953 76.5437 225.526 76.3076 225.008 76.6073C224.5 76.8979 224.064 77.6153 224.064 78.2237C224.073 78.8321 224.491 79.0773 225.008 78.7686ZM233.481 67.5354C233.481 64.3479 232.273 63.3127 230.248 64.4751C228.205 65.6556 226.988 68.0984 226.988 71.2858V72.5844C226.988 75.8354 228.223 76.9614 230.266 75.7809C232.291 74.6095 233.49 72.0849 233.49 68.834V67.5354H233.481ZM232.019 69.9418C232.019 71.9306 231.41 73.656 230.257 74.3279C229.076 75.009 228.441 74.001 228.441 72.0123V70.1779C228.441 68.2346 229.067 66.6091 230.248 65.928C231.41 65.256 232.028 66.1551 232.028 68.1075V69.9418H232.019ZM241.354 62.9858C241.354 59.7984 240.146 58.7631 238.121 59.9255C236.078 61.106 234.861 63.5488 234.861 66.7362V68.0348C234.861 71.2858 236.096 72.4119 238.139 71.2313C240.164 70.0599 241.363 67.5354 241.363 64.2844V62.9858H241.354ZM239.901 65.3923C239.901 67.381 239.293 69.1064 238.139 69.7784C236.959 70.4594 236.323 69.4515 236.323 67.4627V65.6284C236.323 63.685 236.95 62.0595 238.13 61.3785C239.293 60.7065 239.91 61.6055 239.91 63.5579V65.3923H239.901ZM253.25 60.8972L248.255 63.7849L253.214 52.4973V51.3712L246.43 55.2851V56.7472L251.425 53.8685L246.467 65.1562V66.2822L253.25 62.3683V60.8972ZM260.279 58.3L261.95 57.3374L259.925 53.9593C260.96 52.8242 261.595 51.4529 261.595 49.9364C261.595 48.0022 260.587 47.1213 258.326 48.429L254.985 50.3541V61.3694L256.465 60.5158V56.3022L258.453 55.158L260.279 58.3ZM256.456 50.9626L258.317 49.891C259.716 49.0828 260.133 49.7911 260.133 50.7991C260.133 51.9433 259.616 52.9967 258.226 53.7958L256.456 54.822V50.9626ZM264.383 44.9237L262.676 45.9045L265.655 49.6912L262.658 56.9288L264.374 55.9389L266.608 50.4359L266.681 50.3905L268.915 53.3145L270.631 52.3247L267.68 48.5198L270.613 41.3276L268.906 42.3084L266.681 47.8569L266.608 47.9023L264.383 44.9237Z" fill="white"/>
-<path d="M201.897 201.108L300.889 143.961C302.006 143.316 302.905 143.843 302.905 145.123V162.259C302.905 163.549 302.006 165.111 300.889 165.755L201.897 222.902C200.78 223.547 199.881 223.02 199.881 221.74V204.604C199.881 203.314 200.78 201.753 201.897 201.108Z" fill="#4F4F4F"/>
-<path opacity="0.2" d="M201.761 122.975L300.607 65.91C301.161 65.5922 301.615 65.8465 301.615 66.4912V80.4669C301.615 81.1116 301.161 81.8926 300.607 82.2104L201.761 139.275C201.207 139.593 200.753 139.339 200.753 138.694V124.719C200.753 124.083 201.207 123.302 201.761 122.975Z" fill="white"/>
-<path opacity="0.2" d="M200.889 185.089L298.745 128.587" stroke="white" stroke-width="2.16763" stroke-linecap="round"/>
-<path opacity="0.2" d="M200.889 169.651L298.745 113.149" stroke="white" stroke-width="2.16763" stroke-linecap="round"/>
-<path opacity="0.2" d="M200.889 155.122L298.745 98.6196" stroke="white" stroke-width="2.16763" stroke-linecap="round"/>
-</g>
-<defs>
-<clipPath id="clip0">
-<rect width="311.196" height="237.15" fill="white"/>
-</clipPath>
-</defs>
-</svg>
diff --git a/packages/website/public/images/instant/gnt_screenshot.png b/packages/website/public/images/instant/gnt_screenshot.png
deleted file mode 100644
index 595c92703..000000000
--- a/packages/website/public/images/instant/gnt_screenshot.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/instant/gods_screenshot.png b/packages/website/public/images/instant/gods_screenshot.png
deleted file mode 100644
index 07dcd3b7c..000000000
--- a/packages/website/public/images/instant/gods_screenshot.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/instant/kitty_screenshot.png b/packages/website/public/images/instant/kitty_screenshot.png
deleted file mode 100644
index cf201f8d9..000000000
--- a/packages/website/public/images/instant/kitty_screenshot.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/instant/nmr_screenshot.png b/packages/website/public/images/instant/nmr_screenshot.png
deleted file mode 100644
index 9b13e59d7..000000000
--- a/packages/website/public/images/instant/nmr_screenshot.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/instant/rep_screenshot.png b/packages/website/public/images/instant/rep_screenshot.png
deleted file mode 100644
index 813787c16..000000000
--- a/packages/website/public/images/instant/rep_screenshot.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/jobs/calendar-icon.svg b/packages/website/public/images/jobs/calendar-icon.svg
deleted file mode 100644
index 2ce87388f..000000000
--- a/packages/website/public/images/jobs/calendar-icon.svg
+++ /dev/null
@@ -1,15 +0,0 @@
-<svg width="36" height="34" viewBox="0 0 36 34" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path d="M14.5337 0.542553H13.1244V0H12.1554V0.542553H4.66839V0H3.78756V0.542553H2.37824C1.05699 0.542553 0 1.62766 0 2.98404V14.5585C0 15.9149 1.05699 17 2.37824 17H14.6218C15.943 17 17 15.9149 17 14.5585V5.33511V4.43085V2.98404C16.9119 1.62766 15.8549 0.542553 14.5337 0.542553Z" transform="translate(0.410645) scale(2)" fill="black"/>
-<path d="M0.61658 2.53191H1.84974C2.20207 2.53191 2.46632 2.26064 2.46632 1.89894V0.632979C2.46632 0.271276 2.20207 0 1.84974 0H0.61658C0.264249 0 0 0.271276 0 0.632979V1.89894C0 2.26064 0.264249 2.53191 0.61658 2.53191Z" transform="translate(4.63916 24.5938) scale(2)" fill="white"/>
-<path d="M0.61658 2.53191H1.84974C2.20207 2.53191 2.46632 2.26064 2.46632 1.89894V0.632979C2.46632 0.271276 2.20207 0 1.84974 0H0.61658C0.264249 0 0 0.271276 0 0.632979V1.89894C0 2.26064 0.264249 2.53191 0.61658 2.53191Z" transform="translate(11.5103 24.5938) scale(2)" fill="white"/>
-<path d="M0.61658 2.53191H1.84974C2.20207 2.53191 2.46632 2.26064 2.46632 1.89894V0.632979C2.46632 0.271276 2.20207 0 1.84974 0H0.61658C0.264249 0 0 0.271276 0 0.632979V1.89894C0 2.26064 0.264249 2.53191 0.61658 2.53191Z" transform="translate(18.5571 24.5938) scale(2)" fill="white"/>
-<path d="M0.61658 2.53191H1.84974C2.20207 2.53191 2.46632 2.26064 2.46632 1.89894V0.632979C2.46632 0.271276 2.20207 0 1.84974 0H0.61658C0.264249 0 0 0.271276 0 0.632979V1.89894C0 2.26064 0.264249 2.53191 0.61658 2.53191Z" transform="translate(25.6035 24.5938) scale(2)" fill="white"/>
-<path d="M0.61658 2.53192H1.84974C2.20207 2.53192 2.46632 2.26064 2.46632 1.89894V0.632979C2.46632 0.271276 2.20207 0 1.84974 0H0.61658C0.264249 0 0 0.271276 0 0.632979V1.89894C0 2.26064 0.264249 2.53192 0.61658 2.53192Z" transform="translate(4.63916 17.1797) scale(2)" fill="white"/>
-<path d="M0.61658 2.53192H1.84974C2.20207 2.53192 2.46632 2.26064 2.46632 1.89894V0.632979C2.46632 0.271276 2.20207 0 1.84974 0H0.61658C0.264249 0 0 0.271276 0 0.632979V1.89894C0 2.26064 0.264249 2.53192 0.61658 2.53192Z" transform="translate(11.5103 17.1797) scale(2)" fill="white"/>
-<path d="M0.61658 2.53192H1.84974C2.20207 2.53192 2.46632 2.26064 2.46632 1.89894V0.632979C2.46632 0.271276 2.20207 0 1.84974 0H0.61658C0.264249 0 0 0.271276 0 0.632979V1.89894C0 2.26064 0.264249 2.53192 0.61658 2.53192Z" transform="translate(18.5571 17.1797) scale(2)" fill="white"/>
-<path d="M0.61658 2.53192H1.84974C2.20207 2.53192 2.46632 2.26064 2.46632 1.89894V0.632979C2.46632 0.271276 2.20207 0 1.84974 0H0.61658C0.264249 0 0 0.271276 0 0.632979V1.89894C0 2.26064 0.264249 2.53192 0.61658 2.53192Z" transform="translate(25.6035 17.1797) scale(2)" fill="white"/>
-<path d="M0.61658 2.44149H1.84974C2.20207 2.44149 2.46632 2.17021 2.46632 1.80851V0.632979C2.46632 0.271276 2.20207 0 1.84974 0H0.61658C0.264249 0 0 0.271276 0 0.632979V1.89894C0 2.17021 0.264249 2.44149 0.61658 2.44149Z" transform="translate(4.63916 9.76562) scale(2)" fill="white"/>
-<path d="M0.61658 2.44149H1.84974C2.20207 2.44149 2.46632 2.17021 2.46632 1.80851V0.632979C2.46632 0.271276 2.20207 0 1.84974 0H0.61658C0.264249 0 0 0.271276 0 0.632979V1.89894C0 2.17021 0.264249 2.44149 0.61658 2.44149Z" transform="translate(11.5103 9.76562) scale(2)" fill="white"/>
-<path d="M0.61658 2.44149H1.84974C2.20207 2.44149 2.46632 2.17021 2.46632 1.80851V0.632979C2.46632 0.271276 2.20207 0 1.84974 0H0.61658C0.264249 0 0 0.271276 0 0.632979V1.89894C0 2.17021 0.264249 2.44149 0.61658 2.44149Z" transform="translate(18.5571 9.76562) scale(2)" fill="white"/>
-<path d="M0.61658 2.44149H1.84974C2.20207 2.44149 2.46632 2.17021 2.46632 1.80851V0.632979C2.46632 0.271276 2.20207 0 1.84974 0H0.61658C0.264249 0 0 0.271276 0 0.632979V1.89894C0 2.17021 0.264249 2.44149 0.61658 2.44149Z" transform="translate(25.6035 9.76562) scale(2)" fill="white"/>
-</svg>
diff --git a/packages/website/public/images/jobs/heart-icon.svg b/packages/website/public/images/jobs/heart-icon.svg
deleted file mode 100644
index b83067af6..000000000
--- a/packages/website/public/images/jobs/heart-icon.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-<svg width="42" height="36" viewBox="0 0 42 36" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path fill-rule="evenodd" clip-rule="evenodd" d="M19.9861 5.40966C19.9861 6.40787 19.7347 7.34168 19.2634 8.14669C19.1691 8.30769 19.0434 8.46869 18.9491 8.6297L17.9435 9.66011L10.0245 18L1.66551 9.3703C1.66551 9.3703 1.66551 9.3703 1.63409 9.3381L1.44554 9.1449C1.16271 8.8551 0.942742 8.50089 0.722769 8.14669C0.251398 7.37388 0 6.40787 0 5.40966C0 2.41503 2.35685 0 5.24793 0C7.32196 0 9.11317 1.25581 9.99306 3.05903C10.8415 1.25581 12.6327 0 14.7068 0C17.6293 0 19.9861 2.41503 19.9861 5.40966Z" transform="translate(0.0483398) scale(2)" fill="#FF573F"/>
-</svg>
diff --git a/packages/website/public/images/jobs/hero-dots-left.svg b/packages/website/public/images/jobs/hero-dots-left.svg
deleted file mode 100644
index 35f3239a0..000000000
--- a/packages/website/public/images/jobs/hero-dots-left.svg
+++ /dev/null
@@ -1,17 +0,0 @@
-<svg width="730" height="566" viewBox="0 0 730 566" fill="none" xmlns="http://www.w3.org/2000/svg">
-<ellipse cx="5.54373" cy="5.55975" rx="5.54373" ry="5.55975" transform="translate(569.231 541.863) scale(2)" fill="black"/>
-<ellipse cx="5.54373" cy="5.55975" rx="5.54373" ry="5.55975" transform="translate(620.402 302.363) scale(2)" fill="black"/>
-<ellipse cx="5.54373" cy="5.55975" rx="5.54373" ry="5.55975" transform="translate(425.944 249.332) scale(2)" fill="black"/>
-<ellipse cx="5.54373" cy="5.55975" rx="5.54373" ry="5.55975" transform="translate(707.397 74.8438) scale(2)" fill="black"/>
-<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(444.712 430.668) scale(2)" fill="black"/>
-<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(180.317 546.992) scale(2)" fill="black"/>
-<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(620.402 165.508) scale(2)" fill="black"/>
-<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(265.602 182.617) scale(2)" fill="black"/>
-<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(705.691 444.352) scale(2)" fill="black"/>
-<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(269.014 386.188) scale(2)" fill="black"/>
-<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(1.95703 458) scale(2)" fill="black"/>
-<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(1.95703) scale(2)" fill="black"/>
-<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(77.9043 262) scale(2)" fill="black"/>
-<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(465.178 86.8164) scale(2)" fill="black"/>
-<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(159.847 86.8164) scale(2)" fill="black"/>
-</svg>
diff --git a/packages/website/public/images/jobs/hero-dots-right.svg b/packages/website/public/images/jobs/hero-dots-right.svg
deleted file mode 100644
index 93686f128..000000000
--- a/packages/website/public/images/jobs/hero-dots-right.svg
+++ /dev/null
@@ -1,16 +0,0 @@
-<svg width="680" height="506" viewBox="0 0 680 506" fill="none" xmlns="http://www.w3.org/2000/svg">
-<ellipse cx="5.54373" cy="5.55975" rx="5.54373" ry="5.55975" transform="translate(117.916 483.762) scale(-2 2)" fill="black"/>
-<ellipse cx="5.54373" cy="5.55975" rx="5.54373" ry="5.55975" transform="translate(66.7402 196.73) scale(-2 2)" fill="black"/>
-<ellipse cx="5.54373" cy="5.55975" rx="5.54373" ry="5.55975" transform="translate(244.141 280.555) scale(-2 2)" fill="black"/>
-<ellipse cx="5.54373" cy="5.55975" rx="5.54373" ry="5.55975" transform="translate(494.888 148.828) scale(-2 2)" fill="black"/>
-<ellipse cx="5.54373" cy="5.55975" rx="5.54373" ry="5.55975" transform="translate(221.969 22.2383) scale(-2 2)" fill="black"/>
-<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(293.61 409.672) scale(-2 2)" fill="black"/>
-<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(508.535 482.051) scale(-2 2)" fill="black"/>
-<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(15.5688 25.6602) scale(-2 2)" fill="black"/>
-<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(522.182) scale(-2 2)" fill="black"/>
-<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(15.5688 372.93) scale(-2 2)" fill="black"/>
-<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(435.188 314.766) scale(-2 2)" fill="black"/>
-<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(653.747 352) scale(-2 2)" fill="black"/>
-<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(679.729 76) scale(-2 2)" fill="black"/>
-<ellipse cx="3.41153" cy="3.42138" rx="3.41153" ry="3.42138" transform="translate(305.551 138.566) scale(-2 2)" fill="black"/>
-</svg>
diff --git a/packages/website/public/images/jobs/map@2x.png b/packages/website/public/images/jobs/map@2x.png
new file mode 100644
index 000000000..08fa60ec0
--- /dev/null
+++ b/packages/website/public/images/jobs/map@2x.png
Binary files differ
diff --git a/packages/website/public/images/jobs/ship-icon.svg b/packages/website/public/images/jobs/ship-icon.svg
deleted file mode 100644
index 4e507b9c0..000000000
--- a/packages/website/public/images/jobs/ship-icon.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<svg width="42" height="28" viewBox="0 0 42 28" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path fill-rule="evenodd" clip-rule="evenodd" d="M13.4071 11.6878H1.76832C0.771632 11.6878 0 10.9065 0 9.96896V1.71879C0 0.781267 0.803783 0 1.76832 0H13.3749C14.3716 0 15.1433 0.781267 15.1433 1.71879L16.1078 9.93771C16.14 10.9065 14.3716 11.6878 13.4071 11.6878Z" transform="translate(0.410645) scale(2)" fill="#04060C"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M8.32719 7.1564H0.96454C0.417967 7.1564 0 6.75015 0 6.21888V0.93752C0 0.406259 0.417967 0 0.96454 0H8.29504C8.84161 0 9.25958 0.406259 9.25958 0.93752V6.18763C9.29173 6.71889 8.84161 7.1564 8.32719 7.1564Z" transform="translate(21.8877 9.06641) scale(2)" fill="#04060C"/>
-<path d="M2.3792 4.6251C3.69319 4.6251 4.7584 3.58974 4.7584 2.31255C4.7584 1.03536 3.69319 0 2.3792 0C1.0652 0 0 1.03536 0 2.31255C0 3.58974 1.0652 4.6251 2.3792 4.6251Z" transform="translate(4.20508 18.75) scale(2)" fill="#04060C"/>
-<path d="M2.3792 4.6251C3.69319 4.6251 4.7584 3.58974 4.7584 2.31255C4.7584 1.03536 3.69319 0 2.3792 0C1.0652 0 0 1.03536 0 2.31255C0 3.58974 1.0652 4.6251 2.3792 4.6251Z" transform="translate(26.3887 18.75) scale(2)" fill="#04060C"/>
-</svg>
diff --git a/packages/website/public/images/jobs/world-map.svg b/packages/website/public/images/jobs/world-map.svg
deleted file mode 100644
index 7b201dcd2..000000000
--- a/packages/website/public/images/jobs/world-map.svg
+++ /dev/null
@@ -1,64 +0,0 @@
-<svg width="1046" height="594" viewBox="0 0 1046 594" fill="none" xmlns="http://www.w3.org/2000/svg">
-<g filter="url(#filter0_d)">
-<path d="M220.481 72.6818C220.411 73.1706 220.692 73.3102 221.112 73.3102C220.692 74.148 219.92 73.1705 219.57 72.7517C219.64 72.6818 219.64 72.612 219.71 72.4724C219.85 72.5422 219.92 72.6818 220.061 72.7517C220.061 72.612 220.061 72.4724 220.061 72.4026C220.411 72.3328 220.411 72.4724 220.481 72.6818ZM97.4774 35.4009C97.3372 35.5405 97.0566 35.5405 96.9164 35.75C96.4255 34.5631 96.145 34.8424 94.9528 34.7725C95.584 34.3537 96.145 33.9348 96.7761 33.5857C96.5658 33.5159 96.4255 33.2366 96.2151 33.1668C96.4956 32.9574 96.7761 32.8177 97.1268 32.6083C96.4255 32.2592 96.145 31.98 95.4437 32.1894C94.6723 32.4687 94.3918 32.6781 93.6905 32.2592C92.9893 31.9102 92.6386 32.1894 91.8672 32.1894C91.5166 32.1894 91.0958 32.9574 90.8153 33.2366C91.0958 33.3763 92.4983 33.7253 92.4983 34.0744C92.4983 34.7725 92.4984 35.6801 91.5166 35.4707C91.0958 35.4009 90.5348 34.3537 90.0439 34.4933C89.553 34.6329 88.8517 35.1216 89.4127 35.6103C90.5348 36.5179 91.8672 36.7972 92.849 37.984C93.2698 38.5425 93.6204 39.2407 94.2515 39.3803C94.8126 39.5199 95.6541 39.0312 95.4437 38.4029C96.3554 38.8218 98.8098 37.1462 97.1969 36.5877C97.4073 36.5179 97.6878 36.3783 97.8982 36.3085C97.7579 36.0292 97.6177 35.6801 97.4774 35.4009ZM218.798 72.612C218.868 72.8215 218.588 73.2404 219.009 73.5894C219.009 73.1706 218.938 72.8215 219.219 72.4724C219.079 72.4026 218.798 72.4026 218.658 72.4026C218.588 72.612 218.728 72.5422 218.798 72.612ZM124.056 49.5034C124.547 49.9223 125.879 50.6903 126.37 49.8525C126.861 49.0147 126.51 48.5958 126.791 47.7581C125.669 46.292 122.793 48.4562 124.056 49.5034ZM132.05 39.5898C131.7 38.3331 130.087 38.5425 129.245 38.8218C128.754 39.0312 127.492 37.0066 126.931 36.5179C126.3 35.9594 124.897 35.3311 124.126 35.4009C123.705 35.4707 122.793 35.4009 122.513 35.6801C122.303 35.8896 121.601 36.7972 121.321 36.6575C120.409 36.099 120.479 36.099 119.778 36.7972C119.357 37.2161 118.796 37.2161 119.147 36.5179C119.568 35.6801 119.708 35.6801 119.287 34.8424C119.007 34.214 118.796 34.2838 118.446 33.865C118.095 33.4461 118.235 32.6781 117.674 32.6083C117.253 32.6083 116.552 32.3989 116.131 32.5385C115.079 32.9574 114.098 33.4461 113.046 33.5857C113.116 33.1668 113.256 32.8177 113.326 32.3989C111.713 32.1894 111.012 32.1894 109.469 32.8876C108.347 33.3763 107.646 34.0744 107.155 35.4009C106.945 35.8896 106.313 36.9368 106.384 37.4255C106.454 37.6349 106.594 39.2407 106.734 39.2407C108.207 39.3803 109.189 39.2407 110.241 40.3577C109.189 40.2879 108.137 40.1483 107.015 40.0785C107.436 40.9162 108.277 41.5446 109.048 41.9634C109.68 42.3125 109.96 41.8238 110.451 41.8238C111.573 41.754 110.732 42.0333 111.363 42.5918C111.643 42.8012 112.555 43.0107 112.905 43.0107C113.957 43.0805 115.29 42.8012 116.272 43.2201C116.622 43.3597 116.903 43.4994 117.253 43.639C117.464 43.7088 117.604 43.2201 117.744 43.2201C118.235 43.2899 118.375 43.9881 118.936 43.7786C118.516 43.3597 118.095 43.0107 117.674 42.5918C119.287 43.0805 120.339 43.4296 121.952 43.0805C121.671 42.3823 121.531 42.0333 120.83 41.8936C121.671 41.0559 121.601 42.3823 122.232 42.6616C122.443 42.7314 123.004 42.3823 123.074 42.7314C123.144 43.0805 123.214 43.4296 123.284 43.7786C124.056 43.0107 125.388 44.756 126.019 45.2447C124.897 45.5938 124.617 45.3844 124.617 46.7108C125.108 46.5014 125.669 46.292 126.16 46.1523C126.861 45.8731 126.791 45.8032 127.212 46.5014C127.702 47.409 128.824 47.1297 129.385 48.1071C129.736 48.7355 130.087 49.4336 130.437 50.0619C130.578 50.3412 130.227 50.5506 130.017 50.7601C129.175 51.5979 128.334 52.4356 127.492 53.2734C127.773 53.4829 128.824 53.9715 128.614 54.5301C128.544 54.7395 127.001 55.0188 126.721 55.0886C125.739 55.3678 124.547 54.949 123.565 54.8791C123.705 55.5773 122.793 55.7169 122.443 56.3452C122.232 56.7641 122.934 57.6717 123.355 57.6019C124.056 57.5321 124.897 57.7415 125.388 57.2528C125.879 56.7641 126.58 57.183 127.212 57.3226C127.212 57.1132 127.352 56.9038 127.282 56.6943C127.702 56.6245 127.983 56.9038 127.983 57.3226C129.105 56.6245 129.035 57.2528 129.736 58.3699C130.157 58.9982 130.858 58.9284 131.489 59.2775C131.139 59.4869 130.718 59.6265 130.367 59.836C130.998 60.185 131.419 60.5341 132.12 60.4643C132.05 60.6039 131.98 60.6737 131.91 60.8134C132.611 61.0228 133.313 61.1625 134.014 61.3719C134.294 61.4417 134.294 62.07 134.785 62.2097C136.118 62.5587 137.52 62.9078 138.923 63.2569C138.993 62.6286 139.203 62.3493 138.712 62.0002C138.222 61.6512 137.731 61.3021 137.17 60.953C136.819 60.7436 136.118 60.8134 135.907 60.4643C135.627 59.9756 135.346 59.4869 135.066 58.9982C135.557 59.2076 136.048 59.4171 136.539 59.6265C136.398 59.4171 136.398 59.1378 136.328 58.9284C137.17 59.4171 138.011 59.9756 138.853 60.4643C139.273 60.7436 140.115 61.7908 140.396 61.6512C140.255 61.3719 140.185 61.0926 140.045 60.8134C140.185 60.8832 140.396 60.8832 140.536 60.953C140.886 60.185 139.764 60.0454 140.185 59.2775C140.396 59.5567 140.676 59.9058 140.886 60.185C140.816 59.6963 140.886 58.7888 140.676 58.3699C140.396 57.8812 139.835 58.0906 139.694 57.4623C139.554 56.6943 139.624 56.4849 138.993 56.2056C138.502 55.9962 138.011 55.5773 137.871 56.4151C137.661 55.8565 137.52 55.298 137.31 54.7395C137.1 54.1112 136.959 54.3904 136.398 54.5999C136.258 54.2508 136.118 53.8319 136.048 53.413C136.398 53.4828 136.819 53.4828 137.17 53.5527C137.1 52.7847 136.328 52.8545 136.749 52.1564C137.029 51.6677 137.38 51.7375 137.941 52.0167C138.362 52.2262 138.783 53.1338 139.273 53.2036C139.624 53.2734 140.325 52.8545 140.676 52.7149C140.886 53.5527 140.115 53.6225 139.554 53.8319C140.466 54.8791 140.957 55.3678 142.219 55.9264C142.499 55.1584 142.219 54.3206 142.149 53.5527C143.131 54.2508 143.551 53.6923 144.603 53.1338C144.253 52.9941 143.902 52.7847 143.551 52.6451C143.832 52.2262 144.603 52.5753 145.024 52.6451C145.164 51.6677 145.515 51.1092 144.603 50.6903C144.042 50.4808 142.99 50.7601 142.359 50.7601C142.569 50.4808 142.78 50.1318 142.92 49.8525C142.008 49.7129 141.588 49.7827 140.957 49.0845C140.396 48.4562 140.185 48.2468 139.484 47.9675C138.011 47.409 136.539 46.8505 135.066 46.1523C135.487 46.0825 135.907 46.0825 136.328 46.0127C136.258 45.5938 136.188 45.2447 136.118 44.8258C136.679 44.9655 137.31 45.0353 137.871 45.1749C137.52 44.1975 137.59 44.2673 136.679 44.407C136.188 44.4768 135.767 44.1975 135.276 44.0579C136.118 43.5692 136.328 43.4994 137.31 43.4994C137.31 42.7314 136.539 42.4522 136.048 42.1031C135.907 42.871 135.206 43.0107 134.645 43.2899C134.855 42.522 134.294 42.6616 133.733 42.5918C134.365 42.3823 135.487 42.3823 135.697 41.6144C135.136 41.3351 132.261 39.4501 131.91 40.2181C131.63 40.8464 130.648 41.5446 130.367 40.7068C130.437 40.2879 131.77 39.7294 132.05 39.5898ZM89.1322 26.0457C88.7816 26.0457 88.5011 26.1854 88.2206 26.4646C88.6413 26.4646 88.992 26.4646 89.4127 26.4646C88.1504 27.3024 89.9036 27.3722 90.5348 27.2326C91.4464 27.0231 92.3581 26.9533 93.2698 26.8835C93.1295 27.2326 92.849 27.3722 92.4983 27.3024C92.5685 27.3722 92.6386 27.442 92.7087 27.5118C92.3581 27.442 92.0075 27.5817 91.7971 27.9307C92.1477 27.9307 92.5685 28.0005 92.9191 28.21C92.7087 28.21 92.4282 28.2798 92.2178 28.2798C92.288 28.9081 92.7789 28.8383 93.2698 28.9779C93.5503 29.0478 93.6905 28.6289 93.9009 28.6289C94.6022 28.6987 95.6541 28.9779 96.2151 28.4194C96.0047 28.2798 95.7943 28.0704 95.584 27.9307C95.8645 27.7213 95.9346 27.5118 95.9346 27.1628C96.0749 27.3024 96.2852 27.3722 96.4255 27.442C96.5658 26.8835 96.2151 26.7439 96.145 26.325C96.145 25.9061 96.3554 25.557 96.2852 25.208C96.2852 24.9985 95.8645 24.2306 95.6541 24.1607C95.3736 24.0211 94.8126 23.672 94.5321 23.8117C93.6905 24.3004 93.0594 23.6022 92.0075 24.0211C90.8854 24.44 92.7789 24.5098 92.849 25.0683C92.6386 24.9985 92.4282 25.1381 92.2178 25.0683C92.4984 25.4872 92.7789 25.8363 93.0594 26.2552C92.6386 26.0457 89.8335 23.323 89.9036 25.208C90.1841 25.208 90.4646 25.208 90.7452 25.208C90.114 25.4872 90.2543 26.1155 90.8854 25.9061C90.8153 26.4646 89.6932 25.9061 89.1322 26.0457ZM89.2024 44.1975C89.4127 43.0805 89.9738 43.3597 90.6049 43.8484C90.675 43.7088 90.8153 43.5692 90.8854 43.3597C91.727 44.6862 91.5867 42.9409 91.5867 42.3823C90.675 42.5918 89.553 41.8936 88.5712 41.3351C88.2206 41.1257 86.818 40.5672 86.6778 40.1483C86.5375 39.7294 86.9583 39.1011 86.7479 38.5425C86.1869 37.2161 85.8362 35.1914 84.6441 34.5631C84.1532 34.2838 83.6623 33.5159 83.3116 34.1442C83.1012 34.4235 82.1896 33.7253 81.9091 33.5857C82.2597 34.0744 81.6286 34.2838 81.7688 34.5631C81.9091 34.9122 82.0493 35.2613 82.1195 35.6103C82.4 36.4481 82.6805 37.2161 82.961 37.984C82.4 38.1935 82.1195 38.6124 81.839 37.9142C81.5584 37.1462 81.3481 36.4481 81.0675 35.6801C80.7169 34.6329 78.9637 34.6329 78.2624 34.7027C78.6832 35.1216 79.104 35.6103 79.5247 36.0292C79.2442 35.9594 78.2624 35.5405 78.1222 35.8198C77.7014 36.5179 77.7014 36.4481 76.93 36.4481C77.1404 36.1688 77.3508 35.9594 77.491 35.6801C77.0001 35.4707 75.5275 34.4235 75.0366 34.5631C74.6859 34.6329 74.6158 35.4707 74.195 35.4707C73.7743 35.5405 73.3535 35.5405 73.0029 35.5405C73.634 34.982 74.3353 34.2838 73.4236 33.7253C72.7224 33.3064 72.4418 33.5857 71.6704 33.865C70.0575 34.4933 68.9355 34.982 67.603 36.099C67.8134 36.1688 68.0238 36.3783 68.2342 36.3783C67.6732 36.867 66.8316 37.3557 66.9719 38.2633C67.4628 38.2633 67.8836 38.2633 68.3744 38.2633C68.3043 38.4029 68.2342 38.6124 68.1641 38.8218C69.1459 38.752 70.1276 38.752 71.0393 38.752C70.0575 39.1709 69.0056 39.6596 68.0238 40.0785C68.655 40.7068 68.7952 41.0559 69.5666 40.986C70.6185 40.986 71.6003 40.986 72.6522 40.9162C74.1249 40.9162 75.3872 41.2653 76.8599 41.6144C77.9118 41.8936 76.2287 42.1729 75.8781 42.1729C75.1067 42.1729 74.2652 41.9635 73.4938 41.8936C72.2315 41.754 70.6887 42.4522 69.4264 42.6616C70.1276 45.1051 72.512 44.6862 74.4755 44.8258C74.3353 46.0825 74.6158 46.7108 75.7378 46.641C77.1404 46.5014 78.4728 46.4316 79.8754 46.292C80.787 46.2221 81.1377 45.5938 82.1195 45.3844C82.6805 45.3145 82.961 45.2447 83.3818 44.8258C83.8025 44.4768 83.8025 43.9881 84.3635 44.1975C84.2934 44.3371 84.2934 44.6164 84.2233 44.756C84.8544 44.8957 85.5557 45.0353 86.1869 45.1749C86.0466 45.2447 85.9765 45.3844 85.8362 45.4542C86.9583 45.4542 88.0102 46.0825 89.1322 45.9429C89.4127 45.9429 90.5348 45.524 90.5348 45.2447C90.5348 44.756 89.8335 44.8957 90.3244 44.1975C89.553 43.9881 89.1322 44.407 88.5712 44.9655C88.5712 44.407 88.7115 43.9881 88.2907 43.5692C88.5011 43.5692 88.6413 43.5692 88.8517 43.639C88.8517 43.9881 89.0621 44.0579 89.2024 44.1975ZM93.41 45.524C93.5503 45.6636 93.8308 45.9429 93.971 46.0127C94.0412 45.7334 94.1814 45.8032 94.2515 45.6636C94.3217 46.0127 94.5321 46.1523 94.8126 46.2221C94.8827 46.1523 94.8827 46.0127 94.9528 45.8731C95.2333 46.7108 96.4956 46.7807 97.1969 46.9203C97.8982 47.0599 98.5995 46.292 99.2306 45.9429C98.3891 45.1749 97.6177 44.5466 96.6359 43.9183C96.145 43.5692 95.7242 43.0107 95.2333 43.4994C94.8827 43.8484 94.2515 44.2673 94.8827 44.756C94.7424 44.756 94.6723 44.8258 94.5321 44.8258C94.3918 45.4542 93.7607 44.8957 93.41 45.524ZM219.429 71.7743C219.359 71.8441 219.289 71.8441 219.149 71.9139C219.219 71.9837 219.219 72.1233 219.289 72.1932C219.64 71.9139 219.78 71.7044 220.131 71.6346C220.061 71.5648 219.99 71.495 219.92 71.3554C220.481 71.2856 220.411 70.5176 220.131 70.6572C219.78 70.8667 218.588 71.2158 219.429 71.7743ZM119.778 58.5793C118.866 57.8812 118.726 57.8812 117.604 58.0208C118.586 57.0434 116.061 55.8565 115.57 55.5075C115.22 55.2282 114.589 55.3678 114.308 55.0188C113.817 54.5301 113.677 54.3206 113.186 55.0188C113.116 54.8791 112.976 54.5999 112.905 54.4603C113.887 54.3206 113.607 52.9243 112.765 53.2734C111.924 53.6225 111.924 54.3904 111.643 55.3678C111.503 55.7867 111.503 56.2056 111.433 56.5547C111.363 56.8339 111.643 57.3227 111.573 57.5321C111.433 57.8114 110.451 58.5793 110.171 58.9284C110.451 58.9284 112.064 58.5095 112.204 58.5793C112.415 58.7189 112.555 60.3247 112.905 60.1152C113.467 59.7662 113.887 58.9982 114.378 58.7888C115.15 58.5095 115.079 57.8812 115.851 57.5321C115.64 58.7888 117.814 59.068 118.656 59.2775C119.007 59.068 119.357 58.8586 119.778 58.5793ZM103.649 29.3968C103.929 30.095 104.841 29.4666 105.262 29.1874C105.612 29.8855 105.542 29.9553 106.243 30.0252C106.804 30.095 107.365 30.3044 107.506 29.4666C107.576 29.6761 107.786 29.7459 107.926 29.9553C107.926 29.6761 108.067 29.3968 108.067 29.1176C108.838 29.3968 107.997 30.3044 108.838 30.3742C109.68 30.444 110.521 30.444 111.363 30.5139C111.293 30.3044 111.363 30.095 111.363 29.8855C111.783 30.5139 112.976 30.7233 113.186 29.8157C113.396 30.7233 114.659 30.1648 115.29 30.0252C115.22 29.6761 115.15 29.327 115.079 28.9779C115.921 28.9779 115.5 29.8855 116.131 30.1648C116.692 30.3742 117.113 30.5837 117.674 30.444C118.025 30.3742 119.568 30.3742 119.708 30.0252C119.918 29.2572 120.199 29.327 120.9 29.0478C120.549 28.6987 120.129 28.6987 119.708 28.5591C120.059 28.2798 120.409 28.0704 120.69 27.7911C119.357 26.6741 117.744 25.8363 116.061 26.3948C115.36 26.6042 114.729 26.2552 113.957 26.5344C113.186 26.8137 112.555 26.9533 111.783 27.1628C111.924 27.3024 112.064 27.442 112.204 27.5118C111.433 27.3722 110.381 26.8835 109.609 26.9533C109.399 26.9533 108.908 27.442 108.698 27.3024C108.347 27.0929 107.997 26.8137 107.576 26.6042C107.365 26.4646 105.823 25.6268 105.823 25.557C105.682 25.0683 107.225 25.6268 107.365 24.9287C106.945 24.7891 106.524 24.6494 106.033 24.5796C105.402 24.44 105.682 24.0909 105.262 23.8117C104.49 23.323 103.649 24.0211 102.877 23.8117C102.036 23.672 101.615 22.9041 100.914 22.8343C100.072 22.6946 99.0202 22.2757 98.2488 22.555C96.9164 22.9041 97.3372 23.4626 98.1787 24.3702C99.0202 25.208 99.5111 25.0683 100.563 24.9287C101.475 24.7891 101.895 24.44 102.527 25.208C102.947 25.6967 103.999 26.5344 103.298 27.2326C103.018 28.21 103.228 28.4194 103.649 29.3968ZM127.352 48.1769C126.861 48.7355 128.965 48.7355 129.105 48.7355C128.895 47.7581 127.843 47.6184 127.352 48.1769ZM108.067 7.40524C107.436 7.96376 106.734 8.52228 106.103 9.08079C107.225 9.84875 108.347 9.22042 109.68 9.15061C110.872 9.08079 112.134 8.66191 113.256 8.31283C112.204 8.87135 111.363 9.29024 110.171 9.36005C109.048 9.49968 108.347 9.42987 107.295 9.91857C108.417 10.1978 109.609 10.9658 110.591 10.2676C111.854 9.42987 112.485 9.29024 114.028 9.15061C112.695 9.5695 112.064 9.84875 110.942 10.8262C111.924 10.9658 112.835 11.1054 113.817 11.1054C114.589 11.1054 114.659 11.3149 114.799 10.4073C114.869 10.128 115.711 9.98838 115.991 9.91857C115.851 10.0582 115.711 10.2676 115.57 10.4073C116.201 10.1978 116.763 10.0582 117.394 9.84875C116.903 10.2676 116.482 10.6167 115.991 11.0356C116.763 10.896 117.534 10.7563 118.235 10.6167C118.726 10.5469 119.848 10.5469 120.199 10.1978C121.321 9.08079 122.373 8.66191 123.775 7.96376C123.144 8.52228 122.583 9.08079 121.952 9.63931C122.303 9.77894 122.723 9.98838 123.074 10.128C120.62 10.7563 118.235 11.245 115.781 11.7337C116.622 12.5017 117.394 13.2697 118.235 13.9678C117.183 13.3395 115.921 12.1526 114.729 11.8734C114.518 11.8036 111.222 11.8036 111.222 11.7337C110.241 13.6886 112.204 13.5489 113.256 14.3169C114.238 15.015 115.079 16.1321 115.711 17.2491C114.168 16.4113 111.643 16.2019 110.241 17.5982C108.978 18.8548 110.1 18.9945 111.363 19.2039C112.204 19.4133 112.835 18.2963 113.467 17.7378C113.046 19.1341 111.783 19.9021 113.256 20.9493C114.448 21.787 115.781 20.1115 116.482 19.3435C115.36 20.8795 114.659 21.9965 112.695 21.5078C111.924 21.2983 111.854 20.1813 111.152 20.1115C110.171 19.9719 109.68 19.9021 108.768 20.2511C109.329 21.2983 109.329 21.438 110.451 21.5078C109.68 22.2757 109.189 22.0663 108.277 22.4852C107.926 22.6248 107.155 22.7644 106.945 23.0437C106.734 23.323 107.295 23.6022 106.875 23.8815C107.506 24.6494 107.716 24.0909 108.207 23.5324C108.207 24.44 109.469 25.1381 109.82 24.0909C109.96 24.9985 110.521 24.5098 111.152 24.5796C111.783 24.6494 112.344 24.7193 112.976 24.7193C113.677 24.7193 113.887 24.0909 114.378 24.2306C114.799 24.3702 115.57 24.7193 115.43 23.8117C115.711 24.44 117.043 25.0683 117.113 23.9513C117.674 24.5796 118.025 23.8117 118.375 24.0909C118.936 24.5098 118.726 24.7891 118.516 25.4872C119.357 25.208 120.129 24.9985 120.97 24.7193C121.181 24.6494 121.321 24.1607 121.531 24.0909C121.601 24.0909 121.882 24.44 122.162 24.3702C122.373 24.3004 123.004 24.2306 123.004 23.9513C123.004 23.672 123.004 22.9739 122.793 22.8343C122.373 22.555 122.232 22.4154 121.812 22.6248C121.321 22.9041 121.321 23.1135 120.97 22.555C120.69 22.0663 122.162 21.0191 122.443 20.8096C123.284 20.1115 121.952 19.7624 122.373 19.4133C122.653 19.2039 123.775 19.9021 124.266 19.6926C125.248 19.3435 125.458 19.2039 126.089 18.3661C125.599 18.0869 125.178 17.8774 124.687 17.5982C125.528 17.4585 126.3 17.3887 127.141 17.3189C127.212 16.3415 125.108 16.2717 124.406 16.0622C125.318 16.0622 126.3 16.0622 127.212 16.0622C127.422 14.9452 124.757 15.2943 124.056 15.2245C125.739 15.015 127.422 14.8754 129.105 14.5263C129.035 14.2471 128.895 13.898 128.824 13.6187C129.456 13.7584 130.227 14.2471 130.788 13.898C131.63 13.4791 132.05 13.13 132.681 12.4319C132.05 12.4319 131.489 12.3621 130.858 12.3621C131.84 12.1526 132.822 11.9432 133.804 11.7337C134.645 11.5941 135.697 10.6167 136.398 10.128C137.38 9.49968 140.676 8.66191 140.816 7.47506C138.292 7.96376 135.837 8.45246 133.313 9.01098C134.855 8.59209 136.398 8.10339 137.871 7.6845C136.959 7.54487 136.118 7.40524 135.206 7.26561C137.17 7.12599 139.133 6.98636 141.097 6.84673C142.499 6.77691 144.253 5.24099 145.515 4.61266C143.762 3.98433 142.219 3.56544 140.396 3.28619C138.853 3.00693 137.45 3.49563 135.907 3.8447C136.749 3.356 137.59 2.93711 138.432 2.44841C136.889 2.23897 135.206 1.75027 133.663 1.75027C132.191 1.75027 130.578 2.23897 129.105 2.44841C129.315 2.8673 129.526 3.21637 129.736 3.63526C129.035 3.14656 128.053 2.16915 127.212 2.16915C125.949 2.16915 124.757 2.09934 123.565 2.09934C124.266 2.72767 125.038 3.28619 125.739 3.91452C124.897 3.56544 123.986 3.21637 123.144 2.8673C122.653 2.65786 121.251 2.30878 120.76 2.44841C120.409 2.58804 120.339 3.00693 119.918 3.07674C119.357 3.07674 118.796 3.14656 118.235 3.14656C117.604 3.21637 116.903 4.05415 116.412 4.47303C117.885 5.24099 119.287 6.00895 120.76 6.77691C119.147 6.35803 117.534 6.00895 115.991 5.59007C115.29 5.38062 114.518 4.61266 113.887 4.19378C113.396 3.91452 112.625 4.05415 112.064 3.98433C112.204 4.3334 112.344 4.61266 112.415 4.96174C111.783 4.96174 111.222 4.96174 110.591 5.03155C111.012 5.24099 111.433 5.45044 111.854 5.65988C110.241 5.7297 108.067 4.82211 107.225 6.7071C106.103 5.7297 104.701 6.49765 103.579 7.12599C104.35 7.47506 105.051 7.82413 105.823 8.1732C106.594 7.96376 107.365 7.6845 108.067 7.40524ZM91.5867 20.3908C91.0958 19.7624 90.5348 19.9021 89.9036 20.0417C89.2024 20.1813 89.6231 20.67 90.1841 20.67C90.675 20.6002 91.0257 20.2511 91.5867 20.3908ZM120.269 63.7456C120.69 63.3965 121.882 62.1399 120.69 61.7908C120.199 61.6512 119.708 62.2097 119.638 62.6286C119.638 63.2569 119.848 63.3267 120.269 63.7456ZM215.572 84.4805C215.432 84.5503 215.292 84.7598 215.152 84.8296C216.414 85.8768 218.097 83.922 219.289 83.5729C219.71 83.4333 219.99 83.8522 220.131 83.2937C220.271 82.8748 220.411 82.3861 220.551 81.8974C220.762 81.3389 220.411 80.5709 219.99 80.152C220.832 79.5935 221.112 79.5237 221.183 78.4765C220.762 78.6161 220.622 77.8481 220.271 77.4292C220.061 77.2198 219.289 77.5689 219.009 77.6387C219.079 77.4991 219.149 77.4292 219.219 77.2896C218.237 76.7311 217.326 77.7783 216.835 78.5463C217.115 78.6859 217.466 78.7557 217.746 78.8953C217.326 79.1746 217.185 79.5237 216.694 79.384C216.414 79.3142 215.923 79.035 215.642 79.2444C215.152 79.5237 215.292 79.5935 215.432 80.2218C215.502 80.5011 215.011 80.8502 214.871 80.9898C215.432 81.269 215.853 81.4087 216.484 81.4785C216.063 81.8276 215.642 82.2464 215.222 82.805C215.783 82.6653 216.344 82.4559 216.835 82.6653C216.484 82.7351 215.713 82.7351 215.502 83.0842C215.222 83.4333 215.011 83.5729 214.591 83.6427C214.801 83.6427 215.011 83.7824 215.222 83.8522C215.011 83.9918 214.801 84.1314 214.52 84.2012C215.011 84.3409 215.292 84.4107 215.572 84.4805ZM114.659 61.7908C114.729 61.9304 114.799 62.4889 115.009 62.4191C116.131 62.3493 117.464 61.8606 117.604 60.3945C117.324 60.3945 117.043 60.3945 116.763 60.3945C116.061 60.5341 115.64 60.5341 115.079 61.0228C114.659 61.3719 114.518 61.3021 114.659 61.7908ZM101.685 28.5591C101.545 27.7911 100.703 26.6741 99.8617 26.9533C99.3709 27.0929 97.0566 27.5118 97.4073 28.6987C97.5475 29.1874 99.441 29.8157 99.8617 30.095C100.914 29.8855 101.966 30.0252 101.685 28.5591ZM85.9765 16.9C86.6778 16.9698 86.8881 15.9226 87.5193 16.551C87.379 16.6208 87.3089 16.8302 87.1687 16.9C87.5193 16.9698 87.8699 17.0397 88.2206 17.1095C88.3608 18.2963 86.6778 17.3887 85.9765 17.8774C86.1869 19.9021 88.5011 17.9472 88.9218 18.4359C89.4127 18.9945 90.2543 18.8548 90.8854 18.9246C91.5166 18.9945 91.5867 19.3435 91.9373 19.9719C92.2178 20.5304 95.0931 20.4606 93.6905 18.8548C93.4801 18.6454 92.9892 18.2963 93.0594 17.9472C93.1996 17.4585 93.2698 17.5284 92.9191 17.2491C92.288 16.7604 92.1477 16.8302 91.3763 16.9698C91.6568 15.4339 89.7634 16.2019 89.2725 16.4811C88.8517 15.5735 88.4309 14.8754 87.379 15.015C86.1869 15.1547 85.5557 14.9452 85.1349 16.1321C85.5557 16.1321 85.9064 16.1321 86.3271 16.0622C86.1869 16.4113 86.1167 16.6906 85.9765 16.9ZM86.3271 22.3456C86.6778 22.6946 87.0284 22.1361 86.7479 21.7172C86.4674 21.438 86.1869 21.1587 85.9765 20.9493C85.5557 20.6002 85.2051 20.1813 84.6441 20.3908C84.7142 20.8096 84.8544 21.1587 84.9246 21.5776C85.2752 21.9267 86.0466 22.0663 86.3271 22.3456ZM94.4619 12.8508C94.1113 12.013 92.1477 12.2923 92.7087 13.4093C93.6204 13.7584 95.1632 14.5961 94.4619 12.8508ZM97.1268 19.2039C96.7761 19.4133 96.2852 19.3435 95.9346 19.4832C96.2852 19.6228 96.9164 20.2511 96.9865 20.2511C97.4073 20.2511 97.8281 20.1115 98.1787 19.9719C98.5995 19.8322 99.441 19.8322 99.6514 19.4133C99.8618 18.9945 99.3007 18.8548 99.8617 18.2963C99.3709 18.0869 98.6696 18.1567 98.3189 17.9472C97.9683 17.8076 97.5475 17.3189 97.1268 17.1793C96.4956 16.9 94.2515 16.4811 95.5138 17.8076C95.3736 17.8076 95.2333 17.8774 95.0931 17.8774C95.3736 19.1341 96.4255 18.5058 97.1268 19.2039ZM76.4391 19.6228C75.1768 19.8322 74.6158 19.553 74.8963 21.0889C75.4573 21.0889 75.9482 21.8569 76.4391 21.787C77.2105 21.5776 77.9819 21.3682 78.6832 21.2285C79.2442 21.0889 78.9637 20.8795 79.104 20.5304C79.1741 20.1813 78.2624 20.4606 78.0521 20.1115C78.6832 19.9719 79.3144 19.9719 79.7351 19.3435C78.8235 18.9246 77.4209 19.4832 76.4391 19.6228ZM78.7533 24.8589C79.2442 25.1381 79.7351 25.4872 80.226 25.7665C79.8754 25.9061 79.5949 26.0457 79.2442 26.1854C79.5247 26.325 80.8572 26.6741 80.787 27.0231C80.6468 27.7911 79.9455 27.442 79.2442 27.3722C78.8936 27.3722 77.491 27.5118 77.4209 27.0929C77.2105 26.1854 77.1404 26.325 76.2989 26.3948C76.4391 26.325 76.5794 26.2552 76.7196 26.1854C76.1586 25.7665 75.5275 24.8589 74.8262 24.9985C73.5639 25.208 74.0548 24.7193 73.0029 24.3702C72.7925 24.3004 71.2497 24.44 71.2497 24.7891C71.2497 25.1381 72.512 25.3476 72.7925 25.4174C71.7406 25.3476 71.0393 25.208 70.0575 25.6268V26.1155C70.6887 26.4646 71.8107 26.1854 72.5821 26.1854C72.2315 26.3948 69.2861 26.2552 69.3562 26.9533C69.4264 27.6515 71.8808 26.8835 72.2315 26.8137C71.2497 27.5817 69.2861 27.0231 68.7251 28.1402C69.5666 28.4194 69.9173 28.4892 70.7588 28.2798C70.7588 28.4194 70.6887 28.5591 70.6887 28.6987C71.0393 28.8383 71.3899 28.9081 71.7406 28.9779C71.4601 28.2798 72.3016 28.4194 72.4418 29.0478C73.2834 28.4892 73.4938 28.4194 73.7041 27.442C74.3353 27.6515 74.0548 28.1402 73.9847 28.6987C74.4755 28.6289 75.5976 28.9081 75.6677 28.21C75.9482 28.9081 77.1404 28.5591 77.7014 28.21C76.7196 29.2572 74.6158 29.4666 73.2133 29.9553C74.8963 31.0724 75.5976 30.7233 77.4209 30.0252C78.4728 29.6761 79.4546 29.327 80.5065 28.9081C81.0676 28.6987 81.4182 29.2572 81.9792 29.1874C82.2597 29.1874 82.3298 28.6987 82.7506 28.6987C83.2415 28.6987 83.7324 28.6987 84.2233 28.6987C84.8544 28.6987 85.1349 27.9307 85.2752 27.2326C85.4856 26.3948 85.4155 25.6268 84.2934 25.7665C82.961 25.9759 84.083 26.325 83.522 27.0231C83.3116 26.325 83.1012 26.1854 82.4701 26.0457C82.1195 25.9061 81.9792 25.208 81.6987 24.9287C80.9974 24.3702 81.5584 22.8343 80.226 23.3928C79.7351 23.9513 79.3845 24.3702 78.7533 24.8589ZM97.267 12.6413C97.4774 14.2471 99.2306 14.2471 100.212 13.8282C99.8617 14.3867 99.3709 14.3169 98.8098 14.3867C98.3891 14.4565 98.5293 15.015 98.9501 14.9452C99.3709 14.8754 99.3007 15.6434 99.7916 15.2943C100.142 15.015 100.353 14.7358 100.773 14.9452C100.773 15.0848 100.703 15.1547 100.703 15.2943C101.194 15.5735 101.334 15.1547 101.755 14.9452C101.895 14.8754 102.316 15.4339 102.176 14.666C102.947 14.9452 104.28 14.5961 104.771 15.0848C104.14 15.1547 103.508 15.2245 102.877 15.3641C103.859 15.783 104.771 15.5735 105.752 15.5037C103.929 15.8528 102.246 15.7132 100.563 16.4113C101.054 16.7604 101.615 16.9 102.246 17.0397C101.966 17.0397 101.615 17.1095 101.334 17.1095C101.825 17.8774 103.228 17.5982 104.069 17.8076C103.508 17.8774 102.877 17.9472 102.316 18.0171C103.088 19.2039 104.771 18.9945 105.963 19.0643C105.893 18.785 105.682 18.5058 105.402 18.4359C106.173 18.4359 106.524 18.7152 107.085 19.2039C106.804 18.6454 106.524 18.0869 106.243 17.4585C106.804 18.0171 107.365 18.5756 107.926 19.1341C108.207 18.5058 108.347 18.1567 107.926 17.5284C110.311 18.785 107.716 16.551 109.329 16.0622C109.189 16.551 109.399 16.9698 109.609 17.4585C110.03 17.1095 110.732 16.8302 110.381 16.1321C110.802 16.4811 112.485 15.5735 113.186 15.3641C112.905 14.8754 112.485 14.5263 112.064 14.1074C111.994 14.3169 111.783 14.5263 111.713 14.7358C111.643 13.5489 110.311 14.2471 109.75 14.4565C110.381 13.2697 110.661 12.7112 109.189 12.5715C110.1 11.8036 108.838 10.7563 107.997 11.5243C108.207 11.8734 108.347 12.1526 108.558 12.5017C108.067 12.5017 107.646 12.3621 107.365 11.9432C107.225 11.6639 107.646 10.896 106.945 11.1054C106.173 11.3149 105.542 10.9658 104.981 10.4073C104.14 9.49968 103.719 8.73172 102.527 8.38265C101.825 8.1732 100.703 7.82413 100.212 8.59209C100.844 8.80154 101.545 8.59209 102.106 8.94116C101.545 9.98838 99.441 8.52228 98.8098 10.128C99.3007 10.2676 100.072 10.1978 100.493 10.5469C100.002 10.6865 97.6177 10.7563 98.3891 11.5243C98.0384 11.6639 97.6177 11.8036 97.267 11.9432C97.8982 12.2224 98.2488 12.0828 98.88 12.2224C98.8098 12.2923 98.6696 12.3621 98.5995 12.3621C99.1605 12.6413 99.8618 12.013 100.353 12.3621C100.142 12.4319 100.002 12.6413 99.7916 12.6413C99.9319 12.781 100.072 12.9206 100.212 12.9904C100.002 12.9206 99.7916 12.9206 99.5812 12.781C98.88 12.781 98.0384 12.7112 97.267 12.6413ZM86.818 25.3476C87.3089 25.9061 89.4829 26.0457 89.2725 24.9287C88.6413 24.7891 87.2388 24.8589 86.818 25.3476ZM68.9355 25.4872C68.5147 25.6268 66.3407 26.4646 66.6213 27.0929C66.7615 27.5118 67.8836 27.3722 68.0939 27.0231C68.3043 26.6042 69.0757 26.0457 68.9355 25.4872ZM220.271 73.6593C220.201 73.7291 220.131 73.7291 220.061 73.7989L220.201 73.9385C220.201 73.8687 220.341 73.7989 220.271 73.6593ZM83.3116 33.3763C84.0129 33.5857 84.083 33.7253 84.6441 34.214C85.0648 34.6329 85.3453 35.1216 85.9064 34.8424C86.3271 34.6329 86.6778 33.9348 86.6778 33.5159C86.6778 32.8876 86.257 32.8177 85.7661 32.4687C84.7843 32.6083 83.7324 32.2592 83.3116 33.3763ZM87.9401 28.3496C87.5894 27.3722 87.0985 27.5118 86.3972 27.7911C85.4856 29.0478 87.5193 28.5591 87.9401 28.3496ZM86.4674 23.9513C86.6778 24.3702 86.818 24.3702 86.818 24.7891C87.4492 24.8589 88.2206 24.9985 88.7115 24.5098C88.4309 24.3004 88.0803 24.1607 87.7998 23.9513C87.379 23.7419 86.9583 23.8117 86.4674 23.9513ZM101.475 21.3682C101.685 21.0889 101.895 20.7398 102.106 20.4606C100.703 20.0417 99.1605 19.9719 97.8281 20.67C98.1787 21.7172 100.703 21.2983 101.475 21.3682ZM119.778 34.8424C119.988 35.0518 120.479 35.2613 120.69 35.4009C121.181 35.6801 122.653 35.0518 123.144 34.9122C123.775 34.7726 124.687 34.982 125.318 34.982C124.406 33.7951 123.775 33.3763 122.513 32.7479C122.092 32.5385 121.531 32.8876 121.04 32.6781C120.549 32.4687 119.988 32.329 119.497 32.1196C118.656 32.2592 118.516 33.4461 119.287 33.865C119.918 34.214 119.427 34.3537 119.778 34.8424ZM104.841 21.0191C104.35 21.5078 105.332 21.8569 105.612 21.9965C106.103 22.2059 106.524 21.9267 107.015 21.787C106.945 20.7398 105.472 20.4606 104.841 21.0191ZM105.823 23.323C105.332 23.672 106.454 24.44 106.875 24.3004C106.804 24.1607 106.734 23.8815 106.664 23.8117C107.295 23.3928 106.173 23.0437 105.823 23.323ZM429.672 29.8157C431.285 29.8855 432.337 29.8157 433.88 29.327C433.95 29.327 434.09 28.4194 434.02 28.3496C433.95 28.21 433.108 28.0704 432.968 28.0005C432.127 27.7213 431.846 27.8609 431.004 28.1402C431.075 27.9307 431.004 27.7213 431.004 27.5817C430.303 27.5817 429.602 27.3722 428.971 27.8609C428.901 26.3948 427.288 27.3024 427.428 28.21C427.498 28.6289 429.251 29.5365 429.672 29.8157ZM299.866 39.4501C300.707 40.3577 301.759 40.986 302.881 41.0559C303.933 41.1257 306.107 41.8238 307.019 41.0559C305.546 40.0785 304.354 39.1709 304.284 37.1462C304.214 35.5405 305.757 34.214 306.668 33.097C307.229 32.4687 307.72 31.7705 308.211 31.0724C308.702 30.5139 309.754 30.095 310.385 29.6761C311.577 28.9081 312.348 27.9307 313.751 27.5817C315.364 27.093 316.977 26.6042 318.59 26.0457C319.361 25.7665 322.587 25.208 322.727 23.7419C322.868 21.9965 319.572 22.7644 319.011 23.2531C317.678 24.3004 316.206 24.5796 314.593 24.9985C313.12 24.9985 312.138 25.1381 310.806 25.6967C309.754 26.1155 308.071 26.4646 307.159 27.2326C306.177 28.1402 305.195 28.9779 304.284 29.9553C303.653 30.6535 303.022 31.3516 302.39 32.0498C301.899 32.6083 302.18 32.9574 302.32 33.6555C302.39 33.9348 300.988 34.7027 300.777 34.8424C299.936 35.4707 300.707 35.5405 300.287 36.3085C300.006 36.9368 299.094 36.6575 299.024 37.4255C298.954 38.6124 299.094 38.6124 299.866 39.4501ZM302.741 11.8036C301.198 11.245 301.198 11.3149 299.866 12.3621C300.497 12.4319 301.128 12.5017 301.689 12.5715C302.04 12.2923 302.39 12.0828 302.741 11.8036ZM308.421 8.24302C308.071 7.96376 307.72 7.61469 307.369 7.33543C308.071 7.12599 308.842 6.98636 309.543 6.77691C308.351 6.56747 307.86 6.28821 306.879 6.98636C306.107 7.54487 305.266 8.10339 304.494 8.59209C305.266 8.66191 305.967 8.80154 306.738 8.87135C307.299 8.73172 307.86 8.45246 308.421 8.24302ZM308.421 42.1729C308.632 42.7314 310.385 44.1277 310.946 43.639C311.577 43.0805 309.473 41.9635 309.193 41.6842C308.912 41.8936 308.702 42.0333 308.421 42.1729ZM310.315 12.9206C310.034 12.2923 309.403 12.7112 308.912 12.8508C309.123 12.9904 309.333 13.1999 309.543 13.3395C309.824 13.13 310.104 12.9904 310.315 12.9206ZM307.72 9.84875C306.808 9.5695 305.967 9.22042 304.985 9.22042C303.653 9.29024 303.162 9.08079 302.25 10.1978C303.162 10.4073 304.003 10.6865 304.915 10.896C306.037 10.6865 306.808 10.6167 307.72 9.84875ZM294.326 10.6865C293.695 11.1054 292.993 11.5243 292.362 12.013C293.554 12.4319 294.326 12.5017 295.588 12.5017C295.518 12.1526 295.378 11.8036 295.307 11.4545C296.57 11.1752 297.902 10.8262 299.164 10.5469C298.463 10.0582 297.972 9.63931 297.131 9.91857C296.289 10.128 295.588 10.4771 294.746 10.2676C292.993 9.84875 291.871 10.3375 290.118 10.896C290.679 11.0356 291.31 11.1752 291.871 11.3847C292.713 11.1054 293.554 10.896 294.326 10.6865ZM295.027 46.1523C295.448 46.5712 296.78 45.3844 297.131 45.1749C296.5 44.6164 296.219 44.4768 295.448 44.3371C294.466 44.6862 294.115 45.2447 295.027 46.1523ZM258.21 42.5918C259.542 42.3823 260.384 42.0333 261.296 40.986C260.664 40.986 260.664 41.5446 260.174 41.754C259.753 41.9635 259.051 41.8936 258.631 41.8936C258.841 42.2427 258.561 42.4522 258.21 42.5918ZM76.5794 18.4359C77.2105 18.785 77.1404 18.2963 77.7014 18.2265C78.1222 18.1567 80.5065 19.0643 80.226 17.8076C80.0156 17.0397 78.1222 17.1095 77.6313 17.2491C76.7898 17.5284 75.3171 17.5982 74.7561 18.4359C74.8262 18.5058 74.9664 18.5756 75.1067 18.6454C75.5275 18.5756 76.1586 18.2265 76.5794 18.4359ZM308.421 11.245C308.071 11.245 304.564 11.3847 304.915 12.3621C305.266 13.3395 307.65 12.5715 308.491 12.4319C308.351 12.2923 308.281 12.0828 308.141 11.9432C308.562 11.8734 308.982 11.8036 309.403 11.7337C309.123 11.5941 308.772 11.3847 308.421 11.245ZM416.067 29.1176C416.558 29.3968 417.049 29.9553 417.61 29.8855C418.592 29.8157 418.522 29.7459 418.943 28.8383C419.644 29.9553 420.696 29.0478 421.748 28.6289C422.028 28.4892 422.379 29.5365 422.729 29.4666C423.22 29.327 423.781 29.2572 424.272 29.1176C424.062 28.8383 423.922 28.4892 423.711 28.21C424.342 28.4892 424.623 28.6987 425.184 28.3496C425.675 28.0704 426.095 27.7911 426.446 27.3024C425.044 26.7439 423.641 26.2552 422.309 25.6967C421.958 25.557 421.327 25.1381 420.906 25.2778C420.205 25.557 420.555 26.0457 420.696 26.8137C419.714 26.3948 417.75 24.5098 416.769 25.2778C415.857 25.9759 415.436 26.1854 415.086 27.3722C414.945 28.1402 415.717 28.6987 416.067 29.1176ZM220.271 76.8009C220.622 76.6613 220.692 76.382 220.481 76.033C220.341 76.1028 220.131 76.2424 219.99 76.382C220.411 76.4518 220.201 76.5915 220.271 76.8009ZM421.467 33.5857C422.379 34.3537 423.01 34.1442 424.132 34.1442C423.851 33.097 423.781 33.097 422.94 32.5385C422.729 32.3989 421.257 31.7705 421.257 31.7007C421.187 31.0026 420.626 30.3044 419.784 30.8629C418.802 31.4913 419.994 32.1196 420.415 32.4687C419.854 32.8177 419.293 33.2366 418.732 33.5857C419.504 33.5159 420.836 33.0272 421.467 33.5857ZM317.328 9.98838C318.169 9.77894 317.889 9.42987 317.818 8.52228C317.468 8.52228 316.767 8.45246 316.486 8.59209C316.276 8.80154 316.206 9.42987 315.995 9.5695C315.294 9.98838 314.593 8.94116 314.032 9.98838C314.242 10.1978 314.382 10.4073 314.593 10.5469C315.504 10.4073 316.416 10.1978 317.328 9.98838ZM309.894 11.3149C310.385 11.3149 310.665 11.1752 310.946 11.5941C311.507 12.2923 312.91 11.3149 313.4 10.7563C313.961 10.128 312.699 9.15061 312.068 9.36005C311.016 9.63931 310.175 9.91857 309.263 10.4073C309.403 10.8262 309.403 11.3149 309.894 11.3149ZM363.962 19.2737C364.734 20.2511 366.557 18.9945 367.469 18.7152C367.749 18.6454 368.24 19.2039 368.661 19.1341C369.432 18.9945 370.274 18.8548 371.045 18.7152C371.606 18.6454 371.887 18.4359 372.378 18.0171C372.658 17.8076 372.027 16.8302 371.676 16.8302C370.905 16.7604 370.765 16.4113 370.204 15.783C369.993 15.5037 368.941 15.783 368.591 15.783C368.801 15.5735 369.012 15.3641 369.292 15.1547C368.17 14.7358 367.399 14.8056 366.627 15.6434C365.856 16.4811 365.295 17.4585 364.664 18.5058C364.453 18.785 364.173 19.0643 363.962 19.2737ZM353.654 14.1074C354.425 14.0376 355.968 13.5489 356.529 14.2471C357.23 15.1547 357.651 16.2717 358.703 16.2019C360.035 16.0623 360.666 16.0623 361.859 16.4811C362.981 16.9 363.472 16.6906 364.664 16.3415C364.523 15.9924 364.173 15.2245 364.243 14.8056C364.453 14.3169 364.944 13.6886 364.453 13.4093C363.401 12.8508 362.84 13.3395 361.718 13.7584C362.069 13.3395 362.42 12.9904 362.84 12.5715C362.35 12.4319 361.087 12.5017 360.947 11.8734C360.737 10.5469 360.737 10.6865 361.859 10.3375C361.087 9.77894 359.685 8.31283 358.843 8.24302C357.791 8.1732 358.492 8.80154 357.861 9.01098C357.16 9.22042 356.459 9.42987 355.828 9.63931C355.056 9.84875 355.126 10.128 354.916 11.0356C354.846 11.3149 353.654 11.4545 353.373 11.5243C353.093 11.5941 352.742 12.781 352.602 13.13C352.461 13.3395 353.513 13.9678 353.654 14.1074ZM473.572 40.637C473.923 40.4973 474.273 40.7766 474.624 40.7068C475.816 40.4973 476.728 40.4973 477.569 39.5898C477.078 39.1709 476.728 38.6124 476.097 38.6124C475.255 38.5425 474.413 38.5425 473.642 38.4727C473.081 38.4727 472.169 39.0312 471.678 39.3105C471.538 39.3803 471.959 40.8464 472.029 41.1257C472.45 40.9162 473.011 40.7766 473.572 40.637ZM250.917 44.8957C250.426 45.1051 249.795 45.1051 250.005 45.8731C250.286 45.6636 250.566 45.4542 250.776 45.2447C250.776 45.1051 250.847 44.9655 250.917 44.8957ZM247.34 47.8977C247.691 47.9675 247.971 47.8279 248.112 47.4788C247.901 47.2694 247.621 47.2694 247.41 47.5486C247.34 47.6184 247.34 47.7581 247.34 47.8977ZM249.304 45.524C249.023 45.8731 248.743 46.1523 248.462 46.5014C248.743 46.5712 249.023 46.641 249.304 46.7108C249.865 46.292 249.795 45.9429 249.304 45.524ZM224.479 69.6798C224.829 69.7496 224.829 69.6798 225.18 69.5402C224.969 69.5402 224.829 69.4006 224.549 69.4704C224.619 69.4006 224.689 69.4006 224.759 69.3308C224.268 68.9817 224.198 69.4704 224.198 69.6798C224.268 69.7496 224.338 69.8893 224.408 69.9591C224.479 69.8893 224.479 69.8195 224.479 69.6798ZM260.033 41.6144C260.314 41.3351 260.664 41.1955 260.664 40.7068C260.244 40.9162 260.314 41.1955 259.753 41.0559C259.332 40.9162 259.051 40.9162 258.631 40.986C258.841 41.8936 259.472 41.6144 260.033 41.6144ZM220.692 76.3122C220.832 76.1028 220.972 75.8933 221.042 75.6839C220.762 75.6141 220.481 75.8933 220.692 76.3122ZM249.444 46.9203C248.883 46.9203 248.322 46.7807 248.322 47.6184C248.743 47.409 249.093 47.1297 249.444 46.9203ZM221.603 76.5217C221.603 76.7311 221.673 76.9405 221.814 77.15C222.024 76.8009 221.884 76.5915 221.603 76.5217ZM221.253 72.9611C221.183 72.9611 221.112 73.0309 221.042 73.1007C221.183 73.1705 221.253 73.1706 221.323 73.1706C221.042 73.4498 220.902 73.7291 220.832 74.0781C220.762 74.2178 220.341 74.4272 220.201 74.6367C220.762 74.7763 220.762 74.9857 220.201 75.1254C220.551 75.4744 221.463 75.1254 220.692 74.6367C221.183 74.9159 221.393 74.497 221.814 74.148C221.884 74.2178 221.884 74.2876 221.954 74.3574C221.393 74.6367 221.323 75.265 221.183 75.8933C221.112 76.3122 221.323 76.3122 221.112 76.8009C221.042 77.0802 220.832 77.2198 221.042 77.3594C221.463 77.7783 221.393 76.8009 221.463 76.5217C221.533 76.033 221.533 75.5443 222.094 75.3348C221.463 75.8933 222.024 76.382 222.445 75.4744C222.515 75.6141 222.585 75.8235 222.585 75.9631C222.234 75.9631 222.305 76.1028 222.375 76.5217C222.515 77.0104 222.585 76.8707 222.375 77.4991C222.164 78.1274 221.603 78.1972 222.305 78.7557C222.305 78.6161 222.305 78.4765 222.305 78.3368C222.655 78.4765 223.146 78.8953 223.006 78.3368C223.497 78.6859 224.198 77.9878 224.899 78.1274C223.637 78.4066 224.338 80.3615 225.11 79.8029C224.759 80.2916 224.829 81.269 225.25 81.6181L225.11 81.6879C224.899 81.4087 224.969 81.5483 224.759 81.4087C224.759 81.5483 224.829 81.6181 224.829 81.7577C224.338 81.6879 223.988 81.4785 223.567 81.8276C223.427 81.4785 223.146 81.3389 222.796 81.4785C223.357 81.8974 223.076 82.3163 222.585 82.6653C222.866 82.5955 223.216 82.5257 223.497 82.5257C223.427 83.154 223.777 83.2937 223.357 83.8522C223.146 84.1314 222.234 84.3409 221.884 84.4805C221.954 84.6201 221.954 84.8994 221.954 84.8296C222.375 85.5277 222.866 84.6201 223.497 84.9692C223.427 85.039 223.357 85.1088 223.286 85.1787C223.567 85.1787 224.198 85.5277 224.268 85.5277C224.689 85.3881 225.18 85.2485 225.601 85.039C225.32 85.3881 225.04 85.5975 224.969 86.0164C224.128 85.8768 223.216 85.5277 222.936 86.6448C222.796 87.2033 221.814 87.692 221.393 88.1807C222.164 88.6694 222.936 87.1335 223.988 87.9014C224.549 86.4353 224.829 87.6222 225.881 87.1335C226.232 86.9938 226.863 86.4353 227.214 86.5051C227.704 86.5051 227.775 87.0637 228.265 86.924C229.177 86.7146 229.738 86.7146 230.65 86.3655C231.842 85.8768 230.019 85.5277 229.668 85.4579C230.58 84.7598 231.211 84.4805 231.351 83.2238C231.491 81.9672 229.387 82.805 229.177 82.5955C230.019 82.037 228.756 80.9898 228.125 80.9898C228.476 80.8502 228.897 80.92 229.107 81.269C228.826 79.6633 227.494 79.5237 227.073 78.267C226.582 76.5915 225.881 76.4518 224.338 76.2424C224.619 75.8933 224.969 75.7537 225.32 75.8235C224.829 74.8461 227.003 73.7291 226.442 72.8215C226.091 72.263 223.567 72.5422 223.286 73.1007L223.146 72.9611C223.357 72.8215 223.427 72.5422 223.637 72.4026C223.427 72.3328 223.216 72.1932 223.006 72.1932C223.146 72.1932 223.286 72.1932 223.497 72.1932C223.637 71.5648 224.759 71.4252 224.899 70.5176C224.338 70.378 223.497 70.5874 222.936 70.8667C222.655 70.727 222.936 70.6572 222.515 70.8667C222.375 70.2383 221.884 70.7969 222.094 71.2856C221.954 71.2856 221.814 71.3554 221.673 71.3554C221.603 71.495 221.603 71.6346 221.533 71.7044C221.744 71.8441 221.884 72.1233 222.024 72.263C221.744 72.0535 221.393 72.0535 221.042 72.1932C221.183 72.4026 221.183 72.6819 221.323 72.9611C221.183 72.9611 221.042 72.8913 220.972 72.8913C220.832 72.8913 220.972 72.8913 221.253 72.9611ZM222.866 79.1746C222.585 79.3142 222.375 79.5237 222.375 79.8727C222.445 79.8727 222.515 79.8727 222.655 79.8727C222.936 79.7331 223.006 79.5237 222.866 79.1746ZM251.618 46.4316C252.109 45.8731 252.67 45.3145 253.161 44.756C252.81 45.0353 252.459 45.3844 252.109 45.6636C251.688 45.6636 251.478 46.0127 251.618 46.4316ZM254.353 43.2201C254.072 43.5692 253.792 43.7088 253.441 44.0579C253.722 44.0579 254.072 44.0579 254.353 44.1277C254.633 43.639 255.054 43.4296 254.353 43.2201ZM252.53 44.1277C251.898 44.3371 251.898 44.2673 251.828 44.9655C251.758 46.0127 253.231 44.6164 253.511 44.3371C253.301 43.8484 252.95 43.9881 252.53 44.1277ZM255.615 42.9409C255.194 42.6616 254.633 42.6616 254.493 43.2201C254.633 43.2899 254.774 43.3597 254.984 43.4296C255.265 43.3597 255.475 43.2201 255.615 42.9409ZM250.987 45.8032C250.706 46.0127 250.847 46.4316 250.426 46.641C250.496 46.292 250.566 45.9429 250.636 45.6636C250.215 45.6636 250.005 46.0127 250.145 46.5014C250.005 46.5014 249.865 46.5014 249.795 46.5014C249.725 46.9901 249.795 46.7807 249.514 47.1297C250.075 47.1995 250.286 47.409 250.636 46.9203C250.917 46.5712 251.127 46.4316 251.548 46.5712C251.548 46.2919 251.408 45.524 250.987 45.8032ZM249.725 47.7581C249.725 48.3864 249.374 48.526 248.883 48.5958C249.093 48.7355 249.023 48.8053 249.234 48.9449C249.163 49.0845 249.093 49.294 248.953 49.4336C249.514 48.8751 249.865 48.6656 249.725 47.7581ZM250.356 47.5486C250.215 47.4788 250.005 47.4788 249.865 47.4788C249.865 47.6882 249.865 47.9675 249.935 48.1769C250.356 47.7581 250.776 47.2694 251.197 46.8505C250.847 46.8505 250.566 47.1297 250.356 47.5486ZM256.667 43.1503C256.106 42.8012 255.054 43.4296 254.633 43.9881C254.914 43.9183 255.194 43.7786 255.475 43.7088C255.896 43.4994 256.246 43.2899 256.667 43.1503ZM257.158 42.3823C257.018 42.3823 256.667 42.3823 256.527 42.3823C256.597 42.522 256.597 42.6616 256.667 42.8012C257.018 43.0805 257.228 42.871 257.158 42.3823ZM324.691 33.2366C323.849 33.3064 324.06 33.7253 323.99 34.6329C324.761 34.4933 325.532 34.3537 326.304 34.214C325.953 33.4461 325.392 33.1668 324.691 33.2366ZM405.057 118.061C405.127 118.41 405.127 118.759 405.197 119.109C406.039 119.178 405.408 118.201 406.039 118.271C406.81 118.341 406.39 119.318 406.179 119.667C405.759 120.295 405.688 122.32 406.81 121.552C407.652 120.924 408.003 119.737 408.493 118.759C408.634 118.48 408.143 117.852 408.003 117.642C407.722 117.154 407.442 117.712 407.021 117.084C407.722 116.456 408.493 117.433 408.844 116.176C409.195 116.805 409.475 116.525 409.896 116.246C410.106 116.107 410.878 115.967 410.948 115.827C411.439 115.269 412.421 115.618 413.052 115.688C412.07 116.525 412.631 117.154 413.402 117.782C413.823 117.224 414.174 116.176 414.945 116.316C414.454 115.897 414.314 115.478 414.875 115.059C415.506 116.107 416.839 115.618 417.47 114.71C417.61 114.989 417.75 115.269 417.891 115.548C418.241 115.059 418.522 114.501 419.013 114.152C418.943 114.431 418.872 114.78 418.802 115.129C419.504 114.92 419.574 114.361 420.135 114.012C420.205 113.942 419.994 112.616 420.065 112.267C420.205 111.499 420.485 111.499 420.485 110.591C420.485 110.033 420.345 109.055 421.187 109.474C421.187 108.916 421.046 108.497 421.467 108.148C421.958 107.799 421.818 107.17 421.818 106.542C421.818 106.123 421.327 105.495 421.116 105.076C420.906 104.657 421.116 104.238 421.187 103.819C420.485 103.47 420.065 103.959 420.275 104.727C419.854 103.121 418.872 105.215 418.732 105.844C418.592 106.332 419.223 106.542 419.153 106.821C418.943 107.45 418.732 108.148 418.522 108.846C418.241 109.684 417.68 110.661 416.839 111.01C416.348 111.289 415.927 111.499 415.366 111.569C414.875 111.569 415.436 110.661 415.576 110.521C414.875 110.801 414.595 110.731 414.595 111.499C414.595 111.918 413.893 112.476 413.683 112.825C413.402 113.244 413.823 113.593 413.262 113.803C412.491 114.152 412.841 113.523 412.35 113.523C411.439 113.593 409.756 113.384 409.195 114.222C408.564 115.129 407.722 115.757 406.67 115.757C407.301 117.154 405.758 117.573 405.057 118.061ZM403.725 165.605C403.304 165.954 402.673 166.373 402.392 166.862C401.972 167.56 402.252 167.699 402.392 168.328C402.462 168.816 402.533 169.375 402.463 169.934C402.392 170.283 403.234 170.701 403.444 170.911C403.374 170.213 403.094 168.747 404.216 169.235C404.075 169.096 402.883 168.328 403.444 168.188C404.075 168.049 404.146 167.211 403.444 167.071C403.585 166.862 403.655 166.582 403.795 166.443C403.865 166.164 403.725 165.884 403.725 165.605ZM434.16 205.609C433.389 204.911 434.441 203.933 433.178 203.514C433.038 203.445 432.407 204.352 432.267 203.863C432.056 203.235 431.916 202.677 431.706 202.118C431.355 201.071 431.425 200.442 430.514 199.954C430.163 199.744 427.708 198.627 427.708 198.278C427.708 197.231 427.989 196.114 427.288 195.346C426.376 194.299 426.446 193.81 426.376 192.344C426.306 191.367 425.184 190.878 424.553 191.436C424.202 189.272 423.641 187.666 422.8 185.642C421.748 185.851 421.677 187.736 421.467 188.644C421.187 189.621 421.397 190.808 421.467 191.855C421.537 193.112 420.836 197.022 419.083 196.393C418.452 196.184 417.961 195.137 417.33 194.718C416.208 194.02 415.085 193.391 413.963 192.693C412.912 192.065 413.332 191.716 413.683 190.459C413.893 189.412 414.524 188.923 415.156 188.155C414.104 187.108 413.823 187.038 412.421 186.898C411.299 186.759 410.247 186.619 409.125 186.619C409.195 187.108 409.195 187.666 409.265 188.155C408.003 187.946 406.951 187.317 406.179 188.434C405.408 189.551 405.198 190.599 404.917 191.925C403.865 191.367 402.813 190.808 401.761 190.25C401.411 190.04 400.078 191.506 399.798 191.785C398.115 193.252 395.8 194.508 394.889 196.742C394.468 197.859 394.468 198.837 393.346 199.116C391.873 199.465 390.401 199.814 388.928 200.093C387.946 200.303 387.385 200.722 386.473 201.42C385.351 202.188 385.211 202.467 384.65 203.863C384.44 203.375 384.299 202.956 384.089 202.537C383.388 204.352 382.897 205.818 383.598 207.633C384.019 208.681 383.879 208.89 383.528 210.007C383.248 210.775 383.809 211.403 384.089 212.102C384.931 213.917 385.492 215.592 385.772 217.617C385.912 218.385 386.544 220.34 386.263 220.968C386.193 221.177 384.51 222.155 385.351 222.713C385.983 223.202 386.754 224.179 387.595 224.179C388.437 224.179 389.419 224.459 390.05 223.83C390.962 222.923 391.242 222.574 392.434 222.434C393.276 222.364 394.117 222.225 395.029 222.225C395.66 222.225 396.361 222.155 396.993 222.155C397.203 222.155 397.483 221.247 397.624 221.038C397.974 220.34 399.237 220.06 399.938 219.711C400.639 219.362 401.691 219.921 402.322 219.502C402.813 219.223 403.865 218.245 404.426 218.315C406.46 218.594 408.283 218.804 410.177 219.502C411.369 219.991 411.509 220.2 412.14 221.457C412.561 222.294 413.052 222.993 413.543 223.761C414.665 222.504 415.576 221.457 416.348 219.991C416.839 221.526 415.857 222.713 415.086 224.04C416.348 224.319 416.278 223.621 416.909 222.364C416.979 223.132 416.769 225.017 417.54 225.017C418.241 225.017 418.732 226.483 418.872 227.112C419.363 229.276 420.906 229.904 422.8 230.184C423.992 230.393 424.202 230.533 425.114 229.695C426.166 228.787 426.096 229.206 427.007 230.253C427.428 230.742 428.55 230.393 428.971 229.974C429.953 228.997 430.093 228.927 431.355 228.857C433.529 228.787 433.319 225.855 433.669 224.04C433.95 222.434 435.703 221.247 436.124 219.711C436.615 217.826 437.526 215.592 437.596 213.637C437.667 211.822 437.035 209.658 436.755 207.843C435.843 207.145 435.002 206.377 434.16 205.609ZM400.148 174.402C399.728 175.589 401.691 175.1 401.972 174.96C402.042 174.262 400.429 173.634 400.148 174.402ZM407.231 186.48C406.53 186.968 405.759 185.991 405.688 187.248C406.249 187.248 406.881 187.527 407.301 187.248C407.722 186.968 407.932 186.27 407.231 186.48ZM436.825 176.845C437.176 176.147 437.246 176.077 436.825 175.449C436.755 175.379 436.474 175.519 436.404 175.379C436.334 175.239 436.194 174.96 436.054 174.821C435.422 174.262 434.581 173.913 433.88 173.424C433.599 174.262 436.825 174.681 436.474 176.217C436.545 176.426 436.685 176.636 436.825 176.845ZM429.953 233.884C429.532 234.023 428.269 234.861 427.919 234.652C427.218 234.303 426.446 234.023 425.745 233.674C425.605 234.791 425.745 236.188 426.166 237.235C426.727 238.561 427.358 238.84 428.62 239.12C429.953 239.329 431.425 234.372 429.953 233.884ZM432.126 177.823C431.565 177.823 431.004 177.683 430.514 177.892C430.864 178.73 432.547 179.219 433.319 179.009C433.95 178.87 434.721 178.591 434.932 177.962C435.002 177.753 436.194 177.823 435.493 177.055C436.474 176.845 436.054 176.007 435.493 175.658C434.721 175.17 434.932 176.496 434.932 176.915C434.861 176.915 432.407 178.66 433.038 177.194C432.968 177.055 432.617 177.823 432.126 177.823ZM427.077 177.683C426.657 177.194 426.937 176.426 426.306 176.077C425.675 175.728 425.114 175.309 424.483 174.96C423.571 174.402 422.379 174.122 421.397 173.773C419.854 173.215 418.311 172.586 416.698 172.028C415.927 171.749 414.735 172.307 414.244 173.005C414.034 173.215 413.262 174.611 412.982 174.471C412.351 174.122 412 174.122 411.719 173.424C411.439 172.656 411.228 172.028 411.158 171.19C411.018 170.283 410.808 170.492 410.036 170.283C408.774 170.003 407.512 170.283 406.881 171.539C407.301 171.609 407.722 171.679 408.213 171.749C408.423 171.819 408.213 172.517 408.493 172.656C409.195 173.075 410.177 172.796 410.948 172.796C410.948 172.936 410.948 173.285 410.878 173.424C409.896 173.075 409.335 173.285 408.283 173.494C408.704 174.192 409.125 174.96 409.545 175.658C409.896 175.17 410.317 174.751 410.667 174.262C410.878 175.379 410.878 175.309 411.789 175.728C412.841 176.217 413.963 176.636 415.015 177.055C415.436 177.264 416.558 177.473 416.769 177.962C417.119 178.8 417.47 179.708 417.82 180.545C416.558 180.894 416.418 180.755 416.278 182.151C417.259 182.081 418.171 181.942 419.153 181.872C419.644 181.802 419.994 183.338 420.626 183.338C421.607 183.408 422.589 183.687 423.431 183.059C423.922 182.779 424.132 181.243 424.623 181.313C425.184 181.383 426.797 181.313 427.218 181.732C427.989 182.57 428.76 183.338 429.532 184.176C430.163 184.804 430.934 184.734 431.776 184.874C432.337 184.944 433.249 185.642 433.669 185.502C433.319 185.153 432.197 184.385 432.758 183.896C432.267 183.757 431.495 183.827 431.846 183.059C430.584 182.989 430.654 182.71 430.023 181.523C429.882 181.243 429.321 181.034 429.041 180.825C428.76 180.685 428.69 179.987 428.55 179.708C428.971 179.638 429.392 179.638 429.742 179.568C430.023 177.892 427.779 178.451 427.077 177.683ZM422.168 86.2957C422.168 87.2731 422.238 88.1109 421.888 88.9486C421.397 90.0657 421.748 90.0657 422.028 91.1827C422.168 91.8809 422.168 91.8809 421.748 92.5092C421.537 92.7884 421.818 93.2772 421.818 93.6262C421.818 94.6734 421.607 94.9527 422.028 95.9999C422.168 95.4414 422.168 94.5338 422.87 94.3942C423.571 94.2545 423.922 95.1621 423.851 95.7207C424.483 95.0225 423.711 93.9753 423.361 93.2772C422.87 92.4394 422.589 92.2997 422.87 91.3223C423.29 90.0657 423.15 89.6468 424.342 89.4373C425.114 89.2977 425.044 90.6242 425.815 90.6242C425.184 89.5072 424.903 88.5298 424.553 87.2033C424.412 86.575 424.272 86.0164 424.062 85.3881C423.992 84.9692 423.501 84.6899 423.431 84.2711C423.22 82.9446 424.272 82.3163 423.571 80.9898C423.22 80.2916 423.641 78.4066 422.379 79.3142C422.87 79.8029 423.15 80.5709 422.659 80.9898C422.449 81.1992 422.379 80.7803 421.958 81.0596C421.537 81.4087 421.677 81.4087 421.818 81.9672C421.958 82.5955 421.607 83.6427 421.467 84.2711C421.467 85.1787 422.87 85.5277 422.168 86.2957ZM397.554 155.272C398.185 155.412 398.605 154.435 397.764 154.365C397.554 154.574 396.782 155.133 397.554 155.272ZM396.572 155.482C396.642 154.854 396.993 154.365 397.413 154.016C397.694 153.806 397.483 152.969 397.624 152.62C397.554 152.689 397.483 152.689 397.413 152.759C397.203 153.597 396.432 154.644 396.572 155.482ZM398.816 152.48C398.465 152.689 398.115 152.55 397.904 152.27C397.974 152.689 397.904 153.038 398.115 153.318C398.676 152.829 398.255 154.295 398.886 154.644C398.886 154.435 398.886 154.155 398.816 153.946C398.886 154.155 399.026 154.295 399.096 154.505C399.447 154.016 398.746 153.248 398.816 152.48ZM396.782 151.293C396.922 151.642 397.203 151.921 397.483 152.061C397.554 151.852 397.554 151.433 397.554 151.223C396.993 151.293 397.133 150.595 396.361 150.665C396.572 151.014 396.502 151.433 396.151 151.712C396.361 151.572 396.642 151.433 396.782 151.293ZM397.834 150.804C397.834 151.363 398.255 151.502 398.605 151.782C399.026 152.131 398.535 152.201 398.816 152.55C399.728 153.737 399.657 152.131 399.517 151.363C399.307 150.455 398.465 150.735 397.834 150.804ZM394.538 151.921C394.678 153.457 394.468 154.505 396.081 153.806C395.66 154.365 394.748 155.203 395.59 155.622C395.941 155.761 395.8 156.25 396.221 156.18C396.642 156.11 396.432 155.552 396.432 155.133C396.432 154.574 397.133 153.527 396.922 153.178C396.432 152.34 396.151 152.27 395.31 151.921C395.099 151.852 394.748 151.921 394.538 151.921ZM391.032 171.469C390.821 172.028 390.962 172.447 390.681 173.005C390.26 173.843 390.05 173.913 390.541 174.681C390.821 175.1 391.593 174.541 391.382 175.519C391.312 175.938 390.891 177.543 391.032 177.823C391.242 178.102 392.294 178.311 392.504 177.892C392.575 177.753 392.294 177.194 392.294 176.985C392.294 176.706 392.574 176.496 392.574 176.287C392.645 175.798 392.504 175.1 392.574 174.541C392.645 173.983 391.873 173.564 392.995 173.424C393.626 173.354 393.136 174.471 393.206 174.751C393.416 175.379 394.187 175.309 393.977 175.938C393.767 176.636 394.258 176.775 394.748 176.636C394.468 176.706 395.871 175.589 395.73 175.938C396.151 175.03 395.169 175.519 394.889 174.821C394.819 174.681 395.309 174.332 395.169 174.122C395.029 173.773 394.819 173.494 394.678 173.145C394.398 172.656 394.117 172.656 393.767 172.237C395.029 172.726 395.45 170.213 396.572 170.911C396.852 169.794 395.941 170.492 395.52 170.492C395.029 170.492 394.959 170.701 394.608 170.841C394.117 170.981 394.398 170.422 393.907 170.911C392.715 172.168 391.452 169.934 392.364 168.816C392.785 168.258 393.346 168.886 393.977 168.816C394.678 168.747 395.52 168.467 396.151 168.816C397.694 169.724 398.535 168.049 399.026 166.722C398.395 166.722 397.904 167.699 397.343 168.118C397.063 168.328 396.502 167.979 396.151 167.909C395.73 167.909 395.8 168.188 395.31 167.979C394.678 167.769 393.556 167.071 392.925 167.49C392.154 167.979 391.943 168.467 391.523 169.375C392.154 170.422 391.312 170.771 391.032 171.469ZM392.504 149.408C392.925 150.106 393.276 150.735 393.697 151.433C394.468 150.525 394.398 150.036 393.486 149.408C393.135 149.408 392.855 149.408 392.504 149.408ZM384.86 181.732C384.86 182.5 385.422 183.128 385.983 182.43C386.544 181.662 385.351 181.523 384.86 181.732ZM419.854 100.328C419.784 100.608 419.784 101.236 419.574 101.376C419.083 101.655 419.013 101.655 418.872 102.144C418.802 102.283 419.363 103.889 419.504 103.959C419.714 104.029 419.924 103.33 420.205 103.4C420.415 103.47 420.906 103.47 420.626 103.121C420.345 102.632 419.433 102.981 419.574 102.074C419.994 101.934 420.485 102.353 420.696 102.283C420.906 102.144 421.537 101.795 421.748 102.004C422.098 102.353 423.15 103.261 423.641 103.051C423.641 103.051 423.922 102.004 423.992 101.864C424.132 101.655 424.763 101.306 425.044 101.306C425.815 101.306 426.446 101.236 427.007 100.538C425.535 100.608 426.657 99.351 426.446 98.7227C425.394 99.7699 425.394 99.4906 424.062 98.8623C423.15 98.3736 422.729 97.5358 422.028 96.6981C421.257 95.581 421.537 98.0245 421.677 98.3736C421.818 98.7925 421.116 99.1416 421.116 99.6303C421.116 100.049 421.187 100.328 420.976 100.677C420.696 100.538 420.275 100.468 419.854 100.328ZM242.151 76.9405C242.221 77.2896 242.782 78.0576 243.133 77.9878C243.623 77.8481 243.553 77.15 243.133 77.0802C242.992 76.5915 242.571 76.7311 242.151 76.9405ZM275.882 113.942C275.461 114.152 274.76 114.64 274.339 114.571C274.059 114.571 273.007 114.291 272.797 114.71C272.095 116.107 274.97 115.269 275.251 115.199C274.83 114.64 275.461 114.361 275.882 113.942ZM264.592 115.059C264.592 114.571 263.61 114.361 263.119 114.431C262.207 114.571 261.927 114.361 261.155 113.872C261.015 114.012 260.875 114.361 260.805 114.571C262.207 115.059 263.189 115.129 264.592 115.059ZM243.974 76.7311C243.834 77.0802 243.974 77.7783 244.465 77.7783C245.026 77.7085 244.956 78.1972 245.026 78.7557C245.096 78.1274 245.026 77.4292 245.797 77.3594C245.657 77.2896 245.517 77.0104 245.377 76.9405C247.27 76.5915 244.184 74.8461 245.096 76.6613C244.675 76.6613 244.535 76.4518 244.745 76.033C244.605 76.033 244.395 76.033 244.255 76.033C244.395 76.3122 244.325 76.5217 243.974 76.7311ZM260.664 70.5874C259.753 70.3082 259.402 70.378 258.42 70.6572C258.771 71.0063 258.981 71.3554 258.771 71.9139C259.192 71.1459 260.033 71.0063 260.664 70.5874ZM240.538 105.914C240.608 106.123 240.187 106.472 240.187 106.751C240.187 106.891 240.538 107.031 240.538 107.17C240.468 107.799 239.907 107.868 240.398 108.357C240.818 108.706 241.239 108.776 241.309 108.148C241.309 107.799 241.87 108.148 241.94 107.449C242.01 106.751 242.081 106.053 242.221 105.355C242.361 103.959 240.748 104.797 240.398 105.076C240.257 105.006 240.117 105.006 239.977 104.936C239.696 105.634 240.468 105.425 240.538 105.914ZM486.405 58.7189C486.125 58.7189 484.933 58.4397 484.722 58.6491C484.442 58.9284 484.722 59.5567 484.933 59.7662C485.704 60.3945 486.686 59.4869 487.177 60.1152C487.738 60.8134 488.649 61.0926 489 59.9058C488.229 59.4869 487.247 58.7189 486.405 58.7189ZM253.441 73.9385C253.722 73.5196 254.143 73.2404 254.563 73.0309C254.143 72.5422 254.493 72.263 254.844 71.8441C253.511 71.495 253.371 72.8913 253.441 73.9385ZM256.316 67.2363C256.316 67.0967 256.246 66.9571 256.246 66.8174C256.316 66.8174 256.387 66.8174 256.457 66.8174C256.317 65.9098 255.124 66.608 256.316 67.2363ZM240.468 102.632C239.977 103.051 240.888 103.889 241.309 103.889C241.66 102.842 241.73 102.283 241.59 101.166C241.169 101.236 241.52 101.585 241.309 101.864C241.169 102.144 240.748 102.353 240.468 102.632ZM440.051 178.451C439.7 178.241 439.77 177.683 439.139 177.543C439.139 178.032 439.139 178.311 439.42 178.591C439.63 178.87 439.56 179.219 439.7 179.428C439.981 179.777 441.243 180.126 440.822 179.219C440.612 178.94 440.331 178.591 440.051 178.451ZM410.738 117.712C410.948 117.642 411.228 118.271 411.369 118.061C411.509 117.852 412 117.363 412.07 117.154C412.14 115.478 409.966 116.944 409.616 116.665C409.125 117.712 408.704 117.503 409.125 118.829C409.966 119.388 410.106 117.992 410.738 117.712ZM402.743 174.332C402.112 175.17 403.374 175.17 403.725 175.1C404.005 175.1 403.865 174.471 404.146 174.611C404.426 174.681 404.777 174.96 405.057 174.89C405.899 174.681 406.109 174.96 406.81 175.449C407.091 173.983 405.548 173.913 404.707 173.634C403.935 173.773 403.234 173.704 402.743 174.332ZM464.385 235.071C464.385 234.512 464.175 234.023 463.964 233.535C463.333 233.884 463.053 233.884 462.913 234.652C462.702 235.42 462.492 235.071 462.071 235.629C461.79 236.048 461.861 236.746 461.58 237.165C461.3 237.584 460.668 237.933 460.318 238.282C459.897 238.631 459.546 239.05 459.055 239.259C458.705 239.399 457.933 239.608 457.653 239.888C456.882 240.935 456.11 241.912 455.339 242.96C454.567 244.007 456.882 243.728 457.162 244.077C457.653 244.635 459.266 245.194 459.757 244.356C460.248 243.518 461.229 242.471 461.51 241.493C461.861 240.097 462.352 239.888 463.474 239.12C463.544 239.469 463.754 239.678 464.105 239.678C463.684 238.84 463.614 238.771 464.175 238.003C464.736 237.235 465.297 236.537 465.858 235.838C465.718 235.28 465.507 234.791 465.367 234.233C465.086 234.512 464.736 234.791 464.385 235.071ZM457.162 244.705C456.741 244.845 457.022 245.403 456.671 245.822C457.162 245.403 458.354 245.613 457.162 244.705ZM471.117 228.438C469.995 229.136 469.855 229.066 468.593 228.717C467.821 228.508 468.312 227.112 467.541 226.763C467.611 227.531 467.12 228.159 466.629 227.181C466.489 226.902 466.77 226.413 466.559 226.134C466.419 225.925 466.138 225.646 465.998 225.366C465.647 224.319 466.279 224.459 465.086 224.04C464.525 223.83 464.245 223.272 463.684 223.132C463.964 223.761 464.245 224.319 464.525 224.947C464.666 224.878 464.736 224.808 464.876 224.668C465.157 225.296 465.858 227.67 466.559 227.461C466.279 228.229 466.84 228.927 466.559 229.625C466.209 230.602 466.068 230.882 465.227 231.51C465.507 231.789 465.858 232.138 466.209 232.348C466.419 232.487 467.12 232.487 467.26 232.697C467.681 233.465 466.699 234.442 466.349 234.861C467.05 235.28 467.821 235.699 468.383 234.582C468.803 233.674 469.645 232.627 469.645 231.65C469.645 231.021 470.346 230.951 470.697 231.161C471.117 231.37 470.767 230.812 470.907 230.672C471.328 230.114 472.169 228.578 471.117 228.438ZM232.193 107.17C232.473 107.38 232.754 107.589 233.034 107.799C233.245 107.589 233.525 107.38 233.735 107.17C233.245 106.263 232.894 106.682 232.193 107.17ZM484.021 54.181C484.021 55.0886 484.161 55.3678 483.39 55.7169C482.829 55.9962 483.32 56.8339 483.46 57.3925C482.478 57.2528 482.128 57.1132 481.286 56.4849C480.795 56.1358 479.673 56.7641 479.533 56.1358C479.322 55.2282 479.463 54.3904 478.551 54.3206C477.569 54.2508 476.587 54.181 475.676 54.1112C475.115 54.0414 476.096 52.3658 474.834 52.5753C474.203 52.7149 474.413 54.3206 474.413 54.949C474.343 55.9962 471.117 56.2754 470.276 56.4849C471.047 57.0434 471.889 57.2528 471.959 58.3001C472.029 59.4869 472.52 59.9756 473.151 60.953C473.221 61.0228 472.66 61.7908 472.52 61.7908C472.24 61.8606 471.608 61.5813 471.328 61.5813C470.837 61.5115 469.785 61.0228 469.364 61.3021C467.611 62.3493 465.788 63.4663 464.035 64.5135C462.632 65.3513 461.159 65.84 460.528 67.3759C459.266 66.1891 459.196 65.9797 457.583 66.1891C456.04 66.3985 455.97 66.4684 454.988 67.8646C454.988 67.3759 454.988 66.8872 454.918 66.3985C454.427 66.608 453.586 67.3061 453.025 67.2363C452.393 67.1665 451.762 66.8174 451.341 67.4458C450.43 68.842 449.588 70.3082 448.677 71.7044C449.168 71.8441 450.78 72.0535 450.64 72.612C450.29 74.0083 450.219 74.0083 451.061 75.1254C449.658 75.7537 448.466 76.3122 449.168 78.1274C449.308 78.4066 448.116 78.8953 447.765 78.9652C447.064 79.1746 446.503 79.1048 446.433 79.9426C446.362 80.8502 446.643 81.6879 445.731 81.8974C444.609 82.1766 444.539 82.037 444.399 83.2937C444.188 84.4805 442.716 85.7372 441.944 86.6448C441.033 82.3861 437.947 74.3574 443.066 71.8441C444.539 71.1459 445.381 70.9365 446.222 69.4704C446.994 68.0741 447.975 67.5156 449.168 66.608C450.009 65.9797 451.201 65.6306 451.412 64.5135C451.622 63.6758 451.832 62.838 452.043 62.0002C452.113 61.7908 453.235 61.721 453.445 61.6512C452.604 61.4417 452.113 61.3719 451.271 61.4417C450.64 61.5115 450.29 62.4889 449.939 63.0474C449.238 64.1645 447.765 65.0023 446.783 65.7702C446.292 64.5135 446.433 64.0248 446.713 62.6286C445.801 63.1871 445.381 63.3965 444.329 63.3965C443.277 63.3965 442.996 63.3267 442.155 64.0248C440.822 65.0721 439.7 66.3287 438.578 67.6552C438.929 67.9345 439.841 68.3533 439.56 68.842C439.49 69.0515 438.228 69.1213 438.017 69.1213C436.755 69.2609 435.563 69.4006 434.3 69.5402C434.721 69.1911 435.212 68.9119 435.633 68.5628C434.441 68.3533 433.249 68.0741 432.126 67.8646C431.776 67.7948 431.004 68.493 430.724 68.7024C430.373 68.9119 429.882 68.7024 429.462 68.6326C428.34 68.4232 427.428 68.4232 426.306 68.493C425.605 68.493 423.641 68.2137 423.15 68.7024C421.327 70.378 419.504 72.0535 417.75 73.8687C416.137 75.5443 414.314 76.7311 412.421 78.0576C412.701 78.6859 413.122 78.6161 413.613 78.6859C414.314 78.7557 414.384 78.6161 414.665 79.3142C414.735 79.5237 415.015 80.5709 415.226 80.5709C416.628 80.7105 416.769 80.92 417.4 79.5237C417.961 78.3368 421.327 81.0596 421.187 82.037C420.766 84.2013 420.275 86.3655 419.784 88.5996C419.293 90.6242 418.592 91.7412 417.47 93.5564C416.418 95.2319 415.576 96.8377 414.174 98.1642C413.262 99.0718 412.35 99.9793 411.369 100.887C410.878 101.376 409.826 101.376 409.125 101.515C408.774 101.585 408.493 100.608 408.213 100.608C408.003 100.538 407.231 101.166 407.021 101.306C405.969 101.934 405.969 102.213 405.548 103.47C404.917 105.425 403.374 106.472 401.972 107.799C403.514 109.125 404.917 110.591 404.566 112.895C404.356 114.431 404.566 114.78 403.304 115.408C402.252 115.967 401.691 115.897 400.499 115.897C400.639 115.059 400.709 114.152 400.85 113.314C400.99 112.337 400.078 112.406 400.85 111.499C401.34 110.94 401.06 110.172 400.359 110.242C399.728 110.312 398.676 110.731 398.465 109.753C398.325 109.265 399.026 107.938 399.167 107.449C399.167 107.38 397.764 106.402 397.554 106.472C396.993 106.472 396.011 107.38 395.59 107.659C394.959 108.078 394.258 108.427 393.626 108.846C393.136 107.519 394.328 106.612 395.099 105.774C394.258 105.146 394.258 104.936 393.346 105.355C392.715 105.634 392.294 106.053 391.733 106.472C391.032 107.031 390.681 107.38 389.84 107.659C389.699 107.729 388.297 108.217 388.647 108.636C389.208 109.195 389.699 109.753 390.12 110.452C390.751 111.429 390.681 111.289 391.593 110.801C392.995 110.102 394.047 110.731 395.45 111.08C393.837 112.406 392.294 113.733 390.681 115.129C391.382 115.688 392.224 116.176 392.574 117.084C393.065 118.201 393.556 119.248 394.117 120.365C393.276 120.226 392.504 120.086 391.663 119.946C392.504 120.575 393.416 121.203 394.258 121.831C393.626 122.25 392.995 122.739 392.364 123.228C393.136 123.437 393.977 123.716 394.748 123.926C393.767 125.741 392.925 128.045 391.663 129.651C390.33 131.326 389.279 133.211 387.315 134.049C385.211 134.887 383.177 135.794 381.003 136.562C380.372 136.772 379.671 137.051 379.04 137.26C378.479 137.47 378.619 137.47 378.759 138.098C378.829 138.517 378.829 139.355 378.128 139.006C377.918 138.936 377.707 137.958 377.637 137.679C377.848 137.609 378.058 137.4 378.339 137.4C377.637 136.841 376.305 136.423 375.463 137.051C374.762 137.609 373.079 138.447 372.798 139.355C372.728 139.634 372.167 140.821 372.308 141.1C372.728 141.728 373.149 142.427 373.57 143.055C374.131 144.032 374.902 144.87 375.604 145.708C376.445 146.825 376.936 147.174 377.006 148.57C377.076 149.408 377.497 151.433 376.866 152.061C375.043 153.737 373.289 155.272 371.326 156.739C370.695 156.11 371.606 155.063 371.115 154.574C370.484 153.876 369.853 153.248 369.222 152.55C368.1 151.363 367.258 150.665 365.716 150.595C365.786 150.246 365.786 149.827 365.856 149.478C364.383 149.548 364.664 149.757 364.523 151.363C364.453 152.34 363.962 153.248 363.612 154.086C363.472 154.435 363.612 154.923 363.612 155.272C363.682 156.04 363.682 155.901 364.383 155.901C364.734 155.901 365.225 158.274 365.365 158.693C365.575 159.392 366.978 160.09 367.539 160.509C368.03 160.858 368.941 161.765 369.152 162.324C369.503 163.162 369.152 164.348 369.362 165.256C369.573 166.094 370.064 166.932 370.344 167.769C369.082 167.56 368.31 166.792 367.329 165.954C366.347 165.186 366.277 164.767 365.926 163.511C365.645 162.673 365.365 160.718 364.804 160.09C363.892 159.112 363.051 158.205 362.139 157.227C361.718 156.808 362.279 154.435 362.35 153.806C362.49 152.62 362.209 151.223 362.139 150.036C361.999 147.663 361.227 145.638 360.526 143.334C360.035 143.893 359.544 144.521 359.124 145.08C358.492 145.848 358.563 145.778 357.651 145.568C356.669 145.359 356.739 145.429 356.95 144.381C357.02 143.963 357.37 142.776 357.23 142.357C356.599 140.891 356.248 139.564 355.056 138.657C354.004 137.819 353.654 136.353 353.093 135.096C352.532 135.445 351.83 136.283 351.199 136.353C350.077 136.492 348.955 136.632 347.903 136.841C347.763 136.841 347.062 136.841 346.921 136.981C346.711 137.19 347.062 137.958 346.851 138.168C346.29 138.726 345.799 139.285 345.238 139.843C343.696 141.449 342.153 142.985 340.61 144.591C340.119 145.149 338.997 145.359 338.366 145.708C337.524 146.127 337.875 146.685 337.875 147.663C337.875 148.5 338.155 149.687 337.945 150.525C337.735 151.293 337.104 152.48 337.314 153.248C337.594 154.505 337.805 154.993 338.576 155.901C339.277 156.669 339.558 157.507 339.979 158.484C340.75 160.229 337.735 161.765 337.524 159.392C337.384 158.344 337.384 157.367 337.454 156.32C337.524 155.272 337.104 155.133 336.402 154.435C336.332 155.133 336.472 155.901 335.841 156.25C335.21 156.669 334.579 157.088 333.948 157.507C332.195 154.225 330.722 150.874 329.249 147.453C328.828 146.546 328.197 145.498 327.987 144.591C327.847 143.893 327.917 142.985 327.917 142.287C327.847 140.123 327.777 137.889 327.706 135.724C327.216 136.353 326.795 136.981 326.304 137.609C325.813 138.238 325.813 138.168 325.042 138.098C324.2 138.098 323.218 136.423 322.587 135.794C323.218 135.655 324.481 135.724 324.621 134.887C324.27 134.887 323.849 135.026 323.499 134.956C322.587 134.747 321.605 133.909 320.764 133.421C320.203 133.071 319.852 131.675 319.572 131.047C319.291 130.418 314.593 131.396 313.821 131.536C312.068 131.745 310.385 131.047 308.702 130.698C307.93 130.558 307.089 130.628 306.738 129.86C306.037 128.533 306.247 128.115 304.915 128.603C303.793 129.022 303.092 128.883 301.899 128.673C301.198 128.533 300.707 127.626 300.006 127.347C298.814 126.788 298.674 126.649 298.113 125.392C297.692 124.554 297.552 123.437 296.64 123.297C295.097 123.088 295.097 123.158 294.045 124.414C293.695 124.833 294.957 126.439 295.237 126.858C296.219 128.464 297.061 130.209 297.902 131.815C298.042 131.047 298.113 130.279 298.253 129.581C298.884 130.698 298.744 131.815 298.814 133.141C299.936 133.071 301.759 133.281 302.811 132.653C303.793 132.024 304.775 130.488 305.546 129.511C305.616 130.488 305.406 132.024 306.177 132.513C306.598 132.792 307.089 133.281 307.65 133.49C308.071 133.7 308.632 133.49 308.912 133.979C309.123 134.328 309.403 135.305 309.824 135.375C310.525 135.515 310.245 135.934 310.175 136.632C310.104 137.33 308.702 138.517 308.281 139.006C308.281 138.796 308.071 138.587 308.071 138.377C307.72 139.215 307.51 139.634 307.51 140.611C307.51 141.449 307.229 141.379 306.528 141.659C305.827 142.008 305.125 142.357 304.424 142.636C304.003 142.845 304.003 144.032 303.583 144.242C303.232 144.381 302.741 143.963 302.39 144.102C301.899 144.312 301.338 144.591 300.848 144.8C300.146 145.149 300.216 146.057 299.585 146.336C298.393 146.755 297.201 147.174 296.079 147.593C295.728 147.732 295.658 147.872 295.448 148.221C295.167 148.64 294.817 148.64 294.326 148.71C293.274 148.919 292.292 149.199 291.31 149.478C290.539 149.687 290.399 150.525 289.627 150.525C288.365 150.525 288.225 150.804 288.014 149.478C287.734 148.151 287.523 146.825 287.243 145.498C286.822 143.474 285.84 142.078 284.788 140.332C284.157 139.285 284.087 139.076 282.965 138.657C282.334 138.447 282.334 136.492 282.194 135.864C282.053 134.887 281.352 133.979 280.931 133.071C280.651 132.513 280.02 132.303 279.739 131.675C279.038 130.418 278.337 129.162 277.635 127.905C277.285 127.277 277.004 126.23 276.163 126.439C276.233 125.671 276.373 124.903 276.443 124.135C276.163 125.043 275.812 125.95 275.531 126.928C274.48 125.811 273.919 124.833 273.217 123.437C272.446 124.345 273.778 125.95 274.199 126.788C275.041 128.533 275.882 130.279 276.794 132.024C277.285 133.071 277.144 134.258 277.916 135.026C278.266 135.375 279.038 135.934 279.108 136.423C279.248 137.33 279.389 138.168 279.529 139.075C279.599 139.564 279.529 140.611 279.95 140.96C280.44 141.449 281.142 141.938 281.562 142.496C282.264 143.613 282.614 145.359 283.105 146.615C283.246 147.034 284.508 146.965 284.788 147.314C285.279 147.872 285.77 148.431 286.191 148.989C286.962 149.897 288.575 150.944 287.383 152.131C288.225 152.41 289.136 154.086 289.838 153.946C292.152 153.318 294.466 152.689 296.71 152.131C297.131 151.991 298.393 151.502 298.744 152.131C298.954 152.48 298.183 154.714 298.042 155.203C297.622 157.018 296.289 158.763 295.448 160.369C294.676 161.765 294.115 163.231 293.063 164.348C290.258 167.281 287.032 169.934 284.929 173.494C284.438 174.262 281.492 178.311 281.983 179.009C282.825 180.266 282.825 180.476 282.755 182.011C282.685 183.408 282.755 183.478 283.526 184.595C284.788 186.27 284.368 188.853 284.438 191.018C284.508 192.553 283.246 194.369 281.983 194.997C281.282 195.346 279.879 195.695 279.318 196.254C278.617 197.091 277.916 197.859 277.215 198.697C276.583 199.395 275.882 199.744 276.233 200.652C276.513 201.28 277.425 202.677 277.355 203.375C277.285 204.143 277.425 206.028 277.004 206.656C276.654 207.214 274.9 207.633 274.339 207.913C273.358 208.401 273.568 208.82 273.428 210.007C273.358 210.635 273.498 212.381 273.147 212.869C272.025 214.475 270.903 216.43 269.571 217.896C268.869 218.664 267.958 219.292 267.186 219.921C266.766 220.27 265.924 221.387 265.293 221.526C263.259 221.945 261.155 222.364 259.122 222.783C258.21 222.993 257.228 223.202 256.246 223.411C255.755 223.481 254.844 222.294 254.563 222.015C253.441 221.038 253.511 221.038 253.652 219.432C253.722 218.804 253.021 217.757 252.81 217.198C252.319 216.011 251.828 214.824 251.337 213.637C251.057 212.939 250.145 212.381 249.654 211.892C249.304 211.543 249.304 209.867 249.234 209.379C249.023 207.982 248.813 206.656 248.602 205.33C248.322 203.514 247.41 202.048 246.569 200.442C246.008 199.395 245.517 198.348 245.026 197.231C244.816 196.742 245.096 195.905 245.166 195.416C245.517 193.112 245.587 190.878 246.709 188.853C247.831 186.898 247.13 185.363 246.639 183.338C246.148 181.174 245.587 179.009 245.096 176.845C244.956 176.217 244.044 175.379 243.694 174.89C242.922 173.913 242.221 172.936 241.449 171.888C241.029 171.33 241.309 170.632 241.449 170.003C241.59 168.677 241.73 167.281 241.94 165.954C242.081 164.767 242.151 164.697 241.449 163.79C240.678 162.743 240.748 162.603 239.486 162.743C238.785 162.743 237.382 163.231 236.891 162.603C236.19 161.765 235.489 160.858 234.787 160.02C234.507 159.671 230.159 160.299 229.598 160.578C228.546 161.067 227.564 161.626 226.512 162.114C225.741 162.533 225.32 162.324 224.479 162.114C223.567 161.905 223.006 161.626 222.094 161.905C220.972 162.324 219.85 162.673 218.728 163.092C218.167 163.301 217.606 162.533 217.185 162.254C216.133 161.486 215.011 160.718 213.959 159.95C212.627 158.973 211.926 158.484 211.084 157.018C209.682 154.644 208.349 152.27 206.947 149.897C206.526 149.129 206.105 148.361 205.614 147.593C205.404 147.244 206.175 145.917 206.245 145.568C206.456 144.94 207.157 143.753 207.017 143.055C206.736 141.938 206.526 140.821 206.245 139.634C206.105 138.866 205.474 137.54 205.614 136.702C205.684 136.213 206.245 135.515 206.456 135.096C207.788 132.722 209.121 130.349 210.453 127.975C211.365 126.299 212.487 125.811 214.1 124.833C214.941 124.345 215.292 124.275 215.432 123.297C215.642 122.041 215.783 120.784 215.993 119.527C216.204 118.061 219.219 117.782 219.78 116.316C220.201 115.339 220.341 113.872 221.393 113.593C221.673 113.523 222.375 114.92 223.216 114.71C223.567 114.64 224.408 114.291 224.759 114.431C224.969 114.571 225.671 115.059 225.881 114.989C226.653 114.501 227.494 113.942 228.336 113.523C229.878 112.825 231.772 112.127 233.455 111.918C233.876 111.848 234.577 111.638 234.998 111.778C235.348 111.918 235.909 112.197 236.26 112.197C236.681 112.197 237.102 111.708 237.522 111.638C237.873 111.569 238.294 111.708 238.644 111.708C239.766 111.778 240.538 111.987 241.52 111.359C242.291 110.87 243.062 111.499 243.834 111.848C243.203 113.174 243.133 113.244 243.764 114.501C244.114 115.059 242.852 115.967 242.431 116.386C243.062 116.944 243.904 118.061 244.675 118.271C246.078 118.62 247.48 119.039 248.883 119.388C249.935 119.667 249.654 120.854 250.706 121.343C251.618 121.761 252.53 121.622 253.371 122.18C254.633 123.018 255.265 123.228 256.036 121.692C256.246 121.343 255.615 120.784 255.826 120.435C255.966 120.156 256.316 119.318 256.597 119.178C257.929 118.759 258.631 118.55 260.033 118.969C260.314 119.039 260.033 119.667 260.454 119.737C261.085 119.876 261.716 120.016 262.348 120.156C262.838 120.226 262.909 120.505 263.119 120.994C263.259 121.273 263.75 120.644 263.96 120.714C264.942 120.994 265.994 121.343 266.976 121.622C268.098 121.971 268.238 121.971 269.29 121.412C270.482 120.854 270.552 120.644 271.745 121.203C273.147 121.901 275.251 121.692 275.882 119.946C276.233 118.829 278.196 115.478 277.425 114.361C276.934 113.663 277.986 112.127 277.776 111.918C277.495 111.638 277.074 112.127 276.864 112.267C276.583 112.476 276.163 111.918 275.882 111.987C275.461 112.057 275.181 112.895 274.83 113.035C274.48 113.174 273.778 113.104 273.428 113.104C272.516 113.104 272.165 112.197 271.394 112.057C270.833 111.987 270.412 111.638 270.202 112.267C269.991 112.965 269.991 112.965 269.29 113.035C268.589 113.174 267.537 112.267 266.976 111.918C265.994 111.359 264.241 108.427 265.293 107.24C264.942 107.31 264.592 107.31 264.241 107.38C264.101 106.193 265.643 105.844 266.275 105.844C267.537 105.774 268.168 105.774 269.29 105.146C268.939 105.006 268.589 104.797 268.238 104.657C268.449 104.098 269.711 104.308 270.272 104.378C271.324 104.517 271.394 104.238 272.236 103.68C272.797 103.33 273.568 102.772 274.199 102.842C275.041 102.912 275.812 103.051 276.654 102.772C276.443 103.121 276.794 103.4 277.144 103.61C277.705 103.889 277.495 103.121 278.056 103.959C278.266 104.238 279.879 104.517 280.37 104.727C281.212 105.076 281.773 104.587 282.614 104.657C283.596 104.797 284.297 104.378 285.139 103.889C285.84 103.47 285.419 102.213 284.999 101.725C284.368 101.027 283.596 100.887 282.965 100.259C282.264 99.5605 281.703 98.7227 280.721 98.583C280.651 98.583 279.879 98.0943 279.739 98.0245C279.388 97.7453 278.968 97.466 278.617 97.1868C278.687 97.1169 278.898 96.7679 278.898 96.7679C279.248 96.8377 279.599 96.9075 279.95 96.9773C279.599 95.8603 280.37 95.5112 281.212 95.5112C280.791 95.1621 280.3 94.8829 280.09 94.3942C280.44 94.3942 280.791 94.3942 281.142 94.3942C280.861 93.5564 281.913 94.1847 282.123 93.696C282.334 93.1375 281.422 93.347 281.212 93.4168C280.3 93.5564 279.388 93.5564 278.757 94.3942C278.757 94.3244 278.757 94.1847 278.757 94.1149C277.776 94.3244 277.355 94.5338 276.654 95.2319C276.724 95.0923 276.794 94.9527 276.864 94.8829C275.882 94.7432 276.303 95.9999 276.724 96.4886C277.215 97.1169 278.056 96.7679 278.898 96.7679C278.337 97.8151 277.635 97.0471 277.004 97.3962C276.303 97.7453 275.041 98.9321 274.269 98.3736C274.69 97.1169 274.129 97.2566 273.077 96.7679C273.568 96.4886 275.531 95.7905 274.199 95.3018C273.778 95.1621 273.287 95.3018 272.867 95.3018C272.586 95.3018 272.095 94.8131 271.885 94.6734C272.446 94.7433 273.147 95.0225 273.428 94.3942C272.867 94.6734 271.324 93.9753 270.973 94.3942C270.552 94.8131 269.43 95.7206 269.36 96.2792C269.29 96.6282 269.29 97.3962 269.15 97.7453C268.939 98.0245 268.168 97.9547 268.098 98.3038C267.888 99.351 267.958 100.189 267.046 100.747C266.204 101.306 266.415 102.283 266.766 103.121C267.046 103.61 268.378 104.238 268.308 104.517C268.098 105.215 266.836 104.308 266.345 104.727C265.643 105.355 265.012 105.983 264.311 106.612C264.241 105.914 264.662 105.774 265.153 105.425C264.732 105.285 264.311 105.285 263.89 105.076C263.189 104.797 262.768 105.006 262.137 104.797C261.857 104.727 261.436 105.006 261.155 105.076C260.875 105.146 261.296 105.704 261.085 105.844C260.524 106.332 260.174 105.914 259.683 105.565C259.192 106.123 259.753 106.682 260.033 107.24C260.524 108.078 260.524 107.938 259.893 108.636C260.735 109.195 261.646 109.404 261.506 110.661C261.015 110.242 260.664 109.823 260.103 110.452C260.735 110.591 260.805 111.01 260.384 111.359C259.893 111.778 260.103 111.987 260.314 112.616C259.753 112.476 259.332 112.616 259.051 112.057C258.841 111.569 258.561 111.708 258.14 112.057C257.719 110.591 257.368 110.452 258.561 109.474C257.509 109.474 257.509 109.334 256.807 108.357C256.457 107.799 256.176 106.891 255.685 106.472C254.844 105.774 255.124 105.215 255.265 104.098C255.335 103.051 254.984 103.051 254.213 102.423C253.161 101.585 251.969 100.398 250.636 100.259C250.286 100.189 249.514 99.2114 249.444 98.8623C249.163 97.8151 249.023 97.5358 248.252 96.9075C247.901 98.0245 247.48 97.466 247.34 96.6981C247.2 95.9301 247.34 96.1395 246.499 96.349C245.657 96.5584 245.166 96.6282 245.727 97.6057C245.938 97.9547 245.236 98.7227 245.867 99.1416C246.358 99.4906 247.13 99.9095 247.551 100.398C247.901 100.887 247.831 101.725 248.322 102.144C248.883 102.632 249.234 103.051 249.935 103.121C250.426 103.121 251.267 103.121 250.496 103.749C251.197 104.308 254.633 105.774 253.792 106.891C253.441 106.682 252.459 105.355 252.039 105.704C251.618 106.123 251.548 106.193 251.408 106.751C251.267 107.24 251.618 107.24 251.969 107.519C252.95 108.287 251.267 108.497 251.337 108.985C251.408 109.684 250.075 110.87 250.075 109.753C249.374 110.172 249.234 111.01 249.584 111.638C249.935 112.337 248.532 112.546 248.392 111.987C248.112 111.01 244.816 111.15 246.078 109.684C246.288 109.893 248.041 110.033 248.462 109.963C248.953 109.823 249.795 109.823 250.145 109.544C250.566 109.265 250.215 108.985 250.636 108.706C250.987 108.567 250.145 106.472 249.935 106.472C249.654 106.472 249.023 106.402 249.093 105.983C249.163 105.425 248.673 105.215 248.252 105.425C248.322 105.006 247.34 104.238 246.919 104.308C246.218 104.378 245.797 103.68 245.306 103.191C244.395 102.283 243.133 101.864 242.852 100.677C242.571 99.5605 242.571 99.4906 241.59 98.9321C241.099 98.6529 240.468 98.4434 240.117 98.9321C239.837 99.2812 237.242 101.166 236.891 101.027C236.05 100.747 235.138 100.468 234.296 100.189C233.876 100.049 233.174 100.957 232.824 101.306C232.684 101.445 233.174 102.772 232.824 103.261C232.473 103.68 231.351 104.029 230.86 104.238C229.458 104.936 229.037 106.123 228.195 107.519C227.915 107.938 229.037 108.357 228.476 109.055C228.125 109.474 227.284 110.172 227.564 110.731C227.284 110.801 226.512 110.87 226.372 111.15C226.232 111.429 225.881 112.197 225.601 112.197C224.689 112.267 223.847 112.267 222.936 112.197C222.164 112.127 221.673 113.104 221.042 113.314C220.481 113.523 219.429 112.267 220.131 111.778C219.429 112.127 219.079 110.94 218.237 111.429C217.536 111.848 217.045 111.219 216.414 111.708C216.484 111.219 216.624 110.731 216.624 110.172C216.624 109.893 216.554 109.614 216.554 109.334C216.554 109.055 216.204 109.404 216.133 109.265C215.572 108.427 215.993 108.287 216.203 107.38C216.414 106.472 217.045 105.146 216.694 104.308C216.344 103.54 216.554 102.632 216.694 101.795C216.204 102.213 215.853 101.445 216.063 100.957C216.274 100.538 217.185 100.538 217.466 100.468C217.396 100.398 217.396 100.259 217.326 100.189C218.167 99.4208 218.588 100.468 219.289 100.259C220.341 99.9793 220.692 99.9095 221.744 100.259C222.515 100.538 223.216 100.119 223.918 100.398C224.408 100.608 225.39 100.747 225.881 100.608C227.284 100.328 227.073 97.6056 227.073 96.4886C227.073 95.4414 227.214 95.0923 226.232 94.8131C225.671 94.6036 225.601 93.6262 225.671 93.2772C225.11 93.4168 225.32 93.0677 225.11 92.9979C224.899 92.8583 224.268 92.8583 224.128 92.7884C223.707 92.4394 223.567 92.2299 223.006 92.2997C222.655 92.2997 222.375 92.2997 222.164 91.8809C222.305 91.8809 222.445 91.7412 222.585 91.7412C222.234 91.6016 222.024 91.3223 222.024 90.9035C222.655 90.8336 223.286 90.9733 223.777 90.6242C224.829 89.8562 224.268 91.2525 224.899 91.0431C225.18 90.9733 226.442 90.7638 226.442 90.4147C226.372 89.7864 226.162 89.3675 225.881 88.7392C226.162 88.7392 226.653 88.6694 226.793 88.9486C226.933 89.3675 226.863 89.4373 227.284 89.4373C228.055 89.5072 228.406 89.5072 229.177 89.1581C228.967 89.1581 228.826 89.0185 228.616 89.0185C229.037 88.4599 229.738 88.2505 230.299 88.0411C231.141 87.6222 230.229 87.1335 230.65 86.4353C230.86 86.1561 232.122 85.8768 232.473 85.6674C233.104 85.3881 233.525 85.3881 234.226 85.4579C234.016 85.3881 233.315 85.3183 233.315 85.039C233.315 84.9692 233.946 84.8994 234.016 84.8296C234.156 84.69 234.016 84.4107 234.156 84.2711C234.577 83.7125 234.647 83.3635 234.857 82.5955C234.928 82.2464 235.489 82.3163 235.699 82.037C236.47 81.1294 237.172 81.6879 238.013 81.4087C238.153 81.3389 238.013 80.92 238.224 80.92C238.434 80.92 238.714 80.8502 238.925 80.7803C239.275 80.7105 239.696 80.8502 240.047 80.92C239.907 80.2218 240.468 80.4313 240.959 80.3615C240.678 80.2916 239.977 79.6633 240.327 79.384C240.888 78.8953 240.398 78.9652 240.187 78.3368C239.977 77.7085 240.398 77.3594 239.837 76.8707C239.416 76.5217 239.486 76.2424 239.486 75.6839C239.416 74.7065 239.626 73.5894 240.678 73.5196C241.449 73.5196 242.151 72.612 242.922 72.263C242.361 73.0309 242.081 74.7065 243.273 74.9857C242.571 76.033 241.309 76.4518 241.52 77.8481C241.73 78.8953 242.712 79.8029 243.694 79.3142C243.553 79.5935 243.413 79.8727 243.273 80.152C244.255 80.7105 245.026 79.3142 245.867 79.2444C246.148 79.1746 246.99 79.7331 247.06 80.0124C247.2 80.5709 247.691 80.7105 248.182 80.9898C248.252 80.8502 248.252 80.6407 248.252 80.4313C247.971 80.4313 247.691 80.3615 247.48 80.3615C248.041 80.0124 250.145 79.9426 250.566 79.384C251.197 78.4765 253.161 77.9878 254.072 78.7557C254.002 78.6859 253.652 78.6161 253.511 78.4765C253.511 79.384 254.774 79.5237 255.194 78.9652C255.405 78.7557 255.475 78.1972 255.545 78.1274C255.685 78.0576 255.896 78.1274 256.036 77.9878C256.317 77.7085 256.737 77.5689 256.948 77.2198C256.878 77.5689 256.597 77.7783 256.387 78.0576C257.929 78.8255 257.018 76.033 256.948 75.3348C256.948 74.7763 257.088 74.3574 257.439 73.9385C257.789 73.5196 257.509 72.9611 258 72.5422C259.332 71.5648 259.683 73.7291 260.664 73.7989C261.225 73.8687 261.646 73.0309 261.506 72.5422C261.436 72.1932 261.716 70.9365 261.646 70.8667C261.506 70.727 261.225 71.0761 261.085 71.0063C260.875 70.8667 260.664 70.5874 260.454 70.378C260.314 70.2383 260.033 69.0515 260.174 68.9817C261.155 68.5628 262.277 67.9345 263.329 68.0741C264.101 68.1439 264.872 68.2835 265.643 68.3533C266.695 68.493 265.784 68.0741 266.415 67.6552C266.836 67.3759 267.397 67.5854 267.888 67.2363C268.238 67.0269 269.01 67.3061 269.36 67.3759C269.15 66.6778 267.677 66.3985 267.116 66.1193C267.256 65.9797 267.256 65.7004 267.327 65.5608C265.153 65.9797 262.909 66.5382 260.664 66.9571C260.454 67.0269 259.542 67.3061 259.402 67.0967C258.981 66.3985 258.841 66.2589 258.14 65.9797C257.298 65.6306 257.368 65.7004 257.509 64.723C257.649 64.0248 257.649 63.7456 257.509 63.0474C257.368 62.5587 256.878 61.5115 257.018 61.0228C257.088 60.6039 258 59.9058 258.28 59.5567C258.981 58.7189 259.963 58.2302 260.594 57.3925C260.945 56.9736 261.506 55.9962 261.927 55.7169C262.347 55.5075 263.049 55.9264 262.768 55.0886C262.488 53.9716 261.646 53.4828 260.524 53.413C258.981 53.3432 258.911 53.2734 257.859 54.4603C257.158 55.2282 256.807 55.7867 257.368 56.7641C257.859 57.6019 253.722 59.7662 253.441 60.185C252.389 61.4417 250.706 63.5361 251.758 65.4211C252.249 66.2589 253.582 66.1891 254.002 67.1665C254.283 67.8646 253.161 68.4232 252.67 68.842C251.828 69.61 251.127 69.8893 250.987 71.0063C250.847 71.9139 250.917 73.3102 250.496 74.148C250.005 75.3348 249.093 75.3348 248.112 75.5442C247.691 75.6141 247.761 76.1028 247.621 76.5217C247.48 77.0104 247.2 76.8707 246.709 76.8707C246.008 76.9405 245.938 77.0802 245.797 76.3122C245.727 75.8933 245.517 75.265 245.657 74.8461C245.938 74.0083 244.745 73.0309 244.255 72.4026C244.044 72.1233 244.184 71.6346 244.044 71.2856C243.834 70.8667 243.483 70.4478 243.413 69.9591C243.343 69.5402 243.694 68.7722 243.203 68.7024C242.782 68.6326 242.712 67.9345 242.571 67.5156C242.291 68.6326 242.081 68.7722 241.169 69.4006C240.538 69.8195 240.047 70.5176 239.416 70.9365C238.434 71.5648 235.909 71.2158 235.909 69.6798C235.839 67.7948 235.138 65.9797 235.208 64.1645C235.278 62.5587 235.418 62.5587 236.541 61.5813C237.172 61.0228 237.873 60.7436 238.644 60.3247C239.556 59.9058 240.327 59.6265 241.029 58.7888C241.66 58.0906 242.291 57.4623 242.992 56.7641C244.465 55.3678 245.096 53.6923 246.148 51.9469C247.2 50.2714 248.532 49.0147 249.865 47.6184C251.127 46.2221 252.249 44.6862 253.932 43.9183C255.826 43.0805 257.649 42.4522 259.613 41.8238C260.384 41.6144 260.735 40.4275 261.436 40.0086C262.067 39.5898 263.049 39.5199 263.82 39.5898C262.909 40.5672 262.488 41.0559 262.137 42.3823C262.979 42.2427 263.75 40.7766 264.241 40.1483C264.311 40.5672 264.381 40.986 264.521 41.4049C264.942 40.9162 265.293 40.3577 265.643 39.869C265.784 39.6596 266.766 39.869 267.046 39.869C266.836 40.2879 266.555 40.637 266.345 41.0559C267.327 41.8238 266.766 39.9388 267.607 40.2879C268.449 40.637 269.36 40.986 270.202 41.3351C270.903 41.6144 269.571 42.3125 269.29 42.3823C268.659 42.522 267.817 42.2427 267.186 42.1729C267.537 42.8012 268.168 42.522 268.449 43.2201C268.519 43.3597 269.43 43.1503 269.711 43.1503C270.482 43.2201 271.184 43.5692 271.674 42.871C271.885 42.522 272.797 43.2201 273.147 43.4296C272.937 44.1277 272.306 43.7088 271.815 43.5692C271.604 44.9655 274.059 44.4768 274.76 44.4768C276.163 44.5466 276.794 44.8957 278.056 45.5938C279.248 46.2221 280.23 46.8505 281.492 47.1995C282.474 47.4788 283.666 48.1071 284.017 49.2242C284.368 50.2714 284.297 50.2714 283.736 51.179C283.386 51.7375 283.246 52.0866 282.614 52.296C281.212 52.7149 280.791 52.7847 279.459 52.5054C276.934 51.8771 274.83 51.3186 272.446 50.1318C273.147 50.8299 275.111 52.1564 275.111 53.1338C275.111 54.181 274.9 56.2754 275.882 56.6943C276.934 57.183 278.337 58.3699 279.388 57.951C280.02 57.6717 279.669 56.6943 279.038 56.6943C278.407 56.6943 278.126 56.1358 277.705 55.5773C278.687 54.6697 278.757 54.8791 279.95 55.298C280.931 55.6471 281.913 55.9962 282.895 56.3452C282.825 56.066 282.053 54.181 282.123 54.1112C282.895 53.6225 283.596 53.1338 284.297 52.6451C284.648 52.3658 285.419 51.6677 285.84 51.8073C286.612 52.0167 287.383 52.296 288.154 52.5054C288.225 52.0866 288.645 51.2488 288.435 50.8299C288.365 50.6903 287.664 49.5034 287.593 49.643C287.804 48.9449 287.944 48.2468 288.084 47.4788C288.154 47.1995 287.313 46.5014 287.173 46.2221C288.084 46.3618 289.066 46.4316 289.978 46.5712C290.679 46.641 291.17 47.7581 291.591 48.3166C291.1 48.3864 289.767 48.2468 289.487 48.6656C289.066 49.3638 289.838 49.8525 290.258 50.411C290.749 51.0393 291.45 50.6205 292.222 50.5506C293.134 50.411 292.502 49.7827 292.923 49.1543C293.134 48.8751 293.975 48.6656 294.256 48.526C295.097 48.1769 295.939 47.7581 296.78 47.3392C298.113 46.7807 299.375 46.1523 300.637 45.5938C300.988 46.7807 300.988 46.7807 302.11 47.0599C302.881 47.2694 303.232 45.8731 303.863 45.9429C304.845 46.0825 305.406 46.2221 306.247 45.8032C307.229 45.3145 307.51 45.3844 308.632 45.5938C308.491 45.8731 308.281 46.1523 308.141 46.4316C309.333 46.7807 309.263 46.8505 310.104 45.8032C310.806 44.8258 310.385 44.756 309.614 43.7786C311.297 43.0805 313.751 43.2899 315.434 43.9881C316.626 44.4768 317.748 44.8957 318.94 45.3844C319.782 45.7334 320.624 46.641 321.325 47.1995C321.395 46.7807 321.816 45.3145 321.465 45.0353C320.624 44.407 319.782 43.7786 318.87 43.1503C318.309 42.7314 319.221 41.5446 319.431 40.986C319.642 40.4973 318.309 40.0086 317.959 39.7294C318.8 39.1011 319.642 38.4029 320.483 37.7048C321.044 37.2161 321.325 35.6103 321.535 34.9122C321.886 34.0046 325.883 34.982 326.795 35.0518C326.444 36.0292 326.094 37.0066 325.743 37.984C325.533 38.4727 326.444 39.6596 326.655 40.1483C327.075 40.986 325.673 44.8258 326.374 45.3145C327.216 45.8731 328.127 45.9429 327.706 46.9901C327.426 47.5486 327.145 48.9449 326.655 49.2242C325.743 49.7827 324.831 50.3412 323.92 50.8997C323.499 51.179 322.307 50.6903 321.816 50.6903C323.008 51.6677 324.27 52.4356 325.883 51.9469C327.145 51.528 328.478 49.8525 329.39 48.8751C330.441 47.8279 327.777 46.292 329.951 45.5938C330.371 45.4542 331.563 44.8258 331.844 45.2447C332.405 45.8731 332.966 46.5014 333.527 47.1297C333.387 46.292 333.527 45.524 332.826 45.0353C331.914 44.407 331.844 44.407 330.792 44.5466C330.512 44.6164 328.408 45.0353 328.338 44.8258C328.197 44.2673 327.636 43.2201 327.917 42.6616C328.267 41.9634 329.039 41.0559 328.548 40.3577C328.197 39.7992 327.005 38.752 327.426 38.1236C327.917 37.2859 328.688 37.2161 329.53 36.867C330.161 36.5877 329.6 35.1914 329.46 34.7725C329.951 34.6329 330.792 35.8896 330.582 36.3783C329.951 37.5651 330.021 37.5651 330.652 38.752C331.073 39.5898 334.439 39.5898 335.28 39.6596C334.088 39.2407 332.896 38.752 331.704 38.1935C330.371 37.5651 332.686 36.5877 333.247 36.3783C334.859 35.8896 335.561 36.2387 337.174 36.867C337.665 37.0764 338.085 37.4255 338.576 37.7048C338.997 37.984 339.628 37.7048 340.119 37.6349C339.979 37.2161 339.768 36.1688 339.488 35.8896C339.207 35.6103 338.015 35.6103 337.594 35.5405C337.033 35.4707 336.963 33.0272 336.823 32.4687C338.646 32.2592 340.47 32.1196 342.293 31.9102C343.345 31.8403 344.327 31.7007 345.379 31.6309C346.08 31.5611 345.799 30.8629 345.799 30.1648C345.87 28.8383 345.729 28.8383 346.781 28.21C347.553 27.7911 348.324 27.1628 349.095 26.8137C350.778 26.1854 352.812 26.1155 354.565 25.7665C357.861 25.1381 361.087 24.7891 364.313 23.5324C365.084 23.2532 364.734 22.0663 365.295 21.7172C366.207 21.2285 367.188 20.7398 368.1 20.2511C369.222 19.6926 371.256 19.6926 372.097 20.8795C371.186 21.1587 370.344 21.438 369.432 21.7172C370.835 21.9267 372.237 22.1361 373.64 22.3456C373.079 22.8343 372.448 23.323 371.887 23.8815C372.658 23.9513 373.43 23.9513 374.201 24.0211C374.201 23.7419 374.061 22.555 374.341 22.555C374.972 22.555 375.534 22.6248 376.165 22.6248C377.076 22.6248 378.058 22.4852 378.9 22.9739C379.671 23.5324 381.003 24.0909 381.635 24.8589C381.775 25.0683 382.546 25.8363 382.476 26.0457C382.336 26.325 382.125 27.2326 381.845 27.3722C378.058 29.6761 374.341 31.98 370.554 34.2838C373.149 33.5159 375.744 32.8177 378.409 32.0498C377.707 31.98 377.076 31.8403 376.375 31.7705C377.146 31.0724 378.409 30.444 379.391 31.1422C380.793 32.1894 381.144 32.1196 382.897 31.98C385.141 31.7705 387.455 32.2592 389.629 32.4687C389.208 32.7479 388.788 32.9574 388.367 33.2366C388.928 33.5159 389.91 34.2838 390.471 34.214C391.382 34.1442 392.294 34.1442 393.135 34.0744C393.697 34.0744 395.169 34.2839 395.239 33.6555C395.45 32.2592 395.31 32.329 396.502 32.329C397.343 32.329 398.255 32.3989 399.096 32.2592C399.728 32.1196 400.99 31.5611 401.621 31.7705C402.182 31.98 403.024 33.3763 403.444 33.865C403.725 34.1442 403.094 35.8198 403.094 36.2387C403.094 36.5877 403.164 38.6124 403.374 38.752C404.216 39.2407 404.987 39.6596 405.829 40.1483C406.179 40.3577 407.301 38.5425 407.512 38.1935C408.213 37.2859 408.073 37.1462 409.055 37.7746C410.036 38.4029 410.247 38.6822 411.299 38.4029C412 38.1935 412.841 37.7048 413.473 37.984C413.963 38.2633 415.085 39.1011 415.576 38.8916C416.418 38.5425 417.259 38.1935 418.101 37.8444C417.891 37.4255 417.049 36.5179 417.4 36.099C417.61 35.75 418.382 34.3537 418.802 34.4235C420.415 34.6329 422.028 34.8424 423.641 35.0518C424.833 35.1914 426.096 35.6801 427.288 35.9594C428.55 36.3085 430.373 36.3783 431.495 37.0764C432.197 37.4953 433.81 40.0785 434.581 40.0086C436.194 39.7294 437.807 39.4501 439.42 39.1709C440.752 38.9614 442.014 39.5898 443.277 39.9388C444.048 40.1483 444.399 40.0785 444.679 40.8464C444.96 41.754 444.89 41.8936 444.609 42.8012C445.942 43.2201 446.994 43.7786 448.396 43.4994C450.009 43.2201 451.061 43.1503 452.674 43.4296C453.235 43.4994 454.076 43.8484 454.567 43.4994C455.339 42.871 455.269 42.871 455.97 43.5692C456.461 44.0579 457.232 45.1051 457.863 45.3844C458.354 45.5938 459.266 45.2447 459.757 45.1749C459.617 44.1277 459.476 43.0107 459.336 41.9634C461.65 42.1729 463.964 42.3125 466.279 42.522C468.102 42.6616 469.855 43.9183 471.468 44.6862C473.362 45.5938 475.185 46.5712 477.008 47.6184C478.13 48.2468 478.27 48.3166 478.761 49.643C479.322 51.1092 479.112 51.528 480.585 51.528C480.444 50.9695 480.234 50.3412 480.094 49.7827C481.426 49.7827 482.338 49.8525 483.6 50.3412C484.512 50.6903 485.423 51.7375 486.195 52.3658C485.704 52.7847 485.003 53.6225 484.442 53.7621C485.423 54.5999 484.512 54.2508 484.021 54.181ZM302.46 103.889C302.18 103.68 302.25 102.981 301.97 102.842C300.848 102.144 300.637 103.889 300.637 104.517C300.006 103.4 299.866 102.981 300.427 101.795C299.936 101.585 298.954 101.376 298.603 100.957C298.323 100.608 298.323 99.4208 298.253 99.0019C298.253 98.9321 296.71 98.3736 297.411 98.1642C298.113 98.0245 298.253 98.7925 298.954 98.3038C298.533 97.8849 298.042 97.8151 298.463 97.2566C298.674 96.9773 299.235 96.7679 299.515 96.8377C300.287 96.9773 301.549 96.9075 302.25 97.2566C301.759 97.466 301.268 98.0943 301.268 98.7227C301.759 98.0245 301.97 97.6057 302.811 97.466C302.39 96.1395 302.11 97.0471 300.988 96.6981C301.128 96.1395 301.549 95.4414 301.268 94.9527C301.128 94.7432 300.637 93.5564 300.216 94.0451C299.796 94.5338 299.164 94.0451 298.603 93.8357C298.183 93.696 297.481 94.3942 297.061 94.464C295.939 94.6734 296.009 94.1149 295.728 95.4414C295.658 95.7905 294.396 96.0697 294.045 96.2792C293.274 96.6282 293.344 96.6282 293.134 97.5358C293.063 97.9547 292.432 98.3736 292.152 98.6529C292.853 98.7227 293.624 99.2114 293.554 100.049C293.554 101.236 293.695 101.725 294.185 102.772C294.466 103.4 295.237 103.61 295.588 104.238C296.149 105.215 296.359 105.564 297.341 106.053C296.57 106.332 296.359 106.193 296.149 107.1C296.009 107.659 295.798 108.148 295.588 108.706C295.307 109.334 295.448 109.753 295.448 110.452C295.518 111.219 295.728 111.08 296.43 111.219C297.061 111.359 297.061 111.848 297.552 111.987C298.113 112.197 298.744 112.337 299.305 112.546C300.076 112.755 301.409 112.267 302.18 112.197C302.11 111.219 301.899 110.312 302.04 109.404C302.32 107.938 301.689 108.636 301.128 107.589C301.268 107.659 301.479 107.589 301.689 107.659C301.619 107.45 301.549 106.961 301.409 106.751C301.268 106.612 300.777 106.821 300.637 106.612C300.216 106.123 300.497 105.634 300.707 105.215C300.637 105.285 302.881 105.564 303.302 105.355C303.442 104.447 302.881 104.238 302.46 103.889ZM72.6522 23.3928C73.2132 23.5324 73.9847 23.8815 74.5457 23.4626C74.4054 23.323 74.2652 23.1833 74.1249 23.1135C73.5639 23.1135 73.0029 22.9739 72.6522 23.3928ZM122.373 142.008C122.934 142.357 123.284 142.636 123.916 142.845C124.196 142.915 124.617 142.427 125.178 142.636C125.038 142.496 124.967 142.287 124.827 142.147C124.196 141.868 122.934 141.17 122.373 142.008ZM117.604 96.349C117.534 96.4188 117.464 96.4886 117.394 96.5584L117.534 96.6282C117.744 96.349 117.885 96.2094 117.744 95.9301C117.674 95.9999 117.604 96.0697 117.604 96.1395C117.464 95.7206 117.113 95.6508 116.763 95.7905C116.272 95.9999 116.131 95.5112 115.64 95.8603C115.781 95.8603 115.921 95.9301 115.991 95.9301C116.482 96.1395 117.113 96.6282 117.604 96.349ZM114.869 95.2319C114.589 95.0225 114.518 95.1621 114.448 95.2319C114.518 95.3018 114.659 95.4414 114.729 95.5112C114.799 95.4414 114.799 95.3716 114.869 95.2319ZM115.5 95.9301C115.5 95.8603 115.5 95.7905 115.5 95.7207C115.36 95.6508 115.29 95.581 115.079 95.5112C115.009 95.581 114.869 95.6508 114.799 95.7207C115.009 95.8603 115.29 95.8603 115.5 95.9301ZM152.948 86.0863C153.159 85.6674 153.299 85.3183 153.509 84.8994C152.387 84.4107 151.195 85.9466 150.774 86.9938C150.073 88.6694 149.442 89.4373 148.25 90.694C148.039 90.9034 147.899 92.1601 148.11 92.4394C148.39 92.8583 149.372 92.7186 149.793 92.7186C151.055 92.579 152.387 92.579 153.58 93.2073C153.159 93.347 152.878 93.6262 152.878 94.1149C154 93.9055 154.281 93.0677 155.403 92.9979C155.263 93.8357 155.122 93.9055 155.894 94.1847C156.525 94.464 156.665 94.464 157.016 93.9055C157.437 93.2771 156.946 91.811 156.805 91.1129C156.735 90.694 155.894 90.4846 155.964 90.2053C156.104 89.4373 155.964 89.4373 155.473 88.8788C155.122 88.4599 153.509 89.0185 153.018 89.1581C153.018 88.8788 153.089 88.2505 152.808 88.1109C152.598 88.0411 152.107 87.9014 152.107 87.6222C152.037 86.7146 152.317 86.6448 152.948 86.0863ZM137.59 142.357C137.941 143.125 139.273 142.496 139.624 142.008C139.554 141.938 139.484 141.868 139.414 141.798C138.712 141.728 137.1 141.17 137.59 142.357ZM126.3 139.564C126.861 139.425 127.422 139.215 127.983 139.075C127.562 138.726 127.212 138.377 126.651 138.308C126.23 138.238 126.019 137.679 125.879 137.679C125.108 137.749 124.196 137.26 123.635 136.632C123.635 136.702 123.565 136.772 123.565 136.841C121.952 135.794 120.199 134.817 118.305 134.607C117.183 134.468 116.342 134.747 115.22 135.026C114.308 135.236 114.098 136.073 113.396 136.562C114.799 137.33 116.412 134.119 117.814 135.585C117.604 135.724 117.464 135.794 117.113 135.724C117.324 136.004 117.744 136.213 118.095 136.073C118.516 135.934 118.586 136.283 119.007 136.283C119.778 136.283 120.479 136.841 121.321 136.981C122.092 137.051 122.092 137.958 122.934 138.377C123.144 138.447 123.986 138.238 123.986 138.866C123.986 139.075 123.284 139.564 123.144 139.704C124.196 139.704 125.248 139.425 126.3 139.564ZM141.728 93.696C141.097 94.8829 142.219 95.0923 143.06 95.5112C143.902 95.8603 144.112 95.4414 144.673 94.8131C143.832 94.7433 142.99 94.6734 142.079 94.6036C141.938 94.3244 141.798 93.9753 141.728 93.696ZM141.167 88.3203C142.008 89.0185 143.972 90.6242 145.024 89.7864C144.042 88.6694 142.499 88.3203 141.167 88.3203ZM180.999 179.777C181.42 181.593 181.42 181.523 180.438 182.919C179.246 184.664 178.054 186.41 176.792 188.155C176.231 188.993 175.529 189.621 175.459 190.668C175.249 193.252 175.109 195.765 174.898 198.348C174.758 200.024 173.005 201.769 172.163 203.165C171.813 203.724 171.462 204.701 170.761 204.771C170.06 204.841 168.587 204.562 167.956 204.98C166.273 206.167 164.59 207.284 162.836 208.471C162.486 208.681 162.486 211.264 162.486 211.683C162.416 212.241 162.486 213.149 162.205 213.568C160.803 215.383 159.4 217.198 157.998 218.943C156.735 220.619 155.403 222.225 154.141 223.9C153.86 224.249 149.793 222.504 149.161 222.364C148.811 223.761 151.125 223.9 151.335 225.087C151.476 225.646 151.896 226.832 151.826 227.391C151.756 227.949 150.915 228.648 150.634 229.136C149.793 230.393 148.671 230.323 147.268 230.742C145.936 231.091 145.304 231.091 143.972 230.812C144.253 231.65 144.463 231.999 144.112 232.836C143.902 233.325 144.182 234.163 143.902 234.372C142.569 235.28 141.798 234.931 140.396 234.233C140.396 234.931 140.185 235.838 140.325 236.537C140.466 237.025 141.237 237.863 141.027 238.352C140.606 239.259 140.185 240.167 139.764 241.075C139.344 241.982 139.203 241.912 138.222 242.122C137.38 242.331 137.24 243.029 136.819 243.797C136.539 244.286 137.59 245.194 137.871 245.612C138.222 246.171 139.484 245.682 139.203 246.52C138.923 247.358 138.783 247.707 138.292 248.335C137.801 248.894 137.1 249.452 136.889 250.22C136.539 251.337 136.258 251.407 135.276 251.966C134.294 252.524 135.416 255.387 135.557 256.504C135.627 256.922 135.627 257.83 135.907 258.039C136.609 258.668 137.31 259.296 138.081 259.855C139.344 260.902 140.185 260.762 141.798 260.762C140.325 261.391 138.853 262.089 137.45 262.717C136.258 263.276 136.048 262.927 134.855 262.368C133.102 261.53 131.419 260.692 129.736 259.924C128.824 259.506 128.684 258.528 128.334 257.551C127.352 255.317 125.809 253.083 126.089 250.569C126.51 246.799 126.931 243.029 127.352 239.329C127.773 235.699 127.913 231.929 128.614 228.368C129.456 223.9 130.297 219.362 131.209 214.894C131.7 212.171 132.261 209.449 132.752 206.726C132.962 205.539 133.383 204.282 133.453 203.095C133.523 202.118 133.172 200.931 133.032 199.954C132.962 199.325 133.032 197.72 132.681 197.161C132.331 196.603 131.069 196.044 130.578 195.695C129.526 194.997 128.474 194.229 127.422 193.461C126.37 192.693 126.019 191.995 125.388 190.738C124.056 188.295 122.793 185.851 121.461 183.478C120.409 181.453 119.287 179.498 118.235 177.473C117.604 176.217 118.726 173.983 119.007 172.656C119.147 172.028 119.217 170.562 119.638 170.073C120.269 169.305 120.83 168.467 121.461 167.699C122.864 165.954 123.986 164.907 123.635 162.463C123.565 161.905 123.214 161.626 123.635 161.207C123.705 161.137 123.495 160.369 123.565 160.09C123.705 159.322 122.092 158.624 122.232 157.925C122.443 157.018 122.443 157.157 121.671 156.739C121.11 156.459 121.11 156.459 120.62 156.739C120.199 156.948 119.918 157.297 119.568 157.646C119.357 157.856 119.918 158.484 120.059 158.693C119.007 159.112 119.077 159.252 118.586 158.135C118.375 158.763 117.324 157.716 116.692 157.576C116.412 157.507 116.201 157.856 115.991 157.716C115.64 157.507 115.36 157.227 115.009 156.948C114.378 156.459 113.046 155.831 112.555 155.133C112.134 154.505 112.344 153.597 111.854 153.038C110.591 151.572 109.82 150.316 108.067 149.827C106.734 149.478 104.49 149.338 103.368 148.291C102.456 147.383 101.475 146.476 100.563 145.498C99.9319 144.87 99.0903 145.498 98.3189 145.778C96.6359 146.266 94.9528 145.08 93.3399 144.451C92.0776 143.963 90.7452 143.404 89.4829 142.915C89.0621 142.776 88.2907 142.636 88.0102 142.287C87.1687 141.449 86.3271 140.611 85.4856 139.774C84.7142 139.006 85.2051 138.517 85.4856 137.47C85.696 136.772 84.3635 135.375 84.0129 134.817C83.5921 134.188 83.2415 133.77 82.6805 133.211C81.7688 132.373 80.8572 131.536 80.0156 130.698C79.8053 130.488 80.0858 129.93 80.0858 129.651C80.1559 129.371 79.665 128.952 79.5247 128.743C78.8936 127.905 78.3326 127.207 77.5612 126.579C76.8599 126.09 76.1586 125.741 75.8781 124.903C75.7378 124.414 75.3872 122.111 74.9664 121.901C74.1249 121.552 73.2834 121.133 72.4418 120.784C72.7224 121.692 72.9327 123.577 73.4938 124.275C74.4054 125.322 75.1768 126.23 75.7378 127.556C76.0184 128.324 76.2287 128.533 76.8599 129.022C77.2807 129.441 77.4209 130 77.6313 130.628C77.8417 131.256 78.1222 131.815 78.1923 132.443C78.2624 133.49 78.6832 132.722 78.9637 132.932C79.3144 133.211 79.9455 133.77 79.8754 134.328C79.8053 135.026 79.1741 135.166 78.8936 134.677C78.2624 133.56 77.2105 132.932 76.2287 132.234C75.9482 132.024 76.0885 130.768 76.0184 130.418C75.9482 129.86 75.1768 129.511 74.8262 129.162C74.4755 128.883 74.1249 129.022 73.7041 128.673C73.2132 128.254 72.7925 127.835 72.3016 127.416C72.8626 127.347 74.1249 127.207 73.4236 126.16C72.7925 125.252 72.512 124.764 71.5302 124.275C70.899 123.996 70.7588 122.948 70.4783 122.25C70.0575 121.133 69.5666 120.016 69.1459 118.829C68.655 117.573 67.042 116.525 65.8499 116.176C64.8681 115.897 64.5174 115.967 64.0967 115.059C63.6058 114.012 63.1149 112.965 62.6941 111.987C61.9928 110.452 60.5903 109.544 60.0994 107.868C59.4682 105.704 59.5384 104.308 59.6085 102.004C59.6786 100.119 59.8189 98.234 59.889 96.2792C59.9591 94.464 59.5384 93.2772 58.9773 91.5318C60.0293 91.811 61.0812 92.0903 62.063 92.5092C62.1331 90.9733 62.2032 90.7638 61.1513 89.7166C60.3799 88.8788 59.6786 88.3901 58.767 87.7618C57.9956 87.2033 57.154 87.2033 56.3125 86.8542C54.9099 86.2259 54.6996 86.2259 54.0684 84.7598C53.3671 83.0842 50.8425 82.1766 50.9828 80.2916C51.123 78.5463 50.9828 78.6859 49.6504 77.8481C49.44 77.7085 48.5985 79.5237 48.0374 78.6859C47.6167 77.9878 46.9154 76.3122 46.2141 75.9631C45.2323 75.4744 45.0219 75.265 44.4609 74.3574C43.8298 73.4498 43.2688 72.1932 42.5675 71.495C41.9363 70.8667 41.0247 70.4478 40.3234 69.9591C38.5702 68.7722 37.0975 68.1439 35.1339 67.4458C34.3625 67.1665 33.4509 67.7948 32.6795 67.6552C31.8379 67.4458 30.9263 66.608 30.225 66.1193C29.2432 65.491 28.9627 65.2815 27.8407 65.4211C26.8589 65.491 26.368 65.7702 26.7186 67.0269C26.9991 68.0741 23.0019 69.1911 22.0902 69.4704C21.8798 68.9817 22.0902 68.7024 22.5811 68.5628C21.8798 68.3533 22.4408 66.3985 22.8616 66.1193C23.8434 65.5608 24.3343 65.5608 25.5265 65.5608C25.246 65.3513 25.0356 65.0721 24.7551 64.8626C25.0356 64.6532 25.3161 64.4437 25.6667 64.2343C23.8434 64.5834 23.1421 64.9324 21.5993 66.1193C20.2669 67.0967 19.776 68.2137 18.9345 69.6798C19.3552 69.7496 19.776 69.8893 20.1968 69.9591C18.9345 71.6346 17.7423 72.5422 16.0592 73.7291C15.2177 74.2876 12.6931 74.9857 12.5528 76.1726C12.4827 77.2896 9.11659 77.8481 8.13481 78.1274C7.71404 78.267 7.3634 78.267 6.94264 78.3368C6.45174 78.4066 6.66213 78.6859 6.31149 78.8953C5.46996 79.4539 4.90893 79.5935 4.0674 79.384C4.83881 78.6161 5.68034 78.4066 6.592 77.8481C7.29327 77.4292 9.25685 75.4744 9.888 76.5915C10.3088 75.8235 11.9217 74.0781 12.7632 74.6367C12.4827 73.7989 13.9554 73.3102 14.1658 72.4026C14.306 71.6346 14.306 71.4252 14.7969 70.9365C15.1476 70.5874 15.4281 70.4478 15.1476 69.9591C14.0255 70.5874 12.9035 71.495 11.7814 70.727C11.4308 70.4478 10.6594 69.61 10.1685 69.8195C9.60749 70.0987 9.04646 70.3082 8.48544 70.5874C8.27506 69.4704 8.06468 68.2835 7.92442 67.1665C7.64391 67.3061 6.17123 68.4232 5.96085 68.2137C5.39983 67.7948 4.34791 67.2363 3.99728 66.608C3.57651 65.9098 3.57651 64.5834 3.36613 63.8154C3.22587 63.1173 3.71676 62.6286 4.0674 62.07C4.69855 60.953 4.62842 60.6737 5.82059 60.8134C6.80238 60.8832 6.94264 60.1152 7.78417 59.7662C8.6257 59.4171 9.32698 60.1152 9.74774 59.068C10.0984 58.2302 9.60749 58.0906 8.97634 57.4623C9.25685 57.3227 9.46723 57.183 9.74774 57.0434C9.3971 55.9264 8.48544 56.9038 7.8543 57.2528C7.01276 57.7415 6.94264 57.183 6.1011 57.2528C4.48817 57.4623 2.66485 57.8114 1.82332 56.066C2.0337 55.9962 2.24408 55.7867 2.38434 55.7867C1.61294 55.5075 0.561021 55.3678 0 54.5999C1.19217 53.9715 1.96357 53.413 3.22587 53.413C3.15574 53.2734 3.01549 53.2036 2.94536 53.064C3.92715 52.5054 4.48817 52.3658 5.61021 52.296C5.96085 53.064 6.94264 52.8545 7.92442 53.1338C8.76595 53.3432 9.04646 52.9941 9.81787 52.4356C9.46723 52.296 9.11659 52.1564 8.76595 52.0167C8.90621 51.9469 9.04646 51.9469 9.18672 51.8771C8.83608 51.5979 8.69583 51.2488 9.11659 50.8997C8.20493 50.8299 7.43353 50.6903 6.52187 50.411C5.82059 50.2016 5.82059 49.0147 5.11932 48.7355C4.62842 48.526 2.59472 47.9675 2.38434 47.4788C2.31421 47.2694 2.73498 46.292 2.80511 46.0825C2.87523 45.8731 3.296 45.9429 3.43625 45.9429C4.20766 45.8731 5.3297 46.1523 5.82059 45.4542C6.38162 44.6862 6.87251 43.7786 7.57378 43.1503C8.76595 42.0333 10.449 41.4049 11.9918 41.1257C13.0437 40.986 13.8151 40.986 14.6567 40.2879C15.7787 39.3803 15.7086 39.3803 16.9709 40.0086C18.0929 40.5672 21.2487 39.7992 21.7396 41.1257C22.0902 42.1031 25.3862 42.0333 26.5082 42.1729C28.1212 42.3823 29.8042 42.5918 31.4172 42.871C33.8716 43.2899 36.256 43.7088 38.7105 44.1277C40.3234 44.407 41.7961 45.3145 43.2688 46.0127C43.5493 46.1523 45.2323 44.0579 45.5128 43.8484C45.9336 43.3597 46.8453 44.756 47.3362 44.4768C48.1777 44.1277 52.0347 41.754 52.5957 42.6616C51.1932 43.4296 49.7906 44.1277 48.3881 44.8957C49.44 45.6636 53.0866 42.522 53.3671 43.8484C53.7879 43.3597 54.2087 42.871 54.6294 42.3823C54.9801 41.9635 54.1385 41.8936 54.7697 41.4049C55.8216 42.6616 56.9436 43.7786 58.0657 44.8957C58.4163 43.7088 58.5566 43.2899 59.4682 42.522C60.0293 43.0805 59.0475 43.3597 59.8189 43.7786C60.0994 43.9183 59.6786 44.4768 59.5384 44.756C60.0293 44.6164 60.8708 44.6164 61.2214 44.3371C61.3617 44.1975 61.0812 43.639 61.2916 43.639C61.5721 43.5692 61.7824 43.5692 62.063 43.4994C62.9746 43.3597 64.2369 44.2673 65.0784 44.6164C66.8316 45.3844 68.9355 45.6636 70.7588 46.1523C70.6887 46.0127 70.6887 45.8731 70.6185 45.7334C71.8107 45.8032 72.4418 46.3618 73.4938 47.0599C74.2652 47.6184 71.8808 48.3864 71.7406 48.4562C72.512 48.7355 73.3535 49.1544 74.195 49.0845C75.5275 48.9449 76.93 48.8751 78.2624 48.7355C78.8936 48.6656 80.0156 48.526 80.4364 49.1543C81.0675 50.0619 81.6987 50.9695 82.3298 51.9469C82.2597 51.528 82.1195 51.1092 82.0493 50.7601C81.9792 50.4808 82.2597 50.2714 82.1896 50.0619C82.0493 49.0845 81.6286 49.3638 82.1195 48.3864C82.4701 47.7581 85.2752 47.6882 84.6441 46.7108C83.3116 47.2694 82.3298 47.6882 80.8572 47.6184C81.2078 46.4316 81.6987 46.5014 82.7506 46.1523C83.8727 45.8032 84.083 45.6636 85.1349 46.292C85.4155 46.4316 85.6258 47.1297 85.7661 47.4788C85.9765 47.8977 86.257 47.8279 86.7479 47.9675C87.6595 48.1769 88.431 48.4562 89.2725 48.7355C89.9738 49.0147 93.8308 49.4336 93.971 48.8751C94.3217 47.7581 94.3217 47.2694 95.584 47.2694C96.3554 47.2694 97.1969 47.6882 97.9683 47.8977C97.8982 48.2468 97.4073 49.3638 97.4774 49.7129C97.6177 50.0619 98.6696 50.5506 98.9501 50.6903C98.5293 49.4336 98.1086 48.3166 99.6514 48.1071C100.283 48.0373 100.633 47.409 101.124 46.9901C101.475 46.641 101.194 46.2221 101.124 45.8032C100.703 46.0127 100.353 46.1523 99.9319 46.3618C99.7916 45.1051 100.703 44.9655 101.545 44.8258C101.475 43.8484 100.563 44.5466 100.002 44.3371C99.5111 44.1277 97.8982 43.8484 97.6878 43.3597C97.267 42.3125 97.267 41.6144 97.267 40.4973C97.267 39.3803 97.828 39.2407 98.6696 39.5898C98.8098 39.0312 98.4592 38.8916 97.9683 38.8916C98.8098 38.3331 98.9501 38.4029 98.88 37.3557C98.88 36.4481 98.8098 36.0292 98.3891 35.2613C98.1086 34.6329 98.3189 33.7951 98.3189 33.097C98.3189 32.5385 99.2306 32.8177 99.6514 32.8876C98.1086 31.212 100.773 31.7007 101.825 31.7007C103.298 31.7007 104.28 31.8403 105.682 32.2592C105.121 33.097 104.28 34.9122 103.508 35.4009C102.807 35.8198 100.984 35.4707 100.212 35.4707C102.737 35.8198 99.8618 37.4255 100.002 38.2633C101.264 38.0538 101.966 39.1709 102.246 40.3577C102.386 41.1257 103.649 42.0333 104.14 42.6616C103.508 43.0805 102.877 43.4994 102.316 43.9183C102.947 44.1277 103.438 44.5466 103.999 44.1975C104.56 43.7786 105.051 44.2673 105.682 44.6164C105.402 44.8258 105.121 45.0353 104.771 45.2447C105.332 45.7334 105.682 45.7334 105.472 46.5712C105.262 47.3392 105.121 47.5486 105.823 47.9675C106.243 47.3392 106.454 47.0599 106.524 46.292C106.524 46.0127 106.804 44.8258 107.295 45.1749C107.646 45.3844 108.768 45.8032 108.838 46.2221C108.978 46.9203 109.399 47.6882 108.558 47.9675C108.558 47.8279 108.487 47.6184 108.487 47.4788C106.734 48.4562 110.591 51.8771 110.802 49.9921C110.872 49.4336 110.802 49.1543 111.152 48.8053C111.363 48.6656 111.924 48.3166 111.924 48.0373C111.924 46.641 111.924 46.7108 113.116 46.2221C112.625 45.4542 112.204 45.1051 112.415 44.2673C112.625 43.3597 113.046 43.639 113.817 43.7088C114.308 43.7786 115.711 43.7088 116.061 44.1277C116.763 44.8957 116.973 45.0353 117.885 45.2447C117.464 45.9429 118.095 46.4316 117.674 46.9203C117.394 47.2694 116.482 47.1297 116.061 47.1297C116.412 47.8977 116.622 48.5958 117.253 49.0845C117.885 49.6431 118.165 50.1318 117.464 50.9695C117.043 51.528 115.921 51.8771 115.29 52.296C114.729 52.6451 114.308 51.8771 113.817 51.4582C114.028 52.0167 114.308 52.5054 114.518 53.064C114.168 52.8545 113.747 52.6451 113.396 52.5054C113.467 52.6451 113.467 52.7847 113.537 52.9243C113.186 52.8545 112.765 52.7149 112.415 52.6451C112.134 52.5753 112.344 51.9469 112.134 51.9469C111.573 51.9469 110.732 51.7375 110.451 52.3658C110.802 52.5753 111.152 52.7847 111.503 52.9941C111.152 53.5527 110.802 54.2508 110.241 54.5999C109.399 55.0886 109.119 54.6697 108.207 54.2508C106.875 53.5527 105.682 53.6225 104.14 53.5527C105.191 54.0414 106.243 54.5999 107.295 55.0886C108.067 55.4377 109.329 55.3678 110.171 55.4377C109.82 55.9962 109.259 57.5321 108.698 57.8114C108.347 57.951 107.926 58.3001 107.576 58.3001C107.155 58.2302 106.734 58.0906 106.313 58.3699C105.191 59.2076 105.051 59.2076 103.789 58.8586C102.947 58.5793 102.106 58.4397 101.334 58.1604C101.895 58.4397 102.456 58.6491 103.017 58.9284C102.877 58.9982 102.807 59.2076 102.667 59.2775C103.508 59.068 103.719 59.068 104.49 59.4869C104.911 59.6963 105.542 60.3247 104.841 60.6737C104.069 61.0228 103.789 61.0228 102.947 60.953C102.667 60.953 102.246 61.8606 102.106 62.07C101.475 63.1173 100.423 64.2343 100.142 65.491C99.8618 66.8872 99.5812 68.3533 99.2306 69.7496C99.7916 69.8893 101.054 69.8893 101.475 70.3082C101.966 70.727 102.246 72.4026 102.456 73.0309C102.877 74.2178 103.158 73.7989 104.21 73.5196C104.771 73.38 105.472 73.7989 106.033 74.0083C107.716 74.6367 108.908 75.1952 110.381 76.2424C110.872 76.5915 111.713 77.5689 112.274 77.5689C113.116 77.6387 113.957 77.7783 114.729 77.8481C115.009 77.8481 116.622 77.8481 116.622 78.1972C116.552 79.3142 116.552 80.5011 116.482 81.6181C116.412 83.2238 118.025 84.4107 118.936 85.5975C119.848 86.7146 121.812 84.6201 121.601 83.6427C121.461 82.5955 121.251 81.6181 121.11 80.5709C121.04 80.0124 120.269 79.3142 119.988 78.8255C120.97 78.1972 122.934 77.4292 123.635 76.4518C124.266 75.5443 124.406 73.1007 123.635 72.3328C123.074 71.7743 122.513 71.2856 122.092 70.6572C121.461 69.7496 121.251 69.8195 122.022 69.1213C122.934 68.3533 123.004 68.4232 122.653 67.2363C122.513 66.608 122.092 65.84 122.303 65.2117C122.653 64.0248 122.723 63.8154 122.373 62.6984C122.162 62.0002 122.583 61.721 123.355 61.6512C124.757 61.5115 126.019 62.6984 127.352 62.07C128.193 61.6512 128.404 62.1399 129.245 62.6984C129.596 62.9776 130.718 63.3965 130.788 63.955C130.998 64.723 131.419 65.2815 132.261 65.1419C132.962 65.0721 133.383 65.3513 134.014 65.7004C133.663 66.3287 133.453 66.4684 133.593 67.1665C133.733 67.7948 133.874 68.4232 133.663 69.0515C133.874 68.9817 134.014 69.1213 134.224 69.0515C133.874 69.4704 132.962 70.0987 133.453 70.5874C134.294 68.0043 137.45 73.6593 138.151 70.1685C138.292 70.3082 138.572 70.3082 138.712 70.5176C139.063 69.7496 139.624 69.0515 139.484 68.2137C139.344 67.6552 140.255 66.4684 140.816 66.608C140.746 66.8872 140.676 67.2363 140.606 67.5156C141.938 67.5854 142.85 70.378 143.551 71.495C143.902 72.1233 145.024 73.38 145.024 74.0781C145.024 74.497 144.393 74.9857 144.463 75.4046C144.533 75.5443 145.164 75.9631 145.304 76.1028C145.585 76.3122 146.216 76.6613 146.427 77.0104C146.707 77.4292 146.286 77.8481 146.847 77.9179C147.899 77.9878 148.32 77.9878 149.232 78.5463C149.793 78.9652 150.985 79.5237 149.723 79.7331C149.021 79.8727 148.25 80.152 147.549 80.3615C147.969 80.5011 148.53 80.2218 149.021 80.0822C148.671 80.6407 147.689 80.7105 147.128 80.92C146.567 81.1294 146.777 82.1766 147.058 81.8276C147.338 81.4785 147.478 81.4785 147.899 81.269C148.25 81.1294 148.11 80.92 148.32 80.8502C148.811 80.5709 149.442 80.4313 150.003 80.3615C149.652 80.2916 149.582 80.2218 149.372 80.0124C149.793 80.0124 150.564 80.0822 150.774 80.5709C150.985 81.1992 150.284 81.1294 150.704 81.6181C151.195 80.7803 151.756 81.1992 152.457 81.4785C153.018 81.6879 152.598 82.805 152.457 83.154C152.247 83.7824 152.948 83.9918 152.457 84.7598C152.247 85.1088 151.195 85.6674 150.845 85.7372C150.284 85.8768 149.723 85.7372 149.091 85.9466C148.46 86.1561 148.18 86.5749 147.689 87.0636C146.707 88.1109 145.865 88.3203 144.463 88.1807C142.99 88.0411 141.658 87.9712 140.185 88.1109C138.923 88.1807 137.59 87.7618 137.24 89.4373C137.17 89.8562 135.907 89.9959 135.557 90.2751C134.996 90.694 134.505 91.3922 134.014 91.8809C133.172 92.7884 132.681 93.9055 131.7 94.6734C133.453 93.8357 134.365 92.0205 136.118 91.1827C137.31 90.6242 140.536 88.809 141.377 90.9035C141.237 90.8336 141.097 90.8336 140.957 90.7638C141.798 91.3223 140.676 91.811 140.185 92.1601C139.624 92.6488 139.133 91.811 138.502 92.2299C138.783 92.2997 139.414 92.9979 139.414 92.9979C139.835 92.8583 140.185 92.7884 140.606 92.9281C140.536 93.4168 140.185 93.8357 139.835 94.1149C140.045 94.0451 140.255 94.1149 140.466 94.1149C140.115 95.0225 141.097 95.7206 141.798 95.9301C141.728 95.9999 141.658 96.0697 141.588 96.0697C142.569 96.5584 143.551 96.9773 144.463 96.349C144.463 96.4886 144.533 96.6981 144.533 96.8377C144.673 96.8377 144.954 96.7679 145.094 96.6282C144.463 95.8603 145.725 94.7433 146.146 94.1149C146.917 94.3942 146.497 95.0923 146.286 95.7207C146.847 95.3018 147.689 96.1395 147.198 96.349C146.567 96.6282 145.936 97.0471 145.234 96.9075C145.375 97.0471 145.445 97.2566 145.655 97.3962C144.814 97.7453 144.042 98.0943 143.201 98.3736C142.92 98.5132 142.569 98.5831 142.289 98.7925C141.938 99.0718 141.868 98.3736 141.518 98.6529C140.957 99.0718 140.466 99.9793 139.835 100.538C139.414 100.957 139.063 100.398 138.783 100.259C137.941 99.0019 139.975 97.9547 140.676 97.466C141.167 97.117 140.957 97.5358 141.167 97.7453C141.658 98.1642 141.938 97.6056 142.359 97.1868C141.798 97.1868 141.097 96.9773 140.606 97.3264C140.606 97.0471 140.886 96.7679 141.027 96.4188C140.396 96.2792 139.554 97.117 139.063 97.466C138.712 97.6755 138.712 97.1868 138.292 97.6755C138.081 97.8849 137.59 97.7453 137.31 97.7453C137.731 99.0718 135.487 98.5831 135.136 99.2114C135.066 99.1416 134.926 99.0019 134.855 98.9321C134.505 99.6303 134.154 99.7001 133.523 99.9793C133.102 100.119 133.032 100.468 132.892 100.957C132.611 101.655 131.349 104.029 133.102 103.819C133.032 103.68 133.032 103.61 132.962 103.47C133.102 103.54 133.243 103.749 133.313 103.889C132.822 104.238 132.191 103.959 131.63 103.819C131.349 103.749 131.419 104.587 131.069 104.587C129.806 104.657 129.175 104.727 128.053 105.495C128.824 105.425 129.456 105.006 130.297 104.866C130.227 104.936 130.157 105.006 130.017 105.076C130.227 105.076 130.437 105.146 130.648 105.076C130.087 105.355 129.736 105.634 129.105 105.634C128.614 105.704 127.773 105.495 127.492 105.983C128.684 106.123 126.931 108.427 126.51 108.776C126.791 108.287 125.949 107.938 125.739 107.38C125.809 108.078 126.651 109.055 126.37 109.684C126.019 110.312 125.458 111.15 125.318 111.778L125.178 111.708C125.178 111.219 125.388 110.801 125.599 110.382C125.318 110.172 125.458 109.544 124.827 109.753C124.897 109.265 124.967 108.776 125.108 108.357C125.178 108.287 125.528 107.38 125.108 107.659C124.056 108.427 124.406 108.916 124.687 110.102C124.406 109.893 124.056 109.684 123.705 109.614C123.986 109.963 124.617 110.102 124.827 110.452C124.967 110.731 124.617 111.569 124.687 111.848C124.827 112.337 125.528 112.057 125.318 112.895C125.178 113.593 124.757 113.523 124.196 113.663C124.687 113.663 125.599 113.523 125.458 114.222C125.388 114.501 124.336 114.571 124.056 114.571C124.196 114.64 124.336 114.78 124.477 114.92C124.266 114.989 124.126 115.129 123.845 115.129C124.126 115.757 124.477 115.199 124.897 115.408C124.617 115.548 124.336 115.757 124.056 115.897C123.845 116.037 123.495 115.618 123.355 115.757C123.004 115.967 122.653 116.805 122.443 117.154C122.232 117.433 121.671 117.293 121.321 117.712C121.04 118.061 120.76 118.55 120.339 118.829C118.936 119.667 118.726 120.016 117.955 121.482C117.604 122.18 117.814 123.437 118.165 124.135C118.726 125.392 119.147 126.509 119.568 127.835C119.778 128.533 119.918 130.279 119.427 130.768C119.077 131.117 118.726 131.675 118.305 131.047C118.165 130.837 117.324 130.139 117.324 130.069C117.183 129.441 116.903 129.092 116.692 128.603C116.482 128.045 116.201 127.766 116.342 127.137C116.272 127.207 116.131 127.277 116.061 127.416C115.851 126.579 116.552 125.462 115.781 124.833C115.079 124.345 114.659 123.367 113.817 123.646C113.326 123.786 112.905 124.135 112.415 123.856C112.064 123.577 111.503 123.158 111.082 123.018C110.311 122.809 109.048 123.786 108.838 122.529C108.698 123.646 106.243 122.809 105.542 123.437C106.033 123.507 107.926 123.716 106.524 124.414C106.664 124.484 107.436 124.764 107.436 124.903C107.506 125.322 107.155 125.462 106.945 125.392C107.155 124.903 106.384 124.694 106.033 124.484C106.103 124.833 105.963 124.973 105.963 125.252C105.612 124.554 105.332 125.252 104.841 124.903C104.28 124.484 103.999 124.065 103.298 124.275C102.947 124.414 102.386 124.065 102.036 123.926C101.334 123.646 100.212 124.484 99.5812 124.764C98.4592 125.182 95.8645 127.137 95.8645 128.673C95.8645 129.162 96.4956 129.651 96.5658 130.139C96.5658 130.488 96.3554 130.977 96.2151 131.326C96.0047 132.164 95.584 133.071 95.584 133.979C95.584 136.213 95.8645 137.819 97.1268 139.704C97.8281 140.821 98.1086 141.589 99.3709 141.938C99.6514 142.008 100.002 142.636 100.212 142.566C100.703 142.357 101.194 142.217 101.685 142.008C102.176 141.798 102.527 141.728 103.017 141.728C103.368 141.728 103.649 142.147 103.859 142.078C104.069 142.008 104.35 141.938 104.49 141.798C104.63 141.728 104.35 141.379 104.49 141.24C104.911 140.821 105.121 140.751 105.262 140.123C105.542 139.145 105.472 138.028 106.454 137.679C106.875 137.54 108.277 137.191 108.698 137.26C109.259 137.33 110.872 136.981 110.381 138.238C110.171 138.726 109.539 140.193 109.189 140.193C109.399 140.262 109.259 140.472 109.68 140.472C109.539 140.611 109.399 140.751 109.259 140.891L109.329 141.03C109.399 140.96 109.469 140.891 109.539 140.891C109.329 141.449 109.189 142.078 109.048 142.636C108.768 142.357 108.698 142.008 108.768 141.589C108.628 141.728 108.487 142.078 108.347 142.287C109.119 142.357 108.207 143.753 108.487 144.312C108.698 144.8 107.926 145.708 107.576 145.987C108.628 146.336 109.68 146.057 110.872 146.266C111.363 146.336 111.643 145.917 112.134 145.987C112.625 146.057 113.326 145.987 113.817 146.197C114.799 146.615 115.5 147.314 115.29 148.5C115.15 149.268 115.079 149.967 114.939 150.735C114.869 151.153 114.518 151.572 114.448 151.991C114.168 154.016 116.692 157.367 118.516 156.599C119.638 156.11 120.269 155.691 121.461 156.04C122.653 156.389 123.074 157.018 123.916 157.995C123.845 156.529 125.669 154.574 126.37 153.457C126.58 153.108 127.913 152.899 128.263 152.759C129.245 152.41 130.227 152.061 131.209 151.712C132.12 151.363 133.733 152.201 134.575 152.34C136.889 152.899 139.203 153.387 141.518 153.946C142.78 154.225 144.042 154.225 145.024 155.203C146.847 156.948 148.6 158.624 150.424 160.369C151.546 161.486 154.07 161.486 155.473 161.835C156.805 162.184 157.927 164.418 158.769 165.535C159.61 166.652 160.522 167.769 161.364 168.956C161.574 169.235 162.065 170.143 162.345 170.283C164.169 170.981 166.062 171.609 167.886 172.307C169.709 173.005 171.602 173.634 173.496 174.332C175.039 174.89 176.652 176.566 177.984 177.543C178.264 177.543 179.948 177.613 180.018 177.753C180.579 178.102 180.789 178.94 180.999 179.777ZM121.321 100.887C121.321 101.445 119.427 101.934 118.866 101.864C118.025 101.864 117.955 101.864 117.324 102.423C116.903 102.772 116.622 103.191 115.991 102.912C116.061 102.493 116.412 102.213 116.763 102.144C116.552 101.795 116.482 102.074 116.412 101.655C115.991 102.213 115.64 102.772 115.29 103.4C115.57 103.47 115.921 103.54 116.201 103.68C116.131 103.749 116.061 103.889 115.991 103.959C117.253 104.098 117.744 103.47 118.796 103.051C119.848 102.632 120.549 102.213 121.461 101.515C121.531 101.236 121.601 101.096 121.321 100.887ZM122.934 100.538C123.916 101.445 125.949 99.7001 124.897 99.2812C125.178 99.0019 125.458 98.7925 125.739 98.5132C125.178 98.7227 123.916 99.7001 123.495 99.4906C122.723 99.1416 121.812 99.6303 121.04 99.7699C119.427 101.934 122.303 99.8397 122.934 100.538ZM103.649 94.1847C104.21 94.464 104.771 94.1149 105.332 93.9055C105.262 94.0451 105.262 94.1847 105.191 94.2545C106.524 94.9527 108.487 92.2299 109.469 92.9979C109.048 93.1375 108.558 93.6262 108.417 94.1149C108.908 93.8357 109.329 93.8357 109.68 94.2545C110.03 94.6734 110.311 94.464 110.732 94.7432C110.942 94.8131 112.835 94.1847 113.186 94.1149C112.976 94.7433 113.537 94.5338 113.957 94.7432C114.238 94.8829 114.378 95.3716 114.659 95.6508C114.168 95.581 113.677 95.3018 113.467 95.8603C112.765 95.0923 111.433 95.5112 110.942 96.2792L110.802 96.1395C110.872 95.9999 110.942 95.9301 111.012 95.7905C110.802 95.9301 110.661 95.9301 110.451 96.0697C110.451 95.9301 110.381 95.7905 110.381 95.7207C109.89 96.2094 109.119 97.466 108.978 98.0944C109.539 98.234 109.82 97.1868 110.241 96.8377C110.311 97.3264 109.82 98.0944 109.68 98.6529C109.469 99.351 109.119 100.119 109.189 100.887C109.259 102.004 109.82 104.936 110.942 102.702C111.573 101.515 111.363 100.677 111.082 99.4906C110.802 98.1642 111.854 97.9547 112.204 97.117C112.204 97.3264 112.204 97.6755 112.204 97.8849C112.555 97.466 112.415 96.7679 113.186 96.6981C112.555 95.8603 113.817 95.9999 114.238 96.4188C114.659 96.9075 115.29 96.6981 115.43 97.3962C115.29 97.3962 115.29 97.3264 115.22 97.3962C115.5 97.8151 115.57 98.5831 115.15 98.8623C115.079 98.9321 114.448 99.5604 114.518 99.7699C114.659 100.189 115.64 99.2114 115.921 99.2812C116.482 99.2812 116.482 100.747 116.552 101.236C116.833 100.887 117.183 100.538 117.464 100.189C117.674 99.9793 117.464 99.351 117.604 99.0019C117.814 98.3736 118.516 97.6057 117.534 97.117C118.235 96.7679 117.955 97.6755 118.516 97.6057C118.446 97.8151 118.446 97.8151 118.305 98.0245C118.446 98.1642 118.446 98.0944 118.516 98.3038C118.866 97.9547 119.497 98.4434 119.848 98.3038C119.918 98.3038 119.708 97.6755 120.269 98.0245C119.568 97.3962 119.638 95.9999 118.586 95.7905C117.674 95.581 116.622 95.581 115.711 95.3716C115.36 95.3018 113.537 94.7432 113.677 94.5338C113.817 94.2545 113.677 94.1149 113.537 93.9055C113.396 93.696 113.677 93.4866 113.607 93.2772C113.396 92.6488 112.835 92.9979 113.186 92.0205C111.854 92.2299 111.854 91.6714 111.152 90.6242C110.802 90.0657 110.311 90.694 109.96 90.5544C109.469 90.3449 109.048 90.0657 108.558 90.1355C109.048 90.5544 108.628 90.8336 108.207 91.1129C108.347 90.9035 108.417 90.694 108.487 90.4147C108.067 90.6242 108.137 91.1827 107.716 91.3223C107.786 91.1827 107.856 90.9733 107.926 90.8336C107.225 90.9733 107.506 91.6016 107.015 91.8809C106.384 92.1601 105.823 92.4394 105.191 92.7186C104.771 93.1375 104.21 93.6262 103.649 94.1847ZM69.0056 52.1564C68.7952 52.1564 68.655 52.0167 68.4446 52.0167C68.5848 51.8771 68.7251 51.6677 68.8653 51.5979C68.2342 51.528 67.8134 52.296 67.1823 52.3658C66.3407 52.5054 65.9901 52.5753 65.2187 52.2262C65.4291 51.528 66.481 51.3884 67.042 51.1092C65.8498 50.6903 65.5693 50.5506 64.4473 51.0393C63.746 51.3186 63.0447 51.528 62.3435 51.8073C61.5721 52.0866 60.8007 52.1564 60.0293 52.4356C59.6085 52.5753 57.9254 52.6451 59.1877 53.4828C59.2579 53.413 59.4682 53.2734 59.5384 53.2036C59.4682 53.1338 59.4682 53.064 59.3981 52.9941C59.889 52.7847 61.2214 52.7847 61.7123 52.9243C61.6422 52.7847 61.6422 52.7847 61.5721 52.6451C62.4136 52.5054 63.2551 52.6451 64.0265 53.1338C63.6058 53.7621 62.5539 53.2036 61.9227 53.413C62.2032 53.6225 62.4837 53.8319 62.624 54.1112C62.2733 54.181 61.9928 54.3904 61.7123 54.5999C62.2733 55.2282 61.3617 55.298 60.9409 55.3678C61.5019 55.7867 62.1331 55.5075 62.7642 55.7867C63.185 55.9962 63.746 54.949 64.0967 54.6697C64.7278 54.2508 65.7797 54.5999 64.9382 55.1584C64.5876 55.3678 64.5174 55.7169 64.3772 55.7867C64.2369 55.9264 63.8863 55.9264 63.746 56.066C64.5876 56.834 65.4291 54.6697 66.481 54.949C66.3407 54.5999 66.0602 54.3206 65.7096 54.2508C66.5511 53.3432 68.3043 54.6697 68.655 53.6923C68.5147 53.7621 68.3043 53.7621 68.1641 53.7621C68.1641 53.1338 68.5848 53.4828 68.7251 53.1338C68.7952 52.7149 68.9355 52.4356 69.0056 52.1564ZM80.7169 60.8832C79.8053 60.4643 78.3326 60.185 77.491 60.8832C77.1404 61.1624 76.93 61.6511 76.6495 61.9304C76.1586 62.4191 75.9482 62.5587 75.3171 62.6286C74.7561 62.6984 73.7743 62.6286 73.4938 61.9304C73.4236 61.721 72.3717 62.0002 72.0912 61.4417C72.0211 61.3021 71.0393 60.8832 70.9692 61.0228C70.7588 61.2323 71.8808 61.721 72.0912 61.721C71.7406 62.4889 73.4938 63.1173 72.4418 63.3965C72.0912 63.4663 71.8107 63.1871 71.6003 63.606C71.3198 63.955 71.4601 64.1645 71.0393 64.2343C71.1094 64.3041 71.1796 64.3739 71.2497 64.4437C70.899 64.723 70.4783 64.4437 70.0575 64.4437C70.0575 64.5135 70.0575 64.5834 70.1276 64.6532C69.7069 64.6532 69.3562 64.4437 68.8653 64.4437C69.4264 65.2117 70.899 65.4211 71.8107 65.5608C72.3717 65.6306 74.5457 65.3513 74.195 64.5834C74.8963 63.955 75.3171 64.1645 76.0184 63.8154C76.4391 63.606 76.8599 63.0474 77.2807 62.6984C77.1404 62.6984 77.0703 62.6984 76.93 62.6984C77.4209 62.2795 77.7014 62.0002 78.1923 61.8606C78.6832 61.721 78.9637 61.9304 79.3845 61.5115C79.0338 61.6511 78.9637 61.5813 78.6131 61.5115C78.9637 61.4417 79.2442 61.3719 79.5949 61.2323C79.2442 61.2323 78.9637 61.2323 78.6832 61.0228C78.8936 61.0228 79.1741 61.0228 79.4546 61.0228C78.543 60.7436 77.7715 61.3021 76.93 61.8606C77.2105 60.8134 80.0156 60.185 80.1559 61.3719C80.3663 61.3021 80.5767 61.0228 80.7169 60.8832ZM95.8645 84.3409C95.9346 83.7824 95.8645 84.0616 96.2151 83.8522C96.2151 83.9918 96.145 84.1314 96.145 84.2711C96.2151 84.1314 96.2151 84.2013 96.2852 83.9918C96.706 84.1314 96.5658 84.69 96.5658 85.1787C96.706 84.8994 96.9164 84.69 97.1969 84.8296C97.4073 84.8994 97.0566 85.5277 96.9865 85.7372C97.1969 85.5277 97.3372 85.5277 97.4774 85.4579C96.9865 85.807 96.8463 86.5051 97.0566 87.1335C97.267 87.692 97.6177 87.0636 97.5475 86.7146C97.6878 86.7844 97.7579 86.7844 97.8982 86.8542C97.6878 86.2957 98.1086 85.7372 97.7579 85.4579C97.4073 85.1088 97.1268 84.3409 96.9865 83.922C96.706 83.2238 95.3736 80.2916 95.9346 79.9426L95.7944 79.8727C95.584 80.0822 95.584 80.0822 95.3035 80.152C95.3736 79.8029 95.584 79.5935 95.8645 79.5237C95.7943 79.4539 95.584 79.3142 95.584 79.2444C95.1632 80.0124 95.1632 80.2916 95.7944 80.7105C95.3035 80.5011 94.3918 80.0124 94.1814 80.7803C93.8308 82.1068 94.0412 81.8276 95.0229 82.037C93.9009 82.2464 95.3035 83.5729 95.5138 84.1314C95.584 84.2013 95.7242 84.2711 95.8645 84.3409ZM3.50638 66.608C2.59472 66.2589 2.17396 66.8872 1.19217 66.8174C1.61294 67.4458 2.24408 67.5156 2.87523 67.7948C3.01549 67.4458 3.36613 67.5854 3.71676 67.5156C3.71676 67.4458 3.71676 67.3759 3.71676 67.3061C3.57651 66.9571 3.296 67.0269 3.50638 66.608ZM58.4865 37.4953C59.328 37.9142 60.0293 38.1935 60.6604 38.8916C61.7123 40.0785 61.5721 40.0785 62.8344 39.3105C63.0447 39.1709 63.2551 39.1011 63.4655 38.9614C63.6759 38.8916 63.6058 39.2407 63.746 39.2407C64.1668 39.1011 64.5875 38.8916 65.0083 38.6822L65.359 36.867C65.9901 37.2859 66.6213 36.7274 66.7615 36.099C66.9018 35.5405 67.1823 35.5405 67.6732 35.3311C68.7952 34.8424 70.4783 34.4933 71.3899 33.7253C71.951 33.2366 71.951 32.9574 71.2497 32.4687C70.7588 32.1196 70.338 31.7007 69.777 31.4913C68.7251 31.0724 67.603 30.6535 66.6914 31.6309C66.7615 31.4913 66.7615 31.2818 66.8316 31.0724C65.5693 31.4215 64.5174 29.9553 63.3954 30.1648C62.063 30.3742 60.6604 30.5837 59.328 30.7233C59.5384 31.1422 60.5903 32.4687 60.3799 32.6781C59.9591 33.097 58.8371 34.1442 59.4682 34.7725C58.2761 34.9122 59.1877 35.3311 58.6968 35.8896C58.3462 36.3783 57.715 36.867 57.8553 37.5651C57.9956 37.6349 58.2761 37.6349 58.4865 37.4953ZM63.746 26.1854C64.4473 26.2552 64.0967 25.6967 64.2369 25.4872C64.6577 25.1381 65.1486 25.6268 65.0784 26.325C65.4291 26.1854 65.9901 26.1155 66.2706 25.8363C66.5511 25.4872 65.7797 24.9287 66.2706 24.6494C66.5511 24.5098 66.7615 25.557 67.3225 24.9985C67.603 24.6494 67.3927 24.3004 67.042 24.1607C67.4628 23.8815 67.8836 24.3004 67.8836 23.4626C67.8836 23.1135 68.5147 23.1833 68.655 23.323C67.603 23.9513 68.655 24.9985 69.5666 24.7891C70.1978 24.6494 71.7406 23.4626 70.6185 22.9041C70.7588 22.8343 71.1094 22.7644 71.3198 22.7644C69.8471 22.4852 71.1796 21.8569 71.8107 21.6474C70.899 21.1587 70.5484 20.7398 69.5666 21.1587C69.7069 21.2285 69.777 21.3682 69.9874 21.438C69.5666 21.8569 69.1459 21.5776 68.655 21.3682C68.3043 21.2285 67.8134 21.438 67.4628 21.5078C66.481 21.6474 66.2005 21.9965 65.4291 22.6946C64.9382 23.1135 63.9564 24.3702 63.2551 24.44C62.2032 24.5796 61.3617 24.8589 62.2733 25.9759C62.7642 26.1155 63.2551 26.1854 63.746 26.1854ZM74.3353 20.1115C73.4236 19.2737 73.4236 19.2039 72.3016 19.6228C72.7224 19.9021 73.073 20.1813 73.4938 20.4606C73.7743 20.3908 74.0548 20.2511 74.3353 20.1115ZM20.4773 71.495C20.898 71.7743 21.5292 71.3554 21.7396 71.0761C21.8097 71.1459 21.8798 71.2157 21.9499 71.2856C22.0201 71.2157 22.0902 71.0761 22.1603 71.0063C21.8798 70.8667 21.5993 70.727 21.2487 70.6572C20.9682 70.7969 20.6175 71.0761 20.4773 71.495ZM49.6504 80.2218C49.7205 79.4539 47.827 79.7331 47.827 79.8727C47.7569 80.8502 49.8607 84.4805 50.6322 83.6427C50.4218 83.4333 50.2114 83.2238 50.001 83.0842C49.7205 82.037 49.5802 81.269 49.6504 80.2218ZM19.4955 72.5422C18.3033 71.7743 18.0929 74.3574 19.3552 74.2876C19.7059 74.2876 19.9864 73.6593 20.4773 73.5894C20.898 73.5196 21.2487 73.3102 21.2487 72.8215C21.5993 72.9611 21.8097 72.8913 21.9499 72.5422C21.8097 72.5422 21.7396 72.4724 21.5993 72.4724C21.8097 71.5648 19.3552 71.4252 19.4955 72.5422ZM60.45 89.7864C60.3098 89.5072 59.7487 89.4373 59.4682 89.2977C59.0475 89.1581 58.9773 88.8788 58.767 88.4599C58.0657 87.2033 57.8553 87.4825 56.593 87.0636C55.6112 86.7146 55.2606 86.2259 54.2087 86.575C55.8917 88.5996 57.6449 89.7864 59.889 90.9733C61.3617 91.5318 61.1513 90.9733 60.45 89.7864ZM296.78 189.202C296.43 188.714 295.307 186.968 295.237 188.644C295.167 189.97 294.817 189.97 293.975 190.948C293.274 191.716 292.993 192.414 292.152 192.903C291.17 193.391 290.469 193.74 289.417 193.88C288.996 193.95 288.575 195.695 288.715 196.184C288.926 197.022 289.487 198.348 289.417 199.186C289.347 200.093 288.295 201.001 288.014 201.909C287.664 202.956 287.874 203.724 288.154 204.771C288.435 205.748 288.575 206.726 288.715 207.703C288.786 208.052 290.399 208.681 290.749 208.541C290.96 208.401 292.713 207.913 292.783 207.843C292.993 207.075 293.204 206.377 293.484 205.609C294.326 202.886 295.097 200.163 295.939 197.51C296.5 195.695 296.64 194.857 296.5 192.903C296.71 193.112 296.991 193.391 297.201 193.601C297.622 192.065 297.131 190.808 296.78 189.202ZM391.943 144.94C391.663 145.498 392.013 146.406 392.084 147.034C392.154 147.523 392.855 147.593 393.276 147.732C392.434 148.151 392.995 148.989 393.697 149.059C394.328 149.129 394.117 148.64 394.889 149.059C395.169 149.199 395.38 149.548 395.52 149.827C395.59 149.478 395.66 149.129 395.73 148.78C396.502 149.059 396.572 148.989 396.642 149.827C396.642 150.176 397.483 150.525 397.764 150.665C398.185 149.687 397.203 149.967 397.273 149.129C397.904 149.478 398.395 149.129 397.834 148.5C397.554 148.221 397.554 148.85 397.343 148.78C397.063 148.71 396.782 148.431 396.502 148.291C396.221 148.151 396.011 148.082 395.73 148.012C395.38 147.942 395.31 148.5 395.099 148.5C394.398 148.5 394.678 147.802 394.398 147.244C393.907 146.266 394.538 146.546 394.468 145.638C394.468 145.289 394.959 145.638 395.099 145.429C395.239 145.219 395.31 144.8 395.31 144.591C395.66 143.544 395.239 143.963 395.099 143.055C394.959 142.566 395.59 142.287 395.239 141.659C394.187 142.147 394.678 141.659 393.767 141.449C393.486 141.379 392.855 141.589 392.855 141.938C392.715 142.776 392.574 143.613 392.434 144.451C392.364 144.94 392.855 145.01 392.645 145.568C392.364 145.289 392.154 145.149 391.943 144.94ZM394.328 133.351C394.468 132.583 395.239 130.628 393.837 131.326C393.065 131.675 392.364 132.722 392.154 133.7C391.943 134.747 392.645 135.445 393.206 136.283C393.697 135.236 394.047 134.538 394.328 133.351ZM391.172 152.34C390.962 153.457 390.821 154.086 390.05 154.784C389.208 155.552 388.788 156.11 388.227 157.088C389.279 156.459 390.33 156.18 390.541 154.854C390.611 154.505 391.452 154.086 391.733 153.876C391.803 153.806 391.523 152.899 391.663 152.62C391.452 152.55 391.312 152.48 391.172 152.34ZM400.218 155.761C400.078 155.342 399.798 154.993 399.447 154.923C399.517 155.342 399.587 155.691 399.657 156.11C399.167 156.04 399.307 155.971 399.096 156.25C398.676 155.971 398.535 156.32 398.535 156.808C397.904 156.39 397.624 157.367 397.063 157.576C397.413 157.157 397.343 156.529 396.782 156.459C396.151 156.39 396.361 157.297 396.011 157.437C395.38 157.646 394.187 158.344 394.889 159.322C395.169 159.042 395.8 157.088 396.011 158.554C396.151 158.205 396.221 158.274 396.361 158.065C396.432 158.484 396.432 158.344 396.712 158.554C396.642 158.344 396.712 158.135 396.642 157.925C398.115 157.716 397.133 159.112 397.413 159.88C397.624 160.369 398.816 161.207 399.026 160.509H399.167C398.816 161.556 399.868 161.137 399.728 160.229C399.587 159.601 399.167 159.112 399.938 158.554C400.289 159.042 400.078 159.601 400.429 160.159C400.429 159.88 400.499 159.531 400.499 159.252C400.569 159.322 400.639 159.322 400.709 159.392C400.779 158.973 401.34 157.367 400.709 157.367C400.779 157.227 400.779 157.018 400.709 156.878C400.499 156.878 400.429 156.739 400.359 156.739C400.429 156.599 400.569 156.529 400.639 156.459C400.709 156.11 400.569 155.622 400.218 155.761ZM392.925 184.315C392.645 183.687 390.611 182.989 390.681 184.036C391.382 184.315 393.486 185.712 392.925 184.315ZM388.507 182.43C388.297 182.151 387.525 181.872 387.245 181.872C386.614 181.872 386.614 182.151 386.333 182.779C387.666 183.198 388.577 183.128 389.91 182.849C391.873 182.5 389.769 181.453 388.928 181.732C389.208 182.221 388.928 182.361 388.507 182.43ZM394.258 182.989C394.468 182.989 394.538 182.64 394.819 182.71C395.45 182.849 395.73 182.221 396.081 182.221C396.922 182.221 398.395 182.64 399.026 182.011C398.044 181.662 397.413 181.942 396.432 181.872C395.8 181.802 395.8 181.872 395.31 182.291C395.029 182.5 394.748 182.011 394.398 182.221C393.767 182.57 392.434 181.453 391.873 182.151C391.172 182.919 393.065 182.71 393.346 183.059C393.837 182.64 393.977 183.059 394.258 182.989ZM395.099 177.543C395.38 177.753 395.59 178.032 395.871 178.241C396.151 177.753 396.502 177.613 396.151 177.194C395.941 176.845 396.151 176.636 396.502 176.706C396.291 175.938 395.73 176.217 395.871 176.915C395.52 175.938 395.169 177.194 395.099 177.543ZM377.006 168.677C376.936 169.026 377.357 169.235 377.427 169.584C377.497 169.794 377.146 169.864 377.217 170.073C377.287 170.352 377.357 170.562 377.427 170.841C377.497 171.19 377.707 170.911 377.637 171.469C378.058 171.26 377.988 171.469 378.128 171.051C378.829 171.679 378.689 173.005 378.829 173.913C378.9 174.681 380.442 174.053 380.863 173.913C380.933 174.262 381.003 174.611 381.074 174.96C382.266 174.262 382.406 173.983 383.528 174.751C383.738 174.89 384.159 174.681 384.44 174.751C384.72 174.89 384.79 175.519 384.86 175.868C385.492 175.589 386.123 175.239 386.754 174.96C386.614 175.379 386.614 175.728 387.105 175.728C387.105 174.821 387.175 173.913 387.175 173.075C387.175 172.237 387.385 172.237 388.016 171.679C388.858 170.911 388.858 170.981 388.788 169.794C388.788 169.235 389.138 168.328 389.629 168.398C390.611 168.607 391.032 168.467 390.19 167.63C389.98 167.42 389.489 167.141 389.349 166.862C389.279 166.722 389.559 166.303 389.489 166.094C389.138 165.047 388.717 165.116 388.788 163.86C388.788 163.231 390.05 163.231 390.401 163.162C390.19 162.882 389.98 162.603 389.84 162.394C390.33 162.254 390.821 162.114 391.242 161.975C391.102 161.556 390.821 161.626 390.401 161.486C390.12 161.416 389.84 160.927 389.629 160.648C389.349 160.299 388.297 159.322 387.946 159.322C387.525 159.392 386.614 160.858 386.263 161.207C385.702 161.835 386.193 162.324 385.421 162.533C384.44 162.812 384.299 162.812 383.668 163.65C383.248 164.279 383.037 164.977 382.336 165.186C381.564 165.396 380.933 165.465 380.513 166.164C379.952 167.071 379.741 167.071 380.513 167.769C379.811 167.56 378.409 167.63 378.268 166.652C377.988 166.792 377.707 167.001 377.357 167.211C377.146 167.56 377.076 168.118 377.006 168.677ZM398.325 184.595C398.605 184.176 398.816 183.896 399.237 183.687C399.938 183.338 401.621 182.919 401.901 182.081C401.27 182.151 400.639 182.151 400.008 182.291C399.728 182.361 399.377 182.361 399.167 182.5C399.026 182.57 399.026 182.919 398.816 182.989C398.255 183.268 397.694 183.408 397.203 183.827C396.712 184.315 397.483 184.525 396.852 185.083C397.343 185.013 397.974 185.083 398.325 184.595ZM129.947 142.217C130.227 142.287 130.788 142.078 131.069 142.217C131.279 142.357 131.209 143.264 131.77 143.125C132.05 143.055 132.05 142.147 132.261 142.008C132.681 141.728 132.752 142.147 132.892 142.147C133.593 142.147 134.154 141.868 134.926 141.868C135.557 141.868 135.416 142.427 135.837 141.728C135.977 141.449 135.346 141.03 135.066 141.03C134.365 140.891 134.365 140.891 134.014 140.193C133.733 139.704 133.733 140.053 133.313 139.913C132.962 139.774 132.471 139.425 132.12 139.634C131.98 139.704 131.349 139.843 131.209 139.843C130.227 139.843 129.947 139.494 128.965 139.983C129.947 140.472 129.876 140.751 130.508 141.659C129.876 142.078 127.352 141.1 127.702 142.008C128.474 142.496 128.824 142.078 129.947 142.217ZM207.999 57.3925C208.77 57.6019 209.191 57.0434 209.191 56.2056C209.822 56.5547 210.102 55.9264 210.523 55.5075C210.032 55.1584 210.383 54.4603 210.173 54.3206C209.682 54.0414 209.261 53.6225 208.63 53.9017C209.401 52.6451 205.754 51.179 206.386 52.8545C205.334 52.7149 205.053 53.2734 204.001 52.7847C204.071 53.2036 204.142 53.5527 204.142 53.9716C203.721 53.413 203.581 52.9243 202.949 52.8545C202.388 52.8545 202.178 53.4829 202.388 53.9716C202.038 53.5527 201.687 52.9243 201.056 52.9941C201.477 54.0414 200.916 53.5527 200.635 54.0414C200.425 54.3904 200.285 54.8791 200.074 55.298C199.794 54.8791 199.513 54.4603 199.303 53.9716C199.583 54.0414 199.934 53.8319 199.864 53.4828C199.864 53.2036 199.233 53.064 199.092 52.9243C198.321 52.2262 198.391 52.0866 197.339 52.0866C197.479 52.5753 197.83 52.5054 198.321 52.5753C198.461 53.9017 197.129 52.4356 196.708 52.9243C196.217 53.5527 197.129 53.5527 196.989 53.8319C196.848 54.1112 196.357 53.9017 196.147 53.7621C196.147 53.9017 196.147 54.0414 196.147 54.181C195.796 54.1112 195.866 54.2508 195.516 54.3904C196.357 54.7395 196.638 54.5999 197.55 54.2508C197.97 54.1112 198.882 54.5301 199.303 54.5999C198.952 54.8093 198.601 54.949 198.181 55.1584C198.531 55.3678 198.882 55.4377 199.233 55.2282C199.233 55.298 199.233 55.4377 199.233 55.5075C198.181 55.5075 197.129 55.9264 196.147 55.9264C196.287 56.6943 198.04 56.3452 198.601 56.3452C198.321 56.6943 198.461 56.9736 198.882 56.9038C198.882 57.0434 198.812 57.1132 198.812 57.2528C198.952 57.2528 199.022 57.2528 199.162 57.3226C198.882 58.0906 197.62 57.8812 197.9 58.7189C198.742 58.6491 199.583 58.5095 200.425 58.3699C200.635 58.3699 200.846 58.9284 201.056 59.068C201.336 59.2775 201.897 59.2775 202.178 59.3473C202.879 59.4869 203.44 59.5567 204.142 59.2076C204.492 59.068 204.422 58.7888 204.773 58.7189C205.193 58.6491 205.544 58.5793 205.965 58.5793C206.456 58.2302 207.508 57.2528 207.999 57.3925ZM199.162 40.5672C199.022 39.9388 198.321 38.4727 198.601 37.8444C199.162 36.2387 199.513 34.214 200.635 32.9574C201.407 32.1196 202.108 31.2818 202.879 30.444C203.09 30.2346 202.529 28.3496 202.529 28.0005C202.388 27.3024 202.458 26.1155 201.897 25.6967C201.126 25.208 200.425 24.6494 199.653 24.1607C200.775 23.1135 201.827 21.9965 202.949 20.9493C201.757 20.1813 201.056 19.8322 200.495 18.5058C200.074 17.4585 201.407 16.1321 201.897 15.2943C202.458 14.3169 203.581 13.9678 204.492 13.3395C205.474 12.6413 206.245 12.013 207.087 11.0356C206.806 10.8262 206.526 10.5469 206.245 10.3375C207.227 10.128 208.419 10.128 209.331 9.5695C210.453 8.94116 211.645 8.24302 212.767 7.61469C211.505 7.12599 210.102 6.28821 208.77 6.07877C207.788 5.93914 205.825 5.7297 205.193 6.49766C204.773 7.05617 204.492 7.75432 203.791 7.6845C203.02 7.54487 202.178 7.40524 201.407 7.26561C200.495 7.12599 198.672 8.38265 197.83 8.73172C197.97 8.45246 199.653 5.79951 198.461 5.79951C197.409 5.79951 196.428 5.93914 195.516 5.24099C196.918 4.75229 198.391 4.19378 199.794 3.70507C196.989 2.51823 194.534 1.26156 191.589 0.842677C188.293 0.353975 185.137 -0.204542 181.841 0.0747164C180.649 0.144531 179.457 0.28416 178.264 0.353975C177.844 0.353975 177.072 0.28416 176.652 0.493604C176.09 0.842677 176.02 2.09934 175.249 1.95971C174.267 1.82008 173.356 1.61064 172.444 1.47101C171.322 1.26156 169.919 0.703047 168.797 1.19175C167.184 1.88989 165.571 2.65786 164.029 3.356C165.571 4.3334 167.184 5.03155 168.166 6.63728C165.431 5.65988 162.977 4.89192 160.172 4.26359C159.33 4.12396 158.068 4.54285 157.226 4.61266C155.263 4.89192 153.369 5.10136 151.406 5.38062C150.564 5.52025 149.232 5.38062 148.46 5.79951C147.338 6.35803 146.286 6.91654 145.164 7.47506C142.429 8.87135 139.764 10.2676 137.029 11.6639C138.011 12.781 139.203 12.5715 140.606 12.7112C140.325 13.4791 139.975 14.2471 139.694 15.015C139.344 15.8528 139.273 15.7132 138.362 15.7132C137.1 15.783 136.118 16.0622 134.855 16.4113C133.243 16.9 131.7 17.3189 130.087 17.8076C129.736 17.9472 129.736 18.8548 129.666 19.2737C129.596 19.553 130.297 20.2511 130.508 20.5304C130.998 21.1587 131.559 22.4852 132.261 22.8343C133.172 23.3928 134.084 23.9513 135.066 24.44C135.557 24.7193 136.819 25.8363 137.38 25.7665C138.432 25.6268 139.484 25.4872 140.536 25.3476C142.429 25.1381 144.042 25.4872 145.936 25.7665C146.917 25.9061 147.829 26.1155 148.811 26.2552C149.302 26.325 150.284 28.0704 150.564 28.4892C151.826 30.1648 152.528 32.1196 153.439 34.0744C153.93 35.1216 154.07 35.2613 153.72 36.3085C153.369 37.3557 152.808 37.984 153.509 38.752C154.281 39.5898 155.263 40.0086 154.912 41.1955C154.631 42.3125 154.141 43.0107 154.912 43.8484C155.894 44.8957 155.824 44.8957 157.156 44.5466C158.138 44.2673 159.049 43.9881 160.031 43.7088C159.961 44.407 159.821 45.1051 159.751 45.8731C159.751 46.0825 158.839 46.3618 158.629 46.4316C157.998 46.7108 157.296 46.9901 156.665 47.2694C156.525 47.3392 156.525 48.2468 156.455 48.4562C156.314 49.4336 155.824 51.0393 156.104 51.9469C156.595 53.2734 157.086 54.6697 157.577 55.9962C158.348 58.1604 159.751 59.9756 160.943 61.8606C161.644 62.9776 162.416 64.1645 163.117 65.2815C163.468 65.84 164.519 65.9797 165.08 66.1891C166.273 66.608 167.395 67.0269 168.587 67.4458C168.867 67.5156 170.48 67.5854 170.55 67.3759C171.252 65.1419 172.023 62.9078 172.724 60.6737C173.285 58.8586 173.917 57.1132 174.618 55.3678C174.968 54.3904 174.898 54.3904 175.81 54.1112C177.002 53.7621 178.124 53.3432 179.316 52.9941C180.018 52.7847 181.14 52.6451 181.771 52.2262C182.472 51.7375 183.173 50.4808 183.734 49.7827C184.225 49.1544 184.436 48.7355 185.137 48.5958C186.259 48.3166 187.311 48.0373 188.433 47.6882C189.976 47.2694 191.939 47.1297 193.342 46.2221C195.095 45.1051 196.918 44.0579 198.672 42.9409C199.373 41.8238 199.443 41.8936 199.162 40.5672ZM378.128 141.798C378.479 141.659 379.11 141.659 379.18 141.1C379.25 140.611 379.391 139.983 379.881 139.983C379.952 139.494 379.811 139.145 379.391 139.075C379.391 139.215 379.32 139.285 379.32 139.425C378.058 138.726 377.497 139.843 376.585 140.402C376.585 141.24 376.445 141.449 377.146 141.868C377.427 142.078 377.567 142.078 377.918 142.078C378.268 142.147 377.918 141.868 378.128 141.798ZM372.658 178.381C372.869 177.264 372.658 175.798 373.009 174.751C373.43 173.564 371.957 172.656 371.186 173.634C371.817 173.005 371.186 173.005 371.115 172.517C371.045 172.237 371.045 171.26 370.765 171.19C370.484 171.051 369.713 170.981 369.713 170.632C369.643 170.073 370.134 169.934 370.064 169.515C369.923 168.886 369.082 168.956 369.082 168.607C369.082 167.909 368.801 168.188 368.38 167.839C367.89 167.49 368.451 167.35 367.679 167.211C367.188 167.141 366.838 167.141 366.557 166.792C365.996 166.024 365.155 165.745 364.453 165.116C363.892 164.558 362.981 163.999 362.49 163.301C361.859 162.394 362.069 161.975 360.877 161.835C360.526 161.765 358.703 161.137 358.563 161.346C358.282 161.765 359.685 163.511 359.965 163.72C360.526 164.209 361.718 164.418 361.718 165.465C361.788 166.582 363.051 166.373 363.331 167.42C363.472 168.049 363.682 168.677 363.822 169.235C363.962 169.654 364.313 169.515 364.594 169.794C365.225 170.492 365.646 172.028 365.996 172.936C366.347 173.704 366.978 174.262 367.539 174.89C368.661 176.147 369.853 177.404 371.115 178.591C371.115 178.311 371.186 178.102 371.186 177.823C371.747 178.521 372.167 177.404 372.658 178.381ZM375.604 173.354C374.902 172.796 375.183 174.262 375.183 174.541C376.165 174.821 376.235 173.843 375.604 173.354ZM383.388 181.104C382.757 181.243 381.775 180.755 381.985 179.847C381.494 180.057 380.302 179.917 379.952 179.568C379.531 179.079 379.32 179.358 379.18 179.847C379.11 180.126 378.689 179.987 378.479 179.917C377.427 179.777 376.726 180.057 376.165 179.079C376.095 178.94 374.692 178.591 374.411 178.451C374.271 178.94 373.85 178.66 373.43 178.521C373.009 178.451 373.009 178.591 372.728 178.94C371.887 179.917 373.009 179.987 373.71 180.196C373.71 180.336 373.64 180.476 373.64 180.615C374.482 180.755 375.253 181.243 376.095 181.453C376.515 181.523 377.006 181.243 377.427 181.243C377.848 181.313 378.339 181.593 378.689 181.732C379.04 181.872 379.391 182.081 379.741 182.081C380.022 182.081 380.302 182.151 380.653 182.221C380.863 182.221 380.933 182.011 381.074 182.011C381.915 182.081 382.266 182.361 383.177 182.221C383.738 182.43 384.229 182.71 384.79 182.919C384.019 181.942 384.86 180.755 383.388 181.104ZM371.817 172.586C372.027 172.796 372.167 172.796 372.448 172.726C372.588 172.726 372.728 173.075 372.869 173.285C373.079 173.494 372.939 173.634 373.219 173.843C373.5 174.053 373.71 174.192 373.991 174.192C373.78 173.913 373.78 173.634 374.131 173.424C372.939 173.494 373.57 171.749 372.588 171.819C372.588 171.958 372.658 172.098 372.658 172.237C372.308 171.609 372.097 172.237 371.817 172.586Z" transform="translate(34 26) scale(2)" fill="white"/>
-</g>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M0 2.36804C0.590364 2.71089 1.26641 2.92688 1.9936 2.97373C2.99795 3.03839 3.94806 2.77184 4.7373 2.26944C5.12975 2.01962 5.48213 1.71145 5.78153 1.35622C5.53323 1.01235 5.26904 0.657526 4.99001 0.296025L4.76202 0C4.46198 0.471461 4.03057 0.849314 3.52278 1.0857L2.7439 0.32652L0 2.36804Z" transform="translate(859.474 468.395) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M0.604584 0C0.268048 0.58226 0.0560402 1.24712 0.00960309 1.96155C-0.0554133 2.96241 0.212865 3.90916 0.718502 4.69527C0.968667 5.08428 1.27703 5.43372 1.6323 5.73085C1.97783 5.48362 2.33448 5.22058 2.69787 4.94286L2.99492 4.71637C2.52216 4.41772 2.14318 3.98873 1.90604 3.48384L2.67357 2.70084L0.604584 0Z" transform="translate(854.935 460.781) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M5.78206 0.616686C5.19117 0.273085 4.51439 0.0564579 3.78629 0.009566C2.78092 -0.0551811 1.82989 0.211895 1.04024 0.715243C0.649454 0.96431 0.298489 1.2713 0 1.62495C0.248345 1.96895 0.512562 2.32398 0.791518 2.68577L1.019 2.9815C1.31913 2.51066 1.75027 2.13325 2.25773 1.8972L2.99226 2.609L5.78206 0.616686Z" transform="translate(857.07 456.211) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M2.40197 5.71368C2.7324 5.13584 2.94121 4.47796 2.98716 3.77102C3.05213 2.77115 2.78441 1.82527 2.2797 1.03958C2.02876 0.648908 1.71919 0.298102 1.36237 0C1.01698 0.247188 0.660552 0.510198 0.297402 0.788014L0 1.01494C0.474427 1.31415 0.854625 1.74457 1.09198 2.25126L1.09653 2.2618L0.357757 3.02495L2.40197 5.71368Z" transform="translate(867.177 458.332) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M0 2.36804C0.590364 2.71089 1.26641 2.92688 1.9936 2.97373C2.99795 3.03839 3.94806 2.77184 4.7373 2.26944C5.12975 2.01962 5.48213 1.71145 5.78153 1.35622C5.53323 1.01235 5.26904 0.657526 4.99001 0.296025L4.76202 0C4.46198 0.471461 4.03057 0.849314 3.52278 1.0857L2.7439 0.32652L0 2.36804Z" transform="translate(547.667 186.191) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M0.604584 0C0.268048 0.58226 0.0560402 1.24712 0.00960309 1.96155C-0.0554133 2.96241 0.212865 3.90916 0.718502 4.69527C0.968667 5.08428 1.27703 5.43372 1.6323 5.73085C1.97783 5.48362 2.33448 5.22058 2.69787 4.94286L2.99492 4.71637C2.52216 4.41772 2.14318 3.98873 1.90604 3.48384L2.67357 2.70084L0.604584 0Z" transform="translate(543.128 178.578) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M5.78206 0.616686C5.19117 0.273085 4.51439 0.0564579 3.78629 0.009566C2.78092 -0.0551811 1.82989 0.211895 1.04024 0.715243C0.649454 0.96431 0.298489 1.2713 0 1.62495C0.248345 1.96895 0.512562 2.32398 0.791518 2.68577L1.019 2.9815C1.31913 2.51066 1.75027 2.13325 2.25773 1.8972L2.99226 2.609L5.78206 0.616686Z" transform="translate(545.263 174.008) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M2.40197 5.71368C2.7324 5.13584 2.94121 4.47796 2.98716 3.77102C3.05213 2.77115 2.78441 1.82527 2.2797 1.03958C2.02876 0.648908 1.71919 0.298102 1.36237 0C1.01698 0.247188 0.660552 0.510198 0.297402 0.788014L0 1.01494C0.474427 1.31415 0.854625 1.74457 1.09198 2.25126L1.09653 2.2618L0.357757 3.02495L2.40197 5.71368Z" transform="translate(555.37 176.129) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M0 2.36804C0.590364 2.71089 1.26641 2.92688 1.9936 2.97373C2.99795 3.03839 3.94806 2.77184 4.7373 2.26944C5.12975 2.01962 5.48213 1.71145 5.78153 1.35622C5.53323 1.01235 5.26904 0.657526 4.99001 0.296025L4.76202 0C4.46198 0.471461 4.03057 0.849314 3.52278 1.0857L2.7439 0.32652L0 2.36804Z" transform="translate(509.799 195.969) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M0.604584 0C0.268048 0.58226 0.0560402 1.24712 0.00960309 1.96155C-0.0554133 2.96241 0.212865 3.90916 0.718502 4.69527C0.968667 5.08428 1.27703 5.43372 1.6323 5.73085C1.97783 5.48362 2.33448 5.22058 2.69787 4.94286L2.99492 4.71637C2.52216 4.41772 2.14318 3.98873 1.90604 3.48384L2.67357 2.70084L0.604584 0Z" transform="translate(505.26 188.355) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M5.78206 0.616686C5.19117 0.273085 4.51439 0.0564579 3.78629 0.009566C2.78092 -0.0551811 1.82989 0.211895 1.04024 0.715243C0.649454 0.96431 0.298489 1.2713 0 1.62495C0.248345 1.96895 0.512562 2.32398 0.791518 2.68577L1.019 2.9815C1.31913 2.51066 1.75027 2.13325 2.25773 1.8972L2.99226 2.609L5.78206 0.616686Z" transform="translate(507.395 183.785) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M2.40197 5.71368C2.7324 5.13584 2.94121 4.47796 2.98716 3.77102C3.05213 2.77115 2.78441 1.82527 2.2797 1.03958C2.02876 0.648908 1.71919 0.298102 1.36237 0C1.01698 0.247188 0.660552 0.510198 0.297402 0.788014L0 1.01494C0.474427 1.31415 0.854625 1.74457 1.09198 2.25126L1.09653 2.2618L0.357757 3.02495L2.40197 5.71368Z" transform="translate(517.502 185.906) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M0 2.36804C0.590364 2.71089 1.26641 2.92688 1.9936 2.97373C2.99795 3.03839 3.94806 2.77184 4.7373 2.26944C5.12975 2.01962 5.48213 1.71145 5.78153 1.35622C5.53323 1.01235 5.26904 0.657526 4.99001 0.296025L4.76202 0C4.46198 0.471461 4.03057 0.849314 3.52278 1.0857L2.7439 0.32652L0 2.36804Z" transform="translate(796.046 237.02) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M0.604584 0C0.268048 0.58226 0.0560402 1.24712 0.00960309 1.96155C-0.0554133 2.96241 0.212865 3.90916 0.718502 4.69527C0.968667 5.08428 1.27703 5.43372 1.6323 5.73085C1.97783 5.48362 2.33448 5.22058 2.69787 4.94286L2.99492 4.71637C2.52216 4.41772 2.14318 3.98873 1.90604 3.48384L2.67357 2.70084L0.604584 0Z" transform="translate(791.507 229.406) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M5.78206 0.616686C5.19117 0.273085 4.51439 0.0564579 3.78629 0.009566C2.78092 -0.0551811 1.82989 0.211895 1.04024 0.715243C0.649454 0.96431 0.298489 1.2713 0 1.62495C0.248345 1.96895 0.512562 2.32398 0.791518 2.68577L1.019 2.9815C1.31913 2.51066 1.75027 2.13325 2.25773 1.8972L2.99226 2.609L5.78206 0.616686Z" transform="translate(793.642 224.836) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M2.40197 5.71368C2.7324 5.13584 2.94121 4.47796 2.98716 3.77102C3.05213 2.77115 2.78441 1.82527 2.2797 1.03958C2.02876 0.648908 1.71919 0.298102 1.36237 0C1.01698 0.247188 0.660552 0.510198 0.297402 0.788014L0 1.01494C0.474427 1.31415 0.854625 1.74457 1.09198 2.25126L1.09653 2.2618L0.357757 3.02495L2.40197 5.71368Z" transform="translate(803.749 226.957) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M0 2.36804C0.590364 2.71089 1.26641 2.92688 1.9936 2.97373C2.99795 3.03839 3.94806 2.77184 4.7373 2.26944C5.12975 2.01962 5.48213 1.71145 5.78153 1.35622C5.53323 1.01235 5.26904 0.657526 4.99001 0.296025L4.76202 0C4.46198 0.471461 4.03057 0.849314 3.52278 1.0857L2.7439 0.32652L0 2.36804Z" transform="translate(816.046 297.02) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M0.604584 0C0.268048 0.58226 0.0560402 1.24712 0.00960309 1.96155C-0.0554133 2.96241 0.212865 3.90916 0.718502 4.69527C0.968667 5.08428 1.27703 5.43372 1.6323 5.73085C1.97783 5.48362 2.33448 5.22058 2.69787 4.94286L2.99492 4.71637C2.52216 4.41772 2.14318 3.98873 1.90604 3.48384L2.67357 2.70084L0.604584 0Z" transform="translate(811.507 289.406) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M5.78206 0.616686C5.19117 0.273085 4.51439 0.0564579 3.78629 0.009566C2.78092 -0.0551811 1.82989 0.211895 1.04024 0.715243C0.649454 0.96431 0.298489 1.2713 0 1.62495C0.248345 1.96895 0.512562 2.32398 0.791518 2.68577L1.019 2.9815C1.31913 2.51066 1.75027 2.13325 2.25773 1.8972L2.99226 2.609L5.78206 0.616686Z" transform="translate(813.642 284.836) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M2.40197 5.71368C2.7324 5.13584 2.94121 4.47796 2.98716 3.77102C3.05213 2.77115 2.78441 1.82527 2.2797 1.03958C2.02876 0.648908 1.71919 0.298102 1.36237 0C1.01698 0.247188 0.660552 0.510198 0.297402 0.788014L0 1.01494C0.474427 1.31415 0.854625 1.74457 1.09198 2.25126L1.09653 2.2618L0.357757 3.02495L2.40197 5.71368Z" transform="translate(823.749 286.957) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M0 2.36804C0.590364 2.71089 1.26641 2.92688 1.9936 2.97373C2.99795 3.03839 3.94806 2.77184 4.7373 2.26944C5.12975 2.01962 5.48213 1.71145 5.78153 1.35622C5.53323 1.01235 5.26904 0.657526 4.99001 0.296025L4.76202 0C4.46198 0.471461 4.03057 0.849314 3.52278 1.0857L2.7439 0.32652L0 2.36804Z" transform="translate(794.046 301.02) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M0.604584 0C0.268048 0.58226 0.0560402 1.24712 0.00960309 1.96155C-0.0554133 2.96241 0.212865 3.90916 0.718502 4.69527C0.968667 5.08428 1.27703 5.43372 1.6323 5.73085C1.97783 5.48362 2.33448 5.22058 2.69787 4.94286L2.99492 4.71637C2.52216 4.41772 2.14318 3.98873 1.90604 3.48384L2.67357 2.70084L0.604584 0Z" transform="translate(789.507 293.406) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M5.78206 0.616686C5.19117 0.273085 4.51439 0.0564579 3.78629 0.009566C2.78092 -0.0551811 1.82989 0.211895 1.04024 0.715243C0.649454 0.96431 0.298489 1.2713 0 1.62495C0.248345 1.96895 0.512562 2.32398 0.791518 2.68577L1.019 2.9815C1.31913 2.51066 1.75027 2.13325 2.25773 1.8972L2.99226 2.609L5.78206 0.616686Z" transform="translate(791.642 288.836) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M2.40197 5.71368C2.7324 5.13584 2.94121 4.47796 2.98716 3.77102C3.05213 2.77115 2.78441 1.82527 2.2797 1.03958C2.02876 0.648908 1.71919 0.298102 1.36237 0C1.01698 0.247188 0.660552 0.510198 0.297402 0.788014L0 1.01494C0.474427 1.31415 0.854625 1.74457 1.09198 2.25126L1.09653 2.2618L0.357757 3.02495L2.40197 5.71368Z" transform="translate(801.749 290.957) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M0 2.36804C0.590364 2.71089 1.26641 2.92688 1.9936 2.97373C2.99795 3.03839 3.94806 2.77184 4.7373 2.26944C5.12975 2.01962 5.48213 1.71145 5.78153 1.35622C5.53323 1.01235 5.26904 0.657526 4.99001 0.296025L4.76202 0C4.46198 0.471461 4.03057 0.849314 3.52278 1.0857L2.7439 0.32652L0 2.36804Z" transform="translate(352.046 433.02) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M0.604584 0C0.268048 0.58226 0.0560402 1.24712 0.00960309 1.96155C-0.0554133 2.96241 0.212865 3.90916 0.718502 4.69527C0.968667 5.08428 1.27703 5.43372 1.6323 5.73085C1.97783 5.48362 2.33448 5.22058 2.69787 4.94286L2.99492 4.71637C2.52216 4.41772 2.14318 3.98873 1.90604 3.48384L2.67357 2.70084L0.604584 0Z" transform="translate(347.507 425.406) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M5.78206 0.616686C5.19117 0.273085 4.51439 0.0564579 3.78629 0.009566C2.78092 -0.0551811 1.82989 0.211895 1.04024 0.715243C0.649454 0.96431 0.298489 1.2713 0 1.62495C0.248345 1.96895 0.512562 2.32398 0.791518 2.68577L1.019 2.9815C1.31913 2.51066 1.75027 2.13325 2.25773 1.8972L2.99226 2.609L5.78206 0.616686Z" transform="translate(349.642 420.836) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M2.40197 5.71368C2.7324 5.13584 2.94121 4.47796 2.98716 3.77102C3.05213 2.77115 2.78441 1.82527 2.2797 1.03958C2.02876 0.648908 1.71919 0.298102 1.36237 0C1.01698 0.247188 0.660552 0.510198 0.297402 0.788014L0 1.01494C0.474427 1.31415 0.854625 1.74457 1.09198 2.25126L1.09653 2.2618L0.357757 3.02495L2.40197 5.71368Z" transform="translate(359.749 422.957) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M0 2.36804C0.590364 2.71089 1.26641 2.92688 1.9936 2.97373C2.99795 3.03839 3.94806 2.77184 4.7373 2.26944C5.12975 2.01962 5.48213 1.71145 5.78153 1.35622C5.53323 1.01235 5.26904 0.657526 4.99001 0.296025L4.76202 0C4.46198 0.471461 4.03057 0.849314 3.52278 1.0857L2.7439 0.32652L0 2.36804Z" transform="translate(200.046 237.02) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M0.604584 0C0.268048 0.58226 0.0560402 1.24712 0.00960309 1.96155C-0.0554133 2.96241 0.212865 3.90916 0.718502 4.69527C0.968667 5.08428 1.27703 5.43372 1.6323 5.73085C1.97783 5.48362 2.33448 5.22058 2.69787 4.94286L2.99492 4.71637C2.52216 4.41772 2.14318 3.98873 1.90604 3.48384L2.67357 2.70084L0.604584 0Z" transform="translate(195.507 229.406) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M5.78206 0.616686C5.19117 0.273085 4.51439 0.0564579 3.78629 0.009566C2.78092 -0.0551811 1.82989 0.211895 1.04024 0.715243C0.649454 0.96431 0.298489 1.2713 0 1.62495C0.248345 1.96895 0.512562 2.32398 0.791518 2.68577L1.019 2.9815C1.31913 2.51066 1.75027 2.13325 2.25773 1.8972L2.99226 2.609L5.78206 0.616686Z" transform="translate(197.642 224.836) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M2.40197 5.71368C2.7324 5.13584 2.94121 4.47796 2.98716 3.77102C3.05213 2.77115 2.78441 1.82527 2.2797 1.03958C2.02876 0.648908 1.71919 0.298102 1.36237 0C1.01698 0.247188 0.660552 0.510198 0.297402 0.788014L0 1.01494C0.474427 1.31415 0.854625 1.74457 1.09198 2.25126L1.09653 2.2618L0.357757 3.02495L2.40197 5.71368Z" transform="translate(207.749 226.957) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M0 2.36804C0.590364 2.71089 1.26641 2.92688 1.9936 2.97373C2.99795 3.03839 3.94806 2.77184 4.7373 2.26944C5.12975 2.01962 5.48213 1.71145 5.78153 1.35622C5.53323 1.01235 5.26904 0.657526 4.99001 0.296025L4.76202 0C4.46198 0.471461 4.03057 0.849314 3.52278 1.0857L2.7439 0.32652L0 2.36804Z" transform="translate(156.046 243.02) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M0.604584 0C0.268048 0.58226 0.0560402 1.24712 0.00960309 1.96155C-0.0554133 2.96241 0.212865 3.90916 0.718502 4.69527C0.968667 5.08428 1.27703 5.43372 1.6323 5.73085C1.97783 5.48362 2.33448 5.22058 2.69787 4.94286L2.99492 4.71637C2.52216 4.41772 2.14318 3.98873 1.90604 3.48384L2.67357 2.70084L0.604584 0Z" transform="translate(151.507 235.406) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M5.78206 0.616686C5.19117 0.273085 4.51439 0.0564579 3.78629 0.009566C2.78092 -0.0551811 1.82989 0.211895 1.04024 0.715243C0.649454 0.96431 0.298489 1.2713 0 1.62495C0.248345 1.96895 0.512562 2.32398 0.791518 2.68577L1.019 2.9815C1.31913 2.51066 1.75027 2.13325 2.25773 1.8972L2.99226 2.609L5.78206 0.616686Z" transform="translate(153.642 230.836) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M2.40197 5.71368C2.7324 5.13584 2.94121 4.47796 2.98716 3.77102C3.05213 2.77115 2.78441 1.82527 2.2797 1.03958C2.02876 0.648908 1.71919 0.298102 1.36237 0C1.01698 0.247188 0.660552 0.510198 0.297402 0.788014L0 1.01494C0.474427 1.31415 0.854625 1.74457 1.09198 2.25126L1.09653 2.2618L0.357757 3.02495L2.40197 5.71368Z" transform="translate(163.749 232.957) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M0 2.36804C0.590364 2.71089 1.26641 2.92688 1.9936 2.97373C2.99795 3.03839 3.94806 2.77184 4.7373 2.26944C5.12975 2.01962 5.48213 1.71145 5.78153 1.35622C5.53323 1.01235 5.26904 0.657526 4.99001 0.296025L4.76202 0C4.46198 0.471461 4.03057 0.849314 3.52278 1.0857L2.7439 0.32652L0 2.36804Z" transform="translate(208.046 265.02) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M0.604584 0C0.268048 0.58226 0.0560402 1.24712 0.00960309 1.96155C-0.0554133 2.96241 0.212865 3.90916 0.718502 4.69527C0.968667 5.08428 1.27703 5.43372 1.6323 5.73085C1.97783 5.48362 2.33448 5.22058 2.69787 4.94286L2.99492 4.71637C2.52216 4.41772 2.14318 3.98873 1.90604 3.48384L2.67357 2.70084L0.604584 0Z" transform="translate(203.507 257.406) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M5.78206 0.616686C5.19117 0.273085 4.51439 0.0564579 3.78629 0.009566C2.78092 -0.0551811 1.82989 0.211895 1.04024 0.715243C0.649454 0.96431 0.298489 1.2713 0 1.62495C0.248345 1.96895 0.512562 2.32398 0.791518 2.68577L1.019 2.9815C1.31913 2.51066 1.75027 2.13325 2.25773 1.8972L2.99226 2.609L5.78206 0.616686Z" transform="translate(205.642 252.836) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M2.40197 5.71368C2.7324 5.13584 2.94121 4.47796 2.98716 3.77102C3.05213 2.77115 2.78441 1.82527 2.2797 1.03958C2.02876 0.648908 1.71919 0.298102 1.36237 0C1.01698 0.247188 0.660552 0.510198 0.297402 0.788014L0 1.01494C0.474427 1.31415 0.854625 1.74457 1.09198 2.25126L1.09653 2.2618L0.357757 3.02495L2.40197 5.71368Z" transform="translate(215.749 254.957) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M0 2.36804C0.590364 2.71089 1.26641 2.92688 1.9936 2.97373C2.99795 3.03839 3.94806 2.77184 4.7373 2.26944C5.12975 2.01962 5.48213 1.71145 5.78153 1.35622C5.53323 1.01235 5.26904 0.657526 4.99001 0.296025L4.76202 0C4.46198 0.471461 4.03057 0.849314 3.52278 1.0857L2.7439 0.32652L0 2.36804Z" transform="translate(278.046 245.02) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M0.604584 0C0.268048 0.58226 0.0560402 1.24712 0.00960309 1.96155C-0.0554133 2.96241 0.212865 3.90916 0.718502 4.69527C0.968667 5.08428 1.27703 5.43372 1.6323 5.73085C1.97783 5.48362 2.33448 5.22058 2.69787 4.94286L2.99492 4.71637C2.52216 4.41772 2.14318 3.98873 1.90604 3.48384L2.67357 2.70084L0.604584 0Z" transform="translate(273.507 237.406) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M5.78206 0.616686C5.19117 0.273085 4.51439 0.0564579 3.78629 0.009566C2.78092 -0.0551811 1.82989 0.211895 1.04024 0.715243C0.649454 0.96431 0.298489 1.2713 0 1.62495C0.248345 1.96895 0.512562 2.32398 0.791518 2.68577L1.019 2.9815C1.31913 2.51066 1.75027 2.13325 2.25773 1.8972L2.99226 2.609L5.78206 0.616686Z" transform="translate(275.642 232.836) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M2.40197 5.71368C2.7324 5.13584 2.94121 4.47796 2.98716 3.77102C3.05213 2.77115 2.78441 1.82527 2.2797 1.03958C2.02876 0.648908 1.71919 0.298102 1.36237 0C1.01698 0.247188 0.660552 0.510198 0.297402 0.788014L0 1.01494C0.474427 1.31415 0.854625 1.74457 1.09198 2.25126L1.09653 2.2618L0.357757 3.02495L2.40197 5.71368Z" transform="translate(285.749 234.957) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M0 2.36804C0.590364 2.71089 1.26641 2.92688 1.9936 2.97373C2.99795 3.03839 3.94806 2.77184 4.7373 2.26944C5.12975 2.01962 5.48213 1.71145 5.78153 1.35622C5.53323 1.01235 5.26904 0.657526 4.99001 0.296025L4.76202 0C4.46198 0.471461 4.03057 0.849314 3.52278 1.0857L2.7439 0.32652L0 2.36804Z" transform="translate(686.046 311.02) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M0.604584 0C0.268048 0.58226 0.0560402 1.24712 0.00960309 1.96155C-0.0554133 2.96241 0.212865 3.90916 0.718502 4.69527C0.968667 5.08428 1.27703 5.43372 1.6323 5.73085C1.97783 5.48362 2.33448 5.22058 2.69787 4.94286L2.99492 4.71637C2.52216 4.41772 2.14318 3.98873 1.90604 3.48384L2.67357 2.70084L0.604584 0Z" transform="translate(681.507 303.406) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M5.78206 0.616686C5.19117 0.273085 4.51439 0.0564579 3.78629 0.009566C2.78092 -0.0551811 1.82989 0.211895 1.04024 0.715243C0.649454 0.96431 0.298489 1.2713 0 1.62495C0.248345 1.96895 0.512562 2.32398 0.791518 2.68577L1.019 2.9815C1.31913 2.51066 1.75027 2.13325 2.25773 1.8972L2.99226 2.609L5.78206 0.616686Z" transform="translate(683.642 298.836) scale(2)" fill="black"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M2.40197 5.71368C2.7324 5.13584 2.94121 4.47796 2.98716 3.77102C3.05213 2.77115 2.78441 1.82527 2.2797 1.03958C2.02876 0.648908 1.71919 0.298102 1.36237 0C1.01698 0.247188 0.660552 0.510198 0.297402 0.788014L0 1.01494C0.474427 1.31415 0.854625 1.74457 1.09198 2.25126L1.09653 2.2618L0.357757 3.02495L2.40197 5.71368Z" transform="translate(693.749 300.957) scale(2)" fill="black"/>
-<defs>
-<filter id="filter0_d" x="0" y="0" width="1046" height="594" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
-<feFlood flood-opacity="0" result="BackgroundImageFix"/>
-<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0"/>
-<feOffset dy="4"/>
-<feGaussianBlur stdDeviation="8.5"/>
-<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"/>
-<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
-<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
-</filter>
-</defs>
-</svg>
diff --git a/packages/website/public/images/og_image.png b/packages/website/public/images/og_image.png
index 74265bdf8..b9bafeb7e 100644
--- a/packages/website/public/images/og_image.png
+++ b/packages/website/public/images/og_image.png
Binary files differ
diff --git a/packages/website/public/images/press/logo-forbes.png b/packages/website/public/images/press/logo-forbes.png
new file mode 100644
index 000000000..6849c672b
--- /dev/null
+++ b/packages/website/public/images/press/logo-forbes.png
Binary files differ
diff --git a/packages/website/public/images/press/logo-fortune.png b/packages/website/public/images/press/logo-fortune.png
new file mode 100644
index 000000000..981f8c357
--- /dev/null
+++ b/packages/website/public/images/press/logo-fortune.png
Binary files differ
diff --git a/packages/website/public/images/press/logo-techcrunch.png b/packages/website/public/images/press/logo-techcrunch.png
new file mode 100644
index 000000000..7f260d0ea
--- /dev/null
+++ b/packages/website/public/images/press/logo-techcrunch.png
Binary files differ
diff --git a/packages/website/public/images/press/logo-venturebeat.png b/packages/website/public/images/press/logo-venturebeat.png
new file mode 100644
index 000000000..2086bf0b7
--- /dev/null
+++ b/packages/website/public/images/press/logo-venturebeat.png
Binary files differ
diff --git a/packages/website/public/images/relayer-logos/logo.png b/packages/website/public/images/relayer-logos/logo.png
new file mode 100755
index 000000000..d810cef4a
--- /dev/null
+++ b/packages/website/public/images/relayer-logos/logo.png
Binary files differ
diff --git a/packages/website/public/images/relayer-logos/logo_1.png b/packages/website/public/images/relayer-logos/logo_1.png
new file mode 100755
index 000000000..0068a7445
--- /dev/null
+++ b/packages/website/public/images/relayer-logos/logo_1.png
Binary files differ
diff --git a/packages/website/public/images/relayer-logos/logo_2.1.png b/packages/website/public/images/relayer-logos/logo_2.1.png
new file mode 100755
index 000000000..f6cd92b0e
--- /dev/null
+++ b/packages/website/public/images/relayer-logos/logo_2.1.png
Binary files differ
diff --git a/packages/website/public/images/relayer-logos/logo_2.2.png b/packages/website/public/images/relayer-logos/logo_2.2.png
new file mode 100755
index 000000000..9461e91ee
--- /dev/null
+++ b/packages/website/public/images/relayer-logos/logo_2.2.png
Binary files differ
diff --git a/packages/website/public/images/relayer-logos/logo_2.3.png b/packages/website/public/images/relayer-logos/logo_2.3.png
new file mode 100755
index 000000000..fde896972
--- /dev/null
+++ b/packages/website/public/images/relayer-logos/logo_2.3.png
Binary files differ
diff --git a/packages/website/public/images/relayer-logos/logo_2.png b/packages/website/public/images/relayer-logos/logo_2.png
new file mode 100755
index 000000000..e3015110c
--- /dev/null
+++ b/packages/website/public/images/relayer-logos/logo_2.png
Binary files differ
diff --git a/packages/website/public/images/relayer-logos/logo_3.png b/packages/website/public/images/relayer-logos/logo_3.png
new file mode 100755
index 000000000..b3d397fe1
--- /dev/null
+++ b/packages/website/public/images/relayer-logos/logo_3.png
Binary files differ
diff --git a/packages/website/public/images/relayer-logos/logo_4.png b/packages/website/public/images/relayer-logos/logo_4.png
new file mode 100755
index 000000000..578be0af8
--- /dev/null
+++ b/packages/website/public/images/relayer-logos/logo_4.png
Binary files differ
diff --git a/packages/website/public/images/relayer-logos/logo_5.png b/packages/website/public/images/relayer-logos/logo_5.png
new file mode 100755
index 000000000..baf3c4080
--- /dev/null
+++ b/packages/website/public/images/relayer-logos/logo_5.png
Binary files differ
diff --git a/packages/website/public/images/team/advisors/davids.jpg b/packages/website/public/images/team/advisors/davids.jpg
new file mode 100755
index 000000000..904ebda01
--- /dev/null
+++ b/packages/website/public/images/team/advisors/davids.jpg
Binary files differ
diff --git a/packages/website/public/images/team/advisors/frede.jpg b/packages/website/public/images/team/advisors/frede.jpg
new file mode 100755
index 000000000..cb882c53f
--- /dev/null
+++ b/packages/website/public/images/team/advisors/frede.jpg
Binary files differ
diff --git a/packages/website/public/images/team/advisors/joeyk.jpg b/packages/website/public/images/team/advisors/joeyk.jpg
new file mode 100755
index 000000000..c6050242f
--- /dev/null
+++ b/packages/website/public/images/team/advisors/joeyk.jpg
Binary files differ
diff --git a/packages/website/public/images/team/advisors/lindax.jpg b/packages/website/public/images/team/advisors/lindax.jpg
new file mode 100755
index 000000000..766532068
--- /dev/null
+++ b/packages/website/public/images/team/advisors/lindax.jpg
Binary files differ
diff --git a/packages/website/public/images/team/advisors/olafc.jpg b/packages/website/public/images/team/advisors/olafc.jpg
new file mode 100755
index 000000000..bb0dc6cb5
--- /dev/null
+++ b/packages/website/public/images/team/advisors/olafc.jpg
Binary files differ
diff --git a/packages/website/public/images/team/alex.jpg b/packages/website/public/images/team/alex.jpg
deleted file mode 100644
index ae6888804..000000000
--- a/packages/website/public/images/team/alex.jpg
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/team/alexb.jpg b/packages/website/public/images/team/alexb.jpg
new file mode 100755
index 000000000..c076de14b
--- /dev/null
+++ b/packages/website/public/images/team/alexb.jpg
Binary files differ
diff --git a/packages/website/public/images/team/alexbrowne.png b/packages/website/public/images/team/alexbrowne.png
deleted file mode 100644
index 76a61913e..000000000
--- a/packages/website/public/images/team/alexbrowne.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/team/alexv.jpg b/packages/website/public/images/team/alexv.jpg
new file mode 100755
index 000000000..686f4a2e3
--- /dev/null
+++ b/packages/website/public/images/team/alexv.jpg
Binary files differ
diff --git a/packages/website/public/images/team/amir.png b/packages/website/public/images/team/amir.png
deleted file mode 100644
index 2bb795d50..000000000
--- a/packages/website/public/images/team/amir.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/team/amirb.jpg b/packages/website/public/images/team/amirb.jpg
new file mode 100755
index 000000000..19502735d
--- /dev/null
+++ b/packages/website/public/images/team/amirb.jpg
Binary files differ
diff --git a/packages/website/public/images/team/anyone.png b/packages/website/public/images/team/anyone.png
deleted file mode 100644
index 4de26b0ce..000000000
--- a/packages/website/public/images/team/anyone.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/team/ben.jpg b/packages/website/public/images/team/ben.jpg
deleted file mode 100644
index b42d0a42a..000000000
--- a/packages/website/public/images/team/ben.jpg
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/team/benb.jpg b/packages/website/public/images/team/benb.jpg
new file mode 100755
index 000000000..ef7fb69a9
--- /dev/null
+++ b/packages/website/public/images/team/benb.jpg
Binary files differ
diff --git a/packages/website/public/images/team/blake.jpg b/packages/website/public/images/team/blake.jpg
index 44ca0a311..0f5512af4 100644..100755
--- a/packages/website/public/images/team/blake.jpg
+++ b/packages/website/public/images/team/blake.jpg
Binary files differ
diff --git a/packages/website/public/images/team/brandon.png b/packages/website/public/images/team/brandon.png
deleted file mode 100644
index ebd3cf101..000000000
--- a/packages/website/public/images/team/brandon.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/team/brandonm.jpg b/packages/website/public/images/team/brandonm.jpg
new file mode 100755
index 000000000..72368f994
--- /dev/null
+++ b/packages/website/public/images/team/brandonm.jpg
Binary files differ
diff --git a/packages/website/public/images/team/chris.png b/packages/website/public/images/team/chris.png
deleted file mode 100644
index 242a2813f..000000000
--- a/packages/website/public/images/team/chris.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/team/chrisk.jpg b/packages/website/public/images/team/chrisk.jpg
new file mode 100755
index 000000000..cf900faea
--- /dev/null
+++ b/packages/website/public/images/team/chrisk.jpg
Binary files differ
diff --git a/packages/website/public/images/team/clay.png b/packages/website/public/images/team/clay.png
deleted file mode 100644
index 2bc828572..000000000
--- a/packages/website/public/images/team/clay.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/team/clayr.jpg b/packages/website/public/images/team/clayr.jpg
new file mode 100755
index 000000000..3fa550727
--- /dev/null
+++ b/packages/website/public/images/team/clayr.jpg
Binary files differ
diff --git a/packages/website/public/images/team/eugenea.jpg b/packages/website/public/images/team/eugenea.jpg
new file mode 100755
index 000000000..dc9aecea1
--- /dev/null
+++ b/packages/website/public/images/team/eugenea.jpg
Binary files differ
diff --git a/packages/website/public/images/team/fabio.jpg b/packages/website/public/images/team/fabio.jpg
deleted file mode 100644
index da87a9e95..000000000
--- a/packages/website/public/images/team/fabio.jpg
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/team/fabiob.jpg b/packages/website/public/images/team/fabiob.jpg
new file mode 100755
index 000000000..c06a06c9f
--- /dev/null
+++ b/packages/website/public/images/team/fabiob.jpg
Binary files differ
diff --git a/packages/website/public/images/team/fragosti.png b/packages/website/public/images/team/fragosti.png
deleted file mode 100644
index 60c168514..000000000
--- a/packages/website/public/images/team/fragosti.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/team/francesco.jpg b/packages/website/public/images/team/francesco.jpg
new file mode 100755
index 000000000..56ae0e870
--- /dev/null
+++ b/packages/website/public/images/team/francesco.jpg
Binary files differ
diff --git a/packages/website/public/images/team/gene.jpg b/packages/website/public/images/team/gene.jpg
deleted file mode 100644
index 1d4222118..000000000
--- a/packages/website/public/images/team/gene.jpg
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/team/greg.jpeg b/packages/website/public/images/team/greg.jpeg
deleted file mode 100644
index a765e047f..000000000
--- a/packages/website/public/images/team/greg.jpeg
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/team/greg.jpg b/packages/website/public/images/team/greg.jpg
new file mode 100755
index 000000000..0b6df7083
--- /dev/null
+++ b/packages/website/public/images/team/greg.jpg
Binary files differ
diff --git a/packages/website/public/images/team/jacob.jpg b/packages/website/public/images/team/jacob.jpg
deleted file mode 100644
index de8b9e4b5..000000000
--- a/packages/website/public/images/team/jacob.jpg
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/team/jacobe.jpg b/packages/website/public/images/team/jacobe.jpg
new file mode 100755
index 000000000..29eed406d
--- /dev/null
+++ b/packages/website/public/images/team/jacobe.jpg
Binary files differ
diff --git a/packages/website/public/images/team/jason.png b/packages/website/public/images/team/jason.png
deleted file mode 100644
index a39522252..000000000
--- a/packages/website/public/images/team/jason.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/team/jasons.jpg b/packages/website/public/images/team/jasons.jpg
new file mode 100755
index 000000000..b0a40edba
--- /dev/null
+++ b/packages/website/public/images/team/jasons.jpg
Binary files differ
diff --git a/packages/website/public/images/team/leonid.png b/packages/website/public/images/team/leonid.png
deleted file mode 100644
index 4acbf87c8..000000000
--- a/packages/website/public/images/team/leonid.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/team/leonidL.jpg b/packages/website/public/images/team/leonidL.jpg
new file mode 100755
index 000000000..e3dfd6a7d
--- /dev/null
+++ b/packages/website/public/images/team/leonidL.jpg
Binary files differ
diff --git a/packages/website/public/images/team/matt.jpg b/packages/website/public/images/team/matt.jpg
deleted file mode 100644
index 101209c37..000000000
--- a/packages/website/public/images/team/matt.jpg
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/team/mattt.jpg b/packages/website/public/images/team/mattt.jpg
new file mode 100755
index 000000000..03f95a7c1
--- /dev/null
+++ b/packages/website/public/images/team/mattt.jpg
Binary files differ
diff --git a/packages/website/public/images/team/mel.png b/packages/website/public/images/team/mel.png
deleted file mode 100644
index 52d779ad2..000000000
--- a/packages/website/public/images/team/mel.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/team/melo.jpg b/packages/website/public/images/team/melo.jpg
new file mode 100755
index 000000000..2db8ec796
--- /dev/null
+++ b/packages/website/public/images/team/melo.jpg
Binary files differ
diff --git a/packages/website/public/images/team/peter.jpg b/packages/website/public/images/team/peter.jpg
deleted file mode 100644
index fa976cb8d..000000000
--- a/packages/website/public/images/team/peter.jpg
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/team/peterz.jpg b/packages/website/public/images/team/peterz.jpg
new file mode 100755
index 000000000..7708c75db
--- /dev/null
+++ b/packages/website/public/images/team/peterz.jpg
Binary files differ
diff --git a/packages/website/public/images/team/rahul.png b/packages/website/public/images/team/rahul.png
deleted file mode 100644
index b63cc12b1..000000000
--- a/packages/website/public/images/team/rahul.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/team/rahuls.jpg b/packages/website/public/images/team/rahuls.jpg
new file mode 100755
index 000000000..ef2f001dd
--- /dev/null
+++ b/packages/website/public/images/team/rahuls.jpg
Binary files differ
diff --git a/packages/website/public/images/team/remco.jpeg b/packages/website/public/images/team/remco.jpeg
deleted file mode 100644
index e87e7bfd6..000000000
--- a/packages/website/public/images/team/remco.jpeg
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/team/remcoB.jpg b/packages/website/public/images/team/remcoB.jpg
new file mode 100755
index 000000000..bc997a18e
--- /dev/null
+++ b/packages/website/public/images/team/remcoB.jpg
Binary files differ
diff --git a/packages/website/public/images/team/steve.png b/packages/website/public/images/team/steve.png
deleted file mode 100644
index 751583fba..000000000
--- a/packages/website/public/images/team/steve.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/team/steveK.jpg b/packages/website/public/images/team/steveK.jpg
new file mode 100755
index 000000000..aeede8bc5
--- /dev/null
+++ b/packages/website/public/images/team/steveK.jpg
Binary files differ
diff --git a/packages/website/public/images/team/tom.jpg b/packages/website/public/images/team/tom.jpg
deleted file mode 100644
index 3623a2b78..000000000
--- a/packages/website/public/images/team/tom.jpg
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/team/toms.jpg b/packages/website/public/images/team/toms.jpg
new file mode 100755
index 000000000..9d9dd2db8
--- /dev/null
+++ b/packages/website/public/images/team/toms.jpg
Binary files differ
diff --git a/packages/website/public/images/team/weijew.jpg b/packages/website/public/images/team/weijew.jpg
new file mode 100755
index 000000000..0b2464e67
--- /dev/null
+++ b/packages/website/public/images/team/weijew.jpg
Binary files differ
diff --git a/packages/website/public/images/team/weijie.png b/packages/website/public/images/team/weijie.png
deleted file mode 100644
index 69fd51794..000000000
--- a/packages/website/public/images/team/weijie.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/team/will.jpg b/packages/website/public/images/team/will.jpg
deleted file mode 100644
index 7de028032..000000000
--- a/packages/website/public/images/team/will.jpg
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/team/willw.jpg b/packages/website/public/images/team/willw.jpg
new file mode 100755
index 000000000..c1bd8f406
--- /dev/null
+++ b/packages/website/public/images/team/willw.jpg
Binary files differ
diff --git a/packages/website/public/images/team/xianny.jpg b/packages/website/public/images/team/xianny.jpg
new file mode 100755
index 000000000..4e6a3bb8c
--- /dev/null
+++ b/packages/website/public/images/team/xianny.jpg
Binary files differ
diff --git a/packages/website/public/images/team/xianny.png b/packages/website/public/images/team/xianny.png
deleted file mode 100644
index f6fe1ef61..000000000
--- a/packages/website/public/images/team/xianny.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/team/zach.png b/packages/website/public/images/team/zach.png
deleted file mode 100644
index 4565a9af0..000000000
--- a/packages/website/public/images/team/zach.png
+++ /dev/null
Binary files differ
diff --git a/packages/website/public/images/team/zack.jpg b/packages/website/public/images/team/zack.jpg
new file mode 100755
index 000000000..9060d7592
--- /dev/null
+++ b/packages/website/public/images/team/zack.jpg
Binary files differ
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/translations/chinese.json b/packages/website/translations/chinese.json
index b99a3cdcb..88193a181 100644
--- a/packages/website/translations/chinese.json
+++ b/packages/website/translations/chinese.json
@@ -83,7 +83,7 @@
"BUILD_A_RELAYER": "build a relayer",
"BUILD_A_RELAYER_DESCRIPTION": "Learn how to build your own 0x relayer from scratch",
"DEVELOP_ON_ETHEREUM": "develop on Ethereum",
- "DEVELOP_ON_ETHEREUM_DESCRIPTION": "Learn more about building applications ontop of Ethereum",
+ "DEVELOP_ON_ETHEREUM_DESCRIPTION": "Learn more about building applications on top of Ethereum",
"ORDER_BASICS": "Make & take orders",
"ORDER_BASICS_DESCRIPTION": "Tutorial on how to create, validate and fill an order using 0x",
"USE_NETWORKED_LIQUIDITY": "use networked liquidity",
diff --git a/packages/website/translations/english.json b/packages/website/translations/english.json
index 2914ffead..a1d8ecc43 100644
--- a/packages/website/translations/english.json
+++ b/packages/website/translations/english.json
@@ -87,7 +87,7 @@
"BUILD_A_RELAYER": "build a relayer",
"BUILD_A_RELAYER_DESCRIPTION": "Learn how to build your own 0x relayer from scratch",
"DEVELOP_ON_ETHEREUM": "develop on Ethereum",
- "DEVELOP_ON_ETHEREUM_DESCRIPTION": "Learn more about building applications ontop of Ethereum",
+ "DEVELOP_ON_ETHEREUM_DESCRIPTION": "Learn more about building applications on top of Ethereum",
"ORDER_BASICS": "Make & take orders",
"ORDER_BASICS_DESCRIPTION": "Tutorial on how to create, validate and fill an order using 0x",
"USE_NETWORKED_LIQUIDITY": "use networked liquidity",
diff --git a/packages/website/translations/korean.json b/packages/website/translations/korean.json
index a421ffb94..539b81470 100644
--- a/packages/website/translations/korean.json
+++ b/packages/website/translations/korean.json
@@ -83,7 +83,7 @@
"BUILD_A_RELAYER": "build a relayer",
"BUILD_A_RELAYER_DESCRIPTION": "Learn how to build your own 0x relayer from scratch",
"DEVELOP_ON_ETHEREUM": "develop on Ethereum",
- "DEVELOP_ON_ETHEREUM_DESCRIPTION": "Learn more about building applications ontop of Ethereum",
+ "DEVELOP_ON_ETHEREUM_DESCRIPTION": "Learn more about building applications on top of Ethereum",
"ORDER_BASICS": "Make & take orders",
"ORDER_BASICS_DESCRIPTION": "Tutorial on how to create, validate and fill an order using 0x",
"USE_NETWORKED_LIQUIDITY": "use networked liquidity",
diff --git a/packages/website/translations/russian.json b/packages/website/translations/russian.json
index b3ea29cf3..feb5df02e 100644
--- a/packages/website/translations/russian.json
+++ b/packages/website/translations/russian.json
@@ -83,7 +83,7 @@
"BUILD_A_RELAYER": "build a relayer",
"BUILD_A_RELAYER_DESCRIPTION": "Learn how to build your own 0x relayer from scratch",
"DEVELOP_ON_ETHEREUM": "develop on Ethereum",
- "DEVELOP_ON_ETHEREUM_DESCRIPTION": "Learn more about building applications ontop of Ethereum",
+ "DEVELOP_ON_ETHEREUM_DESCRIPTION": "Learn more about building applications on top of Ethereum",
"ORDER_BASICS": "Make & take orders",
"ORDER_BASICS_DESCRIPTION": "Tutorial on how to create, validate and fill an order using 0x",
"USE_NETWORKED_LIQUIDITY": "use networked liquidity",
diff --git a/packages/website/translations/spanish.json b/packages/website/translations/spanish.json
index db75312c5..f4762a67e 100644
--- a/packages/website/translations/spanish.json
+++ b/packages/website/translations/spanish.json
@@ -84,7 +84,7 @@
"BUILD_A_RELAYER": "build a relayer",
"BUILD_A_RELAYER_DESCRIPTION": "Learn how to build your own 0x relayer from scratch",
"DEVELOP_ON_ETHEREUM": "develop on Ethereum",
- "DEVELOP_ON_ETHEREUM_DESCRIPTION": "Learn more about building applications ontop of Ethereum",
+ "DEVELOP_ON_ETHEREUM_DESCRIPTION": "Learn more about building applications on top of Ethereum",
"ORDER_BASICS": "Make & take orders",
"ORDER_BASICS_DESCRIPTION": "Tutorial on how to create, validate and fill an order using 0x",
"USE_NETWORKED_LIQUIDITY": "use networked liquidity",
diff --git a/packages/website/ts/components/aboutPageLayout.tsx b/packages/website/ts/components/aboutPageLayout.tsx
new file mode 100644
index 000000000..a2fd9dd72
--- /dev/null
+++ b/packages/website/ts/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/components/button';
+import { ChapterLink } from 'ts/components/chapter_link';
+import { Column, Section } from 'ts/components/newLayout';
+import { SiteWrap } from 'ts/components/siteWrap';
+import { Heading, Paragraph } from 'ts/components/text';
+
+import { addFadeInAnimation } from 'ts/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/components/animatedChatIcon.tsx b/packages/website/ts/components/animatedChatIcon.tsx
new file mode 100644
index 000000000..9a86e244c
--- /dev/null
+++ b/packages/website/ts/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/components/animatedCompassIcon.tsx b/packages/website/ts/components/animatedCompassIcon.tsx
new file mode 100644
index 000000000..5388f95ca
--- /dev/null
+++ b/packages/website/ts/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/components/banner.tsx b/packages/website/ts/components/banner.tsx
new file mode 100644
index 000000000..76fc1d09e
--- /dev/null
+++ b/packages/website/ts/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/components/button';
+import { ThemeInterface } from 'ts/components/siteWrap';
+import { Paragraph } from 'ts/components/text';
+
+import { Column, Section } from 'ts/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/banner/bottomofcta.png);' : 'url(/images/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/components/blockIconLink.tsx b/packages/website/ts/components/blockIconLink.tsx
new file mode 100644
index 000000000..ff7712595
--- /dev/null
+++ b/packages/website/ts/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/components/button';
+import { Icon } from 'ts/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/components/button.tsx b/packages/website/ts/components/button.tsx
new file mode 100644
index 000000000..569038ae0
--- /dev/null
+++ b/packages/website/ts/components/button.tsx
@@ -0,0 +1,107 @@
+import * as React from 'react';
+import { Link as ReactRouterLink } from 'react-router-dom';
+import styled from 'styled-components';
+
+import { ThemeInterface } from 'ts/components/siteWrap';
+
+import { colors } from 'ts/style/colors';
+
+interface ButtonInterface {
+ bgColor?: string;
+ borderColor?: 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: React.StatelessComponent<ButtonInterface> = (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>
+ );
+};
+
+Button.defaultProps = {
+ borderColor: 'rgba(255, 255, 255, .4)',
+};
+
+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 && props.borderColor};
+ 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/components/chapter_link.tsx b/packages/website/ts/components/chapter_link.tsx
new file mode 100644
index 000000000..fd974cec1
--- /dev/null
+++ b/packages/website/ts/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/components/definition.tsx b/packages/website/ts/components/definition.tsx
new file mode 100644
index 000000000..92fe54f38
--- /dev/null
+++ b/packages/website/ts/components/definition.tsx
@@ -0,0 +1,145 @@
+import * as React from 'react';
+import styled from 'styled-components';
+
+import { Button } from 'ts/components/button';
+import { Icon } from 'ts/components/icon';
+import { Heading, Paragraph } from 'ts/components/text';
+
+export 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/components/dialogs/u2f_not_supported_dialog.tsx b/packages/website/ts/components/dialogs/u2f_not_supported_dialog.tsx
deleted file mode 100644
index bbec1d649..000000000
--- a/packages/website/ts/components/dialogs/u2f_not_supported_dialog.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-import { colors } from '@0x/react-shared';
-import Dialog from 'material-ui/Dialog';
-import FlatButton from 'material-ui/FlatButton';
-import * as React from 'react';
-import { constants } from 'ts/utils/constants';
-
-interface U2fNotSupportedDialogProps {
- isOpen: boolean;
- onToggleDialog: () => void;
-}
-
-export const U2fNotSupportedDialog = (props: U2fNotSupportedDialogProps) => {
- return (
- <Dialog
- title="U2F Not Supported"
- titleStyle={{ fontWeight: 100 }}
- actions={[<FlatButton key="u2fNo" label="Ok" onClick={props.onToggleDialog} />]}
- open={props.isOpen}
- onRequestClose={props.onToggleDialog}
- autoScrollBodyContent={true}
- >
- <div className="pt2" style={{ color: colors.grey700 }}>
- <div>
- It looks like your browser does not support U2F connections required for us to communicate with your
- hardware wallet. Please use a browser that supports U2F connections and try again.
- </div>
- <div>
- <ul>
- <li className="pb1">Chrome version 38 or later</li>
- <li className="pb1">Opera version 40 of later</li>
- <li>
- Firefox with{' '}
- <a
- href={constants.URL_FIREFOX_U2F_ADDON}
- target="_blank"
- style={{ textDecoration: 'underline' }}
- >
- this extension
- </a>.
- </li>
- </ul>
- </div>
- </div>
- </Dialog>
- );
-};
diff --git a/packages/website/ts/components/dialogs/wrapped_eth_section_notice_dialog.tsx b/packages/website/ts/components/dialogs/wrapped_eth_section_notice_dialog.tsx
deleted file mode 100644
index cf2c4dda5..000000000
--- a/packages/website/ts/components/dialogs/wrapped_eth_section_notice_dialog.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import Dialog from 'material-ui/Dialog';
-import FlatButton from 'material-ui/FlatButton';
-import { colors } from 'material-ui/styles';
-import * as React from 'react';
-
-interface WrappedEthSectionNoticeDialogProps {
- isOpen: boolean;
- onToggleDialog: () => void;
-}
-
-export const WrappedEthSectionNoticeDialog = (props: WrappedEthSectionNoticeDialogProps) => {
- return (
- <Dialog
- title="Dedicated Wrapped Ether Section"
- titleStyle={{ fontWeight: 100 }}
- actions={[
- <FlatButton key="acknowledgeWrapEthSection" label="Sounds good" onClick={props.onToggleDialog} />,
- ]}
- open={props.isOpen}
- onRequestClose={props.onToggleDialog}
- autoScrollBodyContent={true}
- modal={true}
- >
- <div className="pt2" style={{ color: colors.grey700 }}>
- <div>
- We have recently updated the Wrapped Ether token (WETH) used by 0x Portal. Don't worry, unwrapping
- Ether tied to the old Wrapped Ether token can be done at any time by clicking on the "Wrap ETH"
- section in the menu to the left.
- </div>
- </div>
- </Dialog>
- );
-};
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/dropdowns/dropdown_developers.tsx b/packages/website/ts/components/dropdowns/dropdown_developers.tsx
new file mode 100644
index 000000000..590d2ead9
--- /dev/null
+++ b/packages/website/ts/components/dropdowns/dropdown_developers.tsx
@@ -0,0 +1,184 @@
+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/components/button';
+import { Column, FlexWrap, WrapGrid } from 'ts/components/newLayout';
+import { ThemeValuesInterface } from 'ts/components/siteWrap';
+import { Heading } from 'ts/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`,
+ },
+ {
+ label: 'Market making',
+ url: `${WebsitePaths.MarketMaker}`,
+ },
+];
+
+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/components/dropdowns/dropdown_products.tsx b/packages/website/ts/components/dropdowns/dropdown_products.tsx
new file mode 100644
index 000000000..93fd1a4fe
--- /dev/null
+++ b/packages/website/ts/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/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/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..3765a32ca 100644
--- a/packages/website/ts/components/footer.tsx
+++ b/packages/website/ts/components/footer.tsx
@@ -1,228 +1,168 @@
-import { ALink, colors, Link } from '@0x/react-shared';
-import { ObjectMap } from '@0x/types';
+import { Link as SmartLink } from '@0x/react-shared';
import * as _ from 'lodash';
-import DropDownMenu from 'material-ui/DropDownMenu';
-import MenuItem from 'material-ui/MenuItem';
import * as React from 'react';
+import MediaQuery from 'react-responsive';
+import styled from 'styled-components';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { Deco, Key, Language, WebsitePaths } from 'ts/types';
+import { Logo } from 'ts/components/logo';
+import { Column, FlexWrap, WrapGrid } from 'ts/components/newLayout';
+import { NewsletterForm } from 'ts/components/newsletter_form';
+import { WebsitePaths } from 'ts/types';
import { constants } from 'ts/utils/constants';
-import { Translate } from 'ts/utils/translate';
-
-const ICON_DIMENSION = 16;
-
-const languageToMenuTitle = {
- [Language.English]: 'English',
- [Language.Russian]: 'Русский',
- [Language.Spanish]: 'Español',
- [Language.Korean]: '한국어',
- [Language.Chinese]: '中文',
-};
-
-export interface FooterProps {
- translate: Translate;
- dispatcher: Dispatcher;
- backgroundColor?: string;
+
+interface LinkInterface {
+ text: string;
+ url: string;
+ shouldOpenInNewTab?: boolean;
+}
+
+interface LinkRows {
+ heading: string;
+ isOnMobile?: boolean;
+ links: LinkInterface[];
}
-interface FooterState {
- selectedLanguage: Language;
+interface LinkListProps {
+ links: LinkInterface[];
}
-export class Footer extends React.Component<FooterProps, FooterState> {
- public static defaultProps = {
- backgroundColor: colors.darkerGrey,
- };
- constructor(props: FooterProps) {
- super(props);
- this.state = {
- selectedLanguage: props.translate.getLanguage(),
- };
+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;
}
- public render(): React.ReactNode {
- const sectionNameToLinks: ObjectMap<ALink[]> = {
- [Key.Documentation]: [
- {
- title: 'Developer Home',
- to: WebsitePaths.Docs,
- },
- {
- title: '0x.js',
- to: WebsitePaths.ZeroExJs,
- },
- {
- title: this.props.translate.get(Key.SmartContracts, Deco.Cap),
- to: WebsitePaths.SmartContracts,
- },
- {
- title: this.props.translate.get(Key.Connect, Deco.Cap),
- to: WebsitePaths.Connect,
- },
- {
- title: this.props.translate.get(Key.Whitepaper, Deco.Cap),
- to: WebsitePaths.Whitepaper,
- shouldOpenInNewTab: true,
- },
- {
- title: this.props.translate.get(Key.Wiki, Deco.Cap),
- to: WebsitePaths.Wiki,
- },
- ],
- [Key.Community]: [
- {
- title: this.props.translate.get(Key.Discord, Deco.Cap),
- to: constants.URL_ZEROEX_CHAT,
- shouldOpenInNewTab: true,
- },
- {
- title: this.props.translate.get(Key.Blog, Deco.Cap),
- to: constants.URL_BLOG,
- shouldOpenInNewTab: true,
- },
- {
- title: 'Twitter',
- to: constants.URL_TWITTER,
- shouldOpenInNewTab: true,
- },
- {
- title: 'Reddit',
- to: constants.URL_REDDIT,
- shouldOpenInNewTab: true,
- },
- {
- title: this.props.translate.get(Key.Forum, Deco.Cap),
- to: constants.URL_DISCOURSE_FORUM,
- shouldOpenInNewTab: true,
- },
- ],
- [Key.Organization]: [
- {
- title: this.props.translate.get(Key.About, Deco.Cap),
- to: WebsitePaths.About,
- },
- {
- title: this.props.translate.get(Key.Careers, Deco.Cap),
- to: WebsitePaths.Careers,
- },
- {
- title: this.props.translate.get(Key.Contact, Deco.Cap),
- to: 'mailto:team@0xproject.com',
- shouldOpenInNewTab: true,
- },
- ],
- };
- const languageMenuItems = _.map(languageToMenuTitle, (menuTitle: string, language: Language) => {
- return <MenuItem key={menuTitle} value={language} primaryText={menuTitle} />;
- });
- return (
- <div className="relative pb4 pt2" style={{ backgroundColor: this.props.backgroundColor }}>
- <div className="mx-auto max-width-4 md-px2 lg-px0 py4 clearfix" style={{ color: colors.white }}>
- <div className="col lg-col-4 md-col-4 col-12 left">
- <div className="sm-mx-auto" style={{ width: 148 }}>
- <div>
- <img src="/images/protocol_logo_white.png" height="30" />
- </div>
- <div
- style={{
- fontSize: 11,
- color: colors.grey,
- paddingLeft: 37,
- paddingTop: 2,
- }}
- >
- © ZeroEx, Intl.
- </div>
- <div className="pt4 center">
- <DropDownMenu
- labelStyle={{ color: colors.white }}
- value={this.state.selectedLanguage}
- onChange={this._updateLanguage.bind(this)}
- >
- {languageMenuItems}
- </DropDownMenu>
- </div>
- </div>
- </div>
- <div className="col lg-col-8 md-col-8 col-12 lg-pl4 md-pl4">
- <div className="col lg-col-4 md-col-4 col-12">
- <div className="lg-right md-right sm-center">
- {this._renderHeader(Key.Documentation)}
- {_.map(sectionNameToLinks[Key.Documentation], this._renderMenuItem.bind(this))}
- </div>
- </div>
- <div className="col lg-col-4 md-col-4 col-12 lg-pr2 md-pr2">
- <div className="lg-right md-right sm-center">
- {this._renderHeader(Key.Community)}
- {_.map(sectionNameToLinks[Key.Community], this._renderMenuItem.bind(this))}
- </div>
- </div>
- <div className="col lg-col-4 md-col-4 col-12">
- <div className="lg-right md-right sm-center">
- {this._renderHeader(Key.Organization)}
- {_.map(sectionNameToLinks[Key.Organization], this._renderMenuItem.bind(this))}
- </div>
- </div>
- </div>
- </div>
- </div>
- );
+`;
+
+const FooterColumn = styled(Column)`
+ @media (min-width: 768px) {
+ width: ${props => props.width};
}
- private _renderIcon(fileName: string): React.ReactNode {
- return (
- <div style={{ height: ICON_DIMENSION, width: ICON_DIMENSION }}>
- <img src={`/images/social/${fileName}`} style={{ width: ICON_DIMENSION }} />
- </div>
- );
+
+ @media (max-width: 768px) {
+ text-align: left;
}
- private _renderMenuItem(link: ALink): React.ReactNode {
- const titleToIcon: { [title: string]: string } = {
- [this.props.translate.get(Key.Discord, Deco.Cap)]: 'discord.png',
- [this.props.translate.get(Key.Blog, Deco.Cap)]: 'medium.png',
- Twitter: 'twitter.png',
- Reddit: 'reddit.png',
- [this.props.translate.get(Key.Forum, Deco.Cap)]: 'discourse.png',
- };
- const iconIfExists = titleToIcon[link.title];
- return (
- <div key={link.title} className="sm-center" style={{ fontSize: 13, paddingTop: 25 }}>
- <Link
- to={link.to}
- shouldOpenInNewTab={link.shouldOpenInNewTab}
- fontColor={colors.white}
- className="text-decoration-none"
- >
- <div>
- {!_.isUndefined(iconIfExists) ? (
- <div className="inline-block">
- <div className="pr1 table-cell">{this._renderIcon(iconIfExists)}</div>
- <div className="table-cell">{link.title}</div>
- </div>
- ) : (
- link.title
- )}
- </div>
- </Link>
- </div>
- );
+`;
+
+const FooterSectionWrap = styled(FooterColumn)`
+ @media (max-width: 768px) {
+ width: 50%;
+
+ & + & {
+ margin-top: 0;
+ margin-bottom: 30px;
+ }
}
- private _renderHeader(key: Key): React.ReactNode {
- const headerStyle = {
- color: colors.grey400,
- letterSpacing: 2,
- fontFamily: 'Roboto Mono',
- fontSize: 13,
- };
- return (
- <div className="lg-pb2 md-pb2 sm-pt4" style={headerStyle}>
- {this.props.translate.get(key, Deco.Upper)}
- </div>
- );
+`;
+
+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;
}
- private _updateLanguage(_event: any, _index: number, value: Language): void {
- this.setState({
- selectedLanguage: value,
- });
- this.props.dispatcher.updateSelectedLanguage(value);
+`;
+
+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/components/forms/subscribe_form.tsx b/packages/website/ts/components/forms/subscribe_form.tsx
deleted file mode 100644
index f5560cfa7..000000000
--- a/packages/website/ts/components/forms/subscribe_form.tsx
+++ /dev/null
@@ -1,127 +0,0 @@
-import { colors } from '@0x/react-shared';
-import * as _ from 'lodash';
-import * as React from 'react';
-
-import { Button } from 'ts/components/ui/button';
-import { Container } from 'ts/components/ui/container';
-import { Input } from 'ts/components/ui/input';
-import { Text } from 'ts/components/ui/text';
-import { analytics } from 'ts/utils/analytics';
-import { backendClient } from 'ts/utils/backend_client';
-
-export interface SubscribeFormProps {}
-
-export enum SubscribeFormStatus {
- None,
- Error,
- Success,
- Loading,
- Other,
-}
-
-export interface SubscribeFormState {
- emailText: string;
- lastSubmittedEmail: string;
- status: SubscribeFormStatus;
-}
-
-const FORM_FONT_SIZE = '15px';
-
-// TODO: Translate visible strings. https://app.asana.com/0/628666249318202/697485674422001
-export class SubscribeForm extends React.Component<SubscribeFormProps, SubscribeFormState> {
- public state = {
- emailText: '',
- lastSubmittedEmail: '',
- status: SubscribeFormStatus.None,
- };
- public render(): React.ReactNode {
- return (
- <Container className="flex flex-column items-center justify-between md-mx2 sm-mx2">
- <Container marginBottom="15px">
- <Text fontFamily="Roboto Mono" fontColor={colors.grey} center={true}>
- Subscribe to our newsletter for 0x relayer and dApp updates
- </Text>
- </Container>
- <form onSubmit={this._handleFormSubmitAsync.bind(this)}>
- <Container className="flex flex-wrap justify-center items-center">
- <Container marginTop="15px">
- <Input
- placeholder="you@email.com"
- value={this.state.emailText}
- fontColor={colors.white}
- fontSize={FORM_FONT_SIZE}
- backgroundColor={colors.projectsGrey}
- width="300px"
- onChange={this._handleEmailInputChange.bind(this)}
- />
- </Container>
- <Container marginLeft="15px" marginTop="15px">
- <Button
- type="submit"
- backgroundColor={colors.darkestGrey}
- fontColor={colors.white}
- fontSize={FORM_FONT_SIZE}
- >
- Subscribe
- </Button>
- </Container>
- </Container>
- </form>
- {this._renderMessage()}
- </Container>
- );
- }
- private _renderMessage(): React.ReactNode {
- let message = null;
- switch (this.state.status) {
- case SubscribeFormStatus.Error:
- message = 'Sorry, something went wrong. Try again later.';
- break;
- case SubscribeFormStatus.Loading:
- message = 'One second...';
- break;
- case SubscribeFormStatus.Success:
- message = `Thanks! ${this.state.lastSubmittedEmail} is now on the mailing list.`;
- break;
- case SubscribeFormStatus.None:
- break;
- default:
- throw new Error(
- 'The SubscribeFormStatus switch statement is not exhaustive when choosing an error message.',
- );
- }
- return (
- <Container isHidden={!message} marginTop="30px">
- <Text center={true} fontFamily="Roboto Mono" fontColor={colors.grey}>
- {message || 'spacer text (never shown to user)'}
- </Text>
- </Container>
- );
- }
- private _handleEmailInputChange(event: React.ChangeEvent<HTMLInputElement>): void {
- this.setState({ emailText: event.target.value });
- }
- private async _handleFormSubmitAsync(event: React.FormEvent<HTMLInputElement>): Promise<void> {
- event.preventDefault();
- if (_.isUndefined(this.state.emailText) || _.isEmpty(this.state.emailText)) {
- return;
- }
- this.setState({
- status: SubscribeFormStatus.Loading,
- lastSubmittedEmail: this.state.emailText,
- });
- try {
- const response = await backendClient.subscribeToNewsletterAsync(this.state.emailText);
- const status = response.status === 200 ? SubscribeFormStatus.Success : SubscribeFormStatus.Error;
- if (status === SubscribeFormStatus.Success) {
- analytics.identify(this.state.emailText, 'email');
- }
- this.setState({ status, emailText: '' });
- } catch (error) {
- this._setStatus(SubscribeFormStatus.Error);
- }
- }
- private _setStatus(status: SubscribeFormStatus): void {
- this.setState({ status });
- }
-}
diff --git a/packages/website/ts/components/hamburger.tsx b/packages/website/ts/components/hamburger.tsx
new file mode 100644
index 000000000..435d206cd
--- /dev/null
+++ b/packages/website/ts/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/components/header.tsx b/packages/website/ts/components/header.tsx
new file mode 100644
index 000000000..90e097070
--- /dev/null
+++ b/packages/website/ts/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/components/button';
+import { DropdownDevelopers } from 'ts/components/dropdowns/dropdown_developers';
+import { DropdownProducts } from 'ts/components/dropdowns/dropdown_products';
+import { Hamburger } from 'ts/components/hamburger';
+import { Logo } from 'ts/components/logo';
+import { MobileNav } from 'ts/components/mobileNav';
+import { FlexWrap } from 'ts/components/newLayout';
+import { ThemeValuesInterface } from 'ts/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/components/hero.tsx b/packages/website/ts/components/hero.tsx
new file mode 100644
index 000000000..a662ee3a5
--- /dev/null
+++ b/packages/website/ts/components/hero.tsx
@@ -0,0 +1,152 @@
+import * as React from 'react';
+import styled from 'styled-components';
+
+import { addFadeInAnimation } from 'ts/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/components/heroAnimation.tsx b/packages/website/ts/components/heroAnimation.tsx
new file mode 100644
index 000000000..42956fb6a
--- /dev/null
+++ b/packages/website/ts/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/components/heroImage.tsx b/packages/website/ts/components/heroImage.tsx
new file mode 100644
index 000000000..af7c055ac
--- /dev/null
+++ b/packages/website/ts/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/components/icon.tsx b/packages/website/ts/components/icon.tsx
new file mode 100644
index 000000000..165e999b9
--- /dev/null
+++ b/packages/website/ts/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/components/text';
+import { getCSSPadding, PaddingInterface } from 'ts/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/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/components/image.tsx b/packages/website/ts/components/image.tsx
new file mode 100644
index 000000000..65b2a9705
--- /dev/null
+++ b/packages/website/ts/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/components/link.tsx b/packages/website/ts/components/link.tsx
new file mode 100644
index 000000000..080a0abcc
--- /dev/null
+++ b/packages/website/ts/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/components/logo.tsx b/packages/website/ts/components/logo.tsx
new file mode 100644
index 000000000..19aeb901e
--- /dev/null
+++ b/packages/website/ts/components/logo.tsx
@@ -0,0 +1,41 @@
+import * as React from 'react';
+import styled from 'styled-components';
+
+import { ThemeInterface } from 'ts/components/siteWrap';
+import LogoIcon from 'ts/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/components/mobileNav.tsx b/packages/website/ts/components/mobileNav.tsx
new file mode 100644
index 000000000..573d21596
--- /dev/null
+++ b/packages/website/ts/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/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/components/modals/input.tsx b/packages/website/ts/components/modals/input.tsx
new file mode 100644
index 000000000..8cfcc9763
--- /dev/null
+++ b/packages/website/ts/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/components/modals/modal_contact.tsx b/packages/website/ts/components/modals/modal_contact.tsx
new file mode 100644
index 000000000..a3a1f13f5
--- /dev/null
+++ b/packages/website/ts/components/modals/modal_contact.tsx
@@ -0,0 +1,395 @@
+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/components/button';
+import { Icon } from 'ts/components/icon';
+import { Input, InputWidth } from 'ts/components/modals/input';
+import { Heading, Paragraph } from 'ts/components/text';
+import { GlobalStyle } from 'ts/constants/globalStyle';
+
+export enum ModalContactType {
+ General = 'GENERAL',
+ MarketMaker = 'MARKET_MAKER',
+}
+
+interface Props {
+ theme?: GlobalStyle;
+ isOpen?: boolean;
+ onDismiss?: () => void;
+ modalContactType: ModalContactType;
+}
+
+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 static defaultProps = {
+ modalContactType: ModalContactType.General,
+ };
+ public state = {
+ isSubmitting: false,
+ isSuccessful: false,
+ errors: {},
+ };
+ // shared fields
+ public nameRef: React.RefObject<HTMLInputElement> = React.createRef();
+ public emailRef: React.RefObject<HTMLInputElement> = React.createRef();
+ public companyProjectRef: React.RefObject<HTMLInputElement> = React.createRef();
+ public commentsRef: React.RefObject<HTMLInputElement> = React.createRef();
+ // general lead fields
+ public linkRef: React.RefObject<HTMLInputElement> = React.createRef();
+ // market maker lead fields
+ public countryRef: React.RefObject<HTMLInputElement> = React.createRef();
+ public fundSizeRef: 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>
+ {this._renderFormContent(errors)}
+ <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>
+ </>
+ );
+ }
+ public _renderFormContent(errors: ErrorProps): React.ReactNode {
+ switch (this.props.modalContactType) {
+ case ModalContactType.MarketMaker:
+ return this._renderMarketMakerFormContent(errors);
+ case ModalContactType.General:
+ default:
+ return this._renderGeneralFormContent(errors);
+ }
+ }
+ private _renderMarketMakerFormContent(errors: ErrorProps): React.ReactNode {
+ return (
+ <>
+ <Paragraph isMuted={true} color={colors.textDarkPrimary}>
+ If you’re considering market making 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="country"
+ label="Country of Location"
+ type="text"
+ ref={this.countryRef}
+ required={true}
+ errors={errors}
+ />
+ </InputRow>
+ <InputRow>
+ <Input
+ name="fundSize"
+ label="Fund Size"
+ type="text"
+ ref={this.fundSizeRef}
+ required={true}
+ errors={errors}
+ />
+ </InputRow>
+ <InputRow>
+ <Input
+ name="companyOrProject"
+ label="Name of your project / company"
+ type="text"
+ ref={this.companyProjectRef}
+ required={false}
+ errors={errors}
+ />
+ </InputRow>
+ <InputRow>
+ <Input
+ name="comments"
+ label="What is prompting you to reach out?"
+ type="textarea"
+ ref={this.commentsRef}
+ required={false}
+ errors={errors}
+ />
+ </InputRow>
+ </>
+ );
+ }
+ private _renderGeneralFormContent(errors: ErrorProps): React.ReactNode {
+ return (
+ <>
+ <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>
+ </>
+ );
+ }
+ private async _onSubmitAsync(e: Event): Promise<void> {
+ e.preventDefault();
+
+ let jsonBody;
+ if (this.props.modalContactType === ModalContactType.MarketMaker) {
+ jsonBody = {
+ name: this.nameRef.current.value,
+ email: this.emailRef.current.value,
+ country: this.countryRef.current.value,
+ fundSize: this.fundSizeRef.current.value,
+ projectOrCompany: this.companyProjectRef.current.value,
+ comments: this.commentsRef.current.value,
+ };
+ } else {
+ jsonBody = {
+ name: this.nameRef.current.value,
+ email: this.emailRef.current.value,
+ projectOrCompany: this.companyProjectRef.current.value,
+ link: this.linkRef.current.value,
+ comments: this.commentsRef.current.value,
+ };
+ }
+
+ this.setState({ ...this.state, errors: [], isSubmitting: true });
+
+ const endpoint =
+ this.props.modalContactType === ModalContactType.MarketMaker ? '/market_maker_leads' : '/leads';
+
+ 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${endpoint}`, {
+ method: 'post',
+ mode: 'cors',
+ credentials: 'same-origin',
+ headers: {
+ 'content-type': 'application/json; charset=utf-8',
+ },
+ body: JSON.stringify(_.omitBy(jsonBody, _.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/components/newLayout.tsx b/packages/website/ts/components/newLayout.tsx
new file mode 100644
index 000000000..28e7653c5
--- /dev/null
+++ b/packages/website/ts/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/components/newsletter_form.tsx b/packages/website/ts/components/newsletter_form.tsx
new file mode 100644
index 000000000..4a7abb7ec
--- /dev/null
+++ b/packages/website/ts/components/newsletter_form.tsx
@@ -0,0 +1,202 @@
+import * as React from 'react';
+import styled, { withTheme } from 'styled-components';
+
+import { ThemeValuesInterface } from 'ts/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/components/old_footer.tsx b/packages/website/ts/components/old_footer.tsx
new file mode 100644
index 000000000..6366bf4ea
--- /dev/null
+++ b/packages/website/ts/components/old_footer.tsx
@@ -0,0 +1,228 @@
+import { ALink, colors, Link } from '@0x/react-shared';
+import { ObjectMap } from '@0x/types';
+import * as _ from 'lodash';
+import DropDownMenu from 'material-ui/DropDownMenu';
+import MenuItem from 'material-ui/MenuItem';
+import * as React from 'react';
+
+import { Dispatcher } from 'ts/redux/dispatcher';
+import { Deco, Key, Language, WebsitePaths } from 'ts/types';
+import { constants } from 'ts/utils/constants';
+import { Translate } from 'ts/utils/translate';
+
+const ICON_DIMENSION = 16;
+
+const languageToMenuTitle = {
+ [Language.English]: 'English',
+ [Language.Russian]: 'Русский',
+ [Language.Spanish]: 'Español',
+ [Language.Korean]: '한국어',
+ [Language.Chinese]: '中文',
+};
+
+export interface FooterProps {
+ translate: Translate;
+ dispatcher: Dispatcher;
+ backgroundColor?: string;
+}
+
+interface FooterState {
+ selectedLanguage: Language;
+}
+
+export class Footer extends React.Component<FooterProps, FooterState> {
+ public static defaultProps = {
+ backgroundColor: colors.darkerGrey,
+ };
+ constructor(props: FooterProps) {
+ super(props);
+ this.state = {
+ selectedLanguage: props.translate.getLanguage(),
+ };
+ }
+ public render(): React.ReactNode {
+ const sectionNameToLinks: ObjectMap<ALink[]> = {
+ [Key.Documentation]: [
+ {
+ title: 'Developer Home',
+ to: WebsitePaths.Docs,
+ },
+ {
+ title: '0x.js',
+ to: WebsitePaths.ZeroExJs,
+ },
+ {
+ title: this.props.translate.get(Key.SmartContracts, Deco.Cap),
+ to: WebsitePaths.SmartContracts,
+ },
+ {
+ title: this.props.translate.get(Key.Connect, Deco.Cap),
+ to: WebsitePaths.Connect,
+ },
+ {
+ title: this.props.translate.get(Key.Whitepaper, Deco.Cap),
+ to: WebsitePaths.Whitepaper,
+ shouldOpenInNewTab: true,
+ },
+ {
+ title: this.props.translate.get(Key.Wiki, Deco.Cap),
+ to: WebsitePaths.Wiki,
+ },
+ ],
+ [Key.Community]: [
+ {
+ title: this.props.translate.get(Key.Discord, Deco.Cap),
+ to: constants.URL_ZEROEX_CHAT,
+ shouldOpenInNewTab: true,
+ },
+ {
+ title: this.props.translate.get(Key.Blog, Deco.Cap),
+ to: constants.URL_BLOG,
+ shouldOpenInNewTab: true,
+ },
+ {
+ title: 'Twitter',
+ to: constants.URL_TWITTER,
+ shouldOpenInNewTab: true,
+ },
+ {
+ title: 'Reddit',
+ to: constants.URL_REDDIT,
+ shouldOpenInNewTab: true,
+ },
+ {
+ title: this.props.translate.get(Key.Forum, Deco.Cap),
+ to: constants.URL_DISCOURSE_FORUM,
+ shouldOpenInNewTab: true,
+ },
+ ],
+ [Key.Organization]: [
+ {
+ title: this.props.translate.get(Key.About, Deco.Cap),
+ to: WebsitePaths.About,
+ },
+ {
+ title: this.props.translate.get(Key.Careers, Deco.Cap),
+ to: WebsitePaths.Careers,
+ },
+ {
+ title: this.props.translate.get(Key.Contact, Deco.Cap),
+ to: 'mailto:team@0x.org',
+ shouldOpenInNewTab: true,
+ },
+ ],
+ };
+ const languageMenuItems = _.map(languageToMenuTitle, (menuTitle: string, language: Language) => {
+ return <MenuItem key={menuTitle} value={language} primaryText={menuTitle} />;
+ });
+ return (
+ <div className="relative pb4 pt2" style={{ backgroundColor: this.props.backgroundColor }}>
+ <div className="mx-auto max-width-4 md-px2 lg-px0 py4 clearfix" style={{ color: colors.white }}>
+ <div className="col lg-col-4 md-col-4 col-12 left">
+ <div className="sm-mx-auto" style={{ width: 148 }}>
+ <div>
+ <img src="/images/protocol_logo_white.png" height="30" />
+ </div>
+ <div
+ style={{
+ fontSize: 11,
+ color: colors.grey,
+ paddingLeft: 37,
+ paddingTop: 2,
+ }}
+ >
+ © ZeroEx, Intl.
+ </div>
+ <div className="pt4 center">
+ <DropDownMenu
+ labelStyle={{ color: colors.white }}
+ value={this.state.selectedLanguage}
+ onChange={this._updateLanguage.bind(this)}
+ >
+ {languageMenuItems}
+ </DropDownMenu>
+ </div>
+ </div>
+ </div>
+ <div className="col lg-col-8 md-col-8 col-12 lg-pl4 md-pl4">
+ <div className="col lg-col-4 md-col-4 col-12">
+ <div className="lg-right md-right sm-center">
+ {this._renderHeader(Key.Documentation)}
+ {_.map(sectionNameToLinks[Key.Documentation], this._renderMenuItem.bind(this))}
+ </div>
+ </div>
+ <div className="col lg-col-4 md-col-4 col-12 lg-pr2 md-pr2">
+ <div className="lg-right md-right sm-center">
+ {this._renderHeader(Key.Community)}
+ {_.map(sectionNameToLinks[Key.Community], this._renderMenuItem.bind(this))}
+ </div>
+ </div>
+ <div className="col lg-col-4 md-col-4 col-12">
+ <div className="lg-right md-right sm-center">
+ {this._renderHeader(Key.Organization)}
+ {_.map(sectionNameToLinks[Key.Organization], this._renderMenuItem.bind(this))}
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ );
+ }
+ private _renderIcon(fileName: string): React.ReactNode {
+ return (
+ <div style={{ height: ICON_DIMENSION, width: ICON_DIMENSION }}>
+ <img src={`/images/social/${fileName}`} style={{ width: ICON_DIMENSION }} />
+ </div>
+ );
+ }
+ private _renderMenuItem(link: ALink): React.ReactNode {
+ const titleToIcon: { [title: string]: string } = {
+ [this.props.translate.get(Key.Discord, Deco.Cap)]: 'discord.png',
+ [this.props.translate.get(Key.Blog, Deco.Cap)]: 'medium.png',
+ Twitter: 'twitter.png',
+ Reddit: 'reddit.png',
+ [this.props.translate.get(Key.Forum, Deco.Cap)]: 'discourse.png',
+ };
+ const iconIfExists = titleToIcon[link.title];
+ return (
+ <div key={link.title} className="sm-center" style={{ fontSize: 13, paddingTop: 25 }}>
+ <Link
+ to={link.to}
+ shouldOpenInNewTab={link.shouldOpenInNewTab}
+ fontColor={colors.white}
+ className="text-decoration-none"
+ >
+ <div>
+ {!_.isUndefined(iconIfExists) ? (
+ <div className="inline-block">
+ <div className="pr1 table-cell">{this._renderIcon(iconIfExists)}</div>
+ <div className="table-cell">{link.title}</div>
+ </div>
+ ) : (
+ link.title
+ )}
+ </div>
+ </Link>
+ </div>
+ );
+ }
+ private _renderHeader(key: Key): React.ReactNode {
+ const headerStyle = {
+ color: colors.grey400,
+ letterSpacing: 2,
+ fontFamily: 'Roboto Mono',
+ fontSize: 13,
+ };
+ return (
+ <div className="lg-pb2 md-pb2 sm-pt4" style={headerStyle}>
+ {this.props.translate.get(key, Deco.Upper)}
+ </div>
+ );
+ }
+ private _updateLanguage(_event: any, _index: number, value: Language): void {
+ this.setState({
+ selectedLanguage: value,
+ });
+ this.props.dispatcher.updateSelectedLanguage(value);
+ }
+}
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/redirector.tsx b/packages/website/ts/components/redirector.tsx
deleted file mode 100644
index a02693003..000000000
--- a/packages/website/ts/components/redirector.tsx
+++ /dev/null
@@ -1,9 +0,0 @@
-import { constants } from 'ts/utils/constants';
-
-interface RedirectorProps {
- location: string;
-}
-
-export function Redirector(_props: RedirectorProps): void {
- window.location.href = constants.URL_ANGELLIST;
-}
diff --git a/packages/website/ts/components/sections/landing/about.tsx b/packages/website/ts/components/sections/landing/about.tsx
new file mode 100644
index 000000000..9c369d83a
--- /dev/null
+++ b/packages/website/ts/components/sections/landing/about.tsx
@@ -0,0 +1,81 @@
+import * as React from 'react';
+import styled from 'styled-components';
+
+import { Button } from 'ts/components/button';
+import { Icon, InlineIconWrap } from 'ts/components/icon';
+import { Column, FlexWrap, Section } from 'ts/components/newLayout';
+import { Paragraph } from 'ts/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/components/sections/landing/clients.tsx b/packages/website/ts/components/sections/landing/clients.tsx
new file mode 100644
index 000000000..9a68fbf4c
--- /dev/null
+++ b/packages/website/ts/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/components/text';
+
+import { Section, WrapGrid } from 'ts/components/newLayout';
+
+interface ProjectLogo {
+ name: string;
+ imageUrl?: string;
+ persistOnMobile?: boolean;
+}
+
+interface StyledProjectInterface {
+ isOnMobile?: boolean;
+}
+
+const projects: ProjectLogo[] = [
+ {
+ name: 'Radar Relay',
+ imageUrl: 'images/clients/radar-relay.svg',
+ persistOnMobile: true,
+ },
+ {
+ name: 'Paradex',
+ imageUrl: 'images/clients/paradex.svg',
+ persistOnMobile: true,
+ },
+ {
+ name: 'Star Bit Ex',
+ imageUrl: 'images/clients/starbitex.svg',
+ },
+ {
+ name: 'LedgerDex',
+ imageUrl: 'images/clients/ledgerdex.svg',
+ },
+ {
+ name: 'OpenRelay',
+ imageUrl: 'images/clients/openrelay.svg',
+ persistOnMobile: true,
+ },
+ {
+ name: 'Bamboo Relay',
+ imageUrl: 'images/clients/bamboo.svg',
+ persistOnMobile: true,
+ },
+ {
+ name: 'dEX',
+ imageUrl: 'images/clients/ercdex.svg',
+ persistOnMobile: true,
+ },
+ {
+ name: 'emoon',
+ imageUrl: 'images/clients/emoon.svg',
+ persistOnMobile: true,
+ },
+ {
+ name: 'Gods Unchained',
+ imageUrl: 'images/clients/godsUnchained.svg',
+ },
+ {
+ name: 'Instex',
+ imageUrl: 'images/clients/instex.svg',
+ },
+ {
+ name: 'Lake Trade',
+ imageUrl: 'images/clients/laketrade.svg',
+ },
+ {
+ name: 'Veil',
+ imageUrl: 'images/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/components/sections/landing/cta.tsx b/packages/website/ts/components/sections/landing/cta.tsx
new file mode 100644
index 000000000..ec5a58a58
--- /dev/null
+++ b/packages/website/ts/components/sections/landing/cta.tsx
@@ -0,0 +1,29 @@
+import * as React from 'react';
+
+import { BlockIconLink } from 'ts/components/blockIconLink';
+import { Section } from 'ts/components/newLayout';
+
+import { AnimatedChatIcon } from 'ts/components/animatedChatIcon';
+import { AnimatedCompassIcon } from 'ts/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/components/sections/landing/hero.tsx b/packages/website/ts/components/sections/landing/hero.tsx
new file mode 100644
index 000000000..489757286
--- /dev/null
+++ b/packages/website/ts/components/sections/landing/hero.tsx
@@ -0,0 +1,31 @@
+import * as React from 'react';
+
+import { Button } from 'ts/components/button';
+import { Hero } from 'ts/components/hero';
+import { LandingAnimation } from 'ts/components/heroImage';
+
+import { HeroAnimation } from 'ts/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/components/siteWrap.tsx b/packages/website/ts/components/siteWrap.tsx
new file mode 100644
index 000000000..316896dbb
--- /dev/null
+++ b/packages/website/ts/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/components/footer';
+import { Header } from 'ts/components/header';
+import { GlobalStyles } from 'ts/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/components/slider/slider.tsx b/packages/website/ts/components/slider/slider.tsx
new file mode 100644
index 000000000..f0a29f894
--- /dev/null
+++ b/packages/website/ts/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/components/icon';
+import { Heading, Paragraph } from 'ts/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/components/text.tsx b/packages/website/ts/components/text.tsx
new file mode 100644
index 000000000..10f272e73
--- /dev/null
+++ b/packages/website/ts/components/text.tsx
@@ -0,0 +1,83 @@
+import * as React from 'react';
+import styled from 'styled-components';
+import { getCSSPadding, PaddingInterface } from 'ts/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/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/filled_image.tsx b/packages/website/ts/components/ui/filled_image.tsx
deleted file mode 100644
index 7f58ee5b9..000000000
--- a/packages/website/ts/components/ui/filled_image.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import * as React from 'react';
-
-export interface FilledImageProps {
- src: string;
-}
-export const FilledImage = (props: FilledImageProps) => (
- <div
- style={{
- width: '100%',
- height: '100%',
- objectFit: 'cover',
- backgroundImage: `url(${props.src})`,
- backgroundRepeat: 'no-repeat',
- backgroundPosition: 'center',
- backgroundSize: 'cover',
- }}
- />
-);
diff --git a/packages/website/ts/components/ui/input.tsx b/packages/website/ts/components/ui/input.tsx
deleted file mode 100644
index d21b9fd0e..000000000
--- a/packages/website/ts/components/ui/input.tsx
+++ /dev/null
@@ -1,49 +0,0 @@
-import { colors } from '@0x/react-shared';
-import * as React from 'react';
-import { styled } from 'ts/style/theme';
-
-export interface InputProps {
- className?: string;
- value?: string;
- width?: string;
- fontSize?: string;
- fontColor?: string;
- border?: string;
- padding?: string;
- placeholderColor?: string;
- placeholder?: string;
- backgroundColor?: string;
- onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
-}
-
-const PlainInput: React.StatelessComponent<InputProps> = ({ value, className, placeholder, onChange }) => (
- <input className={className} value={value} onChange={onChange} placeholder={placeholder} />
-);
-
-export const Input = styled(PlainInput)`
- font-size: ${props => props.fontSize};
- width: ${props => props.width};
- padding: ${props => props.padding};
- border-radius: 3px;
- box-sizing: border-box;
- font-family: 'Roboto Mono';
- color: ${props => props.fontColor};
- border: ${props => props.border};
- outline: none;
- background-color: ${props => props.backgroundColor};
- &::placeholder {
- color: ${props => props.placeholderColor};
- }
-`;
-
-Input.defaultProps = {
- width: 'auto',
- backgroundColor: colors.white,
- fontColor: colors.darkestGrey,
- placeholderColor: colors.darkGrey,
- fontSize: '12px',
- border: 'none',
- padding: '0.8em 1.2em',
-};
-
-Input.displayName = 'Input';
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/simple_loading.tsx b/packages/website/ts/components/ui/simple_loading.tsx
deleted file mode 100644
index 81744196d..000000000
--- a/packages/website/ts/components/ui/simple_loading.tsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import CircularProgress from 'material-ui/CircularProgress';
-import * as React from 'react';
-
-export interface SimpleLoadingProps {
- message: string;
-}
-
-export const SimpleLoading = (props: SimpleLoadingProps) => {
- return (
- <div className="mx-auto pt3" style={{ maxWidth: 400, height: 409 }}>
- <div className="relative" style={{ top: '50%', transform: 'translateY(-50%)', height: 95 }}>
- <CircularProgress />
- <div className="pt3 pb3">{props.message}</div>
- </div>
- </div>
- );
-};
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/components/ui/typed_text.tsx b/packages/website/ts/components/ui/typed_text.tsx
deleted file mode 100644
index 6d38580b9..000000000
--- a/packages/website/ts/components/ui/typed_text.tsx
+++ /dev/null
@@ -1,75 +0,0 @@
-import * as _ from 'lodash';
-import * as React from 'react';
-import Typist from 'react-typist';
-
-import { Text, TextProps } from 'ts/components/ui/text';
-
-import 'react-typist/dist/Typist.css';
-
-export interface TypedTextProps extends TextProps {
- textList: string[];
- shouldRepeat?: boolean;
- wordDelayMs?: number;
- avgKeystrokeDelayMs?: number;
- stdKeystrokeDelay?: number;
-}
-
-export interface TypedTextState {
- cycleCount: number;
-}
-
-export class TypedText extends React.Component<TypedTextProps, TypedTextState> {
- public static defaultProps = {
- shouldRepeat: false,
- avgKeystrokeDelayMs: 90,
- wordDelayMs: 1000,
- };
- public state = {
- cycleCount: 0,
- };
- public render(): React.ReactNode {
- const {
- textList,
- shouldRepeat,
- wordDelayMs,
- avgKeystrokeDelayMs,
- stdKeystrokeDelay,
- // tslint:disable-next-line
- ...textProps
- } = this.props;
- const { cycleCount } = this.state;
- if (_.isEmpty(textList)) {
- return null;
- }
- const typistChildren: React.ReactNode[] = [];
- _.forEach(textList, text => {
- typistChildren.push(
- <Text key={`text-${text}-${cycleCount}`} {...textProps}>
- {text}
- </Text>,
- );
- if (wordDelayMs) {
- typistChildren.push(<Typist.Delay key={`delay-${text}-${cycleCount}`} ms={wordDelayMs} />);
- }
- typistChildren.push(<Typist.Backspace key={`backspace-${text}-${cycleCount}`} count={text.length} />);
- });
- return (
- <Typist
- avgTypingDelay={avgKeystrokeDelayMs}
- stdTypingDelay={stdKeystrokeDelay}
- className="inline"
- key={`typist-key-${cycleCount}`}
- onTypingDone={this._onTypingDone.bind(this)}
- >
- {typistChildren}
- </Typist>
- );
- }
- private _onTypingDone(): void {
- if (this.props.shouldRepeat) {
- this.setState({
- cycleCount: this.state.cycleCount + 1,
- });
- }
- }
-}
diff --git a/python-packages/order_utils/stubs/jsonschema/exceptions.pyi b/packages/website/ts/constants/.gitkeep
index e69de29bb..e69de29bb 100644
--- a/python-packages/order_utils/stubs/jsonschema/exceptions.pyi
+++ b/packages/website/ts/constants/.gitkeep
diff --git a/packages/website/ts/constants/animations.tsx b/packages/website/ts/constants/animations.tsx
new file mode 100644
index 000000000..6a58c4b40
--- /dev/null
+++ b/packages/website/ts/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/constants/cssReset.js b/packages/website/ts/constants/cssReset.js
new file mode 100644
index 000000000..4c5105b50
--- /dev/null
+++ b/packages/website/ts/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/constants/globalStyle.tsx b/packages/website/ts/constants/globalStyle.tsx
new file mode 100644
index 000000000..5abb758c5
--- /dev/null
+++ b/packages/website/ts/constants/globalStyle.tsx
@@ -0,0 +1,109 @@
+import { createGlobalStyle, withTheme } from 'styled-components';
+import { cssReset } from 'ts/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/constants/utilities.tsx b/packages/website/ts/constants/utilities.tsx
new file mode 100644
index 000000000..ee5c5b4ce
--- /dev/null
+++ b/packages/website/ts/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/containers/about.ts b/packages/website/ts/containers/about.ts
deleted file mode 100644
index 3b1c99d79..000000000
--- a/packages/website/ts/containers/about.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import * as React from 'react';
-import { connect } from 'react-redux';
-import { Dispatch } from 'redux';
-import { About as AboutComponent, AboutProps } from 'ts/pages/about/about';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { State } from 'ts/redux/reducer';
-import { Translate } from 'ts/utils/translate';
-
-interface ConnectedState {
- translate: Translate;
-}
-
-interface ConnectedDispatch {
- dispatcher: Dispatcher;
-}
-
-const mapStateToProps = (state: State, _ownProps: AboutProps): ConnectedState => ({
- translate: state.translate,
-});
-
-const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({
- dispatcher: new Dispatcher(dispatch),
-});
-
-export const About: React.ComponentClass<AboutProps> = connect(mapStateToProps, mapDispatchToProps)(AboutComponent);
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/jobs.ts b/packages/website/ts/containers/jobs.ts
deleted file mode 100644
index b18485882..000000000
--- a/packages/website/ts/containers/jobs.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import * as React from 'react';
-import { connect } from 'react-redux';
-import { Dispatch } from 'redux';
-import { Jobs as JobsComponent, JobsProps } from 'ts/pages/jobs/jobs';
-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: JobsProps): ConnectedState => ({
- translate: state.translate,
- screenWidth: state.screenWidth,
-});
-
-const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({
- dispatcher: new Dispatcher(dispatch),
-});
-
-export const Jobs: React.ComponentClass<JobsProps> = connect(mapStateToProps, mapDispatchToProps)(JobsComponent);
diff --git a/packages/website/ts/containers/landing.ts b/packages/website/ts/containers/landing.ts
deleted file mode 100644
index 972ed4c23..000000000
--- a/packages/website/ts/containers/landing.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import * as React from 'react';
-import { connect } from 'react-redux';
-import { Dispatch } from 'redux';
-import { Landing as LandingComponent, LandingProps } from 'ts/pages/landing/landing';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { State } from 'ts/redux/reducer';
-import { Translate } from 'ts/utils/translate';
-
-interface ConnectedState {
- translate: Translate;
-}
-
-interface ConnectedDispatch {
- dispatcher: Dispatcher;
-}
-
-const mapStateToProps = (state: State, _ownProps: LandingProps): ConnectedState => ({
- translate: state.translate,
-});
-
-const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({
- dispatcher: new Dispatcher(dispatch),
-});
-
-export const Landing: React.ComponentClass<LandingProps> = connect(mapStateToProps, mapDispatchToProps)(
- LandingComponent,
-);
diff --git a/packages/website/ts/containers/launch_kit.ts b/packages/website/ts/containers/launch_kit.ts
deleted file mode 100644
index 2557f38a5..000000000
--- a/packages/website/ts/containers/launch_kit.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import * as React from 'react';
-import { connect } from 'react-redux';
-import { Dispatch } from 'redux';
-import { LaunchKit as LaunchKitComponent, LaunchKitProps } from 'ts/pages/launch_kit/launch_kit';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { State } from 'ts/redux/reducer';
-import { Translate } from 'ts/utils/translate';
-
-interface ConnectedState {
- translate: Translate;
-}
-
-interface ConnectedDispatch {
- dispatcher: Dispatcher;
-}
-
-const mapStateToProps = (state: State, _ownProps: LaunchKitProps): ConnectedState => ({
- translate: state.translate,
-});
-
-const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({
- dispatcher: new Dispatcher(dispatch),
-});
-
-export const LaunchKit: React.ComponentClass<LaunchKitProps> = connect(mapStateToProps, mapDispatchToProps)(
- LaunchKitComponent,
-);
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/icons/illustrations/0x.svg b/packages/website/ts/icons/illustrations/0x.svg
new file mode 100755
index 000000000..b0810f751
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/buildBusiness.svg b/packages/website/ts/icons/illustrations/buildBusiness.svg
new file mode 100755
index 000000000..48e5b3b1c
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/checkmark.svg b/packages/website/ts/icons/illustrations/checkmark.svg
new file mode 100644
index 000000000..e17a7ab8b
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/code-repo.svg b/packages/website/ts/icons/illustrations/code-repo.svg
new file mode 100644
index 000000000..43e412198
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/coin.svg b/packages/website/ts/icons/illustrations/coin.svg
new file mode 100644
index 000000000..a1fb123a4
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/consistently-ship.svg b/packages/website/ts/icons/illustrations/consistently-ship.svg
new file mode 100644
index 000000000..733655a3f
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/customize.svg b/packages/website/ts/icons/illustrations/customize.svg
new file mode 100644
index 000000000..1f018ee7a
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/decentralisedLoans.svg b/packages/website/ts/icons/illustrations/decentralisedLoans.svg
new file mode 100755
index 000000000..72d0de7fc
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/description.svg b/packages/website/ts/icons/illustrations/description.svg
new file mode 100755
index 000000000..1887b182e
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/descriptionBolt.svg b/packages/website/ts/icons/illustrations/descriptionBolt.svg
new file mode 100755
index 000000000..45e51240f
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/descriptionCoin.svg b/packages/website/ts/icons/illustrations/descriptionCoin.svg
new file mode 100755
index 000000000..d1015b98d
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/descriptionCopy.svg b/packages/website/ts/icons/illustrations/descriptionCopy.svg
new file mode 100755
index 000000000..6c9b5f0fc
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/descriptionFlask.svg b/packages/website/ts/icons/illustrations/descriptionFlask.svg
new file mode 100755
index 000000000..703b069d5
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/eficientDesign.svg b/packages/website/ts/icons/illustrations/eficientDesign.svg
new file mode 100755
index 000000000..6b8f852c3
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/eth-based-tokens.svg b/packages/website/ts/icons/illustrations/eth-based-tokens.svg
new file mode 100644
index 000000000..b0370d234
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/extensibleArchitecture.svg b/packages/website/ts/icons/illustrations/extensibleArchitecture.svg
new file mode 100755
index 000000000..7674b3289
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/flexibleIntegration.svg b/packages/website/ts/icons/illustrations/flexibleIntegration.svg
new file mode 100755
index 000000000..dee44d4c0
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/flexibleIntegration0xInstant.svg b/packages/website/ts/icons/illustrations/flexibleIntegration0xInstant.svg
new file mode 100755
index 000000000..bb5116b8b
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/flexibleOrders.svg b/packages/website/ts/icons/illustrations/flexibleOrders.svg
new file mode 100755
index 000000000..f4545ae38
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/gamingAndCollectibles.svg b/packages/website/ts/icons/illustrations/gamingAndCollectibles.svg
new file mode 100755
index 000000000..c66af5088
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/generateRevenueForYourBusiness-large.svg b/packages/website/ts/icons/illustrations/generateRevenueForYourBusiness-large.svg
new file mode 100755
index 000000000..681b8c41e
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/getInTouch.svg b/packages/website/ts/icons/illustrations/getInTouch.svg
new file mode 100755
index 000000000..f44365351
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/getStarted.svg b/packages/website/ts/icons/illustrations/getStarted.svg
new file mode 100644
index 000000000..627e1810b
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/launchKit.svg b/packages/website/ts/icons/illustrations/launchKit.svg
new file mode 100644
index 000000000..fa11584af
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/launchKit_versionB.svg b/packages/website/ts/icons/illustrations/launchKit_versionB.svg
new file mode 100755
index 000000000..45f9ecc75
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/legalResources.svg b/packages/website/ts/icons/illustrations/legalResources.svg
new file mode 100755
index 000000000..a8ba7fceb
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/logo-mark.svg b/packages/website/ts/icons/illustrations/logo-mark.svg
new file mode 100644
index 000000000..4e9c9d2cb
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/logo-outlined.svg b/packages/website/ts/icons/illustrations/logo-outlined.svg
new file mode 100644
index 000000000..a09d2355f
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/long-term-impact.svg b/packages/website/ts/icons/illustrations/long-term-impact.svg
new file mode 100644
index 000000000..dbd051598
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/low-cost.svg b/packages/website/ts/icons/illustrations/low-cost.svg
new file mode 100644
index 000000000..530cbdd79
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/marketingDesignHelp.svg b/packages/website/ts/icons/illustrations/marketingDesignHelp.svg
new file mode 100755
index 000000000..1e65bd54f
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/milestoneGrants.svg b/packages/website/ts/icons/illustrations/milestoneGrants.svg
new file mode 100755
index 000000000..2c581864f
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/networkedLiquidity-small.svg b/packages/website/ts/icons/illustrations/networkedLiquidity-small.svg
new file mode 100755
index 000000000..4b65a5353
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/networkedLiquidity.svg b/packages/website/ts/icons/illustrations/networkedLiquidity.svg
new file mode 100755
index 000000000..c50ba7e7c
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/orderBooks.svg b/packages/website/ts/icons/illustrations/orderBooks.svg
new file mode 100755
index 000000000..44e001ff0
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/predictionMarkets.svg b/packages/website/ts/icons/illustrations/predictionMarkets.svg
new file mode 100755
index 000000000..820b79416
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/protocol.svg b/packages/website/ts/icons/illustrations/protocol.svg
new file mode 100644
index 000000000..5c9c1531a
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/ready-to-build.svg b/packages/website/ts/icons/illustrations/ready-to-build.svg
new file mode 100644
index 000000000..a26a4e236
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/recruitingSupport.svg b/packages/website/ts/icons/illustrations/recruitingSupport.svg
new file mode 100755
index 000000000..d630b23d7
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/right-thing.svg b/packages/website/ts/icons/illustrations/right-thing.svg
new file mode 100644
index 000000000..eba2bbc36
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/robustSmartContracts.svg b/packages/website/ts/icons/illustrations/robustSmartContracts.svg
new file mode 100755
index 000000000..060f2d00c
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/rocketship.svg b/packages/website/ts/icons/illustrations/rocketship.svg
new file mode 100644
index 000000000..e9b4b83ab
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/secureTrading.svg b/packages/website/ts/icons/illustrations/secureTrading.svg
new file mode 100755
index 000000000..21912961d
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/social-discord.svg b/packages/website/ts/icons/illustrations/social-discord.svg
new file mode 100644
index 000000000..144f6e061
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/social-fb.svg b/packages/website/ts/icons/illustrations/social-fb.svg
new file mode 100644
index 000000000..e50cf107a
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/social-github.svg b/packages/website/ts/icons/illustrations/social-github.svg
new file mode 100644
index 000000000..ef0025582
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/social-newsletter.svg b/packages/website/ts/icons/illustrations/social-newsletter.svg
new file mode 100644
index 000000000..572cb8ed9
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/social-reddit.svg b/packages/website/ts/icons/illustrations/social-reddit.svg
new file mode 100644
index 000000000..b93510b36
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/social-twitter.svg b/packages/website/ts/icons/illustrations/social-twitter.svg
new file mode 100644
index 000000000..bc8e2f7d7
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/stableTokens.svg b/packages/website/ts/icons/illustrations/stableTokens.svg
new file mode 100755
index 000000000..9e854b0e6
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/standardForExchange.svg b/packages/website/ts/icons/illustrations/standardForExchange.svg
new file mode 100755
index 000000000..f8075ed6d
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/support.svg b/packages/website/ts/icons/illustrations/support.svg
new file mode 100644
index 000000000..368e7cc02
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/supportForAllEthereumStandards-large.svg b/packages/website/ts/icons/illustrations/supportForAllEthereumStandards-large.svg
new file mode 100755
index 000000000..1f840204a
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/supportForAllEthereumStandards.svg b/packages/website/ts/icons/illustrations/supportForAllEthereumStandards.svg
new file mode 100755
index 000000000..32a4d8602
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/techSupport.svg b/packages/website/ts/icons/illustrations/techSupport.svg
new file mode 100755
index 000000000..e52084f67
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/tokens.svg b/packages/website/ts/icons/illustrations/tokens.svg
new file mode 100644
index 000000000..966615265
--- /dev/null
+++ b/packages/website/ts/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/icons/illustrations/vcIntroductions.svg b/packages/website/ts/icons/illustrations/vcIntroductions.svg
new file mode 100755
index 000000000..024cadab3
--- /dev/null
+++ b/packages/website/ts/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/icons/logo-with-type.svg b/packages/website/ts/icons/logo-with-type.svg
new file mode 100644
index 000000000..25abf149e
--- /dev/null
+++ b/packages/website/ts/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/index.tsx b/packages/website/ts/index.tsx
index 050c201a3..45054772c 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,18 @@ 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/pages/about/jobs';
+import { NextAboutMission } from 'ts/pages/about/mission';
+import { NextAboutPress } from 'ts/pages/about/press';
+import { NextAboutTeam } from 'ts/pages/about/team';
+import { NextEcosystem } from 'ts/pages/ecosystem';
+import { Next0xInstant } from 'ts/pages/instant';
+import { NextLanding } from 'ts/pages/landing';
+import { NextLaunchKit } from 'ts/pages/launch_kit';
+import { NextMarketMaker } from 'ts/pages/market_maker';
+import { NextWhy } from 'ts/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 +97,34 @@ 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.MarketMaker}
+ component={NextMarketMaker 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 +192,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/about/about.tsx b/packages/website/ts/pages/about/about.tsx
deleted file mode 100644
index 81a3f59e1..000000000
--- a/packages/website/ts/pages/about/about.tsx
+++ /dev/null
@@ -1,421 +0,0 @@
-import { colors, Link, Styles } 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 { TopBar } from 'ts/components/top_bar/top_bar';
-import { Profile } from 'ts/pages/about/profile';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { ProfileInfo, WebsitePaths } from 'ts/types';
-import { Translate } from 'ts/utils/translate';
-import { utils } from 'ts/utils/utils';
-
-const teamRow1: ProfileInfo[] = [
- {
- name: 'Will Warren',
- title: 'Co-founder & CEO',
- description: `Smart contract R&D. Previously applied physics at Los Alamos \
- Nat Lab. Mechanical engineering at UC San Diego. PhD dropout.`,
- image: '/images/team/will.jpg',
- linkedIn: 'https://www.linkedin.com/in/will-warren-92aab62b/',
- github: 'https://github.com/willwarren89',
- medium: 'https://medium.com/@willwarren89',
- },
- {
- name: 'Amir Bandeali',
- title: 'Co-founder & CTO',
- description: `Smart contract R&D. Previously fixed income trader at DRW. \
- Finance at University of Illinois, Urbana-Champaign.`,
- image: '/images/team/amir.png',
- linkedIn: 'https://www.linkedin.com/in/abandeali1/',
- github: 'https://github.com/abandeali1',
- medium: 'https://medium.com/@abandeali1',
- },
- {
- name: 'Fabio Berger',
- title: 'Senior Engineer',
- description: `Full-stack blockchain engineer. Previously software engineer \
- at Airtable and founder of WealthLift. Computer Science at Duke.`,
- image: '/images/team/fabio.jpg',
- linkedIn: 'https://www.linkedin.com/in/fabio-berger-03ab261a/',
- github: 'https://github.com/fabioberger',
- medium: 'https://medium.com/@fabioberger',
- },
-];
-
-const teamRow2: ProfileInfo[] = [
- {
- name: 'Alex Xu',
- title: 'Director of Operations',
- description: `Strategy and operations. Previously digital marketing at Google \
- and vendor management at Amazon. Economics at UC San Diego.`,
- image: '/images/team/alex.jpg',
- linkedIn: 'https://www.linkedin.com/in/alex-xu/',
- github: '',
- medium: 'https://medium.com/@aqxu',
- },
- {
- name: 'Leonid Logvinov',
- title: 'Engineer',
- description: `Full-stack blockchain engineer. Previously blockchain engineer \
- at Neufund. Computer Science at University of Warsaw.`,
- image: '/images/team/leonid.png',
- linkedIn: 'https://www.linkedin.com/in/leonidlogvinov/',
- github: 'https://github.com/LogvinovLeon',
- medium: 'https://medium.com/@Logvinov',
- },
- {
- name: 'Ben Burns',
- title: 'Designer',
- description: `Product, motion, and graphic designer. Previously designer \
- at Airtable and Apple. Digital Design at University of Cincinnati.`,
- image: '/images/team/ben.jpg',
- linkedIn: 'https://www.linkedin.com/in/ben-burns-30170478/',
- github: '',
- medium: '',
- },
-];
-
-const teamRow3: ProfileInfo[] = [
- {
- name: 'Brandon Millman',
- title: 'Senior Engineer',
- description: `Full-stack engineer. Previously senior software engineer at \
- Twitter. Computer Science and Electrical Engineering at Duke.`,
- image: '/images/team/brandon.png',
- linkedIn: 'https://www.linkedin.com/in/brandon-millman-b093a022/',
- github: 'https://github.com/BMillman19',
- medium: 'https://medium.com/@bchillman',
- },
- {
- name: 'Tom Schmidt',
- title: 'Product Manager',
- description: `Previously engineering at Apple, product management at Facebook and Instagram. Computer Science at Stanford.`,
- image: '/images/team/tom.jpg',
- linkedIn: 'https://www.linkedin.com/in/tomhschmidt/',
- github: 'https://github.com/tomhschmidt',
- medium: '',
- },
- {
- name: 'Jacob Evans',
- title: 'Ecosystem Engineer',
- description: `Previously software engineer at Qantas and RSA Security.`,
- image: '/images/team/jacob.jpg',
- linkedIn: 'https://www.linkedin.com/in/dekzter/',
- github: 'https://github.com/dekz',
- medium: '',
- },
-];
-
-const teamRow4: ProfileInfo[] = [
- {
- name: 'Blake Henderson',
- title: 'Operations Associate',
- description: `Operations and Analytics. Previously analytics at LinkedIn. Economics at UC San Diego.`,
- image: '/images/team/blake.jpg',
- linkedIn: 'https://www.linkedin.com/in/blakerhenderson/',
- github: '',
- medium: '',
- },
- {
- name: 'Zack Skelly',
- title: 'Lead Recruiter',
- description: `Talent. Previously first recruiter at Heap, recruiting at Dropbox and Google. English Rhetoric and Composition at Pepperdine.`,
- image: '/images/team/zach.png',
- linkedIn: 'https://www.linkedin.com/in/zackaryskelly/',
- github: '',
- medium: '',
- },
- {
- name: 'Greg Hysen',
- title: 'Blockchain Engineer',
- description: `Smart contract R&D. Previously lead distributed systems engineer at Hivemapper. Computer Science at University of Waterloo.`,
- image: '/images/team/greg.jpeg',
- linkedIn: 'https://www.linkedin.com/in/gregory-hysen-71741463/',
- github: 'https://github.com/hysz',
- medium: '',
- },
-];
-
-const teamRow5: ProfileInfo[] = [
- {
- name: 'Remco Bloemen',
- title: 'Technical Fellow',
- description: `Previously cofounder at Neufund and Coblue. Part III at Cambridge. PhD dropout at Twente Business School.`,
- image: '/images/team/remco.jpeg',
- linkedIn: 'https://www.linkedin.com/in/remcobloemen/',
- github: 'http://github.com/recmo',
- medium: '',
- },
- {
- name: 'Francesco Agosti',
- title: 'Engineer',
- description: `Full-stack engineer. Previously senior software engineer at Yelp. Computer Science at Duke.`,
- image: 'images/team/fragosti.png',
- linkedIn: 'https://www.linkedin.com/in/fragosti/',
- github: 'http://github.com/fragosti',
- },
- {
- name: 'Mel Oberto',
- title: 'Office Ops / Executive Assistant',
- description: `Daily Operations. Previously People Operations Associate at Heap. Marketing and MBA at Sacred Heart University.`,
- image: 'images/team/mel.png',
- linkedIn: 'https://www.linkedin.com/in/melanieoberto',
- },
-];
-
-const teamRow6: ProfileInfo[] = [
- {
- name: 'Alex Browne',
- title: 'Engineer in Residence',
- description: `Full-stack blockchain engineer. Previously at Plaid. Open source guru and footgun dismantler. Computer Science and Electrical Engineering at Duke.`,
- image: 'images/team/alexbrowne.png',
- linkedIn: 'https://www.linkedin.com/in/stephenalexbrowne/',
- github: 'http://github.com/albrow',
- },
- {
- name: 'Peter Zeitz',
- title: 'Research Fellow',
- description: `Researching decentralized governance. Previously Assistant Professor of Economics at National University of Singapore Business School. PhD in Economics at UCLA.`,
- image: 'images/team/peter.jpg',
- linkedIn: 'https://www.linkedin.com/in/peter-z-7b9595163/',
- },
- {
- name: 'Chris Kalani',
- title: 'Director of Design',
- description: `Previously founded Wake (acquired by InVision). Early Facebook product designer.`,
- image: 'images/team/chris.png',
- linkedIn: 'https://www.linkedin.com/in/chriskalani/',
- github: 'https://github.com/chriskalani',
- },
-];
-
-const teamRow7: ProfileInfo[] = [
- {
- name: 'Clay Robbins',
- title: 'Ecosystem Development Lead',
- description: `Growth & Business Development. Previously product and partnerships at Square. Economics at Dartmouth College.`,
- image: 'images/team/clay.png',
- linkedIn: 'https://www.linkedin.com/in/robbinsclay/',
- },
- {
- name: 'Matt Taylor',
- title: 'Marketing Lead',
- description: `Growth & Marketing. Previously marketing at Abra and Square. Economics and Philosophy at Claremont McKenna College.`,
- image: 'images/team/matt.jpg',
- linkedIn: 'https://www.linkedin.com/in/mattytay/',
- },
- {
- name: 'Eugene Aumson',
- title: 'Engineer',
- description: `Developer Experience. Previously senior software engineer in foreign exchange applications at Bloomberg LP.`,
- image: 'images/team/gene.jpg',
- linkedIn: 'https://www.linkedin.com/in/aumson/',
- github: 'https://github.com/feuGeneA',
- },
-];
-
-const teamRow8: ProfileInfo[] = [
- {
- name: 'Weijie Wu',
- title: 'Research Fellow',
- description: `Researching decentralized governance. Previously Researcher at Huawei and Assistant Professor at Shanghai Jiao Tong University. PhD in Computer Science at The Chinese University of Hong Kong.`,
- image: 'images/team/weijie.png',
- linkedIn: 'https://www.linkedin.com/in/weijiewu/',
- },
- {
- name: 'Rahul Singireddy',
- title: 'Relayer Success Manager',
- description: `Previously community at Zeppelin, growth at Dharma, and cryptocurrency contributor at Forbes. Symbolic Systems at Stanford.`,
- image: 'images/team/rahul.png',
- linkedIn: 'https://www.linkedin.com/in/rahul-singireddy-3037908a/',
- },
- {
- name: 'Jason Somensatto',
- title: 'Strategic Legal Counsel',
- description: `Legal. Previously head of blockchain and crypto practice at Orrick. JD from George Washington University and undergrad at UVA.`,
- image: 'images/team/jason.png',
- linkedIn: 'https://www.linkedin.com/in/jasonsomensatto/',
- },
-];
-
-const teamRow9: ProfileInfo[] = [
- {
- name: 'Steve Klebanoff',
- title: 'Senior Engineer',
- description: ` Full-stack engineer. Previously Staff Software Engineer at AppFolio. Computer Science & Cognitive Psychology at Northeastern University.`,
- image: 'images/team/steve.png',
- linkedIn: 'https://www.linkedin.com/in/steveklebanoff/',
- github: 'https://github.com/steveklebanoff',
- },
- {
- name: 'Xianny Ng',
- title: 'Engineer',
- description: `Developer Experience. Previously telemetry at Mapbox and platform engineering at Bench Accounting.`,
- image: 'images/team/xianny.png',
- linkedIn: 'https://www.linkedin.com/in/xianny/',
- github: 'https://github.com/xianny',
- },
-];
-
-const advisors1: ProfileInfo[] = [
- {
- name: 'Fred Ehrsam',
- description: 'Co-founder of Coinbase. Previously FX trader at Goldman Sachs.',
- image: '/images/advisors/fred.jpg',
- linkedIn: 'https://www.linkedin.com/in/fredehrsam/',
- medium: 'https://medium.com/@FEhrsam',
- twitter: 'https://twitter.com/FEhrsam',
- },
- {
- name: 'Olaf Carlson-Wee',
- image: '/images/advisors/olaf.png',
- description: 'Founder of Polychain Capital. First hire at Coinbase. Angel investor.',
- linkedIn: 'https://www.linkedin.com/in/olafcw/',
- angellist: 'https://angel.co/olafcw',
- },
- {
- name: 'Joey Krug',
- description: `Co-CIO at Pantera Capital. Founder of Augur. Thiel 20 Under 20 Fellow.`,
- image: '/images/advisors/joey.jpg',
- linkedIn: 'https://www.linkedin.com/in/joeykrug/',
- github: 'https://github.com/joeykrug',
- angellist: 'https://angel.co/joeykrug',
- },
-];
-
-const advisors2: ProfileInfo[] = [
- {
- name: 'Linda Xie',
- description: 'Co-founder of Scalar Capital. Previously PM at Coinbase.',
- image: '/images/advisors/linda.jpg',
- linkedIn: 'https://www.linkedin.com/in/lindaxie/',
- medium: 'https://medium.com/@linda.xie',
- twitter: 'https://twitter.com/ljxie',
- },
- {
- name: 'David Sacks',
- description: 'General Partner at Craft Ventures. Original COO of PayPal. Founder of Yammer.',
- image: '/images/advisors/david.png',
- linkedIn: 'https://www.linkedin.com/in/davidoliversacks/',
- medium: 'https://medium.com/@davidsacks',
- twitter: 'https://twitter.com/DavidSacks',
- },
-];
-
-export interface AboutProps {
- source: string;
- location: Location;
- translate: Translate;
- dispatcher: Dispatcher;
-}
-
-interface AboutState {}
-
-const styles: Styles = {
- header: {
- fontFamily: 'Roboto Mono',
- fontSize: 36,
- color: 'black',
- paddingTop: 110,
- },
- weAreHiring: {
- fontSize: 30,
- color: colors.darkestGrey,
- fontFamily: 'Roboto Mono',
- letterSpacing: 7.5,
- },
-};
-
-export class About extends React.Component<AboutProps, AboutState> {
- public componentDidMount(): void {
- window.scrollTo(0, 0);
- }
- public render(): React.ReactNode {
- return (
- <div style={{ backgroundColor: colors.lightestGrey }}>
- <DocumentTitle title="0x About Us" />
- <TopBar
- blockchainIsLoaded={false}
- location={this.props.location}
- style={{ backgroundColor: colors.lightestGrey }}
- translate={this.props.translate}
- />
- <div id="about" className="mx-auto max-width-4 py4" style={{ color: colors.grey800 }}>
- <div className="mx-auto pb4 sm-px3" style={{ maxWidth: 435 }}>
- <div style={styles.header}>About us:</div>
- <div
- className="pt3"
- style={{
- fontSize: 17,
- color: colors.darkestGrey,
- lineHeight: 1.5,
- }}
- >
- Our team is a globally distributed group with backgrounds in engineering, research, business
- and design. We are passionate about decentralized technology and its potential to act as an
- equalizing force in the world.
- </div>
- </div>
- <div className="pt3 md-px4 lg-px0">
- <div className="clearfix pb3">{this._renderProfiles(teamRow1)}</div>
- <div className="clearfix">{this._renderProfiles(teamRow2)}</div>
- <div className="clearfix">{this._renderProfiles(teamRow3)}</div>
- <div className="clearfix">{this._renderProfiles(teamRow4)}</div>
- <div className="clearfix">{this._renderProfiles(teamRow5)}</div>
- <div className="clearfix">{this._renderProfiles(teamRow6)}</div>
- <div className="clearfix">{this._renderProfiles(teamRow7)}</div>
- <div className="clearfix">{this._renderProfiles(teamRow8)}</div>
- <div className="clearfix">{this._renderProfiles(teamRow9)}</div>
- </div>
- <div className="pt3 pb2">
- <div
- className="pt2 pb3 sm-center md-pl4 lg-pl0 md-ml3"
- style={{
- color: colors.grey,
- fontSize: 24,
- fontFamily: 'Roboto Mono',
- }}
- >
- Advisors:
- </div>
- <div className="clearfix">{this._renderProfiles(advisors1)}</div>
- <div className="clearfix">{this._renderProfiles(advisors2)}</div>
- </div>
- <div className="mx-auto py4 sm-px3" style={{ maxWidth: 308 }}>
- <div className="pb2" style={styles.weAreHiring}>
- WE'RE HIRING
- </div>
- <div
- className="pb4 mb4"
- style={{
- fontSize: 16,
- color: colors.darkestGrey,
- lineHeight: 1.5,
- letterSpacing: '0.5px',
- }}
- >
- We are seeking outstanding candidates to{' '}
- <Link to={WebsitePaths.Careers} textDecoration="underline" fontColor="black">
- join our team
- </Link>
- . We value passion, diversity and unique perspectives.
- </div>
- </div>
- </div>
- <Footer translate={this.props.translate} dispatcher={this.props.dispatcher} />
- </div>
- );
- }
- private _renderProfiles(profiles: ProfileInfo[]): React.ReactNode {
- const numIndiv = profiles.length;
- const colSize = utils.getColSize(numIndiv);
- return _.map(profiles, profile => {
- return (
- <div key={`profile-${profile.name}`}>
- <Profile colSize={colSize} profileInfo={profile} />
- </div>
- );
- });
- }
-}
diff --git a/packages/website/ts/pages/about/jobs.tsx b/packages/website/ts/pages/about/jobs.tsx
new file mode 100644
index 000000000..ee1aa6cef
--- /dev/null
+++ b/packages/website/ts/pages/about/jobs.tsx
@@ -0,0 +1,236 @@
+import * as _ from 'lodash';
+import * as React from 'react';
+import DocumentTitle from 'react-document-title';
+import styled from 'styled-components';
+
+import { AboutPageLayout } from 'ts/components/aboutPageLayout';
+import { Link } from 'ts/components/link';
+import { Column, FlexWrap, Section } from 'ts/components/newLayout';
+import { Heading, Paragraph } from 'ts/components/text';
+import { Container } from 'ts/components/ui/container';
+import { colors } from 'ts/style/colors';
+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="50%">
+ <Container position="relative" top="-3px" paddingRight="12px">
+ <Heading asElement="h3" size="small" fontWeight="400" marginBottom="0">
+ <a href={position.href} target="_blank">
+ {position.title}
+ </a>
+ </Heading>
+ </Container>
+ </StyledColumn>
+
+ <StyledColumn width="30%" padding="0 40px 0 0">
+ <Paragraph isMuted={true} marginBottom="0">
+ {position.location}
+ </Paragraph>
+ </StyledColumn>
+
+ <StyledColumn width="20%">
+ <Paragraph marginBottom="0" textAlign="right" color={colors.brandDark} fontWeight={400}>
+ <Link href={position.href} target="_blank">
+ Apply
+ </Link>
+ </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/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/pages/about/mission.tsx b/packages/website/ts/pages/about/mission.tsx
new file mode 100644
index 000000000..ab8949fae
--- /dev/null
+++ b/packages/website/ts/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/components/aboutPageLayout';
+import { Definition } from 'ts/components/definition';
+import { Image } from 'ts/components/image';
+import { Column, Section } from 'ts/components/newLayout';
+import { Heading } from 'ts/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/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/pages/about/press.tsx b/packages/website/ts/pages/about/press.tsx
new file mode 100644
index 000000000..03003d656
--- /dev/null
+++ b/packages/website/ts/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/components/aboutPageLayout';
+import { Button } from 'ts/components/button';
+import { Column, FlexWrap } from 'ts/components/newLayout';
+import { Paragraph } from 'ts/components/text';
+
+interface HighlightProps {
+ logo: string;
+ title?: string;
+ text: string;
+ href: string;
+}
+
+interface HighlightItemProps {
+ highlight: HighlightProps;
+}
+
+const highlights: HighlightProps[] = [
+ {
+ logo: '/images/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/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/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/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/pages/about/profile.tsx b/packages/website/ts/pages/about/profile.tsx
deleted file mode 100644
index 2361c6418..000000000
--- a/packages/website/ts/pages/about/profile.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-import { colors, Styles } from '@0x/react-shared';
-import * as _ from 'lodash';
-import * as React from 'react';
-import { ProfileInfo } from 'ts/types';
-
-const IMAGE_DIMENSION = 149;
-const styles: Styles = {
- subheader: {
- textTransform: 'uppercase',
- fontSize: 32,
- margin: 0,
- },
- imageContainer: {
- width: IMAGE_DIMENSION,
- height: IMAGE_DIMENSION,
- boxShadow: 'rgba(0, 0, 0, 0.19) 2px 5px 10px',
- },
-};
-
-interface ProfileProps {
- colSize: number;
- profileInfo: ProfileInfo;
-}
-
-export const Profile = (props: ProfileProps) => {
- return (
- <div className={`lg-col md-col lg-col-${props.colSize} md-col-6`}>
- <div style={{ maxWidth: 300 }} className="mx-auto lg-px3 md-px3 sm-px4 sm-pb3">
- <div className="circle overflow-hidden mx-auto" style={styles.imageContainer}>
- <img width={IMAGE_DIMENSION} src={props.profileInfo.image} />
- </div>
- <div className="center" style={{ fontSize: 18, fontWeight: 'bold', paddingTop: 20 }}>
- {props.profileInfo.name}
- </div>
- {!_.isUndefined(props.profileInfo.title) && (
- <div
- className="pt1 center"
- style={{
- fontSize: 14,
- fontFamily: 'Roboto Mono',
- color: colors.darkGrey,
- whiteSpace: 'nowrap',
- }}
- >
- {props.profileInfo.title.toUpperCase()}
- </div>
- )}
- <div style={{ minHeight: 60, lineHeight: 1.4 }} className="pt1 pb2 mx-auto lg-h6 md-h6 sm-h5 sm-center">
- {props.profileInfo.description}
- </div>
- <div className="flex pb3 sm-hide xs-hide" style={{ width: 280, opacity: 0.5 }}>
- {renderSocialMediaIcons(props.profileInfo)}
- </div>
- </div>
- </div>
- );
-};
-
-function renderSocialMediaIcons(profileInfo: ProfileInfo): React.ReactNode {
- const icons = [
- renderSocialMediaIcon('zmdi-github-box', profileInfo.github),
- renderSocialMediaIcon('zmdi-linkedin-box', profileInfo.linkedIn),
- renderSocialMediaIcon('zmdi-twitter-box', profileInfo.twitter),
- ];
- return icons;
-}
-
-function renderSocialMediaIcon(iconName: string, url: string): React.ReactNode {
- if (_.isEmpty(url)) {
- return null;
- }
-
- return (
- <div key={url} className="pr1">
- <a href={url} style={{ color: 'inherit' }} target="_blank" className="text-decoration-none">
- <i className={`zmdi ${iconName}`} style={{ ...styles.socalIcon }} />
- </a>
- </div>
- );
-}
diff --git a/packages/website/ts/pages/about/team.tsx b/packages/website/ts/pages/about/team.tsx
new file mode 100644
index 000000000..41d6c2cf8
--- /dev/null
+++ b/packages/website/ts/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/components/aboutPageLayout';
+import { Column, Section } from 'ts/components/newLayout';
+import { Heading, Paragraph } from 'ts/components/text';
+import { WebsitePaths } from 'ts/types';
+
+interface TeamMember {
+ name: string;
+ title: string;
+ imageUrl?: string;
+}
+
+const team: TeamMember[] = [
+ {
+ imageUrl: '/images/team/willw.jpg',
+ name: 'Will Warren',
+ title: 'co-founder & CEO',
+ },
+ {
+ imageUrl: '/images/team/amirb.jpg',
+ name: 'Amir Bandeali',
+ title: 'Co-founder & CTO',
+ },
+ {
+ imageUrl: '/images/team/fabiob.jpg',
+ name: 'Fabio Berger',
+ title: 'senior engineer',
+ },
+ {
+ imageUrl: '/images/team/alexv.jpg',
+ name: 'Alex Xu',
+ title: 'Director of operations',
+ },
+ {
+ imageUrl: '/images/team/leonidL.jpg',
+ name: 'Leonid Logvinov',
+ title: 'engineer',
+ },
+ {
+ imageUrl: '/images/team/benb.jpg',
+ name: 'Ben Burns',
+ title: 'designer',
+ },
+ {
+ imageUrl: '/images/team/brandonm.jpg',
+ name: 'Brandon Millman',
+ title: 'senior engineer',
+ },
+ {
+ imageUrl: '/images/team/toms.jpg',
+ name: 'Tom Schmidt',
+ title: 'product manager',
+ },
+ {
+ imageUrl: '/images/team/jacobe.jpg',
+ name: 'Jacob Evans',
+ title: 'ecosystem engineer',
+ },
+ {
+ imageUrl: '/images/team/blake.jpg',
+ name: 'Blake Henderson',
+ title: 'ecosystem programs lead',
+ },
+ {
+ imageUrl: '/images/team/zack.jpg',
+ name: 'Zack Skelly',
+ title: 'lead recruiter',
+ },
+ {
+ imageUrl: '/images/team/greg.jpg',
+ name: 'Greg Hysen',
+ title: 'blockchain engineer',
+ },
+ {
+ imageUrl: '/images/team/remcoB.jpg',
+ name: 'Remco Bloemen',
+ title: 'technical fellow',
+ },
+ {
+ imageUrl: '/images/team/francesco.jpg',
+ name: 'Francesco Agosti',
+ title: 'engineer',
+ },
+ {
+ imageUrl: '/images/team/melo.jpg',
+ name: 'Mel Oberto',
+ title: 'people operations associate',
+ },
+ {
+ imageUrl: '/images/team/alexb.jpg',
+ name: 'Alex Browne',
+ title: 'engineer in residence',
+ },
+ {
+ imageUrl: '/images/team/peterz.jpg',
+ name: 'Peter Zeitz',
+ title: 'research fellow',
+ },
+ {
+ imageUrl: '/images/team/chrisk.jpg',
+ name: 'Chris Kalani',
+ title: 'director of design',
+ },
+ {
+ imageUrl: '/images/team/clayr.jpg',
+ name: 'Clay Robbins',
+ title: 'ecosystem development lead',
+ },
+ {
+ imageUrl: '/images/team/mattt.jpg',
+ name: 'Matt Taylor',
+ title: 'marketing lead',
+ },
+ {
+ imageUrl: '/images/team/eugenea.jpg',
+ name: 'Eugene Aumson',
+ title: 'engineer',
+ },
+ {
+ imageUrl: '/images/team/weijew.jpg',
+ name: 'Weijie Wu',
+ title: 'research fellow',
+ },
+ {
+ imageUrl: '/images/team/rahuls.jpg',
+ name: 'Rahul Singireddy',
+ title: 'relayer success manager',
+ },
+ {
+ imageUrl: '/images/team/jasons.jpg',
+ name: 'Jason Somensatto',
+ title: 'strategic legal counsel',
+ },
+ {
+ imageUrl: '/images/team/steveK.jpg',
+ name: 'Steve Klebanoff',
+ title: 'senior engineer',
+ },
+ {
+ imageUrl: '/images/team/xianny.jpg',
+ name: 'Xianny Ng',
+ title: 'engineer',
+ },
+];
+
+const advisors: TeamMember[] = [
+ {
+ imageUrl: '/images/team/advisors/frede.jpg',
+ name: 'Fred Ehrsam',
+ title: 'Advisor',
+ },
+ {
+ imageUrl: '/images/team/advisors/olafc.jpg',
+ name: 'Olaf Carlson-Wee',
+ title: 'Advisor',
+ },
+ {
+ imageUrl: '/images/team/advisors/joeyk.jpg',
+ name: 'Joey Krug',
+ title: 'Advisor',
+ },
+ {
+ imageUrl: '/images/team/advisors/lindax.jpg',
+ name: 'Linda Xie',
+ title: 'Advisor',
+ },
+ {
+ imageUrl: '/images/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/pages/community.tsx b/packages/website/ts/pages/community.tsx
new file mode 100644
index 000000000..7c02fed82
--- /dev/null
+++ b/packages/website/ts/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/components/banner';
+import { Button } from 'ts/components/button';
+import { Icon } from 'ts/components/icon';
+import { ModalContact } from 'ts/components/modals/modal_contact';
+import { Column, Section, WrapGrid } from 'ts/components/newLayout';
+import { SiteWrap } from 'ts/components/siteWrap';
+import { Heading, Paragraph } from 'ts/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/events/london.jpg',
+ signupUrl: '#',
+ },
+ {
+ title: '0x Berlin Meetup',
+ date: 'October 20th 2018',
+ imageUrl: '/images/events/berlin.jpg',
+ signupUrl: '#',
+ },
+ {
+ title: '0x San Francisco Meetup',
+ date: 'October 20th 2018',
+ imageUrl: '/images/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/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/ecosystem.tsx b/packages/website/ts/pages/ecosystem.tsx
new file mode 100644
index 000000000..8e367b21f
--- /dev/null
+++ b/packages/website/ts/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/components/button';
+import { Icon } from 'ts/components/icon';
+import { Column, Section, WrapGrid } from 'ts/components/newLayout';
+import { SiteWrap } from 'ts/components/siteWrap';
+import { Heading, Paragraph } from 'ts/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/pages/faq/faq.tsx b/packages/website/ts/pages/faq/faq.tsx
index c4965e61c..8cde7224e 100644
--- a/packages/website/ts/pages/faq/faq.tsx
+++ b/packages/website/ts/pages/faq/faq.tsx
@@ -2,7 +2,7 @@ import { colors, Styles } 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 { Footer } from 'ts/components/old_footer';
import { TopBar } from 'ts/components/top_bar/top_bar';
import { Question } from 'ts/pages/faq/question';
import { Dispatcher } from 'ts/redux/dispatcher';
diff --git a/packages/website/ts/pages/instant.tsx b/packages/website/ts/pages/instant.tsx
new file mode 100644
index 000000000..b97bb35a4
--- /dev/null
+++ b/packages/website/ts/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/components/banner';
+import { Button } from 'ts/components/button';
+import { Definition } from 'ts/components/definition';
+import { Hero } from 'ts/components/hero';
+import { Section, SectionProps } from 'ts/components/newLayout';
+import { SiteWrap } from 'ts/components/siteWrap';
+import { Heading, Paragraph } from 'ts/components/text';
+import { Configurator } from 'ts/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/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/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/code_demo.tsx b/packages/website/ts/pages/instant/code_demo.tsx
index a3b5fe847..c59f148b8 100644
--- a/packages/website/ts/pages/instant/code_demo.tsx
+++ b/packages/website/ts/pages/instant/code_demo.tsx
@@ -2,9 +2,8 @@ import * as React from 'react';
import * as CopyToClipboard from 'react-copy-to-clipboard';
import SyntaxHighlighter from 'react-syntax-highlighter';
-import { Button } from 'ts/components/ui/button';
+import { Button } from 'ts/components/button';
import { Container } from 'ts/components/ui/container';
-import { colors } from 'ts/style/colors';
import { styled } from 'ts/style/theme';
import { zIndex } from 'ts/style/z_index';
@@ -12,7 +11,7 @@ const CustomPre = styled.pre`
margin: 0px;
line-height: 24px;
overflow: scroll;
- width: 600px;
+ width: 100%;
height: 100%;
max-height: 800px;
border-radius: 4px;
@@ -23,19 +22,21 @@ const CustomPre = styled.pre`
border: none;
}
code:first-of-type {
- background-color: #2a2a2a !important;
+ background-color: #060d0d !important;
color: #999;
- min-height: 98%;
+ min-height: 100%;
text-align: center;
- padding-right: 5px !important;
- padding-left: 5px;
margin-right: 15px;
line-height: 25px;
- padding-top: 10px;
+ padding: 10px 7px !important;
}
code:last-of-type {
position: relative;
top: 10px;
+ top: 0;
+ padding-top: 11px;
+ display: inline-block;
+ line-height: 25px;
}
`;
@@ -130,7 +131,7 @@ const customStyle = {
hljs: {
display: 'block',
overflowX: 'hidden',
- background: colors.instantSecondaryBackground,
+ background: '#1B2625',
color: 'white',
fontSize: '12px',
},
@@ -160,9 +161,7 @@ export class CodeDemo extends React.Component<CodeDemoProps, CodeDemoState> {
<Container position="relative" height="100%">
<Container position="absolute" top="10px" right="10px" zIndex={zIndex.overlay - 1}>
<CopyToClipboard text={this.props.children} onCopy={this._handleCopyClick}>
- <Button fontSize="14px">
- <b>{copyButtonText}</b>
- </Button>
+ <StyledButton>{copyButtonText}</StyledButton>
</CopyToClipboard>
</Container>
<SyntaxHighlighter language="html" style={customStyle} showLineNumbers={true} PreTag={CustomPre}>
@@ -175,3 +174,10 @@ export class CodeDemo extends React.Component<CodeDemoProps, CodeDemoState> {
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/pages/instant/config_generator.tsx
index fbeeeaeaf..e43d47119 100644
--- a/packages/website/ts/pages/instant/config_generator.tsx
+++ b/packages/website/ts/pages/instant/config_generator.tsx
@@ -4,11 +4,11 @@ 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 { 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';
@@ -17,6 +17,10 @@ import { colors } from 'ts/style/colors';
import { WebsitePaths } from 'ts/types';
import { constants } from 'ts/utils/constants';
+// New components
+import { Heading } from 'ts/components/text';
+import { Select, SelectItemConfig } from 'ts/pages/instant/select';
+
import { assetMetaDataMap } from '../../../../instant/src/data/asset_meta_data_map';
import { ERC20AssetMetaData, ZeroExInstantBaseConfig } from '../../../../instant/src/types';
@@ -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/pages/instant/config_generator_address_input.tsx b/packages/website/ts/pages/instant/config_generator_address_input.tsx
index ccbaf4482..890e39da6 100644
--- a/packages/website/ts/pages/instant/config_generator_address_input.tsx
+++ b/packages/website/ts/pages/instant/config_generator_address_input.tsx
@@ -1,11 +1,13 @@
-import { colors } from '@0x/react-shared';
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 { Input } from 'ts/components/ui/input';
-import { Text } from 'ts/components/ui/text';
+
+import { Paragraph } from 'ts/components/text';
export interface ConfigGeneratorAddressInputProps {
value?: string;
@@ -16,6 +18,19 @@ 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
@@ -26,22 +41,13 @@ export class ConfigGeneratorAddressInput extends React.Component<
public render(): React.ReactNode {
const { errMsg } = this.state;
const hasError = !_.isEmpty(errMsg);
- const border = hasError ? '1px solid red' : undefined;
return (
<Container height="80px">
- <Input
- width="100%"
- fontSize="16px"
- padding="0.7em 1em"
- value={this.props.value}
- onChange={this._handleChange}
- placeholder="0xe99...aa8da4"
- border={border}
- />
+ <Input value={this.props.value} onChange={this._handleChange} placeholder="0xe99...aa8da4" />
<Container marginTop="5px" isHidden={!hasError} height="25px">
- <Text fontSize="14px" fontColor={colors.grey} fontStyle="italic">
+ <Paragraph size="small" isNoMargin={true}>
{errMsg}
- </Text>
+ </Paragraph>
</Container>
</Container>
);
@@ -57,3 +63,22 @@ export class ConfigGeneratorAddressInput extends React.Component<
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/pages/instant/configurator.tsx
index 2cb1a1c1c..a63e1752e 100644
--- a/packages/website/ts/pages/instant/configurator.tsx
+++ b/packages/website/ts/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 { Link } from 'ts/components/link';
+import { Column, FlexWrap } from 'ts/components/newLayout';
+import { Heading } from 'ts/components/text';
import { WebsitePaths } from 'ts/types';
import { ZeroExInstantBaseConfig } from '../../../../instant/src/types';
-export interface ConfiguratorProps {
- hash: string;
-}
-
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/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/fee_percentage_slider.tsx b/packages/website/ts/pages/instant/fee_percentage_slider.tsx
index d76cee58f..c4d9f908f 100644
--- a/packages/website/ts/pages/instant/fee_percentage_slider.tsx
+++ b/packages/website/ts/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/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/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/pages/instant/introducing_0x_instant.tsx b/packages/website/ts/pages/instant/introducing_0x_instant.tsx
deleted file mode 100644
index da3f09faa..000000000
--- a/packages/website/ts/pages/instant/introducing_0x_instant.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-import * as React from 'react';
-
-import { Button } from 'ts/components/ui/button';
-import { Container } from 'ts/components/ui/container';
-import { Text } from 'ts/components/ui/text';
-import { colors } from 'ts/style/colors';
-import { ScreenWidths } from 'ts/types';
-
-export interface Introducing0xInstantProps {
- screenWidth: ScreenWidths;
- onCTAClick: () => void;
-}
-
-export const Introducing0xInstant = (props: Introducing0xInstantProps) => {
- const isSmallScreen = props.screenWidth === ScreenWidths.Sm;
- const zero = (
- <Text fontColor={colors.white} fontSize="42px" fontWeight="600" fontFamily="Roboto Mono" Tag="span">
- 0
- </Text>
- );
- const title = isSmallScreen ? (
- <div>
- Introducing<br />
- {zero}x Instant
- </div>
- ) : (
- <div>Introducing {zero}x Instant</div>
- );
- return (
- <div className="clearfix center lg-pt4 md-pt4" style={{ backgroundColor: colors.instantPrimaryBackground }}>
- <div className="mx-auto inline-block align-middle py4" style={{ lineHeight: '44px', textAlign: 'center' }}>
- <Container className="sm-center sm-pt3">
- <Text fontColor={colors.white} fontSize="42px" lineHeight="52px" fontWeight="600">
- {title}
- </Text>
- </Container>
- <Container className="pb2 lg-pt2 md-pt2 sm-pt3 sm-px3 sm-center" maxWidth="600px">
- <Text fontColor={colors.grey500} fontSize="20px" lineHeight="32px" fontFamily="Roboto Mono">
- A free and flexible way to offer simple crypto
- <br /> purchasing in any app or website.
- </Text>
- </Container>
- <div className="py3">
- <Button
- type="button"
- backgroundColor={colors.mediumBlue}
- fontColor={colors.white}
- fontSize="18px"
- onClick={props.onCTAClick}
- >
- Get Started
- </Button>
- </div>
- </div>
- </div>
- );
-};
diff --git a/packages/website/ts/pages/instant/need_more.tsx b/packages/website/ts/pages/instant/need_more.tsx
deleted file mode 100644
index 70aea7363..000000000
--- a/packages/website/ts/pages/instant/need_more.tsx
+++ /dev/null
@@ -1,62 +0,0 @@
-import * as React from 'react';
-
-import { Button } from 'ts/components/ui/button';
-import { Container } from 'ts/components/ui/container';
-import { Text } from 'ts/components/ui/text';
-import { colors } from 'ts/style/colors';
-import { ScreenWidths, WebsitePaths } from 'ts/types';
-import { constants } from 'ts/utils/constants';
-import { utils } from 'ts/utils/utils';
-
-export interface NeedMoreProps {
- screenWidth: ScreenWidths;
-}
-export const NeedMore = (props: NeedMoreProps) => {
- const isSmallScreen = props.screenWidth === ScreenWidths.Sm;
- const backgroundColor = isSmallScreen ? colors.instantTertiaryBackground : colors.instantSecondaryBackground;
- const className = isSmallScreen ? 'flex flex-column items-center' : 'flex';
- const marginRight = isSmallScreen ? undefined : '200px';
- return (
- <Container className="flex flex-column items-center py4 px3" backgroundColor={backgroundColor}>
- <Container className={className}>
- <Container className="sm-center" marginRight={marginRight}>
- <Text fontColor={colors.white} fontSize="32px" lineHeight="45px">
- Need more flexibility?
- </Text>
- <Text fontColor={colors.grey500} fontSize="18px" lineHeight="27px">
- View our full documentation or reach out if you have any questions.
- </Text>
- </Container>
- <Container className="py3 flex">
- <Container marginRight="20px">
- <Button
- type="button"
- backgroundColor={colors.white}
- fontColor={backgroundColor}
- fontSize="18px"
- onClick={onGetInTouchClick}
- >
- Get in Touch
- </Button>
- </Container>
- <Button
- type="button"
- backgroundColor={colors.mediumBlue}
- fontColor={colors.white}
- fontSize="18px"
- onClick={onDocsClick}
- >
- Explore the Docs
- </Button>
- </Container>
- </Container>
- </Container>
- );
-};
-
-const onGetInTouchClick = () => {
- utils.openUrl(constants.URL_ZEROEX_CHAT);
-};
-const onDocsClick = () => {
- utils.openUrl(`${WebsitePaths.Wiki}#Get-Started-With-Instant`);
-};
diff --git a/packages/website/ts/pages/instant/rc-slider.css b/packages/website/ts/pages/instant/rc-slider.css
new file mode 100644
index 000000000..63038324e
--- /dev/null
+++ b/packages/website/ts/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/pages/instant/screenshots.tsx b/packages/website/ts/pages/instant/screenshots.tsx
deleted file mode 100644
index 7dcf17fd1..000000000
--- a/packages/website/ts/pages/instant/screenshots.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-import * as _ from 'lodash';
-import * as React from 'react';
-
-import { Container } from 'ts/components/ui/container';
-import { colors } from 'ts/style/colors';
-import { ScreenWidths } from 'ts/types';
-
-export interface ScreenshotsProps {
- screenWidth: ScreenWidths;
-}
-
-export const Screenshots = (props: ScreenshotsProps) => {
- const isSmallScreen = props.screenWidth === ScreenWidths.Sm;
- const images = isSmallScreen
- ? [
- 'images/instant/rep_screenshot.png',
- 'images/instant/dai_screenshot.png',
- 'images/instant/gods_screenshot.png',
- ]
- : [
- 'images/instant/nmr_screenshot.png',
- 'images/instant/kitty_screenshot.png',
- 'images/instant/rep_screenshot.png',
- 'images/instant/dai_screenshot.png',
- 'images/instant/gods_screenshot.png',
- 'images/instant/gnt_screenshot.png',
- ];
- return (
- <Container backgroundColor={colors.instantPrimaryBackground} className="py3 flex justify-center">
- {_.map(images, image => {
- return <img className="px1 flex-none" width="300px" height="420px" src={image} key={image} />;
- })}
- </Container>
- );
-};
diff --git a/packages/website/ts/pages/instant/select.tsx b/packages/website/ts/pages/instant/select.tsx
new file mode 100644
index 000000000..d4146cfb0
--- /dev/null
+++ b/packages/website/ts/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/pages/jobs/benefits.tsx b/packages/website/ts/pages/jobs/benefits.tsx
deleted file mode 100644
index 563b72e63..000000000
--- a/packages/website/ts/pages/jobs/benefits.tsx
+++ /dev/null
@@ -1,158 +0,0 @@
-import * as _ from 'lodash';
-import * as React from 'react';
-
-import { Circle } from 'ts/components/ui/circle';
-import { Container } from 'ts/components/ui/container';
-import { Image } from 'ts/components/ui/image';
-import { Text } from 'ts/components/ui/text';
-import { colors } from 'ts/style/colors';
-import { styled } from 'ts/style/theme';
-import { ScreenWidths } from 'ts/types';
-import { constants } from 'ts/utils/constants';
-
-const BENEFITS = [
- 'Comprehensive insurance (medical, dental, and vision)',
- 'Unlimited vacation (three weeks per year minimum)',
- 'Meals and snacks provided in-office daily',
- 'Flexible hours and liberal work-from-home-policy',
- 'Supportive remote working environment',
- 'Transportation, phone, and wellness expense',
- 'Relocation assistance',
- 'Optional team excursions (fully paid, often international)',
- 'Competitive salary and cryptocurrency-based compensation',
-];
-
-interface Value {
- iconSrc: string;
- text: string;
-}
-const VALUES: Value[] = [
- {
- iconSrc: 'images/jobs/heart-icon.svg',
- text: 'Do the right thing',
- },
- {
- iconSrc: 'images/jobs/ship-icon.svg',
- text: 'Consistently ship',
- },
- {
- iconSrc: 'images/jobs/calendar-icon.svg',
- text: 'Focus on long term impact',
- },
-];
-
-export interface BenefitsProps {
- screenWidth: ScreenWidths;
-}
-
-export const Benefits = (props: BenefitsProps) => {
- const isSmallScreen = props.screenWidth === ScreenWidths.Sm;
- return (
- <Container className="flex flex-column items-center py4 px3" backgroundColor={colors.white}>
- {!isSmallScreen ? (
- <Container className="flex" maxWidth="1200px">
- <BenefitsList />
- <Container marginLeft="120px">
- <ValuesList />
- </Container>
- </Container>
- ) : (
- <Container className="flex-column">
- <BenefitsList />
- <Container marginTop="50px">
- <ValuesList />
- </Container>
- </Container>
- )}
- </Container>
- );
-};
-
-const Header: React.StatelessComponent = ({ children }) => (
- <Container marginBottom="30px">
- <Text fontFamily="Roboto Mono" fontSize="24px" fontColor={colors.black}>
- {children}
- </Text>
- </Container>
-);
-
-interface BenefitsListProps {
- className?: string;
-}
-const PlainBenefitsList: React.StatelessComponent<BenefitsListProps> = ({ className }) => {
- return (
- <Container className={className}>
- <Header>Benefits</Header>
- {_.map(BENEFITS, benefit => <BenefitItem key={benefit} description={benefit} />)}
- </Container>
- );
-};
-const BenefitsList = styled(PlainBenefitsList)`
- transform: translateY(30px);
-`;
-
-interface BenefitItemProps {
- description: string;
-}
-
-const BenefitItem: React.StatelessComponent<BenefitItemProps> = ({ description }) => (
- <Container marginBottom="15px">
- <div className="flex">
- <Circle className="flex-none pr2 pt1" diameter={8} fillColor={colors.black} />
- <div className="flex-auto">
- <Text fontSize="14px" lineHeight="24px">
- {description}
- </Text>
- </div>
- </div>
- </Container>
-);
-
-interface ValuesListProps {
- className?: string;
-}
-const PlainValuesList: React.StatelessComponent<ValuesListProps> = ({ className }) => {
- return (
- <Container className={className} maxWidth="270px">
- <Header>Our Values</Header>
- {_.map(VALUES, value => <ValueItem key={value.text} {...value} />)}
- <Text fontSize="14px" lineHeight="26px">
- We care deeply about our culture and values, and encourage you to{' '}
- <a
- style={{ color: colors.mediumBlue, textDecoration: 'none' }}
- target="_blank"
- href={constants.URL_MISSION_AND_VALUES_BLOG_POST}
- >
- read more on our blog
- </a>.
- </Text>
- </Container>
- );
-};
-
-const ValuesList = styled(PlainValuesList)`
- border-color: ${colors.beigeWhite};
- border-radius: 7px;
- border-width: 1px;
- border-style: solid;
- padding-left: 38px;
- padding-right: 38px;
- padding-top: 28px;
- padding-bottom: 28px;
-`;
-
-type ValueItemProps = Value;
-const ValueItem: React.StatelessComponent<ValueItemProps> = ({ iconSrc, text }) => {
- return (
- <Container marginBottom="25px">
- <div className="flex items-center">
- <Image className="flex-none pr2" width="20px" src={iconSrc} />
- <div className="flex-auto">
- <Text fontSize="14px" lineHeight="24px" fontWeight="bold">
- {text}
- </Text>
- </div>
- </div>
- </Container>
- );
-};
diff --git a/packages/website/ts/pages/jobs/jobs.tsx b/packages/website/ts/pages/jobs/jobs.tsx
deleted file mode 100644
index 728e17f9e..000000000
--- a/packages/website/ts/pages/jobs/jobs.tsx
+++ /dev/null
@@ -1,71 +0,0 @@
-import { colors, 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 { Benefits } from 'ts/pages/jobs/benefits';
-import { Join0x } from 'ts/pages/jobs/join_0x';
-import { Mission } from 'ts/pages/jobs/mission';
-import { OpenPositions } from 'ts/pages/jobs/open_positions';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { ScreenWidths } from 'ts/types';
-import { Translate } from 'ts/utils/translate';
-import { utils } from 'ts/utils/utils';
-
-const OPEN_POSITIONS_HASH = 'positions';
-const THROTTLE_TIMEOUT = 100;
-const DOCUMENT_TITLE = 'Careers at 0x';
-const DOCUMENT_DESCRIPTION = 'Join 0x in creating a tokenized world where all value can flow freely';
-
-export interface JobsProps {
- location: Location;
- translate: Translate;
- dispatcher: Dispatcher;
- screenWidth: ScreenWidths;
-}
-
-export interface JobsState {}
-
-export class Jobs extends React.Component<JobsProps, JobsState> {
- // 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: JobsProps) {
- 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.white, position: 'relative' }}
- translate={this.props.translate}
- />
- <Join0x onCallToActionClick={this._onJoin0xCallToActionClick.bind(this)} />
- <Mission screenWidth={this.props.screenWidth} />
- <Benefits screenWidth={this.props.screenWidth} />
- <OpenPositions hash={OPEN_POSITIONS_HASH} screenWidth={this.props.screenWidth} />
- <Footer translate={this.props.translate} dispatcher={this.props.dispatcher} />
- </Container>
- );
- }
- private _onJoin0xCallToActionClick(): void {
- sharedUtils.setUrlHash(OPEN_POSITIONS_HASH);
- sharedUtils.scrollToHash(OPEN_POSITIONS_HASH, '');
- }
- private _updateScreenWidth(): void {
- const newScreenWidth = utils.getScreenWidth();
- this.props.dispatcher.updateScreenWidth(newScreenWidth);
- }
-}
diff --git a/packages/website/ts/pages/jobs/join_0x.tsx b/packages/website/ts/pages/jobs/join_0x.tsx
deleted file mode 100644
index e869cd455..000000000
--- a/packages/website/ts/pages/jobs/join_0x.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-import { colors } from '@0x/react-shared';
-
-import * as React from 'react';
-
-import { Button } from 'ts/components/ui/button';
-import { Container } from 'ts/components/ui/container';
-import { Image } from 'ts/components/ui/image';
-import { Text } from 'ts/components/ui/text';
-import { constants } from 'ts/utils/constants';
-
-const BUTTON_TEXT = 'View open positions';
-
-export interface Join0xProps {
- onCallToActionClick: () => void;
-}
-
-export const Join0x = (props: Join0xProps) => (
- <div className="clearfix center lg-py4 md-py4" style={{ backgroundColor: colors.white, color: colors.black }}>
- <div
- className="mx-auto inline-block align-middle py4"
- style={{ lineHeight: '44px', textAlign: 'center', position: 'relative' }}
- >
- <Container className="sm-hide xs-hide" position="absolute" left="100%" marginLeft="80px">
- <Image src="images/jobs/hero-dots-right.svg" width="400px" />
- </Container>
- <Container className="sm-hide xs-hide" position="absolute" right="100%" marginRight="80px">
- <Image src="images/jobs/hero-dots-left.svg" width="400px" />
- </Container>
- <div className="h2 sm-center sm-pt3" style={{ fontFamily: 'Roboto Mono' }}>
- Join Us in Our Mission
- </div>
- <Container className="pb2 lg-pt2 md-pt2 sm-pt3 sm-px3 sm-center" maxWidth="537px">
- <Text fontSize="14px" lineHeight="30px">
- At 0x, our mission is to create a tokenized world where all value can flow freely.
- <br />
- <br />We are powering a growing ecosystem of decentralized applications and solving novel challenges
- to make our technology intuitive, flexible, and accessible to all.{' '}
- <a
- style={{ color: colors.mediumBlue, textDecoration: 'none' }}
- target="_blank"
- href={constants.URL_MISSION_AND_VALUES_BLOG_POST}
- >
- Read more
- </a>{' '}
- about our mission, and join us in building financial infrastructure upon which the exchange of
- anything of value will take place.
- </Text>
- </Container>
- <div className="py3">
- <Button
- type="button"
- backgroundColor={colors.black}
- width="290px"
- fontColor={colors.white}
- fontSize="18px"
- fontFamily="Roboto Mono"
- onClick={props.onCallToActionClick}
- >
- {BUTTON_TEXT}
- </Button>
- </div>
- </div>
- </div>
-);
diff --git a/packages/website/ts/pages/jobs/mission.tsx b/packages/website/ts/pages/jobs/mission.tsx
deleted file mode 100644
index 28546f985..000000000
--- a/packages/website/ts/pages/jobs/mission.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-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 { colors } from 'ts/style/colors';
-import { ScreenWidths } from 'ts/types';
-
-export interface MissionProps {
- screenWidth: ScreenWidths;
-}
-export const Mission = (props: MissionProps) => {
- const shouldShowImage = props.screenWidth === ScreenWidths.Lg;
- const image = <Image src="/images/jobs/world-map.svg" maxWidth="500px" maxHeight="280px" />;
- const missionStatementClassName = !shouldShowImage ? 'center' : undefined;
- const missionStatement = (
- <Container className={missionStatementClassName} maxWidth="388px">
- <Text fontFamily="Roboto Mono" fontSize="22px" lineHeight="31px">
- Powered by a Diverse<br />Worldwide Community
- </Text>
- <Container marginTop="32px">
- <Text fontSize="14px" lineHeight="2em">
- 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 globally. We're passionate about
- open-source software and decentralized technology's potential to act as an equalizing force in the
- world.
- </Text>
- </Container>
- </Container>
- );
- return (
- <div
- className="flex flex-column items-center py4 px3"
- style={{ backgroundColor: colors.jobsPageBackground, color: colors.black }}
- >
- {shouldShowImage ? (
- <Container className="flex items-center" maxWidth="1200px">
- {image}
- <Container marginLeft="115px">{missionStatement}</Container>
- </Container>
- ) : (
- <Container className="flex flex-column items-center">{missionStatement}</Container>
- )}
- </div>
- );
-};
diff --git a/packages/website/ts/pages/jobs/open_positions.tsx b/packages/website/ts/pages/jobs/open_positions.tsx
deleted file mode 100644
index b8442a9c4..000000000
--- a/packages/website/ts/pages/jobs/open_positions.tsx
+++ /dev/null
@@ -1,179 +0,0 @@
-import * as _ from 'lodash';
-import CircularProgress from 'material-ui/CircularProgress';
-import * as React from 'react';
-
-import { Container } from 'ts/components/ui/container';
-import { Retry } from 'ts/components/ui/retry';
-import { Text } from 'ts/components/ui/text';
-import { colors } from 'ts/style/colors';
-import { styled } from 'ts/style/theme';
-import { ScreenWidths, WebsiteBackendJobInfo } from 'ts/types';
-import { backendClient } from 'ts/utils/backend_client';
-import { constants } from 'ts/utils/constants';
-import { utils } from 'ts/utils/utils';
-
-const TABLE_ROW_MIN_HEIGHT = 100;
-
-export interface OpenPositionsProps {
- hash: string;
- screenWidth: ScreenWidths;
-}
-export interface OpenPositionsState {
- jobInfos?: WebsiteBackendJobInfo[];
- error?: Error;
-}
-
-export class OpenPositions extends React.Component<OpenPositionsProps, OpenPositionsState> {
- private _isUnmounted: boolean;
- constructor(props: OpenPositionsProps) {
- super(props);
- this._isUnmounted = false;
- this.state = {
- jobInfos: undefined,
- error: undefined,
- };
- }
- public componentWillMount(): void {
- // tslint:disable-next-line:no-floating-promises
- this._fetchJobInfosAsync();
- }
- public componentWillUnmount(): void {
- this._isUnmounted = true;
- }
- public render(): React.ReactNode {
- const isReadyToRender = _.isUndefined(this.state.error) && !_.isUndefined(this.state.jobInfos);
- const isSmallScreen = utils.isMobileWidth(this.props.screenWidth);
- return (
- <Container id={this.props.hash} className="mx-auto pb4 px3 max-width-4">
- {!isSmallScreen && (
- <hr style={{ border: 0, borderTop: 1, borderStyle: 'solid', borderColor: colors.beigeWhite }} />
- )}
- <Container marginTop="64px" marginBottom="50px">
- <Text fontFamily="Roboto Mono" fontSize="24px" fontColor={colors.black}>
- Open Positions
- </Text>
- </Container>
- {isReadyToRender ? this._renderTable() : this._renderLoading()}
- </Container>
- );
- }
- private _renderLoading(): React.ReactNode {
- return (
- // TODO: consolidate this loading component with the one in portal and RelayerIndex
- // TODO: possibly refactor into a generic loading container with spinner and retry UI
- <div className="center">
- {_.isUndefined(this.state.error) ? (
- <CircularProgress size={40} thickness={5} />
- ) : (
- <Retry onRetry={this._fetchJobInfosAsync.bind(this)} />
- )}
- </div>
- );
- }
- private _renderTable(): React.ReactNode {
- return (
- <Container width="100%">
- <div>
- {_.map(this.state.jobInfos, jobInfo => {
- return (
- <JobInfoTableRow
- key={jobInfo.id}
- screenWidth={this.props.screenWidth}
- jobInfo={jobInfo}
- onClick={this._openJobInfoUrl.bind(this, jobInfo)}
- />
- );
- })}
- </div>
- <Container className="center" marginTop="70px">
- <Text fontStyle="italic" fontSize="14px">
- Interested in telling us why you'd be a valuable addition to the team outside of the positions
- listed above?{' '}
- <a
- style={{ color: colors.mediumBlue, textDecoration: 'none' }}
- href={`mailto:${constants.EMAIL_JOBS}`}
- >
- Email us!
- </a>
- </Text>
- </Container>
- </Container>
- );
- }
- private async _fetchJobInfosAsync(): Promise<void> {
- try {
- if (!this._isUnmounted) {
- this.setState({
- jobInfos: undefined,
- error: undefined,
- });
- }
- const jobInfos = await backendClient.getJobInfosAsync();
- if (!this._isUnmounted) {
- this.setState({
- jobInfos,
- });
- }
- } catch (error) {
- if (!this._isUnmounted) {
- this.setState({
- error,
- });
- }
- }
- }
- private _openJobInfoUrl(jobInfo: WebsiteBackendJobInfo): void {
- const url = jobInfo.url;
- utils.openUrl(url);
- }
-}
-
-export interface JobInfoTableRowProps {
- className?: string;
- screenWidth: ScreenWidths;
- jobInfo: WebsiteBackendJobInfo;
- onClick?: (event: React.MouseEvent<HTMLElement>) => void;
-}
-
-const PlainJobInfoTableRow: React.StatelessComponent<JobInfoTableRowProps> = ({
- className,
- screenWidth,
- jobInfo,
- onClick,
-}) => {
- const isSmallScreen = screenWidth === ScreenWidths.Sm;
- const titleClassName = isSmallScreen ? 'col col-12 center' : 'col col-5';
- const paddingLeft = isSmallScreen ? undefined : '30px';
- return (
- <Container className={className} onClick={onClick} marginBottom="30px" paddingLeft={paddingLeft}>
- <Container className="flex items-center" minHeight={TABLE_ROW_MIN_HEIGHT} width="100%">
- <Container className="clearfix container" width="100%">
- <Container className={titleClassName}>
- <Text fontSize="16px" fontWeight="bold" fontColor={colors.mediumBlue}>
- {jobInfo.title}
- </Text>
- </Container>
- {!isSmallScreen && (
- <Container className="col col-3">
- <Text fontSize="16px">{jobInfo.department}</Text>
- </Container>
- )}
- {!isSmallScreen && (
- <Container className="col col-4 center">
- <Text fontSize="16px">{jobInfo.office}</Text>
- </Container>
- )}
- </Container>
- </Container>
- </Container>
- );
-};
-
-export const JobInfoTableRow = styled(PlainJobInfoTableRow)`
- cursor: pointer;
- background-color: ${colors.grey100};
- border-radius: 7px;
- &:hover {
- opacity: 0.5;
- }
-`;
diff --git a/packages/website/ts/pages/jobs/photo_rail.tsx b/packages/website/ts/pages/jobs/photo_rail.tsx
deleted file mode 100644
index acc9dcb91..000000000
--- a/packages/website/ts/pages/jobs/photo_rail.tsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import * as _ from 'lodash';
-import * as React from 'react';
-
-import { FilledImage } from 'ts/components/ui/filled_image';
-
-export interface PhotoRailProps {
- images: string[];
-}
-
-export const PhotoRail = (props: PhotoRailProps) => {
- return (
- <div className="clearfix" style={{ height: 490 }}>
- {_.map(props.images, (image: string) => {
- return (
- <div key={image} className="col lg-col-4 md-col-4 col-12 center" style={{ height: '100%' }}>
- <FilledImage src={image} />
- </div>
- );
- })}
- </div>
- );
-};
diff --git a/packages/website/ts/pages/landing.tsx b/packages/website/ts/pages/landing.tsx
new file mode 100644
index 000000000..b47d34dce
--- /dev/null
+++ b/packages/website/ts/pages/landing.tsx
@@ -0,0 +1,44 @@
+import * as React from 'react';
+import DocumentTitle from 'react-document-title';
+
+import { SectionLandingAbout } from 'ts/components/sections/landing/about';
+import { SectionLandingClients } from 'ts/components/sections/landing/clients';
+import { SectionLandingCta } from 'ts/components/sections/landing/cta';
+import { SectionLandingHero } from 'ts/components/sections/landing/hero';
+import { SiteWrap } from 'ts/components/siteWrap';
+
+import { ModalContact } from 'ts/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/pages/landing/landing.tsx b/packages/website/ts/pages/landing/landing.tsx
deleted file mode 100644
index b75b55edb..000000000
--- a/packages/website/ts/pages/landing/landing.tsx
+++ /dev/null
@@ -1,620 +0,0 @@
-import { colors, Link } from '@0x/react-shared';
-import * as _ from 'lodash';
-import * as React from 'react';
-import DocumentTitle from 'react-document-title';
-import { Footer } from 'ts/components/footer';
-import { SubscribeForm } from 'ts/components/forms/subscribe_form';
-import { TopBar } from 'ts/components/top_bar/top_bar';
-import { CallToAction } from 'ts/components/ui/button';
-import { Container } from 'ts/components/ui/container';
-import { Image } from 'ts/components/ui/image';
-import { Text } from 'ts/components/ui/text';
-import { TypedText } from 'ts/components/ui/typed_text';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { Deco, Key, Language, ScreenWidths, WebsitePaths } from 'ts/types';
-import { constants } from 'ts/utils/constants';
-import { Translate } from 'ts/utils/translate';
-import { utils } from 'ts/utils/utils';
-
-interface BoxContent {
- title: string;
- description: string;
- imageUrl: string;
- classNames: string;
- maxWidth: number;
-}
-interface UseCase {
- imageUrl: string;
- type: string;
- description: string;
- classNames: string;
- style?: React.CSSProperties;
-}
-interface Project {
- logoFileName: string;
- projectUrl: string;
-}
-
-const THROTTLE_TIMEOUT = 100;
-const WHATS_NEW_TITLE = 'Introducing 0x Instant';
-const WHATS_NEW_URL = WebsitePaths.Instant;
-const TITLE_STYLE: React.CSSProperties = {
- fontFamily: 'Roboto Mono',
- color: colors.grey,
- fontWeight: 300,
- letterSpacing: 3,
-};
-const ROTATING_LIST = [
- 'tokens',
- 'game items',
- 'digital art',
- 'futures',
- 'stocks',
- 'derivatives',
- 'loans',
- 'cats',
- 'everything',
-];
-
-const relayerProjects: Project[] = [
- {
- logoFileName: 'ethfinex.png',
- projectUrl: constants.PROJECT_URL_ETHFINEX,
- },
- {
- logoFileName: 'radar_relay.png',
- projectUrl: constants.PROJECT_URL_RADAR_RELAY,
- },
- {
- logoFileName: 'paradex.png',
- projectUrl: constants.PROJECT_URL_PARADEX,
- },
- {
- logoFileName: 'the_ocean.png',
- projectUrl: constants.PROJECT_URL_0CEAN,
- },
- {
- logoFileName: 'amadeus.png',
- projectUrl: constants.PROJECT_URL_AMADEUS,
- },
- {
- logoFileName: 'ddex.png',
- projectUrl: constants.PROJECT_URL_DDEX,
- },
- {
- logoFileName: 'decent_ex.png',
- projectUrl: constants.PROJECT_URL_DECENT_EX,
- },
- {
- logoFileName: 'dextroid.png',
- projectUrl: constants.PROJECT_URL_DEXTROID,
- },
- {
- logoFileName: 'ercdex.png',
- projectUrl: constants.PROJECT_URL_ERC_DEX,
- },
- {
- logoFileName: 'open_relay.png',
- projectUrl: constants.PROJECT_URL_OPEN_RELAY,
- },
- {
- logoFileName: 'idt.png',
- projectUrl: constants.PROJECT_URL_IDT,
- },
- {
- logoFileName: 'imtoken.png',
- projectUrl: constants.PROJECT_URL_IMTOKEN,
- },
-];
-
-export interface LandingProps {
- location: Location;
- translate: Translate;
- dispatcher: Dispatcher;
-}
-
-interface LandingState {
- screenWidth: ScreenWidths;
-}
-
-export class Landing extends React.Component<LandingProps, LandingState> {
- private readonly _throttledScreenWidthUpdate: () => void;
- constructor(props: LandingProps) {
- super(props);
- this.state = {
- screenWidth: utils.getScreenWidth(),
- };
- this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT);
- }
- public componentDidMount(): void {
- window.addEventListener('resize', this._throttledScreenWidthUpdate);
- window.scrollTo(0, 0);
- }
- public componentWillUnmount(): void {
- window.removeEventListener('resize', this._throttledScreenWidthUpdate);
- }
- public render(): React.ReactNode {
- return (
- <div id="landing" className="clearfix" style={{ color: colors.grey500 }}>
- <DocumentTitle title="0x Protocol" />
- <TopBar
- blockchainIsLoaded={false}
- location={this.props.location}
- isNightVersion={true}
- style={{ backgroundColor: colors.heroGrey, position: 'relative' }}
- translate={this.props.translate}
- />
- {this._renderHero()}
- {this._renderProjects(
- relayerProjects,
- this.props.translate.get(Key.RelayersHeader, Deco.Upper),
- colors.projectsGrey,
- true,
- )}
- {this._renderInfoBoxes()}
- {this._renderTokenizationSection()}
- {this._renderUseCases()}
- {this._renderCallToAction()}
- <Footer translate={this.props.translate} dispatcher={this.props.dispatcher} />
- </div>
- );
- }
- private _renderHero(): React.ReactNode {
- const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
- const left = 'col lg-col-6 md-col-6 col-12 lg-pl4 md-pl4 sm-pl0 sm-px3 sm-center';
- const flexClassName = isSmallScreen
- ? 'flex items-center flex-column justify-center'
- : 'flex items-center justify-center';
- return (
- <div className="clearfix py4" style={{ backgroundColor: colors.heroGrey }}>
- <div className="mx-auto max-width-4 clearfix">
- {this._renderWhatsNew()}
- <div className={`${flexClassName} lg-pt4 md-pt4 sm-pt2 lg-pb4 md-pb4 lg-mt4 md-mt4 sm-mt2 sm-mb4`}>
- <Container marginTop="30px" marginBottom="30px" marginLeft="15px" marginRight="15px">
- <Image src="/images/landing/0x_homepage.svg" maxWidth="100%" height="auto" />
- </Container>
- <div className={left} style={{ color: colors.white, height: 390, lineHeight: '390px' }}>
- <div
- className="inline-block lg-align-middle md-align-middle sm-align-top"
- style={{
- paddingLeft: isSmallScreen ? 0 : 12,
- lineHeight: '36px',
- }}
- >
- <Text
- className="sm-pb2"
- fontFamily="Roboto"
- display="inline-block"
- fontColor={colors.grey300}
- fontWeight={500}
- lineHeight="1.3em"
- fontSize={isSmallScreen ? '28px' : '36px'}
- >
- {this.props.translate.get(Key.TopHeader, Deco.Cap)}
- {this.props.translate.getLanguage() === Language.English && (
- <React.Fragment>
- {' '}
- for{' '}
- <TypedText
- fontFamily="Roboto"
- display="inline-block"
- fontColor={colors.white}
- fontWeight={700}
- lineHeight="1.3em"
- fontSize={isSmallScreen ? '28px' : '36px'}
- textList={ROTATING_LIST}
- shouldRepeat={true}
- />
- </React.Fragment>
- )}
- </Text>
- <Container
- className={`pt3 flex clearfix sm-mx-auto ${isSmallScreen ? 'justify-center' : ''}`}
- >
- <Container paddingRight="20px">
- <Link to={WebsitePaths.Docs}>
- <CallToAction type="light">
- {this.props.translate.get(Key.BuildCallToAction, Deco.Cap)}
- </CallToAction>
- </Link>
- </Container>
- <div>
- <Link to={WebsitePaths.Portal}>
- <CallToAction>
- {this.props.translate.get(Key.TradeCallToAction, Deco.Cap)}
- </CallToAction>
- </Link>
- </div>
- </Container>
- </div>
- </div>
- </div>
- </div>
- {this.props.translate.getLanguage() === Language.English && <SubscribeForm />}
- </div>
- );
- }
- private _renderWhatsNew(): React.ReactNode {
- return (
- <div className="sm-center sm-px1">
- <a href={WHATS_NEW_URL} className="inline-block text-decoration-none">
- <div className="flex items-center sm-pl0 md-pl2 lg-pl0">
- <Container
- paddingTop="3px"
- paddingLeft="8px"
- paddingBottom="3px"
- paddingRight="8px"
- backgroundColor={colors.white}
- borderRadius={6}
- >
- <Text fontSize="14px" fontWeight={500} fontColor={colors.heroGrey}>
- New
- </Text>
- </Container>
- <Container marginLeft="12px">
- <Text fontSize="16px" fontWeight={500} fontColor={colors.grey300}>
- {WHATS_NEW_TITLE}
- </Text>
- </Container>
- </div>
- </a>
- </div>
- );
- }
- private _renderProjects(
- projects: Project[],
- title: string,
- backgroundColor: string,
- isTitleCenter: boolean,
- ): React.ReactNode {
- const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
- const projectList = _.map(projects, (project: Project, i: number) => {
- const isRelayersOnly = projects.length === 12;
- let colWidth: number;
- switch (this.state.screenWidth) {
- case ScreenWidths.Sm:
- colWidth = 4;
- break;
-
- case ScreenWidths.Md:
- colWidth = 3;
- break;
-
- case ScreenWidths.Lg:
- colWidth = isRelayersOnly ? 2 : 2 - i % 2;
- break;
-
- default:
- throw new Error(`Encountered unknown ScreenWidths value: ${this.state.screenWidth}`);
- }
- return (
- <div key={`project-${project.logoFileName}`} className={`col col-${colWidth} center`}>
- <div>
- <a href={project.projectUrl} target="_blank" className="text-decoration-none">
- <img
- src={`/images/landing/project_logos/${project.logoFileName}`}
- height={isSmallScreen ? 60 : 92}
- />
- </a>
- </div>
- </div>
- );
- });
- return (
- <div className={`clearfix py4 ${isTitleCenter && 'center'}`} style={{ backgroundColor }}>
- <div className="mx-auto max-width-4 clearfix sm-px3">
- <div className="h4 pb3 lg-pl0 md-pl3 sm-pl2" style={TITLE_STYLE}>
- {title}
- </div>
- <div className="clearfix">{projectList}</div>
- <div
- className="pt3 mx-auto center"
- style={{
- color: colors.landingLinkGrey,
- fontFamily: 'Roboto Mono',
- maxWidth: 300,
- fontSize: 14,
- }}
- >
- {this.props.translate.get(Key.FullListPrompt)}{' '}
- <Link to={WebsitePaths.Portal} textDecoration="underline" fontColor={colors.landingLinkGrey}>
- {this.props.translate.get(Key.FullListLink)}
- </Link>
- </div>
- </div>
- </div>
- );
- }
- private _renderTokenizationSection(): React.ReactNode {
- const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
- return (
- <div className="clearfix lg-py4 md-py4 sm-pb4 sm-pt2" style={{ backgroundColor: colors.grey100 }}>
- <div className="mx-auto max-width-4 py4 clearfix">
- {isSmallScreen && this._renderTokenCloud()}
- <div
- className="col lg-col-6 md-col-6 col-12 center"
- style={{ color: colors.darkestGrey, height: 364, lineHeight: '364px' }}
- >
- <div
- className="mx-auto inline-block lg-align-middle md-align-middle sm-align-top"
- style={{ maxWidth: 385, lineHeight: '44px', textAlign: 'left' }}
- >
- <div className="lg-h1 md-h1 sm-h2 sm-center sm-pt3" style={{ fontFamily: 'Roboto Mono' }}>
- {this.props.translate.get(Key.TokenizedSectionHeader, Deco.Cap)}
- </div>
- <div
- className="pb2 lg-pt2 md-pt2 sm-pt3 sm-px3 h5 sm-center"
- style={{ fontFamily: 'Roboto Mono', lineHeight: 1.7, maxWidth: 370 }}
- >
- {this.props.translate.get(Key.TokenizedSectionDescription, Deco.Cap)}
- </div>
- <div className="flex pt1 sm-px3">{this._renderMissionAndValuesButton()}</div>
- </div>
- </div>
- {!isSmallScreen && this._renderTokenCloud()}
- </div>
- </div>
- );
- }
- private _renderTokenCloud(): React.ReactNode {
- const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
- return (
- <div className="col lg-col-6 md-col-6 col-12 center">
- <img src="/images/landing/tokenized_world.png" height={isSmallScreen ? 280 : 364.5} />
- </div>
- );
- }
- private _renderMissionAndValuesButton(): React.ReactNode {
- return (
- <a
- href={constants.URL_MISSION_AND_VALUES_BLOG_POST}
- target="_blank"
- className="inline-block text-decoration-none"
- >
- <CallToAction>{this.props.translate.get(Key.OurMissionAndValues, Deco.CapWords)}</CallToAction>
- </a>
- );
- }
- private _renderInfoBoxes(): React.ReactNode {
- const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
- const boxStyle: React.CSSProperties = {
- maxWidth: 253,
- height: 402,
- backgroundColor: colors.grey50,
- borderRadius: 5,
- padding: '10px 24px 24px',
- };
- const boxContents: BoxContent[] = [
- {
- title: this.props.translate.get(Key.BenefitOneTitle, Deco.Cap),
- description: this.props.translate.get(Key.BenefitOneDescription, Deco.Cap),
- imageUrl: '/images/landing/distributed_network.png',
- classNames: '',
- maxWidth: 160,
- },
- {
- title: this.props.translate.get(Key.BenefitTwoTitle, Deco.Cap),
- description: this.props.translate.get(Key.BenefitTwoDescription, Deco.Cap),
- imageUrl: '/images/landing/liquidity.png',
- classNames: 'mx-auto',
- maxWidth: 160,
- },
- {
- title: this.props.translate.get(Key.BenefitThreeTitle, Deco.Cap),
- description: this.props.translate.get(Key.BenefitThreeDescription, Deco.Cap),
- imageUrl: '/images/landing/exchange_everywhere.png',
- classNames: 'right',
- maxWidth: 130,
- },
- ];
- const boxes = _.map(boxContents, (boxContent: BoxContent) => {
- return (
- <div key={`box-${boxContent.title}`} className="col lg-col-4 md-col-4 col-12 sm-pb4">
- <div className={`center sm-mx-auto ${!isSmallScreen && boxContent.classNames}`} style={boxStyle}>
- <Container className="flex items-center" height="210px">
- <img
- className="mx-auto"
- src={boxContent.imageUrl}
- style={{ height: 'auto', maxWidth: boxContent.maxWidth }}
- />
- </Container>
- <div className="h3" style={{ color: 'black', fontFamily: 'Roboto Mono' }}>
- {boxContent.title}
- </div>
- <div className="pt2 pb2" style={{ fontFamily: 'Roboto Mono', fontSize: 14 }}>
- {boxContent.description}
- </div>
- </div>
- </div>
- );
- });
- return (
- <div className="clearfix" style={{ backgroundColor: colors.heroGrey }}>
- <div className="center pb3 pt4" style={TITLE_STYLE}>
- {this.props.translate.get(Key.BenefitsHeader, Deco.Upper)}
- </div>
- <div className="mx-auto pb4 sm-mt2 clearfix" style={{ maxWidth: '60em' }}>
- {boxes}
- </div>
- </div>
- );
- }
- private _getUseCases(): UseCase[] {
- const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
- const isEnglish = this.props.translate.getLanguage() === Language.English;
- if (isEnglish) {
- return [
- {
- imageUrl: '/images/landing/governance_icon.png',
- type: this.props.translate.get(Key.GamingAndCollectables, Deco.Upper),
- description: this.props.translate.get(Key.GamingAndCollectablesDescription, Deco.Cap),
- classNames: 'lg-px2 md-px2',
- },
- {
- imageUrl: '/images/landing/prediction_market_icon.png',
- type: this.props.translate.get(Key.PredictionMarkets, Deco.Upper),
- description: this.props.translate.get(Key.PredictionMarketsDescription, Deco.Cap),
- classNames: 'lg-px2 md-px2',
- },
- {
- imageUrl: '/images/landing/fund_management_icon.png',
- type: this.props.translate.get(Key.OrderBooks, Deco.Upper),
- description: this.props.translate.get(Key.OrderBooksDescription, Deco.Cap),
- classNames: 'lg-px2 md-px2',
- },
- {
- imageUrl: '/images/landing/loans_icon.png',
- type: this.props.translate.get(Key.DecentralizedLoans, Deco.Upper),
- description: this.props.translate.get(Key.DecentralizedLoansDescription, Deco.Cap),
- classNames: 'lg-pr2 md-pr2 lg-col-6 md-col-6',
- style: {
- width: 291,
- float: 'right',
- marginTop: !isSmallScreen ? 38 : 0,
- },
- },
- {
- imageUrl: '/images/landing/stable_tokens_icon.png',
- type: this.props.translate.get(Key.StableTokens, Deco.Upper),
- description: this.props.translate.get(Key.StableTokensDescription, Deco.Cap),
- classNames: 'lg-pl2 md-pl2 lg-col-6 md-col-6',
- style: { width: 291, marginTop: !isSmallScreen ? 38 : 0 },
- },
- ];
- } else {
- return [
- {
- imageUrl: '/images/landing/governance_icon.png',
- type: this.props.translate.get(Key.DecentralizedGovernance, Deco.Upper),
- description: this.props.translate.get(Key.DecentralizedGovernanceDescription, Deco.Cap),
- classNames: 'lg-px2 md-px2',
- },
- {
- imageUrl: '/images/landing/prediction_market_icon.png',
- type: this.props.translate.get(Key.PredictionMarkets, Deco.Upper),
- description: this.props.translate.get(Key.PredictionMarketsDescription, Deco.Cap),
- classNames: 'lg-px2 md-px2',
- },
- {
- imageUrl: '/images/landing/stable_tokens_icon.png',
- type: this.props.translate.get(Key.StableTokens, Deco.Upper),
- description: this.props.translate.get(Key.StableTokensDescription, Deco.Cap),
- classNames: 'lg-px2 md-px2',
- },
- {
- imageUrl: '/images/landing/loans_icon.png',
- type: this.props.translate.get(Key.DecentralizedLoans, Deco.Upper),
- description: this.props.translate.get(Key.DecentralizedLoansDescription, Deco.Cap),
- classNames: 'lg-pr2 md-pr2 lg-col-6 md-col-6',
- style: {
- width: 291,
- float: 'right',
- marginTop: !isSmallScreen ? 38 : 0,
- },
- },
- {
- imageUrl: '/images/landing/fund_management_icon.png',
- type: this.props.translate.get(Key.FundManagement, Deco.Upper),
- description: this.props.translate.get(Key.FundManagementDescription, Deco.Cap),
- classNames: 'lg-pl2 md-pl2 lg-col-6 md-col-6',
- style: { width: 291, marginTop: !isSmallScreen ? 38 : 0 },
- },
- ];
- }
- }
- private _renderUseCases(): React.ReactNode {
- const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
- const useCases = this._getUseCases();
- const cases = _.map(useCases, (useCase: UseCase) => {
- const style = _.isUndefined(useCase.style) || isSmallScreen ? {} : useCase.style;
- const useCaseBoxStyle = {
- color: colors.grey,
- border: `1px solid ${colors.grey750}`,
- borderRadius: 4,
- maxWidth: isSmallScreen ? 375 : 'none',
- ...style,
- };
- const typeStyle: React.CSSProperties = {
- color: colors.lightGrey,
- fontSize: 13,
- textTransform: 'uppercase',
- fontFamily: 'Roboto Mono',
- fontWeight: 300,
- };
- return (
- <div
- key={`useCase-${useCase.type}`}
- className={`col lg-col-4 md-col-4 col-12 sm-pt3 sm-px3 sm-pb3 ${useCase.classNames}`}
- >
- <div className="relative p2 pb2 sm-mx-auto" style={useCaseBoxStyle}>
- <div className="absolute center" style={{ top: -35, width: 'calc(100% - 32px)' }}>
- <img src={useCase.imageUrl} style={{ height: 50 }} />
- </div>
- <div className="pt2 center" style={typeStyle}>
- {useCase.type}
- </div>
- <div
- className="pt2"
- style={{
- lineHeight: 1.5,
- fontSize: 14,
- overflow: 'hidden',
- height: 124,
- }}
- >
- {useCase.description}
- </div>
- </div>
- </div>
- );
- });
- return (
- <div className="clearfix py4" style={{ backgroundColor: colors.heroGrey }}>
- <div className="center h4 pb3 lg-pl0 md-pl3 sm-pl2" style={TITLE_STYLE}>
- {this.props.translate.get(Key.UseCasesHeader, Deco.Upper)}
- </div>
- <div className="mx-auto pb4 pt3 mt1 sm-mt2 clearfix" style={{ maxWidth: '67em' }}>
- {cases}
- </div>
- </div>
- );
- }
- private _renderCallToAction(): React.ReactNode {
- const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
- const callToActionClassNames =
- 'lg-pr3 md-pr3 lg-right-align md-right-align sm-center sm-px3 h4 lg-table-cell md-table-cell';
- return (
- <div className="clearfix pb4" style={{ backgroundColor: colors.heroGrey }}>
- <div className="mx-auto max-width-4 pb4 mb3 clearfix center">
- <div className="center inline-block" style={{ textAlign: 'left' }}>
- <div
- className={callToActionClassNames}
- style={{
- fontFamily: 'Roboto Mono',
- color: colors.white,
- lineHeight: isSmallScreen ? 1.7 : 3,
- }}
- >
- {this.props.translate.get(Key.FinalCallToAction, Deco.Cap)}
- </div>
- <div className="sm-center sm-pt2 lg-table-cell md-table-cell">
- <Link to={WebsitePaths.Docs}>
- <CallToAction fontSize="15px">
- {this.props.translate.get(Key.BuildCallToAction, Deco.Cap)}
- </CallToAction>
- </Link>
- </div>
- </div>
- </div>
- </div>
- );
- }
- private _updateScreenWidth(): void {
- const newScreenWidth = utils.getScreenWidth();
- if (newScreenWidth !== this.state.screenWidth) {
- this.setState({
- screenWidth: newScreenWidth,
- });
- }
- }
-} // tslint:disable:max-file-line-count
diff --git a/packages/website/ts/pages/launch_kit.tsx b/packages/website/ts/pages/launch_kit.tsx
new file mode 100644
index 000000000..dd4de4d99
--- /dev/null
+++ b/packages/website/ts/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/components/hero';
+
+import { Banner } from 'ts/components/banner';
+import { Button } from 'ts/components/button';
+import { Definition } from 'ts/components/definition';
+import { Icon } from 'ts/components/icon';
+import { SiteWrap } from 'ts/components/siteWrap';
+
+import { Section } from 'ts/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/pages/launch_kit/launch_kit.tsx b/packages/website/ts/pages/launch_kit/launch_kit.tsx
deleted file mode 100644
index 4ea56dbd4..000000000
--- a/packages/website/ts/pages/launch_kit/launch_kit.tsx
+++ /dev/null
@@ -1,335 +0,0 @@
-import { colors, Link } from '@0x/react-shared';
-import * as _ from 'lodash';
-import * as React from 'react';
-import DocumentTitle from 'react-document-title';
-import { Footer } from 'ts/components/footer';
-import { TopBar } from 'ts/components/top_bar/top_bar';
-import { Button } from 'ts/components/ui/button';
-import { Container } from 'ts/components/ui/container';
-import { Image } from 'ts/components/ui/image';
-import { Text } from 'ts/components/ui/text';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { Deco, Key, ScreenWidths } from 'ts/types';
-import { constants } from 'ts/utils/constants';
-import { Translate } from 'ts/utils/translate';
-import { utils } from 'ts/utils/utils';
-
-export interface LaunchKitProps {
- location: Location;
- translate: Translate;
- dispatcher: Dispatcher;
-}
-
-interface LaunchKitState {
- screenWidth: ScreenWidths;
-}
-
-const THROTTLE_TIMEOUT = 100;
-const lighterBackgroundColor = '#222222';
-const darkerBackgroundColor = '#1B1B1B';
-const grayText = '#999999';
-
-interface Benefit {
- icon: string;
- description: string;
-}
-
-export class LaunchKit extends React.Component<LaunchKitProps, LaunchKitState> {
- private readonly _throttledScreenWidthUpdate: () => void;
- constructor(props: LaunchKitProps) {
- super(props);
- this.state = {
- screenWidth: utils.getScreenWidth(),
- };
- this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT);
- }
- public componentDidMount(): void {
- window.addEventListener('resize', this._throttledScreenWidthUpdate);
- window.scrollTo(0, 0);
- }
- public componentWillUnmount(): void {
- window.removeEventListener('resize', this._throttledScreenWidthUpdate);
- }
- public render(): React.ReactNode {
- return (
- <div id="launchKit" className="clearfix" style={{ color: colors.grey500 }}>
- <DocumentTitle title="0x Launch Kit" />
- <TopBar
- blockchainIsLoaded={false}
- location={this.props.location}
- isNightVersion={true}
- style={{ backgroundColor: lighterBackgroundColor, position: 'relative' }}
- translate={this.props.translate}
- />
- {this._renderHero()}
- {this._renderSection()}
- {this._renderCallToAction()}
- {this._renderDisclaimer()}
- <Footer
- backgroundColor={darkerBackgroundColor}
- translate={this.props.translate}
- dispatcher={this.props.dispatcher}
- />
- </div>
- );
- }
- private _renderHero(): React.ReactNode {
- const BENEFITS_1: Benefit[] = [
- {
- icon: '/images/launch_kit/shared_liquidity.svg',
- description: this.props.translate.get(Key.TapIntoAndShare, Deco.Cap),
- },
- {
- icon: '/images/launch_kit/fork.svg',
- description: this.props.translate.get(Key.ForkAndExtend, Deco.Cap),
- },
- {
- icon: '/images/launch_kit/enable_trading.svg',
- description: this.props.translate.get(Key.EnableTrading, Deco.Cap),
- },
- ];
- const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
- const smallButtonPadding = '12px 30px 12px 30px';
- const largeButtonPadding = '14px 60px 14px 60px';
- const left = 'col lg-col-6 md-col-6 col-12 lg-pl2 md-pl2 sm-pl0 sm-px3 sm-center';
- const flexClassName = isSmallScreen
- ? 'flex items-center flex-column justify-center'
- : 'flex items-center justify-center';
- return (
- <div className="clearfix pt4" style={{ backgroundColor: lighterBackgroundColor }}>
- <div className="mx-auto max-width-4 clearfix">
- <div className={`${flexClassName} lg-pb4 md-pb4 sm-mb4`}>
- <div className={left} style={{ color: colors.white }}>
- <div
- className="inline-block lg-align-middle md-align-middle sm-align-top"
- style={{
- paddingLeft: isSmallScreen ? 0 : 12,
- lineHeight: '36px',
- }}
- >
- <Text
- className="sm-pb2"
- fontFamily="Roboto"
- display="inline-block"
- fontColor={colors.white}
- fontWeight="bold"
- lineHeight="1.3em"
- letterSpacing="1px"
- fontSize={isSmallScreen ? '38px' : '46px'}
- >
- {this.props.translate.get(Key.LaunchKit, Deco.CapWords)}
- </Text>
- <Container paddingTop="18px">
- <Text fontColor={colors.linkSectionGrey} fontSize="18px">
- {this.props.translate.get(Key.LaunchKitPitch, Deco.Cap)}
- </Text>
- </Container>
- <Container
- paddingTop="54px"
- className={`flex clearfix sm-mx-auto ${isSmallScreen ? 'justify-center' : ''}`}
- >
- <Container paddingRight="20px">
- <Link to={constants.URL_LAUNCH_KIT} shouldOpenInNewTab={true}>
- <Button
- padding={isSmallScreen ? smallButtonPadding : largeButtonPadding}
- borderRadius="4px"
- borderColor={colors.white}
- >
- <Text fontSize="16px" fontWeight="bold">
- {this.props.translate.get(Key.GetStarted, Deco.Cap)}
- </Text>
- </Button>
- </Link>
- </Container>
- <div>
- <Link to={constants.URL_LAUNCH_KIT_BLOG_POST} shouldOpenInNewTab={true}>
- <Button
- backgroundColor={lighterBackgroundColor}
- borderColor={colors.white}
- fontColor={colors.white}
- padding={isSmallScreen ? smallButtonPadding : largeButtonPadding}
- borderRadius="4px"
- >
- <Text fontSize="16px" fontWeight="bold" fontColor={colors.white}>
- {this.props.translate.get(Key.LearnMore, Deco.Cap)}
- </Text>
- </Button>
- </Link>
- </div>
- </Container>
- </div>
- </div>
- <Container
- marginTop={isSmallScreen ? '60px' : '30px'}
- marginBottom="30px"
- marginLeft="15px"
- marginRight="15px"
- >
- <Image
- src="/images/launch_kit/0x_cupboard.svg"
- maxWidth={isSmallScreen ? '75%' : '100%'}
- height="auto"
- />
- </Container>
- </div>
- </div>
- {this._renderBenefits(BENEFITS_1)}
- </div>
- );
- }
- private _renderSection(): React.ReactNode {
- const BENEFITS_2: Benefit[] = [
- {
- icon: '/images/launch_kit/secondary_market.svg',
- description: this.props.translate.get(Key.QuicklyLaunch, Deco.Cap),
- },
- {
- icon: '/images/launch_kit/in_game_marketplace.svg',
- description: this.props.translate.get(Key.SeemlesslyCreate, Deco.Cap),
- },
- {
- icon: '/images/launch_kit/local_market.svg',
- description: this.props.translate.get(Key.LocalMarket, Deco.Cap),
- },
- ];
- return (
- <div className="clearfix pb4" style={{ backgroundColor: darkerBackgroundColor }}>
- <Container
- className="mx-auto"
- textAlign="center"
- paddingTop="89px"
- paddingBottom="89px"
- maxWidth="421px"
- paddingLeft="10px"
- paddingRight="10px"
- >
- <Text fontSize="26px" lineHeight="37px" fontWeight="medium" fontColor={colors.white}>
- {this.props.translate.get(Key.PerfectForDevelopers, Deco.Cap)}
- </Text>
- </Container>
- {this._renderBenefits(BENEFITS_2)}
- </div>
- );
- }
- private _renderCallToAction(): React.ReactNode {
- const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
- const smallButtonPadding = '8px 14px 8px 14px';
- const largeButtonPadding = '8px 14px 8px 14px';
- return (
- <Container
- className="clearfix"
- backgroundColor={lighterBackgroundColor}
- paddingTop="90px"
- paddingBottom="90px"
- >
- <Container className="clearfix mx-auto" maxWidth="850px">
- <Container className="lg-left md-left sm-mx-auto sm-pb3" width="348px">
- <Text fontColor={colors.white} fontSize="18px">
- View our comprehensive documentation to start building today.
- </Text>
- </Container>
- <Container
- className={`lg-right md-right flex clearfix sm-mx-auto ${
- isSmallScreen ? 'justify-center' : ''
- }`}
- paddingTop="5px"
- >
- <Container paddingRight="20px">
- <Link to={`${constants.URL_LAUNCH_KIT}/#table-of-contents`} shouldOpenInNewTab={true}>
- <Button
- padding={isSmallScreen ? smallButtonPadding : largeButtonPadding}
- borderRadius="4px"
- backgroundColor={lighterBackgroundColor}
- borderColor={colors.white}
- >
- <Text fontSize="16px" fontWeight="bold" fontColor={colors.white}>
- {this.props.translate.get(Key.ExploreTheDocs, Deco.Cap)}
- </Text>
- </Button>
- </Link>
- </Container>
- <div>
- <Link to={constants.URL_ZEROEX_CHAT} shouldOpenInNewTab={true}>
- <Button
- padding={isSmallScreen ? smallButtonPadding : largeButtonPadding}
- borderRadius="4px"
- >
- <Text fontSize="16px" fontWeight="bold">
- {this.props.translate.get(Key.GetInTouch, Deco.Cap)}
- </Text>
- </Button>
- </Link>
- </div>
- </Container>
- </Container>
- </Container>
- );
- }
- private _renderBenefits(benefits: Benefit[]): React.ReactNode {
- return (
- <Container className="lg-flex md-flex justify-between mx-auto pb4" maxWidth="890px">
- {_.map(benefits, benefit => {
- return (
- <Container className="mx-auto sm-pb4" width="240px">
- <Container textAlign="center">
- <img src={benefit.icon} />
- </Container>
- <Container paddingTop="26px">
- <Text
- fontSize="18px"
- lineHeight="28px"
- textAlign="center"
- fontColor={colors.linkSectionGrey}
- >
- {benefit.description}
- </Text>
- </Container>
- </Container>
- );
- })}
- </Container>
- );
- }
- private _renderDisclaimer(): React.ReactNode {
- return (
- <Container
- className="clearfix"
- backgroundColor={darkerBackgroundColor}
- paddingTop="70px"
- paddingBottom="70px"
- >
- <Container className="mx-auto" maxWidth="850px" paddingLeft="20px" paddingRight="20px">
- <Text fontColor={grayText} fontSize="10px">
- <b>Disclaimer:</b> 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.
- </Text>
- <Container paddingTop="15px">
- <Text fontColor={grayText} fontSize="10px">
- See the{' '}
- <Link
- to={constants.URL_APACHE_LICENSE}
- shouldOpenInNewTab={true}
- textDecoration="underline"
- >
- Apache License, Version 2.0
- </Link>{' '}
- for the specific language governing all applicable permissions and limitations.
- </Text>
- </Container>
- </Container>
- </Container>
- );
- }
- private _updateScreenWidth(): void {
- const newScreenWidth = utils.getScreenWidth();
- if (newScreenWidth !== this.state.screenWidth) {
- this.setState({
- screenWidth: newScreenWidth,
- });
- }
- }
-}
diff --git a/packages/website/ts/pages/market_maker.tsx b/packages/website/ts/pages/market_maker.tsx
new file mode 100644
index 000000000..854870358
--- /dev/null
+++ b/packages/website/ts/pages/market_maker.tsx
@@ -0,0 +1,162 @@
+import * as _ from 'lodash';
+import { opacify } from 'polished';
+import * as React from 'react';
+
+import { Banner } from 'ts/components/banner';
+import { Button } from 'ts/components/button';
+import { Action, Definition } from 'ts/components/definition';
+import { Hero } from 'ts/components/hero';
+import { ModalContact, ModalContactType } from 'ts/components/modals/modal_contact';
+import { Section } from 'ts/components/newLayout';
+import { SiteWrap } from 'ts/components/siteWrap';
+import { colors } from 'ts/style/colors';
+import { WebsitePaths } from 'ts/types';
+
+interface OfferData {
+ icon: string;
+ title: string;
+ description: string;
+ links?: Action[];
+}
+export interface NextMarketMakerProps {}
+
+export class NextMarketMaker extends React.Component<NextMarketMakerProps> {
+ public state = {
+ isContactModalOpen: false,
+ };
+
+ private readonly _offersData: OfferData[];
+
+ constructor(props: NextMarketMakerProps) {
+ super(props);
+ this._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, find arbitrage opportunities, and trade on new types of exchanges like prediction markets and non-fungible token marketplaces.',
+ links: [
+ {
+ label: 'Explore the Docs',
+ url: `${WebsitePaths.Wiki}#Market-Making-on-0x`,
+ },
+ ],
+ },
+ {
+ icon: 'generateRevenueForYourBusiness-large',
+ title: 'Market Making Compensation',
+ description: 'Accepted applicants can receive up to $15,000 for completing onboarding',
+ },
+ {
+ icon: 'getInTouch',
+ title: 'Dedicated Support',
+ description:
+ 'The 0x team will provide 1:1 onboarding assistance and promptly answer all your questions. They will walk you through the tutorials so that you know how to read 0x order types, spin up an Ethereum node, and execute trades on the blockchain.',
+ links: [
+ {
+ label: 'Contact Us',
+ onClick: this._onOpenContactModal,
+ shouldUseAnchorTag: true,
+ },
+ ],
+ },
+ ];
+ }
+
+ public render(): React.ReactNode {
+ return (
+ <SiteWrap theme="light">
+ <Hero
+ maxWidth="865px"
+ maxWidthHeading="715px"
+ isLargeTitle={false}
+ isFullWidth={false}
+ isCenteredMobile={false}
+ title="Bring liquidity to the markets 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 to bring liquidity to the 0x network. The Program includes tutorials, monetary incentives, and 1:1 support from the 0x team."
+ actions={this._renderHeroActions()}
+ />
+
+ <Section bgColor="light" isFlex={true} maxWidth="1170px">
+ <Definition
+ title="Secure Trading"
+ 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 gas fees to make 0x orders"
+ icon="low-cost"
+ iconSize="medium"
+ isInline={true}
+ />
+ </Section>
+
+ <Section>
+ {_.map(this._offersData, (item, index) => (
+ <Definition
+ key={`offers-${index}`}
+ icon={item.icon}
+ title={item.title}
+ description={item.description}
+ isInlineIcon={true}
+ iconSize={240}
+ fontSize="medium"
+ actions={item.links}
+ />
+ ))}
+ </Section>
+
+ <Banner
+ heading="Start trading today."
+ subline="Check out our Market Making tutorials to get started"
+ mainCta={{ text: 'Tutorials', href: `${WebsitePaths.Wiki}#Market-Making-on-0x` }}
+ secondaryCta={{ text: 'Apply Now', onClick: this._onOpenContactModal }}
+ />
+ <ModalContact
+ isOpen={this.state.isContactModalOpen}
+ onDismiss={this._onDismissContactModal}
+ modalContactType={ModalContactType.MarketMaker}
+ />
+ </SiteWrap>
+ );
+ }
+
+ private readonly _onOpenContactModal = (): void => {
+ this.setState({ isContactModalOpen: true });
+ };
+
+ private readonly _onDismissContactModal = (): void => {
+ this.setState({ isContactModalOpen: false });
+ };
+
+ private readonly _renderHeroActions = () => (
+ <>
+ <Button href={`${WebsitePaths.Wiki}#Market-Making-on-0x`} bgColor="dark" isInline={true}>
+ Get Started
+ </Button>
+ <Button
+ onClick={this._onOpenContactModal}
+ borderColor={opacify(0.4)(colors.brandDark)}
+ isTransparent={true}
+ isInline={true}
+ >
+ Apply Now
+ </Button>
+ </>
+ );
+}
diff --git a/packages/website/ts/pages/not_found.tsx b/packages/website/ts/pages/not_found.tsx
index a7992a8fa..6abd8fc80 100644
--- a/packages/website/ts/pages/not_found.tsx
+++ b/packages/website/ts/pages/not_found.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { Footer } from 'ts/components/footer';
+import { Footer } from 'ts/components/old_footer';
import { TopBar } from 'ts/components/top_bar/top_bar';
import { FullscreenMessage } from 'ts/pages/fullscreen_message';
import { Dispatcher } from 'ts/redux/dispatcher';
diff --git a/packages/website/ts/pages/why.tsx b/packages/website/ts/pages/why.tsx
new file mode 100644
index 000000000..197ce5fc9
--- /dev/null
+++ b/packages/website/ts/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/components/banner';
+import { Button } from 'ts/components/button';
+import { Definition } from 'ts/components/definition';
+import { Hero } from 'ts/components/hero';
+import { Column, Section, WrapSticky } from 'ts/components/newLayout';
+import { SiteWrap } from 'ts/components/siteWrap';
+import { Slide, Slider } from 'ts/components/slider/slider';
+import { Heading } from 'ts/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/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..fab382b07 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',
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/json_schemas/.discharge.json b/python-packages/json_schemas/.discharge.json
new file mode 100644
index 000000000..66d95679f
--- /dev/null
+++ b/python-packages/json_schemas/.discharge.json
@@ -0,0 +1,13 @@
+{
+ "domain": "0x-json-schemas-py",
+ "build_command": "python setup.py build_sphinx",
+ "upload_directory": "build/docs/html",
+ "index_key": "index.html",
+ "error_key": "index.html",
+ "trailing_slashes": true,
+ "cache": 3600,
+ "aws_profile": "default",
+ "aws_region": "us-east-1",
+ "cdn": false,
+ "dns_configured": true
+}
diff --git a/python-packages/json_schemas/.pylintrc b/python-packages/json_schemas/.pylintrc
new file mode 100644
index 000000000..937bc6313
--- /dev/null
+++ b/python-packages/json_schemas/.pylintrc
@@ -0,0 +1,3 @@
+[MESSAGES CONTROL]
+disable=C0330,line-too-long,fixme,too-few-public-methods,too-many-ancestors
+# C0330 is "bad hanging indent". we use indents per `black`.
diff --git a/python-packages/json_schemas/README.md b/python-packages/json_schemas/README.md
new file mode 100644
index 000000000..ef8e888f3
--- /dev/null
+++ b/python-packages/json_schemas/README.md
@@ -0,0 +1,45 @@
+## 0x-json-schemas
+
+0x JSON schemas for those developing on top of 0x protocol.
+
+Read the [documentation](http://0x-json-schemas-py.s3-website-us-east-1.amazonaws.com/)
+
+## Installing
+
+```bash
+pip install 0x-json-schemas
+```
+
+## Contributing
+
+We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository.
+
+Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
+
+### Install Code and Dependencies
+
+Ensure that you have installed Python >=3.6 and Docker. Then:
+
+```bash
+pip install -e .[dev]
+```
+
+### Test
+
+Tests depend on a running ganache instance with the 0x contracts deployed in it. For convenience, a docker container is provided that has ganache-cli and a snapshot containing the necessary contracts. A shortcut is provided to run that docker container: `./setup.py ganache`. With that running, the tests can be run with `./setup.py test`.
+
+### Clean
+
+`./setup.py clean --all`
+
+### Lint
+
+`./setup.py lint`
+
+### Build Documentation
+
+`./setup.py build_sphinx`
+
+### More
+
+See `./setup.py --help-commands` for more info.
diff --git a/python-packages/json_schemas/setup.py b/python-packages/json_schemas/setup.py
new file mode 100755
index 000000000..7813f101f
--- /dev/null
+++ b/python-packages/json_schemas/setup.py
@@ -0,0 +1,191 @@
+#!/usr/bin/env python
+
+"""setuptools module for json_schemas package."""
+
+import distutils.command.build_py
+from distutils.command.clean import clean
+import subprocess # nosec
+from shutil import rmtree
+from os import environ, path
+from sys import argv
+
+from setuptools import find_packages, setup
+from setuptools.command.test import test as TestCommand
+
+
+class TestCommandExtension(TestCommand):
+ """Run pytest tests."""
+
+ def run_tests(self):
+ """Invoke pytest."""
+ import pytest
+
+ exit(pytest.main())
+
+
+class LintCommand(distutils.command.build_py.build_py):
+ """Custom setuptools command class for running linters."""
+
+ description = "Run linters"
+
+ def run(self):
+ """Run linter shell commands."""
+ lint_commands = [
+ # formatter:
+ "black --line-length 79 --check --diff src test setup.py".split(),
+ # style guide checker (formerly pep8):
+ "pycodestyle src test setup.py".split(),
+ # docstring style checker:
+ "pydocstyle src test setup.py".split(),
+ # static type checker:
+ "mypy src test setup.py".split(),
+ # security issue checker:
+ "bandit -r src ./setup.py".split(),
+ # general linter:
+ "pylint src test setup.py".split(),
+ # pylint takes relatively long to run, so it runs last, to enable
+ # fast failures.
+ ]
+
+ # tell mypy where to find interface stubs for 3rd party libs
+ environ["MYPYPATH"] = path.join(
+ path.dirname(path.realpath(argv[0])), "stubs"
+ )
+
+ for lint_command in lint_commands:
+ print(
+ "Running lint command `", " ".join(lint_command).strip(), "`"
+ )
+ subprocess.check_call(lint_command) # nosec
+
+
+class CleanCommandExtension(clean):
+ """Custom command to do custom cleanup."""
+
+ def run(self):
+ """Run the regular clean, followed by our custom commands."""
+ super().run()
+ rmtree("dist", ignore_errors=True)
+ rmtree(".mypy_cache", ignore_errors=True)
+ rmtree(".tox", ignore_errors=True)
+ rmtree(".pytest_cache", ignore_errors=True)
+ rmtree("src/*.egg-info", ignore_errors=True)
+
+
+class TestPublishCommand(distutils.command.build_py.build_py):
+ """Custom command to publish to test.pypi.org."""
+
+ description = (
+ "Publish dist/* to test.pypi.org. Run sdist & bdist_wheel first."
+ )
+
+ def run(self):
+ """Run twine to upload to test.pypi.org."""
+ subprocess.check_call( # nosec
+ (
+ "twine upload --repository-url https://test.pypi.org/legacy/"
+ + " --verbose dist/*"
+ ).split()
+ )
+
+
+class PublishCommand(distutils.command.build_py.build_py):
+ """Custom command to publish to pypi.org."""
+
+ description = "Publish dist/* to pypi.org. Run sdist & bdist_wheel first."
+
+ def run(self):
+ """Run twine to upload to pypi.org."""
+ subprocess.check_call("twine upload dist/*".split()) # nosec
+
+
+class PublishDocsCommand(distutils.command.build_py.build_py):
+ """Custom command to publish docs to S3."""
+
+ description = (
+ "Publish docs to "
+ + "http://0x-json-schemas-py.s3-website-us-east-1.amazonaws.com/"
+ )
+
+ def run(self):
+ """Run npm package `discharge` to build & upload docs."""
+ subprocess.check_call("discharge deploy".split()) # nosec
+
+
+with open("README.md", "r") as file_handle:
+ README_MD = file_handle.read()
+
+
+setup(
+ name="0x-json-schemas",
+ version="1.0.0",
+ description="JSON schemas for 0x applications",
+ long_description=README_MD,
+ long_description_content_type="text/markdown",
+ url=(
+ "https://github.com/0xProject/0x-monorepo/tree/development"
+ + "/python-packages/json_schemas"
+ ),
+ author="F. Eugene Aumson",
+ author_email="feuGeneA@users.noreply.github.com",
+ cmdclass={
+ "clean": CleanCommandExtension,
+ "lint": LintCommand,
+ "test": TestCommandExtension,
+ "test_publish": TestPublishCommand,
+ "publish": PublishCommand,
+ "publish_docs": PublishDocsCommand,
+ },
+ install_requires=["jsonschema", "mypy_extensions", "stringcase"],
+ extras_require={
+ "dev": [
+ "bandit",
+ "black",
+ "coverage",
+ "coveralls",
+ "mypy",
+ "mypy_extensions",
+ "pycodestyle",
+ "pydocstyle",
+ "pylint",
+ "pytest",
+ "sphinx",
+ "tox",
+ "twine",
+ ]
+ },
+ python_requires=">=3.6, <4",
+ package_data={"zero_ex.json_schemas": ["py.typed", "schemas/*"]},
+ package_dir={"": "src"},
+ license="Apache 2.0",
+ keywords=(
+ "ethereum cryptocurrency 0x decentralized blockchain dex exchange"
+ ),
+ namespace_packages=["zero_ex"],
+ packages=find_packages("src"),
+ classifiers=[
+ "Development Status :: 2 - Pre-Alpha",
+ "Intended Audience :: Developers",
+ "Intended Audience :: Financial and Insurance Industry",
+ "License :: OSI Approved :: Apache Software License",
+ "Natural Language :: English",
+ "Operating System :: OS Independent",
+ "Programming Language :: Python",
+ "Programming Language :: Python :: 3 :: Only",
+ "Programming Language :: Python :: 3.6",
+ "Programming Language :: Python :: 3.7",
+ "Topic :: Internet :: WWW/HTTP",
+ "Topic :: Office/Business :: Financial",
+ "Topic :: Other/Nonlisted Topic",
+ "Topic :: Security :: Cryptography",
+ "Topic :: Software Development :: Libraries",
+ "Topic :: Utilities",
+ ],
+ zip_safe=False, # required per mypy
+ command_options={
+ "build_sphinx": {
+ "source_dir": ("setup.py", "src"),
+ "build_dir": ("setup.py", "build/docs"),
+ }
+ },
+)
diff --git a/python-packages/json_schemas/src/conf.py b/python-packages/json_schemas/src/conf.py
new file mode 100644
index 000000000..1ae1493e3
--- /dev/null
+++ b/python-packages/json_schemas/src/conf.py
@@ -0,0 +1,54 @@
+"""Configuration file for the Sphinx documentation builder."""
+
+# Reference: http://www.sphinx-doc.org/en/master/config
+
+from typing import List
+import pkg_resources
+
+
+# pylint: disable=invalid-name
+# because these variables are not named in upper case, as globals should be.
+
+project = "0x-json-schemas"
+# pylint: disable=redefined-builtin
+copyright = "2018, ZeroEx, Intl."
+author = "F. Eugene Aumson"
+version = pkg_resources.get_distribution("0x-json-schemas").version
+release = "" # The full version, including alpha/beta/rc tags
+
+extensions = [
+ "sphinx.ext.autodoc",
+ "sphinx.ext.doctest",
+ "sphinx.ext.intersphinx",
+ "sphinx.ext.coverage",
+ "sphinx.ext.viewcode",
+]
+
+templates_path = ["doc_templates"]
+
+source_suffix = ".rst"
+# eg: source_suffix = [".rst", ".md"]
+
+master_doc = "index" # The master toctree document.
+
+language = None
+
+exclude_patterns: List[str] = []
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = None
+
+html_theme = "alabaster"
+
+html_static_path = ["doc_static"]
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = "json_schemaspydoc"
+
+# -- Extension configuration:
+
+# Example configuration for intersphinx: refer to the Python standard library.
+intersphinx_mapping = {"https://docs.python.org/": None}
diff --git a/python-packages/json_schemas/src/doc_static/.gitkeep b/python-packages/json_schemas/src/doc_static/.gitkeep
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/python-packages/json_schemas/src/doc_static/.gitkeep
diff --git a/python-packages/json_schemas/src/index.rst b/python-packages/json_schemas/src/index.rst
new file mode 100644
index 000000000..3de809aa3
--- /dev/null
+++ b/python-packages/json_schemas/src/index.rst
@@ -0,0 +1,18 @@
+.. source for the sphinx-generated build/docs/web/index.html
+
+Python zero_ex.json_schemas
+===========================
+
+.. toctree::
+ :maxdepth: 2
+ :caption: Contents:
+
+.. automodule:: zero_ex.json_schemas
+ :members:
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
diff --git a/python-packages/json_schemas/src/zero_ex/__init__.py b/python-packages/json_schemas/src/zero_ex/__init__.py
new file mode 100644
index 000000000..e90d833db
--- /dev/null
+++ b/python-packages/json_schemas/src/zero_ex/__init__.py
@@ -0,0 +1,2 @@
+"""0x Python API."""
+__import__("pkg_resources").declare_namespace(__name__)
diff --git a/python-packages/order_utils/src/zero_ex/json_schemas/__init__.py b/python-packages/json_schemas/src/zero_ex/json_schemas/__init__.py
index a76a2fa3b..10c564b99 100644
--- a/python-packages/order_utils/src/zero_ex/json_schemas/__init__.py
+++ b/python-packages/json_schemas/src/zero_ex/json_schemas/__init__.py
@@ -6,6 +6,7 @@ from typing import Mapping
from pkg_resources import resource_string
import jsonschema
+from stringcase import snakecase
class _LocalRefResolver(jsonschema.RefResolver):
@@ -13,20 +14,10 @@ class _LocalRefResolver(jsonschema.RefResolver):
def __init__(self):
"""Initialize a new instance."""
- self.ref_to_file = {
- "/addressSchema": "address_schema.json",
- "/hexSchema": "hex_schema.json",
- "/orderSchema": "order_schema.json",
- "/wholeNumberSchema": "whole_number_schema.json",
- "/ECSignature": "ec_signature_schema.json",
- "/signedOrderSchema": "signed_order_schema.json",
- "/ecSignatureParameterSchema": (
- "ec_signature_parameter_schema.json" + ""
- ),
- }
jsonschema.RefResolver.__init__(self, "", "")
- def resolve_from_url(self, url: str) -> str:
+ @staticmethod
+ def resolve_from_url(url: str) -> str:
"""Resolve the given URL.
:param url: a string representing the URL of the JSON schema to fetch.
@@ -35,15 +26,11 @@ class _LocalRefResolver(jsonschema.RefResolver):
`url` does not exist.
"""
ref = url.replace("file://", "")
- if ref in self.ref_to_file:
- return json.loads(
- resource_string(
- "zero_ex.json_schemas", f"schemas/{self.ref_to_file[ref]}"
- )
+ return json.loads(
+ resource_string(
+ "zero_ex.json_schemas",
+ f"schemas/{snakecase(ref.lstrip('/'))}.json",
)
- raise jsonschema.ValidationError(
- f"Unknown ref '{ref}'. "
- + f"Known refs: {list(self.ref_to_file.keys())}."
)
@@ -65,10 +52,32 @@ def assert_valid(data: Mapping, schema_id: str) -> None:
>>> assert_valid(
... {'v': 27, 'r': '0x'+'f'*64, 's': '0x'+'f'*64},
- ... '/ECSignature',
+ ... '/ecSignatureSchema',
... )
"""
# noqa
_, schema = _LOCAL_RESOLVER.resolve(schema_id)
jsonschema.validate(data, schema, resolver=_LOCAL_RESOLVER)
+
+
+def assert_valid_json(data: str, schema_id: str) -> None:
+ """Validate the given `data` against the specified `schema`.
+
+ :param data: JSON string to be validated.
+ :param schema_id: id property of the JSON schema to validate against. Must
+ be one of those listed in `the 0x JSON schema files
+ <https://github.com/0xProject/0x-monorepo/tree/development/packages/json-schemas/schemas>`_.
+
+ Raises an exception if validation fails.
+
+ >>> assert_valid_json(
+ ... r'''{
+ ... "v": 27,
+ ... "r": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ ... "s": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ ... }''',
+ ... '/ecSignatureSchema',
+ ... )
+ """ # noqa: E501 (line too long)
+ assert_valid(json.loads(data), schema_id)
diff --git a/python-packages/json_schemas/src/zero_ex/json_schemas/py.typed b/python-packages/json_schemas/src/zero_ex/json_schemas/py.typed
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/python-packages/json_schemas/src/zero_ex/json_schemas/py.typed
diff --git a/python-packages/order_utils/src/zero_ex/json_schemas/schemas b/python-packages/json_schemas/src/zero_ex/json_schemas/schemas
index b8257372c..b8257372c 120000
--- a/python-packages/order_utils/src/zero_ex/json_schemas/schemas
+++ b/python-packages/json_schemas/src/zero_ex/json_schemas/schemas
diff --git a/python-packages/json_schemas/stubs/distutils/__init__.pyi b/python-packages/json_schemas/stubs/distutils/__init__.pyi
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/python-packages/json_schemas/stubs/distutils/__init__.pyi
diff --git a/python-packages/json_schemas/stubs/distutils/command/__init__.pyi b/python-packages/json_schemas/stubs/distutils/command/__init__.pyi
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/python-packages/json_schemas/stubs/distutils/command/__init__.pyi
diff --git a/python-packages/json_schemas/stubs/distutils/command/clean.pyi b/python-packages/json_schemas/stubs/distutils/command/clean.pyi
new file mode 100644
index 000000000..46a42ddb1
--- /dev/null
+++ b/python-packages/json_schemas/stubs/distutils/command/clean.pyi
@@ -0,0 +1,7 @@
+from distutils.core import Command
+
+class clean(Command):
+ def initialize_options(self: clean) -> None: ...
+ def finalize_options(self: clean) -> None: ...
+ def run(self: clean) -> None: ...
+ ...
diff --git a/python-packages/order_utils/stubs/jsonschema/__init__.pyi b/python-packages/json_schemas/stubs/jsonschema/__init__.pyi
index 442e2f65e..442e2f65e 100644
--- a/python-packages/order_utils/stubs/jsonschema/__init__.pyi
+++ b/python-packages/json_schemas/stubs/jsonschema/__init__.pyi
diff --git a/python-packages/json_schemas/stubs/jsonschema/exceptions.pyi b/python-packages/json_schemas/stubs/jsonschema/exceptions.pyi
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/python-packages/json_schemas/stubs/jsonschema/exceptions.pyi
diff --git a/python-packages/json_schemas/stubs/pytest/__init__.pyi b/python-packages/json_schemas/stubs/pytest/__init__.pyi
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/python-packages/json_schemas/stubs/pytest/__init__.pyi
diff --git a/python-packages/json_schemas/stubs/pytest/raises.pyi b/python-packages/json_schemas/stubs/pytest/raises.pyi
new file mode 100644
index 000000000..2e3b29f3d
--- /dev/null
+++ b/python-packages/json_schemas/stubs/pytest/raises.pyi
@@ -0,0 +1 @@
+def raises(exception: Exception) -> ExceptionInfo: ...
diff --git a/python-packages/json_schemas/stubs/setuptools/__init__.pyi b/python-packages/json_schemas/stubs/setuptools/__init__.pyi
new file mode 100644
index 000000000..8ea8d32b7
--- /dev/null
+++ b/python-packages/json_schemas/stubs/setuptools/__init__.pyi
@@ -0,0 +1,8 @@
+from distutils.dist import Distribution
+from typing import Any, List
+
+def setup(**attrs: Any) -> Distribution: ...
+
+class Command: ...
+
+def find_packages(where: str) -> List[str]: ...
diff --git a/python-packages/json_schemas/stubs/setuptools/command/__init__.pyi b/python-packages/json_schemas/stubs/setuptools/command/__init__.pyi
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/python-packages/json_schemas/stubs/setuptools/command/__init__.pyi
diff --git a/python-packages/json_schemas/stubs/setuptools/command/test.pyi b/python-packages/json_schemas/stubs/setuptools/command/test.pyi
new file mode 100644
index 000000000..c5ec770ad
--- /dev/null
+++ b/python-packages/json_schemas/stubs/setuptools/command/test.pyi
@@ -0,0 +1,3 @@
+from setuptools import Command
+
+class test(Command): ...
diff --git a/python-packages/json_schemas/stubs/stringcase/__init__.pyi b/python-packages/json_schemas/stubs/stringcase/__init__.pyi
new file mode 100644
index 000000000..56d784cf5
--- /dev/null
+++ b/python-packages/json_schemas/stubs/stringcase/__init__.pyi
@@ -0,0 +1,2 @@
+def snakecase(_: str):
+ ...
diff --git a/python-packages/json_schemas/test/__init__.py b/python-packages/json_schemas/test/__init__.py
new file mode 100644
index 000000000..ce724e180
--- /dev/null
+++ b/python-packages/json_schemas/test/__init__.py
@@ -0,0 +1 @@
+"""Tests of zero_ex.json_schemas."""
diff --git a/python-packages/json_schemas/test/test_doctest.py b/python-packages/json_schemas/test/test_doctest.py
new file mode 100644
index 000000000..2aa576422
--- /dev/null
+++ b/python-packages/json_schemas/test/test_doctest.py
@@ -0,0 +1,25 @@
+"""Exercise doctests for all of our modules."""
+
+from doctest import testmod
+import pkgutil
+import importlib
+
+import zero_ex.json_schemas
+
+
+def test_all_doctests():
+ """Gather zero_ex.json_schemas.* modules and doctest them."""
+ # json_schemas module
+ module = "zero_ex.json_schemas"
+ print(module)
+ failure_count, _ = testmod(importlib.import_module(module))
+ assert failure_count == 0
+
+ # any json_schemas.* sub-modules
+ for (_, modname, _) in pkgutil.walk_packages(
+ path=zero_ex.json_schemas.__path__, prefix="zero_ex.json_schemas"
+ ):
+ module = importlib.import_module(modname)
+ print(module)
+ (failure_count, _) = testmod(module)
+ assert failure_count == 0
diff --git a/python-packages/order_utils/test/test_json_schemas.py b/python-packages/json_schemas/test/test_json_schemas.py
index 51cecbd4f..d0e9840b3 100644
--- a/python-packages/order_utils/test/test_json_schemas.py
+++ b/python-packages/json_schemas/test/test_json_schemas.py
@@ -1,10 +1,28 @@
"""Tests of zero_ex.json_schemas"""
-from zero_ex.order_utils import make_empty_order
from zero_ex.json_schemas import _LOCAL_RESOLVER, assert_valid
+NULL_ADDRESS = "0x0000000000000000000000000000000000000000"
+
+EMPTY_ORDER = {
+ "makerAddress": NULL_ADDRESS,
+ "takerAddress": NULL_ADDRESS,
+ "senderAddress": NULL_ADDRESS,
+ "feeRecipientAddress": NULL_ADDRESS,
+ "makerAssetData": NULL_ADDRESS,
+ "takerAssetData": NULL_ADDRESS,
+ "salt": "0",
+ "makerFee": "0",
+ "takerFee": "0",
+ "makerAssetAmount": "0",
+ "takerAssetAmount": "0",
+ "expirationTimeSeconds": "0",
+ "exchangeAddress": NULL_ADDRESS,
+}
+
+
def test_assert_valid_caches_resources():
"""Test that the JSON ref resolver in `assert_valid()` caches resources
@@ -15,7 +33,7 @@ def test_assert_valid_caches_resources():
"""
_LOCAL_RESOLVER._remote_cache.cache_clear() # pylint: disable=W0212
- assert_valid(make_empty_order(), "/orderSchema")
+ assert_valid(EMPTY_ORDER, "/orderSchema")
cache_info = (
_LOCAL_RESOLVER._remote_cache.cache_info() # pylint: disable=W0212
)
diff --git a/python-packages/json_schemas/tox.ini b/python-packages/json_schemas/tox.ini
new file mode 100644
index 000000000..1d5de646e
--- /dev/null
+++ b/python-packages/json_schemas/tox.ini
@@ -0,0 +1,25 @@
+# tox (https://tox.readthedocs.io/) is a tool for running tests
+# in multiple virtualenvs. This configuration file will run the
+# test suite on all supported python versions. To use it, "pip install tox"
+# and then run "tox" from this directory.
+
+[tox]
+envlist = py37
+
+[testenv]
+commands =
+ pip install -e .[dev]
+ python setup.py test
+
+[testenv:run_tests_against_test_deployment]
+commands =
+ # install dependencies from real PyPI
+ pip install jsonschema mypy_extensions pytest
+ # install package-under-test from test PyPI
+ pip install --index-url https://test.pypi.org/legacy/ 0x-json-schemas
+ pytest test
+
+[testenv:run_tests_against_deployment]
+commands =
+ pip install 0x-json-schemas
+ pytest test
diff --git a/python-packages/order_utils/setup.py b/python-packages/order_utils/setup.py
index 31631d8d4..06533e60a 100755
--- a/python-packages/order_utils/setup.py
+++ b/python-packages/order_utils/setup.py
@@ -165,9 +165,9 @@ setup(
"ganache": GanacheCommand,
},
install_requires=[
+ "0x-json-schemas",
"eth-abi",
"eth_utils",
- "jsonschema",
"mypy_extensions",
"web3",
],
@@ -192,7 +192,6 @@ setup(
package_data={
"zero_ex.order_utils": ["py.typed"],
"zero_ex.contract_artifacts": ["artifacts/*"],
- "zero_ex.json_schemas": ["schemas/*"],
},
package_dir={"": "src"},
license="Apache 2.0",
diff --git a/python-packages/order_utils/src/index.rst b/python-packages/order_utils/src/index.rst
index 551487ab1..4d27a4b17 100644
--- a/python-packages/order_utils/src/index.rst
+++ b/python-packages/order_utils/src/index.rst
@@ -22,9 +22,6 @@ See source for class properties. Sphinx does not easily generate class property
.. autoclass:: zero_ex.order_utils.asset_data_utils.ERC721AssetData
-.. automodule:: zero_ex.json_schemas
- :members:
-
Indices and tables
==================
diff --git a/python-packages/order_utils/stubs/web3/__init___BASE_31011.pyi b/python-packages/order_utils/stubs/web3/__init___BASE_31011.pyi
new file mode 100644
index 000000000..fcecc7434
--- /dev/null
+++ b/python-packages/order_utils/stubs/web3/__init___BASE_31011.pyi
@@ -0,0 +1,26 @@
+from typing import Dict, Optional, Union
+
+from web3.utils import datatypes
+
+
+class Web3:
+ class HTTPProvider: ...
+
+ def __init__(self, provider: HTTPProvider) -> None: ...
+
+ @staticmethod
+ def sha3(
+ primitive: Optional[Union[bytes, int, None]] = None,
+ text: Optional[str] = None,
+ hexstr: Optional[str] = None
+ ) -> bytes: ...
+
+ class net:
+ version: str
+ ...
+
+ class eth:
+ @staticmethod
+ def contract(address: str, abi: Dict) -> datatypes.Contract: ...
+ ...
+ ...
diff --git a/python-packages/sra_client/README.md b/python-packages/sra_client/README.md
index ab3939b41..279fb41a4 100644
--- a/python-packages/sra_client/README.md
+++ b/python-packages/sra_client/README.md
@@ -6,6 +6,35 @@ A Python client for interacting with servers conforming to [the Standard Relayer
The [JSON schemas](http://json-schema.org/) for the API payloads and responses can be found in [@0xproject/json-schemas](https://github.com/0xProject/0x.js/tree/development/packages/json-schemas). Examples of each payload and response can be found in the 0x.js library's [test suite](https://github.com/0xProject/0x.js/blob/development/packages/json-schemas/test/schema_test.ts#L1).
+```bash
+pip install 0x-json-schemas
+```
+
+You can easily validate your API's payloads and responses using the [0x-json-schemas](https://github.com/0xProject/0x.js/tree/development/python-packages/json_schemas) package:
+
+```python
+from zero_ex.json_schemas import assert_valid
+from zero_ex.order_utils import Order
+
+order: Order = {
+ 'makerAddress': "0x0000000000000000000000000000000000000000",
+ 'takerAddress': "0x0000000000000000000000000000000000000000",
+ 'feeRecipientAddress': "0x0000000000000000000000000000000000000000",
+ 'senderAddress': "0x0000000000000000000000000000000000000000",
+ 'makerAssetAmount': "1000000000000000000",
+ 'takerAssetAmount': "1000000000000000000",
+ 'makerFee': "0",
+ 'takerFee': "0",
+ 'expirationTimeSeconds': "12345",
+ 'salt': "12345",
+ 'makerAssetData': "0x0000000000000000000000000000000000000000",
+ 'takerAssetData': "0x0000000000000000000000000000000000000000",
+ 'exchangeAddress': "0x0000000000000000000000000000000000000000",
+}
+
+assert_valid(order, "/orderSchema")
+```
+
# Pagination
Requests that return potentially large collections should respond to the **?page** and **?perPage** parameters. For example:
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
diff --git a/yarn.lock b/yarn.lock
index 8327a4ee8..b86969e3b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -507,7 +507,7 @@
lodash "^4.17.5"
uuid "^3.1.0"
-"@0x/order-utils@^2.0.0", "@0x/order-utils@^2.0.1":
+"@0x/order-utils@^2.0.1":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@0x/order-utils/-/order-utils-2.0.1.tgz#8c46d7aeb9e2cce54a0822824c12427cbe5f7eb4"
dependencies:
@@ -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"
@@ -2563,6 +2655,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 +2788,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 +2807,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 +3007,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 +3097,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 +3110,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 +3306,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 +3459,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"
@@ -3890,6 +4085,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 +4150,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 +4449,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 +4980,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 +5463,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 +5748,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"
@@ -6212,6 +6443,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 +6642,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 +6836,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 +6919,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 +7037,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 +7060,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 +7078,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 +7245,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:
@@ -7124,6 +7434,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 +7859,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"
@@ -7801,6 +8122,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 +8185,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 +8272,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 +8284,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 +8302,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 +8340,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 +8548,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 +9725,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 +10197,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 +10258,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 +10596,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 +11763,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 +12331,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 +12840,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 +12997,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 +13047,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 +13115,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 +13252,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 +13308,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 +13322,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 +13368,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 +13406,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 +13420,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 +14330,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 +15441,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 +15503,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 +15587,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 +15600,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 +16063,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 +16312,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 +16417,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 +16444,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 +16540,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"
@@ -16687,6 +17185,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 +17534,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"