├── .nvmrc ├── src ├── routes │ ├── Scoreboard │ │ ├── api │ │ │ └── index.js │ │ ├── store │ │ │ ├── reducers │ │ │ │ ├── index.js │ │ │ │ └── users.js │ │ │ ├── models │ │ │ │ ├── index.js │ │ │ │ └── user.js │ │ │ ├── index.js │ │ │ └── actions │ │ │ │ ├── addUsers.js │ │ │ │ ├── index.js │ │ │ │ ├── fetchTournamentUsers.js │ │ │ │ ├── fetchTournamentUserData.js │ │ │ │ └── rewards.js │ │ ├── components │ │ │ ├── Table │ │ │ │ ├── ScoreTable │ │ │ │ │ ├── index.css │ │ │ │ │ └── index.stories.js │ │ │ │ └── Table.scss │ │ │ ├── RewardClaimAddress │ │ │ │ ├── AddressSection │ │ │ │ │ └── AddressSection.scss │ │ │ │ └── RewardClaim.scss │ │ │ ├── Layout.scss │ │ │ └── Layout.stories.js │ │ ├── containers │ │ │ ├── index.js │ │ │ ├── actions.js │ │ │ └── selector.js │ │ └── assets │ │ │ ├── ok.svg │ │ │ └── trophy.svg │ ├── Dashboard │ │ ├── api │ │ │ ├── fetchTrades.js │ │ │ └── fetchShares.js │ │ ├── components │ │ │ └── Dashboard │ │ │ │ ├── Dashboard.scss │ │ │ │ ├── Markets │ │ │ │ ├── Markets.scss │ │ │ │ ├── Market │ │ │ │ │ ├── index.js │ │ │ │ │ └── NoMarket.js │ │ │ │ ├── ConditionalList.scss │ │ │ │ ├── Category.scss │ │ │ │ └── Category.js │ │ │ │ ├── UserSection │ │ │ │ ├── Category.scss │ │ │ │ ├── UserSection.scss │ │ │ │ └── Category.js │ │ │ │ ├── Title │ │ │ │ ├── DashboardTitle.scss │ │ │ │ └── index.js │ │ │ │ └── Metrics │ │ │ │ └── Metric.js │ │ ├── assets │ │ │ ├── group.png │ │ │ ├── arrows.svg │ │ │ ├── shape.svg │ │ │ ├── crystal-ball.svg │ │ │ ├── badges │ │ │ │ └── crystal-gazer.svg │ │ │ └── icon_outstandingPredictions.svg │ │ └── containers │ │ │ ├── Dashboard │ │ │ ├── utils │ │ │ │ ├── index.js │ │ │ │ └── calculateProfit.js │ │ │ ├── index.js │ │ │ └── actions.js │ │ │ └── index.js │ ├── MarketDetails │ │ ├── components │ │ │ ├── ExpandableViews │ │ │ │ ├── MarketBuySharesForm │ │ │ │ │ ├── OutcomesSection │ │ │ │ │ │ ├── OutcomesSection.scss │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── SubmitError │ │ │ │ │ │ └── index.js │ │ │ │ │ └── LimitMarginAnnotation │ │ │ │ │ │ └── index.js │ │ │ │ ├── MarketMySharesForm │ │ │ │ │ └── SharesTable │ │ │ │ │ │ ├── ShareRow │ │ │ │ │ │ └── ShareRow.scss │ │ │ │ │ │ └── SharesTable.scss │ │ │ │ └── MarketMyTrades │ │ │ │ │ ├── marketMyTrades.scss │ │ │ │ │ └── TableHeader │ │ │ │ │ └── index.js │ │ │ ├── MarketGraph │ │ │ │ ├── MarketGraph.scss │ │ │ │ └── DateAxisTick │ │ │ │ │ └── index.js │ │ │ └── MarketDetail │ │ │ │ ├── Details │ │ │ │ ├── Details.scss │ │ │ │ ├── RedeemWinnings │ │ │ │ │ └── RedeemWinnings.scss │ │ │ │ └── MarketTimer │ │ │ │ │ └── MarketTimer.scss │ │ │ │ ├── marketDetail.scss │ │ │ │ ├── Infos │ │ │ │ └── utils │ │ │ │ │ └── embeddedLink.js │ │ │ │ └── Controls │ │ │ │ └── Controls.scss │ │ ├── api │ │ │ ├── index.js │ │ │ ├── sellShares.js │ │ │ └── calculateGasCost.js │ │ ├── store │ │ │ ├── selectors │ │ │ │ ├── isGasPriceFetched.js │ │ │ │ ├── isGasCostFetched.js │ │ │ │ ├── getGasCosts.js │ │ │ │ ├── index.js │ │ │ │ ├── getGasPrice.js │ │ │ │ ├── getMarketTradesForAccount.js │ │ │ │ └── getMarketShares.js │ │ │ └── actions │ │ │ │ ├── index.js │ │ │ │ ├── requestMarketTradesForAccount.js │ │ │ │ ├── requestMarketSharesForAccount.js │ │ │ │ ├── requestGasCost.js │ │ │ │ └── requestMarket.js │ │ └── containers │ │ │ └── index.js │ ├── Transactions │ │ ├── store │ │ │ ├── reducers │ │ │ │ └── index.js │ │ │ ├── models │ │ │ │ └── transaction.js │ │ │ └── selectors │ │ │ │ └── transactions.spec.js │ │ ├── components │ │ │ └── Transactions │ │ │ │ └── Transaction │ │ │ │ └── DetailLabel │ │ │ │ ├── DetailLabel.scss │ │ │ │ └── index.js │ │ └── containers │ │ │ ├── index.js │ │ │ └── TransactionsPage │ │ │ └── index.js │ ├── reducers.js │ ├── GameGuide │ │ ├── assets │ │ │ ├── claim.png │ │ │ ├── login1.png │ │ │ ├── login2.png │ │ │ ├── login3.png │ │ │ ├── login4.png │ │ │ ├── profits1.png │ │ │ ├── profits2.png │ │ │ ├── profits3.png │ │ │ ├── prediction1.png │ │ │ ├── prediction2.png │ │ │ ├── prediction3.png │ │ │ ├── prediction4.png │ │ │ ├── prediction5.png │ │ │ ├── claimRewards.png │ │ │ ├── connectWallet.png │ │ │ ├── registerWallet.png │ │ │ ├── switchNetwork.png │ │ │ ├── switchNetwork2.png │ │ │ ├── marketoverview1.png │ │ │ ├── claimSwitchNetwork.png │ │ │ └── dashboardoverview1.png │ │ ├── containers │ │ │ └── GameGuide.js │ │ └── components │ │ │ ├── metamaskComponents │ │ │ └── SignUp │ │ │ │ └── SignUp.scss │ │ │ ├── uPortComponents │ │ │ ├── index.css │ │ │ └── SignUp │ │ │ │ └── index.js │ │ │ ├── index.js │ │ │ └── LayoutMetamask.js │ └── MarketList │ │ ├── components │ │ ├── MarketsTitle │ │ │ ├── MarketsTitle.scss │ │ │ └── index.js │ │ ├── Filter │ │ │ ├── Filter.scss │ │ │ └── index.js │ │ ├── MarketOverview │ │ │ ├── MarketOverview.scss │ │ │ └── index.js │ │ ├── Markets │ │ │ ├── Markets.scss │ │ │ └── Market │ │ │ │ ├── MarketResolution.js │ │ │ │ └── MarketTrading.js │ │ ├── NoMarkets │ │ │ └── index.js │ │ └── MarketStats │ │ │ └── MarketStats.scss │ │ ├── containers │ │ ├── MarketList │ │ │ ├── actions.js │ │ │ ├── index.js │ │ │ └── selector.js │ │ └── index.js │ │ └── store │ │ └── test │ │ ├── marketlist.spec.js │ │ └── market.selector.js ├── store │ ├── models │ │ ├── index.js │ │ ├── share │ │ │ └── index.js │ │ ├── market │ │ │ ├── index.js │ │ │ ├── scalar.js │ │ │ └── categorical.js │ │ └── trade │ │ │ └── index.js │ ├── selectors │ │ ├── interface.js │ │ ├── notifications.js │ │ ├── modal.js │ │ ├── market │ │ │ └── index.js │ │ └── account │ │ │ └── trades.js │ ├── actions │ │ ├── market │ │ │ ├── addMarkets.js │ │ │ ├── updateMarket.js │ │ │ ├── index.js │ │ │ └── constants │ │ │ │ └── index.js │ │ ├── interface.js │ │ ├── shares │ │ │ ├── updateShare.js │ │ │ ├── addShare.js │ │ │ ├── redeemShare.js │ │ │ └── index.js │ │ ├── modal.js │ │ └── trades │ │ │ ├── addTrade.js │ │ │ └── index.js │ ├── middlewares │ │ ├── Storage │ │ │ ├── actions.js │ │ │ ├── constants.js │ │ │ ├── index.js │ │ │ └── Load.js │ │ ├── CrashReporter.js │ │ └── Notifications.js │ ├── reducers │ │ ├── notifications │ │ │ ├── models │ │ │ │ └── notification.js │ │ │ └── index.js │ │ ├── accountTrades.js │ │ ├── interface.js │ │ ├── market.js │ │ ├── accountShares.js │ │ ├── modal.js │ │ └── index.js │ └── utils │ │ └── marketStatus.js ├── verification │ └── onfido │ │ ├── index.js │ │ ├── containers │ │ └── store │ │ │ └── selectors.js │ │ └── api │ │ └── utils │ │ └── checks.js ├── components │ ├── Form │ │ ├── MandatoryHint.scss │ │ ├── InputError.scss │ │ ├── RadioButtonGroup.scss │ │ ├── TextInputAdornment.scss │ │ ├── index.js │ │ ├── Select.scss │ │ ├── InputError.js │ │ ├── MandatoryHint.js │ │ └── TextInputAdornment.js │ ├── layout │ │ ├── PageFrame │ │ │ ├── index.scss │ │ │ └── index.js │ │ ├── Title │ │ │ ├── index.scss │ │ │ └── index.js │ │ ├── Subtitle │ │ │ ├── index.scss │ │ │ └── index.js │ │ ├── Img │ │ │ ├── index.css │ │ │ └── index.js │ │ ├── Block │ │ │ ├── index.scss │ │ │ └── index.js │ │ ├── Hairline │ │ │ ├── index.stories.js │ │ │ └── index.js │ │ ├── Bold │ │ │ └── index.js │ │ ├── Span │ │ │ └── index.js │ │ └── Paragraph │ │ │ ├── index.scss │ │ │ └── index.js │ ├── WalletAddress │ │ └── style.scss │ ├── Header │ │ ├── Layouts │ │ │ ├── DesktopHeader │ │ │ │ └── components │ │ │ │ │ └── WrongNetwork │ │ │ │ │ ├── WrongNetwork.scss │ │ │ │ │ └── index.js │ │ │ ├── MobileHeader │ │ │ │ ├── assets │ │ │ │ │ ├── icon_copy.png │ │ │ │ │ └── icon_copy.svg │ │ │ │ ├── BurgerIcon │ │ │ │ │ ├── BurgerIcon.scss │ │ │ │ │ ├── assets │ │ │ │ │ │ └── menu_icon.svg │ │ │ │ │ └── index.js │ │ │ │ └── AccountOverview │ │ │ │ │ └── AccountOverview.scss │ │ │ └── index.js │ │ ├── Balance │ │ │ └── Balance.scss │ │ ├── MenuAccountDropdown │ │ │ ├── Separator.js │ │ │ ├── MenuActions.js │ │ │ ├── List.js │ │ │ ├── index.js │ │ │ ├── tooltip.scss │ │ │ └── LogOut.js │ │ ├── BadgeIcon.js │ │ └── ProviderIcon.js │ ├── Outcome │ │ ├── OutcomeColorBox │ │ │ ├── OutcomeColorBox.scss │ │ │ └── index.js │ │ ├── WinningOutcome │ │ │ └── WinningOutcome.scss │ │ └── OutcomeScalar │ │ │ └── TrendingOutcomeScalar │ │ │ └── index.js │ ├── Icon │ │ └── Icon.scss │ ├── Spinner │ │ ├── Indefinite.scss │ │ └── Transaction.js │ ├── Responsive │ │ └── index.js │ ├── Footer │ │ ├── index.stories.js │ │ └── Footer.scss │ ├── ModalContent │ │ ├── TransactionsExplanation │ │ │ ├── TransactionExplanation.scss │ │ │ └── index.js │ │ ├── Verification │ │ │ ├── Verification.scss │ │ │ └── index.js │ │ ├── OutcomePriceChanged.js │ │ ├── InitialisationError │ │ │ └── InitialisationError.scss │ │ └── InstallProvider │ │ │ └── InstallProvider.scss │ ├── Root │ │ └── index.js │ ├── Notifications │ │ └── Notifications.scss │ └── TransactionFloater │ │ └── Notifications │ │ └── Notifications.scss ├── integrations │ ├── store │ │ └── models │ │ │ ├── index.js │ │ │ └── provider.js │ ├── trust │ │ └── utils.js │ ├── status │ │ ├── utils.js │ │ └── assets │ │ │ └── status-logo.svg │ ├── metamask │ │ ├── utils.js │ │ └── components │ │ │ └── UnlockMetamask │ │ │ └── UnlockMetamask.scss │ ├── utils.js │ ├── index.js │ └── uport │ │ ├── uportQr.js │ │ └── uportNotifications.js ├── assets │ ├── images │ │ ├── image1.png │ │ └── image2.png │ ├── img │ │ ├── icons │ │ │ ├── icon_oly.png │ │ │ ├── icon_wallet.svg │ │ │ ├── icon_logout.svg │ │ │ ├── icon_checkmark.svg │ │ │ ├── icon_link.svg │ │ │ ├── icon_incomeForecast.svg │ │ │ ├── icon_share.svg │ │ │ ├── icon_next.svg │ │ │ ├── icon_cross.svg │ │ │ ├── icon_winningOutcome.svg │ │ │ ├── icon_currency.svg │ │ │ ├── icon_enddate.svg │ │ │ └── gno_token.svg │ │ ├── gnosis_logo_favicon.png │ │ ├── gnosis_apollo_favicon.png │ │ ├── olympia_logo_favicon.png │ │ ├── placeholder.svg │ │ └── badges │ │ │ └── crystal-gazer.svg │ ├── fonts │ │ ├── Montserrat-Light.ttf │ │ ├── Montserrat-Medium.ttf │ │ └── Montserrat-Regular.ttf │ ├── content │ │ ├── footer.md │ │ └── footerOlympia.md │ ├── verification │ │ └── onfido │ │ │ ├── id-type-driverlicense.svg │ │ │ └── id-type-id.svg │ └── badges │ │ └── crystal-gazer.svg ├── embedded │ ├── routes │ │ ├── EmbeddedView │ │ │ ├── index.js │ │ │ ├── components │ │ │ │ └── NoMatch │ │ │ │ │ └── index.js │ │ │ └── api │ │ │ │ └── index.js │ │ └── index.js │ ├── html │ │ └── index.html │ ├── components │ │ └── Root │ │ │ └── index.js │ ├── index.js │ └── style │ │ └── embedded.css ├── containers │ ├── Modals │ │ ├── ModalOutcomePriceChanged.js │ │ ├── ModalRegisterWallet │ │ │ ├── selectors.js │ │ │ ├── api.js │ │ │ └── actions.js │ │ ├── ModalAcceptTOS │ │ │ └── index.js │ │ ├── ModalTransactionExplanation.js │ │ ├── ModalInstallProvider.js │ │ ├── ModalInitialisationError.js │ │ ├── ModalClaimReward │ │ │ ├── api.js │ │ │ └── action.js │ │ ├── ModalVerification.js │ │ ├── ModalRegisterWalletUport.js │ │ ├── ModalSelectProvider.js │ │ └── index.js │ ├── CookieBannerContainer │ │ └── index.js │ ├── EnableIntercom │ │ ├── index.js │ │ └── EnableIntercom.scss │ ├── App │ │ ├── transitions.scss │ │ └── app.scss │ ├── InteractionButton │ │ └── interactionButton.scss │ ├── LegalCompliance │ │ ├── index.js │ │ ├── components │ │ │ ├── Form.scss │ │ │ ├── DocumentExplanation.js │ │ │ └── DocumentField.js │ │ └── store │ │ │ └── selectors.js │ ├── HeaderContainer │ │ ├── index.js │ │ └── store │ │ │ └── actions.js │ ├── BackdropProvider │ │ └── backdrop.scss │ └── TransactionFloaterContainer │ │ └── index.js ├── api │ ├── index.js │ ├── rewards.js │ ├── utils │ │ └── fetch.js │ ├── token.js │ └── market.js ├── html │ └── index.html ├── utils │ ├── transactionExplanations.js │ ├── analytics │ │ ├── intercom │ │ │ └── index.js │ │ ├── google │ │ │ └── index.js │ │ └── index.js │ └── marginPrice.js ├── scss │ └── main.scss └── setup.js ├── jsconfig.json ├── postcss.config.js ├── docker-compose.yml ├── scripts ├── configuration.jest.js ├── env_build.sh └── configuration.browser.js ├── Dockerfile ├── .github └── ISSUE_TEMPLATE │ ├── tech-task.md │ ├── feature_request.md │ └── bug_report.md ├── .bootstraprc ├── .travis └── scripts │ └── prepare_production_deployment.sh ├── .gitignore ├── PULL_REQUEST_TEMPLATE.md ├── config └── mainnet │ └── development.json ├── LICENSE └── .eslintrc /.nvmrc: -------------------------------------------------------------------------------- 1 | 10.5.0 2 | -------------------------------------------------------------------------------- /src/routes/Scoreboard/api/index.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/routes/Dashboard/api/fetchTrades.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/store/models/index.js: -------------------------------------------------------------------------------- 1 | export * from './market' 2 | -------------------------------------------------------------------------------- /src/verification/onfido/index.js: -------------------------------------------------------------------------------- 1 | export default from './containers' 2 | -------------------------------------------------------------------------------- /src/components/Form/MandatoryHint.scss: -------------------------------------------------------------------------------- 1 | .mandatoryHint { 2 | color: red; 3 | } -------------------------------------------------------------------------------- /src/routes/Dashboard/api/fetchShares.js: -------------------------------------------------------------------------------- 1 | export default async () => { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /src/components/layout/PageFrame/index.scss: -------------------------------------------------------------------------------- 1 | .pageFrame { 2 | margin-top: 30px; 3 | } 4 | -------------------------------------------------------------------------------- /src/routes/Scoreboard/store/reducers/index.js: -------------------------------------------------------------------------------- 1 | export { default as users } from './users' 2 | -------------------------------------------------------------------------------- /src/integrations/store/models/index.js: -------------------------------------------------------------------------------- 1 | export { default as ProviderRecord } from './provider' 2 | -------------------------------------------------------------------------------- /src/routes/Dashboard/components/Dashboard/Dashboard.scss: -------------------------------------------------------------------------------- 1 | .dashboard { 2 | margin-top: 30px; 3 | } -------------------------------------------------------------------------------- /src/routes/Scoreboard/store/models/index.js: -------------------------------------------------------------------------------- 1 | export { default as UserRecord } from './user' 2 | -------------------------------------------------------------------------------- /src/routes/MarketDetails/components/ExpandableViews/MarketBuySharesForm/OutcomesSection/OutcomesSection.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/routes/Transactions/store/reducers/index.js: -------------------------------------------------------------------------------- 1 | export { default as transactions } from './transactions' 2 | -------------------------------------------------------------------------------- /src/store/selectors/interface.js: -------------------------------------------------------------------------------- 1 | export const getUiState = (state, key) => state.interfaceState.get(key) 2 | -------------------------------------------------------------------------------- /src/assets/images/image1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/assets/images/image1.png -------------------------------------------------------------------------------- /src/assets/images/image2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/assets/images/image2.png -------------------------------------------------------------------------------- /src/assets/img/icons/icon_oly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/assets/img/icons/icon_oly.png -------------------------------------------------------------------------------- /src/routes/reducers.js: -------------------------------------------------------------------------------- 1 | export * from './Transactions/store/reducers' 2 | export * from './Scoreboard/store/reducers' 3 | -------------------------------------------------------------------------------- /src/routes/Scoreboard/store/index.js: -------------------------------------------------------------------------------- 1 | export * from './actions' 2 | export * from './models' 3 | export * from './selectors' 4 | -------------------------------------------------------------------------------- /src/assets/fonts/Montserrat-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/assets/fonts/Montserrat-Light.ttf -------------------------------------------------------------------------------- /src/assets/fonts/Montserrat-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/assets/fonts/Montserrat-Medium.ttf -------------------------------------------------------------------------------- /src/assets/img/gnosis_logo_favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/assets/img/gnosis_logo_favicon.png -------------------------------------------------------------------------------- /src/routes/Dashboard/assets/group.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/routes/Dashboard/assets/group.png -------------------------------------------------------------------------------- /src/routes/GameGuide/assets/claim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/routes/GameGuide/assets/claim.png -------------------------------------------------------------------------------- /src/routes/GameGuide/assets/login1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/routes/GameGuide/assets/login1.png -------------------------------------------------------------------------------- /src/routes/GameGuide/assets/login2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/routes/GameGuide/assets/login2.png -------------------------------------------------------------------------------- /src/routes/GameGuide/assets/login3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/routes/GameGuide/assets/login3.png -------------------------------------------------------------------------------- /src/routes/GameGuide/assets/login4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/routes/GameGuide/assets/login4.png -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "experimentalDecorators": true 4 | }, 5 | "exclude": ["node_modules"] 6 | } 7 | -------------------------------------------------------------------------------- /src/assets/fonts/Montserrat-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/assets/fonts/Montserrat-Regular.ttf -------------------------------------------------------------------------------- /src/assets/img/gnosis_apollo_favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/assets/img/gnosis_apollo_favicon.png -------------------------------------------------------------------------------- /src/assets/img/olympia_logo_favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/assets/img/olympia_logo_favicon.png -------------------------------------------------------------------------------- /src/routes/GameGuide/assets/profits1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/routes/GameGuide/assets/profits1.png -------------------------------------------------------------------------------- /src/routes/GameGuide/assets/profits2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/routes/GameGuide/assets/profits2.png -------------------------------------------------------------------------------- /src/routes/GameGuide/assets/profits3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/routes/GameGuide/assets/profits3.png -------------------------------------------------------------------------------- /src/embedded/routes/EmbeddedView/index.js: -------------------------------------------------------------------------------- 1 | import EmbeddedViewContainer from './containers' 2 | 3 | export default EmbeddedViewContainer 4 | -------------------------------------------------------------------------------- /src/routes/GameGuide/assets/prediction1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/routes/GameGuide/assets/prediction1.png -------------------------------------------------------------------------------- /src/routes/GameGuide/assets/prediction2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/routes/GameGuide/assets/prediction2.png -------------------------------------------------------------------------------- /src/routes/GameGuide/assets/prediction3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/routes/GameGuide/assets/prediction3.png -------------------------------------------------------------------------------- /src/routes/GameGuide/assets/prediction4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/routes/GameGuide/assets/prediction4.png -------------------------------------------------------------------------------- /src/routes/GameGuide/assets/prediction5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/routes/GameGuide/assets/prediction5.png -------------------------------------------------------------------------------- /src/store/actions/market/addMarkets.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions' 2 | 3 | export default createAction('ADD_MARKET_LIST') 4 | -------------------------------------------------------------------------------- /src/routes/GameGuide/assets/claimRewards.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/routes/GameGuide/assets/claimRewards.png -------------------------------------------------------------------------------- /src/routes/GameGuide/assets/connectWallet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/routes/GameGuide/assets/connectWallet.png -------------------------------------------------------------------------------- /src/routes/GameGuide/assets/registerWallet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/routes/GameGuide/assets/registerWallet.png -------------------------------------------------------------------------------- /src/routes/GameGuide/assets/switchNetwork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/routes/GameGuide/assets/switchNetwork.png -------------------------------------------------------------------------------- /src/routes/GameGuide/assets/switchNetwork2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/routes/GameGuide/assets/switchNetwork2.png -------------------------------------------------------------------------------- /src/components/WalletAddress/style.scss: -------------------------------------------------------------------------------- 1 | .walletAddress { 2 | &:hover { 3 | text-decoration: underline; 4 | cursor: pointer; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/integrations/trust/utils.js: -------------------------------------------------------------------------------- 1 | export const hasTrust = () => window && typeof window.web3 !== 'undefined' && !!window.web3.currentProvider.isTrust 2 | -------------------------------------------------------------------------------- /src/routes/GameGuide/assets/marketoverview1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/routes/GameGuide/assets/marketoverview1.png -------------------------------------------------------------------------------- /src/store/actions/interface.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions' 2 | 3 | export const changeUiState = createAction('CHANGE_UI_STATE') 4 | -------------------------------------------------------------------------------- /src/integrations/status/utils.js: -------------------------------------------------------------------------------- 1 | export const hasStatus = () => window && typeof window.web3 !== 'undefined' && !!window.web3.currentProvider.isStatus 2 | -------------------------------------------------------------------------------- /src/routes/GameGuide/assets/claimSwitchNetwork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/routes/GameGuide/assets/claimSwitchNetwork.png -------------------------------------------------------------------------------- /src/routes/GameGuide/assets/dashboardoverview1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/routes/GameGuide/assets/dashboardoverview1.png -------------------------------------------------------------------------------- /src/store/middlewares/Storage/actions.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions' 2 | 3 | export const loadStorage = createAction('LOAD_STORAGE') 4 | -------------------------------------------------------------------------------- /src/components/Header/Layouts/DesktopHeader/components/WrongNetwork/WrongNetwork.scss: -------------------------------------------------------------------------------- 1 | .wrongNetwork { 2 | background-size: cover; 3 | margin-right: 10px; 4 | } 5 | -------------------------------------------------------------------------------- /src/containers/Modals/ModalOutcomePriceChanged.js: -------------------------------------------------------------------------------- 1 | import OutcomePriceChanged from 'components/ModalContent/OutcomePriceChanged' 2 | 3 | export default OutcomePriceChanged 4 | -------------------------------------------------------------------------------- /src/components/Header/Layouts/MobileHeader/assets/icon_copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnosis/pm-trading-ui/HEAD/src/components/Header/Layouts/MobileHeader/assets/icon_copy.png -------------------------------------------------------------------------------- /src/routes/MarketList/components/MarketsTitle/MarketsTitle.scss: -------------------------------------------------------------------------------- 1 | @import '~style/vars.scss'; 2 | 3 | .marketListTitle { 4 | h1 { 5 | margin: $page-heading-margins; 6 | } 7 | } -------------------------------------------------------------------------------- /src/routes/Transactions/components/Transactions/Transaction/DetailLabel/DetailLabel.scss: -------------------------------------------------------------------------------- 1 | @import '~style/vars.scss'; 2 | 3 | .detailLabel { 4 | color: $font-color-dark; 5 | } 6 | -------------------------------------------------------------------------------- /src/routes/MarketDetails/api/index.js: -------------------------------------------------------------------------------- 1 | export { default as buyShares } from './buyShares' 2 | export { default as sellShares } from './sellShares' 3 | export * from './calculateGasCost' 4 | -------------------------------------------------------------------------------- /src/routes/MarketList/components/Filter/Filter.scss: -------------------------------------------------------------------------------- 1 | .filterInput { 2 | input { 3 | font-size: 12px; 4 | } 5 | 6 | label { 7 | margin: 12px 0; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/store/actions/shares/updateShare.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions' 2 | 3 | const UPDATE_SHARE = 'UPDATE_SHARE' 4 | 5 | export default createAction(UPDATE_SHARE) 6 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | sourceMap: true, 3 | plugins: [ 4 | require('autoprefixer')({ 5 | browsers: ['> 1%', 'last 2 versions'], 6 | }), 7 | ], 8 | } 9 | -------------------------------------------------------------------------------- /src/api/index.js: -------------------------------------------------------------------------------- 1 | export * from './gnosis' 2 | export * from './account' 3 | export * from './market' 4 | export * from './gasPrice' 5 | export * from './token' 6 | export * from './rewards' 7 | -------------------------------------------------------------------------------- /src/routes/MarketDetails/store/selectors/isGasPriceFetched.js: -------------------------------------------------------------------------------- 1 | const isGasPriceFetched = state => state.blockchain.get('gasPrice') !== undefined 2 | 3 | export default isGasPriceFetched 4 | -------------------------------------------------------------------------------- /src/routes/Scoreboard/store/actions/addUsers.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions' 2 | 3 | export const ADD_USERS = 'ADD_USERS' 4 | 5 | export default createAction(ADD_USERS) 6 | -------------------------------------------------------------------------------- /src/routes/Dashboard/components/Dashboard/Markets/Markets.scss: -------------------------------------------------------------------------------- 1 | @import "~style/vars.scss"; 2 | 3 | .dashboardOverview { 4 | background-color: $bg-color-muted; 5 | padding: 40px 0 20px; 6 | } -------------------------------------------------------------------------------- /src/routes/Dashboard/containers/Dashboard/utils/index.js: -------------------------------------------------------------------------------- 1 | export { default as calcShareWinnings } from './calcShareWinnings' 2 | export { default as calculateProfit } from './calculateProfit' 3 | -------------------------------------------------------------------------------- /src/store/actions/market/updateMarket.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions' 2 | 3 | export const UPDATE_MARKET = 'UPDATE_MARKET' 4 | 5 | export default createAction(UPDATE_MARKET) 6 | -------------------------------------------------------------------------------- /src/store/actions/modal.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions' 2 | 3 | export const openModal = createAction('OPEN_MODAL') 4 | export const closeModal = createAction('CLOSE_MODAL') 5 | -------------------------------------------------------------------------------- /src/routes/GameGuide/containers/GameGuide.js: -------------------------------------------------------------------------------- 1 | import Loadable from 'react-loadable' 2 | 3 | export default Loadable({ 4 | loader: () => import('../components'), 5 | loading: () => null, 6 | }) 7 | -------------------------------------------------------------------------------- /src/store/actions/shares/addShare.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions' 2 | 3 | export const ADD_ACCOUNT_SHARE = 'ADD_ACCOUNT_SHARE' 4 | 5 | export default createAction(ADD_ACCOUNT_SHARE) 6 | -------------------------------------------------------------------------------- /src/store/actions/trades/addTrade.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions' 2 | 3 | export const ADD_ACCOUNT_TRADE = 'ADD_ACCOUNT_TRADE' 4 | 5 | export default createAction(ADD_ACCOUNT_TRADE) 6 | -------------------------------------------------------------------------------- /src/routes/MarketList/containers/MarketList/actions.js: -------------------------------------------------------------------------------- 1 | import { fetchMarkets } from 'store/actions/market' 2 | 3 | export default dispatch => ({ 4 | fetchMarkets: () => dispatch(fetchMarkets()), 5 | }) 6 | -------------------------------------------------------------------------------- /src/components/Form/InputError.scss: -------------------------------------------------------------------------------- 1 | @import "~style/vars.scss"; 2 | 3 | .inputError { 4 | position: absolute; 5 | font-weight: 800; 6 | color: $active-highlight-error; 7 | padding: $paddings-inputs; 8 | } -------------------------------------------------------------------------------- /src/routes/MarketDetails/store/selectors/isGasCostFetched.js: -------------------------------------------------------------------------------- 1 | const isGasCostFetched = (state, property) => state.blockchain.getIn(['gasCosts', property]) !== undefined 2 | 3 | export default isGasCostFetched 4 | -------------------------------------------------------------------------------- /src/routes/Scoreboard/components/Table/ScoreTable/index.css: -------------------------------------------------------------------------------- 1 | .greenRank { 2 | color: green; 3 | } 4 | 5 | .redRank { 6 | color: red; 7 | } 8 | 9 | .neutralRank { 10 | color: #626262; 11 | } -------------------------------------------------------------------------------- /src/components/layout/Title/index.scss: -------------------------------------------------------------------------------- 1 | .ol-title { 2 | font-family: Montserrat; 3 | font-size: 42px; 4 | font-weight: 300; 5 | text-align: left; 6 | color: #333333; 7 | margin-bottom: 32px; 8 | } -------------------------------------------------------------------------------- /src/routes/MarketList/components/MarketOverview/MarketOverview.scss: -------------------------------------------------------------------------------- 1 | @import '~style/vars.scss'; 2 | 3 | .marketOverview { 4 | padding: 40px 0; 5 | background-color: $bg-color-muted; 6 | min-height: 420px; 7 | } -------------------------------------------------------------------------------- /src/store/actions/shares/redeemShare.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions' 2 | 3 | export const REDEEM_ACCOUNT_SHARE = 'REDEEM_ACCOUNT_SHARE' 4 | 5 | export default createAction(REDEEM_ACCOUNT_SHARE) 6 | -------------------------------------------------------------------------------- /src/store/actions/trades/index.js: -------------------------------------------------------------------------------- 1 | export { default as requestTrades } from './requestTrades' 2 | export { default as addTrade } from './addTrade' 3 | export * from './addTrade' 4 | export * from './requestTrades' 5 | -------------------------------------------------------------------------------- /src/embedded/routes/EmbeddedView/components/NoMatch/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const NoMatch = () => ( 4 | Sorry, the specified Market can not be found 5 | ) 6 | 7 | export default NoMatch 8 | -------------------------------------------------------------------------------- /src/routes/Dashboard/components/Dashboard/UserSection/Category.scss: -------------------------------------------------------------------------------- 1 | @import '~style/vars.scss'; 2 | 3 | .category { 4 | min-height: 200px; 5 | 6 | @media (max-width: $screen-sm) { 7 | min-height: auto; 8 | } 9 | } -------------------------------------------------------------------------------- /src/components/Header/Balance/Balance.scss: -------------------------------------------------------------------------------- 1 | .weth-explanation { 2 | max-width: 250px; 3 | text-align: center; 4 | } 5 | 6 | .symbol.wrapped { 7 | text-decoration: underline; 8 | text-decoration-style: dotted; 9 | } 10 | -------------------------------------------------------------------------------- /src/store/selectors/notifications.js: -------------------------------------------------------------------------------- 1 | import { List } from 'immutable' 2 | 3 | export const getVisibleNotifications = state => 4 | state.notifications.get('currentVisible', List()).map(id => state.notifications.getIn(['log', id])) 5 | -------------------------------------------------------------------------------- /src/routes/Dashboard/components/Dashboard/Markets/Market/index.js: -------------------------------------------------------------------------------- 1 | export { default as ClosingSoonMarket } from './ClosingSoonMarket' 2 | export { default as NewMarket } from './NewMarket' 3 | export { default as NoMarket } from './NoMarket' 4 | -------------------------------------------------------------------------------- /src/routes/Dashboard/containers/index.js: -------------------------------------------------------------------------------- 1 | import Loadable from 'react-loadable' 2 | 3 | const LoadableDashboard = Loadable({ 4 | loader: () => import('./Dashboard'), 5 | loading: () => null, 6 | }) 7 | 8 | export default LoadableDashboard 9 | -------------------------------------------------------------------------------- /src/store/actions/market/index.js: -------------------------------------------------------------------------------- 1 | export { default as addMarkets } from './addMarkets' 2 | export { default as fetchMarkets } from './fetchMarkets' 3 | export { default as updateMarket } from './updateMarket' 4 | export * from './fetchMarkets' 5 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | web: 4 | command: npm run start 5 | build: 6 | context: . 7 | dockerfile: Dockerfile 8 | volumes: 9 | - ./dist:/app/dist 10 | ports: 11 | - 5000:5000 -------------------------------------------------------------------------------- /src/integrations/metamask/utils.js: -------------------------------------------------------------------------------- 1 | export const hasMetamask = () => window 2 | && typeof window.web3 !== 'undefined' 3 | && (window.web3.currentProvider.constructor.name === 'MetamaskInpageProvider' || window.web3.currentProvider.isMetaMask) 4 | -------------------------------------------------------------------------------- /src/routes/MarketList/containers/index.js: -------------------------------------------------------------------------------- 1 | import Loadable from 'react-loadable' 2 | 3 | const LoadableMarketList = Loadable({ 4 | loader: () => import('./MarketList'), 5 | loading: () => null, 6 | }) 7 | 8 | export default LoadableMarketList 9 | -------------------------------------------------------------------------------- /src/routes/Scoreboard/containers/index.js: -------------------------------------------------------------------------------- 1 | import Loadable from 'react-loadable' 2 | 3 | const LoadableScoreboard = Loadable({ 4 | loader: () => import('./ScoreBoard'), 5 | loading: () => null, 6 | }) 7 | 8 | export default LoadableScoreboard 9 | -------------------------------------------------------------------------------- /src/components/layout/Subtitle/index.scss: -------------------------------------------------------------------------------- 1 | .ol-subtitle { 2 | font-family: Montserrat; 3 | font-size: 20px; 4 | font-weight: bold; 5 | letter-spacing: 2px; 6 | text-align: left; 7 | color: #333333; 8 | margin-bottom: 15px; 9 | } -------------------------------------------------------------------------------- /src/routes/MarketDetails/containers/index.js: -------------------------------------------------------------------------------- 1 | import Loadable from 'react-loadable' 2 | 3 | const LoadableScoreboard = Loadable({ 4 | loader: () => import('./MarketDetailPage'), 5 | loading: () => null, 6 | }) 7 | 8 | export default LoadableScoreboard 9 | -------------------------------------------------------------------------------- /src/routes/Transactions/containers/index.js: -------------------------------------------------------------------------------- 1 | import Loadable from 'react-loadable' 2 | 3 | const LoadableTransactions = Loadable({ 4 | loader: () => import('./TransactionsPage'), 5 | loading: () => null, 6 | }) 7 | 8 | export default LoadableTransactions 9 | -------------------------------------------------------------------------------- /src/routes/GameGuide/components/metamaskComponents/SignUp/SignUp.scss: -------------------------------------------------------------------------------- 1 | @import '~style/vars.scss'; 2 | .link { 3 | text-decoration: underline; 4 | color: $link-color; 5 | 6 | &:visited, 7 | &:active { 8 | color: $link-color; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/containers/CookieBannerContainer/index.js: -------------------------------------------------------------------------------- 1 | import Loadable from 'react-loadable' 2 | 3 | const LoadableCookieBanner = Loadable({ 4 | loader: () => import('./CookieBannerContainer'), 5 | loading: () => null, 6 | }) 7 | 8 | export default LoadableCookieBanner 9 | -------------------------------------------------------------------------------- /src/containers/EnableIntercom/index.js: -------------------------------------------------------------------------------- 1 | import Loadable from 'react-loadable' 2 | 3 | const LoadableEnableIntercom = Loadable({ 4 | loader: () => import('./EnableIntercomContainer'), 5 | loading: () => null, 6 | }) 7 | 8 | export default LoadableEnableIntercom 9 | -------------------------------------------------------------------------------- /src/components/Outcome/OutcomeColorBox/OutcomeColorBox.scss: -------------------------------------------------------------------------------- 1 | .OutcomeColorBox { 2 | display: inline-block; 3 | width: 20px; 4 | height: 20px; 5 | border-radius: 4px; 6 | vertical-align: middle; 7 | margin-right: 4px; 8 | 9 | background-color: #fff; 10 | } 11 | -------------------------------------------------------------------------------- /src/store/selectors/modal.js: -------------------------------------------------------------------------------- 1 | import { createSelector } from 'reselect' 2 | 3 | export const getModalData = state => state.modal.get('modalData', []) 4 | 5 | export const getProviderModalData = createSelector( 6 | getModalData, 7 | data => data.get('provider', {}), 8 | ) 9 | -------------------------------------------------------------------------------- /src/components/Header/Layouts/MobileHeader/BurgerIcon/BurgerIcon.scss: -------------------------------------------------------------------------------- 1 | .burgerIcon { 2 | display: flex; 3 | flex-direction: column; 4 | 5 | .icon { 6 | height: 30px; 7 | width: 30px; 8 | } 9 | 10 | .menuLabel { 11 | font-size: 10px; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/components/Icon/Icon.scss: -------------------------------------------------------------------------------- 1 | .icon { 2 | display: inline-block; 3 | position: relative; 4 | 5 | height: 16px; 6 | width: 16px; 7 | 8 | content: '\00a0'; 9 | background-position: center center; 10 | background-repeat: no-repeat; 11 | 12 | font-style: normal; 13 | } -------------------------------------------------------------------------------- /src/store/reducers/notifications/models/notification.js: -------------------------------------------------------------------------------- 1 | import { Record } from 'immutable' 2 | 3 | const NotificationRecord = Record({ 4 | id: undefined, 5 | title: undefined, 6 | message: undefined, 7 | icon: undefined, 8 | }) 9 | 10 | export default NotificationRecord 11 | -------------------------------------------------------------------------------- /scripts/configuration.jest.js: -------------------------------------------------------------------------------- 1 | const configLoader = require('./configuration') 2 | 3 | const ENV = 'local' 4 | 5 | // console.info(`[JEST]: using env configuration: '${ENV}'`) 6 | const config = configLoader(ENV) 7 | 8 | window.__GNOSIS_CONFIG__ = config 9 | global.__GNOSIS_CONFIG__ = config 10 | -------------------------------------------------------------------------------- /src/components/Header/MenuAccountDropdown/Separator.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import cn from 'classnames/bind' 3 | import style from './dropdown.scss' 4 | 5 | const cx = cn.bind(style) 6 | 7 | const Separator = () =>
  • 8 | 9 | export default Separator 10 | -------------------------------------------------------------------------------- /src/components/layout/Img/index.css: -------------------------------------------------------------------------------- 1 | .ol-img { 2 | max-width: 100%; 3 | box-sizing: border-box; 4 | } 5 | 6 | .bordered { 7 | border: 1px solid #ddd; 8 | } 9 | 10 | .fullwidth { 11 | padding: 0; 12 | width: 40% !important; 13 | margin: 0 60% 25px !important; 14 | } 15 | -------------------------------------------------------------------------------- /src/containers/App/transitions.scss: -------------------------------------------------------------------------------- 1 | .enter { 2 | opacity: 0; 3 | } 4 | 5 | .enterActive { 6 | transition: opacity 0.3s ease-in; 7 | opacity: 1; 8 | } 9 | 10 | .exit { 11 | opacity: 1; 12 | } 13 | 14 | .exitActive { 15 | transition: opacity 0.3s ease-out; 16 | opacity: 0; 17 | } 18 | -------------------------------------------------------------------------------- /src/containers/EnableIntercom/EnableIntercom.scss: -------------------------------------------------------------------------------- 1 | .container { 2 | position: fixed; 3 | bottom: 10px; 4 | right: 15px; 5 | z-index: 11; 6 | 7 | & > div { 8 | transition: transform 0.2s ease-in-out; 9 | &:hover { 10 | transform: scale(1.15); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /scripts/env_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export GNOSIS_ENV=olympia/staging; 4 | 5 | if [[ ${TRAVIS_BRANCH} == "master" ]] || [[ -n ${TRAVIS_TAG} ]]; then 6 | export NODE_ENV=production; 7 | else 8 | export NODE_ENV=development; 9 | fi 10 | 11 | npm run build 12 | PROJECT=embedded npm run build 13 | -------------------------------------------------------------------------------- /src/routes/MarketList/containers/MarketList/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import actions from './actions' 3 | import selector from './selector' 4 | import MarketList from '../../components/MarketList' 5 | 6 | export default connect( 7 | selector, 8 | actions, 9 | )(MarketList) 10 | -------------------------------------------------------------------------------- /src/routes/Scoreboard/store/actions/index.js: -------------------------------------------------------------------------------- 1 | export { default as fetchTournamentUserData } from './fetchTournamentUserData' 2 | export { default as fetchTournamentUsers } from './fetchTournamentUsers' 3 | export * from './addUsers' 4 | export { default as addUsers } from './addUsers' 5 | export * from './rewards' 6 | -------------------------------------------------------------------------------- /src/api/rewards.js: -------------------------------------------------------------------------------- 1 | import { getGnosisConnection } from 'api' 2 | 3 | export const claimRewards = async (contractAddress) => { 4 | const gnosis = await getGnosisConnection() 5 | const rewardContract = await gnosis.contracts.RewardClaimHandler.at(contractAddress) 6 | 7 | await rewardContract.claimReward() 8 | } 9 | -------------------------------------------------------------------------------- /src/routes/MarketList/components/Markets/Markets.scss: -------------------------------------------------------------------------------- 1 | @import '~style/vars.scss'; 2 | 3 | .markets { 4 | .title { 5 | margin: 12px 0; 6 | text-transform: uppercase; 7 | color: $font-color-light; 8 | font-weight: 400; 9 | } 10 | 11 | .container { 12 | min-height: 420px; 13 | } 14 | } -------------------------------------------------------------------------------- /src/store/middlewares/Storage/constants.js: -------------------------------------------------------------------------------- 1 | const INIT = 'INIT' 2 | 3 | export const STORAGE_KEY = `GNOSIS_${process.env.VERSION}` 4 | export const STORAGE_SAVE_INTERVAL = 1000 5 | 6 | export const IGNORE_ACTIONS = [INIT, 'LOAD_STORAGE'] 7 | 8 | export const NOOP_MIDDLEWARE = () => next => action => next(action) 9 | -------------------------------------------------------------------------------- /src/assets/img/placeholder.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/containers/InteractionButton/interactionButton.scss: -------------------------------------------------------------------------------- 1 | .interactionButton { 2 | text-align: center; 3 | 4 | display: inline-flex; 5 | justify-content: center; 6 | align-items: center; 7 | height: 45px; 8 | 9 | &.loading { 10 | .interactionButtonInner { 11 | visibility: hidden; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /src/components/Spinner/Indefinite.scss: -------------------------------------------------------------------------------- 1 | .indefiniteSpinner { 2 | &.centered { 3 | position: absolute; 4 | left: 50%; 5 | top: 50%; 6 | transform: translate(-50%, -50%); 7 | } 8 | 9 | path { 10 | fill: #000; 11 | } 12 | 13 | &.inverted { 14 | path { 15 | fill: #fff; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/containers/Modals/ModalRegisterWallet/selectors.js: -------------------------------------------------------------------------------- 1 | import { GAS_COST } from 'utils/constants' 2 | 3 | const getRegistrationGasCost = (state) => { 4 | const gasCost = state.blockchain.getIn(['gasCosts', GAS_COST.MAINNET_ADDRESS_REGISTRATION], 0) 5 | 6 | return gasCost 7 | } 8 | 9 | export { getRegistrationGasCost } 10 | -------------------------------------------------------------------------------- /src/routes/GameGuide/components/uPortComponents/index.css: -------------------------------------------------------------------------------- 1 | .slider { 2 | display: flex; 3 | flex-wrap: wrap; 4 | align-items: flex-start; 5 | margin: 50px auto; 6 | justify-content: center; 7 | 8 | & img { 9 | width: 33%; 10 | height: auto; 11 | margin: 0; 12 | margin: 0 25px 25px 0; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/routes/MarketDetails/store/selectors/getGasCosts.js: -------------------------------------------------------------------------------- 1 | const getGasCosts = (state) => { 2 | const gasCosts = state.blockchain.get('gasCosts') 3 | 4 | return gasCosts.map((cost) => { 5 | if (!cost) { 6 | return undefined 7 | } 8 | 9 | return cost 10 | }) 11 | } 12 | 13 | export default getGasCosts 14 | -------------------------------------------------------------------------------- /src/routes/Scoreboard/assets/ok.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/verification/onfido/containers/store/selectors.js: -------------------------------------------------------------------------------- 1 | import { getCurrentAccount, hasAcceptedTermsAndConditions, isVerified } from 'integrations/store/selectors' 2 | 3 | export default state => ({ 4 | account: getCurrentAccount(state), 5 | tosAccepted: hasAcceptedTermsAndConditions(state), 6 | isVerified: isVerified(state), 7 | }) 8 | -------------------------------------------------------------------------------- /src/routes/Dashboard/components/Dashboard/UserSection/UserSection.scss: -------------------------------------------------------------------------------- 1 | @import '~style/vars.scss'; 2 | 3 | .userSection { 4 | padding: 40px 0 66px 0; 5 | 6 | background-color: $bg-color-dark; 7 | min-height: 200px; 8 | color: $font-color-bright; 9 | 10 | @media (max-width: $screen-sm) { 11 | min-height: auto; 12 | } 13 | } -------------------------------------------------------------------------------- /src/components/Form/RadioButtonGroup.scss: -------------------------------------------------------------------------------- 1 | @import '~style/vars.scss'; 2 | 3 | .formRadioButtonGroup { 4 | & > label { 5 | margin: 20px 0 6px 0; 6 | display: block; 7 | } 8 | 9 | 10 | &.error { 11 | label { 12 | color: $active-highlight-error; 13 | } 14 | 15 | color: $active-highlight-error; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/components/Header/MenuAccountDropdown/MenuActions.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import List from './List' 4 | import Separator from './Separator' 5 | import LogOut from './LogOut' 6 | 7 | const MenuActions = () => ( 8 | 9 | 10 | 11 | 12 | ) 13 | 14 | export default MenuActions 15 | -------------------------------------------------------------------------------- /src/components/layout/Block/index.scss: -------------------------------------------------------------------------------- 1 | .sm { 2 | margin-bottom: 17px; 3 | } 4 | 5 | .md { 6 | margin-bottom: 42px; 7 | } 8 | 9 | .xl { 10 | margin-bottom: 96px; 11 | } 12 | 13 | .xxl { 14 | margin-bottom: 200px; 15 | } 16 | 17 | .center { 18 | display: flex; 19 | align-items: center; 20 | justify-content: center; 21 | } -------------------------------------------------------------------------------- /src/routes/GameGuide/components/index.js: -------------------------------------------------------------------------------- 1 | import { getProviderConfig } from 'utils/features' 2 | import { WALLET_PROVIDER } from 'integrations/constants' 3 | import LayoutMetamask from './LayoutMetamask' 4 | import LayoutUport from './LayoutUport' 5 | 6 | export default getProviderConfig().default === WALLET_PROVIDER.METAMASK ? LayoutMetamask : LayoutUport 7 | -------------------------------------------------------------------------------- /src/embedded/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Gnosis Trading Interface Widget 8 | 9 | 10 |
    11 | 12 | -------------------------------------------------------------------------------- /src/store/actions/shares/index.js: -------------------------------------------------------------------------------- 1 | export { default as requestShares } from './requestShares' 2 | export { default as addShare } from './addShare' 3 | export { default as redeemShare } from './redeemShare' 4 | export { default as updateShare } from './updateShare' 5 | export * from './addShare' 6 | export * from './redeemShare' 7 | export * from './requestShares' 8 | -------------------------------------------------------------------------------- /src/containers/Modals/ModalRegisterWallet/api.js: -------------------------------------------------------------------------------- 1 | import { getGnosisConnection } from 'api' 2 | 3 | const calcRegistrationGasCost = async (account) => { 4 | const gnosis = await getGnosisConnection() 5 | const gasCost = await gnosis.olympiaAddressRegistry.register.estimateGas(account) 6 | return gasCost 7 | } 8 | 9 | export { calcRegistrationGasCost } 10 | -------------------------------------------------------------------------------- /src/integrations/utils.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line 2 | export const getLogo = providerName => require(`integrations/${providerName}/assets/${providerName}-logo.svg`) 3 | 4 | export const getLastUsedProvider = () => { 5 | if (window && window.localStorage) { 6 | return localStorage.getItem('LAST_USED_PROVIDER') 7 | } 8 | 9 | return undefined 10 | } 11 | -------------------------------------------------------------------------------- /src/components/Responsive/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Responsive from 'react-responsive' 3 | 4 | const Desktop = props => 5 | const Tablet = props => 6 | const Mobile = props => 7 | 8 | export { Desktop, Tablet, Mobile } 9 | -------------------------------------------------------------------------------- /src/routes/MarketDetails/components/MarketGraph/MarketGraph.scss: -------------------------------------------------------------------------------- 1 | @import "~style/vars.scss"; 2 | 3 | .marketGraph { 4 | width: 100%; 5 | min-height: 400px; 6 | padding: 60px 0; 7 | height: 60vh; 8 | background-color: $bg-color-dark; 9 | color: $font-color-light; 10 | } 11 | 12 | .marketGraphContainer { 13 | width: 100%; 14 | height: 100%; 15 | } 16 | -------------------------------------------------------------------------------- /src/store/middlewares/CrashReporter.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sends crash reports as state is updated and listeners are notified. 3 | */ 4 | const CrashReporter = () => next => (action) => { 5 | try { 6 | return next(action) 7 | } catch (err) { 8 | console.error('Caught an exception!', err) 9 | throw err 10 | } 11 | } 12 | 13 | export default CrashReporter 14 | -------------------------------------------------------------------------------- /src/containers/LegalCompliance/index.js: -------------------------------------------------------------------------------- 1 | import { reduxForm } from 'redux-form' 2 | import { connect } from 'react-redux' 3 | import LegalComplianceForm from './components/Form' 4 | 5 | import selectors from './store/selectors' 6 | 7 | const form = { 8 | form: 'legalCompliance', 9 | } 10 | 11 | export default reduxForm(form)(connect(selectors)(LegalComplianceForm)) 12 | -------------------------------------------------------------------------------- /src/assets/content/footer.md: -------------------------------------------------------------------------------- 1 | Trading on prediction markets carries a high degree of financial risk to your capital. Please read our full [Risk Disclaimer](/assets/content/mainnet/RiskDisclaimerPolicy.html), [Privacy Policy](/assets/PrivacyPolicy.html) and [Terms of Service](/assets/content/mainnet/TermsOfService.html) before trading. – [Imprint](/assets/content/mainnet/Imprint.html) 2 | -------------------------------------------------------------------------------- /src/assets/img/icons/icon_wallet.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/routes/Dashboard/components/Dashboard/Markets/ConditionalList.scss: -------------------------------------------------------------------------------- 1 | @import '~style/vars.scss'; 2 | 3 | .list { 4 | min-height: inherit; 5 | 6 | &.loading { 7 | display: flex; 8 | flex-direction: column; 9 | justify-content: center; 10 | align-items: center; 11 | } 12 | 13 | @media (max-width: $screen-sm) { 14 | min-height: none; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/routes/Scoreboard/store/actions/fetchTournamentUsers.js: -------------------------------------------------------------------------------- 1 | import { requestFromRestAPI } from 'api/utils/fetch' 2 | import addUsers from './addUsers' 3 | 4 | export default () => dispatch => requestFromRestAPI('scoreboard').then((response) => { 5 | if (!response) { 6 | dispatch(addUsers([])) 7 | return 8 | } 9 | 10 | dispatch(addUsers(response.results)) 11 | }) 12 | -------------------------------------------------------------------------------- /src/components/Header/Layouts/MobileHeader/BurgerIcon/assets/menu_icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/routes/Dashboard/components/Dashboard/Title/DashboardTitle.scss: -------------------------------------------------------------------------------- 1 | @import '~style/vars.scss'; 2 | 3 | .dashboardTitle { 4 | .title { 5 | margin-bottom: 30px; 6 | font-family: Montserrat; 7 | font-size: 42px; 8 | font-weight: 300; 9 | text-align: left; 10 | color: #333; 11 | 12 | @media (max-width: $screen-sm) { 13 | text-align: center; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /src/containers/Modals/ModalAcceptTOS/index.js: -------------------------------------------------------------------------------- 1 | import AcceptTOS from 'components/ModalContent/AcceptTOS' 2 | import { connect } from 'react-redux' 3 | import { initProviders, setLegalDocumentsAccepted } from 'integrations/store/actions' 4 | 5 | const mapDispatchToProps = { 6 | initProviders, 7 | setLegalDocumentsAccepted, 8 | } 9 | 10 | export default connect(null, mapDispatchToProps)(AcceptTOS) 11 | -------------------------------------------------------------------------------- /src/containers/Modals/ModalTransactionExplanation.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import TransactionsExplanation from 'components/ModalContent/TransactionsExplanation' 3 | import { getModalData } from 'store/selectors/modal' 4 | 5 | const mapStateToProps = state => ({ 6 | transactions: getModalData(state), 7 | }) 8 | 9 | export default connect(mapStateToProps)(TransactionsExplanation) 10 | -------------------------------------------------------------------------------- /src/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Gnosis Trading Interface 9 | 10 | 11 |
    12 | 13 | 14 | -------------------------------------------------------------------------------- /src/routes/Scoreboard/store/models/user.js: -------------------------------------------------------------------------------- 1 | import { Record } from 'immutable' 2 | 3 | const UserRecord = Record( 4 | { 5 | currentRank: undefined, 6 | diffRank: undefined, 7 | pastRank: undefined, 8 | account: undefined, 9 | balance: undefined, 10 | score: 0, 11 | predictedProfit: 0, 12 | predictions: 0, 13 | }, 14 | 'User', 15 | ) 16 | 17 | export default UserRecord 18 | -------------------------------------------------------------------------------- /src/components/Footer/index.stories.js: -------------------------------------------------------------------------------- 1 | import { storiesOf } from '@storybook/react' 2 | import * as React from 'react' 3 | import { host } from 'storybook-host' 4 | import Component from './index' 5 | 6 | storiesOf('Components', module) 7 | .addDecorator(host({ 8 | title: 'Footer', 9 | align: 'center', 10 | height: 250, 11 | width: '100%', 12 | })) 13 | .add('Footer', () => ) 14 | -------------------------------------------------------------------------------- /src/components/Form/TextInputAdornment.scss: -------------------------------------------------------------------------------- 1 | @import "~style/vars.scss"; 2 | 3 | .adornment { 4 | display: block; 5 | 6 | font-size: $font-size-inputs; 7 | letter-spacing: $letter-spacing-inputs; 8 | font-weight: $font-weight-inputs; 9 | padding: $paddings-inputs; 10 | 11 | margin: auto 0; 12 | } 13 | 14 | .end { 15 | padding-right: 5px; 16 | } 17 | 18 | .start { 19 | padding-left: 5px; 20 | } -------------------------------------------------------------------------------- /src/embedded/routes/EmbeddedView/api/index.js: -------------------------------------------------------------------------------- 1 | import { requestFromRestAPI } from 'api/utils/fetch' 2 | import { extractMarkets } from 'store/actions/market/fetchMarkets' 3 | 4 | export const getMarketById = async (marketAddress) => { 5 | const response = await requestFromRestAPI(`markets/${marketAddress}`) 6 | const processedMarkets = extractMarkets([response]) 7 | 8 | return processedMarkets[0] 9 | } 10 | -------------------------------------------------------------------------------- /src/routes/Dashboard/containers/Dashboard/utils/calculateProfit.js: -------------------------------------------------------------------------------- 1 | import Decimal from 'decimal.js' 2 | import calcShareWinnings from './calcShareWinnings' 3 | 4 | const calculateProfit = (share) => { 5 | if (share.resolved) { 6 | return calcShareWinnings(share, share.market) 7 | } 8 | 9 | return new Decimal(share.balance).mul(share.marginalPrice) 10 | } 11 | 12 | export default calculateProfit 13 | -------------------------------------------------------------------------------- /src/routes/MarketDetails/components/MarketDetail/Details/Details.scss: -------------------------------------------------------------------------------- 1 | .marketDescription { 2 | margin-bottom: 40px; 3 | font-size: 18px; 4 | line-height: 30px; 5 | letter-spacing: 0.25px; 6 | font-weight: 300; 7 | 8 | a { 9 | color: #00a6c4; 10 | 11 | &:focus, &:visited { 12 | color: #00a6c4; 13 | } 14 | } 15 | } 16 | 17 | 18 | .outcomes { 19 | margin-bottom: 40px; 20 | } 21 | -------------------------------------------------------------------------------- /src/routes/MarketList/components/NoMarkets/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { withNamespaces } from 'react-i18next' 4 | 5 | const NoMarkets = ({ t }) => ( 6 |
    7 |

    {t('markets.no_markets')}

    8 |
    9 | ) 10 | 11 | NoMarkets.propTypes = { 12 | t: PropTypes.func.isRequired, 13 | } 14 | 15 | export default withNamespaces()(NoMarkets) 16 | -------------------------------------------------------------------------------- /src/assets/img/icons/icon_logout.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/containers/Modals/ModalInstallProvider.js: -------------------------------------------------------------------------------- 1 | import InstallProvider from 'components/ModalContent/InstallProvider' 2 | import { connect } from 'react-redux' 3 | import { getProviderModalData } from 'store/selectors/modal' 4 | 5 | const mapStateToProps = state => ({ 6 | providerName: getProviderModalData(state), 7 | }) 8 | 9 | export default connect( 10 | mapStateToProps, 11 | null, 12 | )(InstallProvider) 13 | -------------------------------------------------------------------------------- /src/routes/Dashboard/components/Dashboard/Markets/Market/NoMarket.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import classname from 'classnames/bind' 3 | 4 | import style from './Market.scss' 5 | 6 | const cx = classname.bind(style) 7 | 8 | const NoMarket = () => ( 9 |
    10 |
    No Markets yet
    11 |
    12 | ) 13 | 14 | export default NoMarket 15 | -------------------------------------------------------------------------------- /src/routes/MarketDetails/components/ExpandableViews/MarketMySharesForm/SharesTable/ShareRow/ShareRow.scss: -------------------------------------------------------------------------------- 1 | @import '~style/vars.scss'; 2 | 3 | .ShareSellButton { 4 | color: $link-color !important; 5 | text-transform: uppercase; 6 | letter-spacing: .5px; 7 | border: none; 8 | background: transparent; 9 | 10 | &:focus { 11 | outline: none; 12 | font-weight: bold; 13 | } 14 | } -------------------------------------------------------------------------------- /src/store/selectors/market/index.js: -------------------------------------------------------------------------------- 1 | import { createSelector } from 'reselect' 2 | import { isMarketFunded } from 'store/utils/marketStatus' 3 | 4 | export const marketsSelector = createSelector( 5 | state => state.marketList, 6 | marketList => marketList.filter(market => isMarketFunded(market.stage)), 7 | ) 8 | 9 | export const getMarketById = state => marketAddress => state.marketList.get(marketAddress, {}) 10 | -------------------------------------------------------------------------------- /src/store/reducers/accountTrades.js: -------------------------------------------------------------------------------- 1 | import { Map } from 'immutable' 2 | import { handleActions } from 'redux-actions' 3 | import { ADD_ACCOUNT_TRADE } from 'store/actions/trades' 4 | 5 | export default handleActions( 6 | { 7 | [ADD_ACCOUNT_TRADE]: (state, { payload }) => state.withMutations((stateMap) => { 8 | payload.forEach(trade => stateMap.set(trade.id, trade)) 9 | }), 10 | }, 11 | Map(), 12 | ) 13 | -------------------------------------------------------------------------------- /src/components/layout/Hairline/index.stories.js: -------------------------------------------------------------------------------- 1 | import { storiesOf } from '@storybook/react' 2 | import * as React from 'react' 3 | import { host } from 'storybook-host' 4 | import Component from './index' 5 | 6 | storiesOf('Components', module) 7 | .addDecorator(host({ 8 | title: 'Hairline', 9 | align: 'center', 10 | height: 5, 11 | width: '100%', 12 | })) 13 | .add('Hairline', () => ) 14 | -------------------------------------------------------------------------------- /src/embedded/components/Root/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { I18nextProvider } from 'react-i18next' 3 | import { hot } from 'react-hot-loader' 4 | import i18n from 'i18n' 5 | 6 | import EmbeddedRouter from '../../routes' 7 | 8 | const RootComponent = () => ( 9 | 10 | 11 | 12 | ) 13 | 14 | export default hot(module)(RootComponent) 15 | -------------------------------------------------------------------------------- /src/routes/Scoreboard/store/actions/fetchTournamentUserData.js: -------------------------------------------------------------------------------- 1 | import { requestFromRestAPI } from 'api/utils/fetch' 2 | import addUsers from './addUsers' 3 | 4 | export default account => dispatch => requestFromRestAPI(`scoreboard/${account}`).then((response) => { 5 | if (!response || response.detail === 'Not found.') { 6 | dispatch(addUsers([])) 7 | return 8 | } 9 | 10 | dispatch(addUsers([response])) 11 | }) 12 | -------------------------------------------------------------------------------- /src/containers/Modals/ModalInitialisationError.js: -------------------------------------------------------------------------------- 1 | import InitialisationError from 'components/ModalContent/InitialisationError' 2 | import { connect } from 'react-redux' 3 | import { getProviderModalData } from 'store/selectors/modal' 4 | 5 | const mapStateToProps = state => ({ 6 | providerName: getProviderModalData(state), 7 | }) 8 | 9 | export default connect( 10 | mapStateToProps, 11 | null, 12 | )(InitialisationError) 13 | -------------------------------------------------------------------------------- /src/routes/Transactions/store/models/transaction.js: -------------------------------------------------------------------------------- 1 | import { Record, List } from 'immutable' 2 | 3 | const TxRecord = Record( 4 | { 5 | id: undefined, 6 | label: '', 7 | events: List(), 8 | startTime: undefined, 9 | progress: undefined, 10 | endTime: undefined, 11 | completed: undefined, 12 | completionStatus: undefined, 13 | }, 14 | 'Transaction', 15 | ) 16 | 17 | export default TxRecord 18 | -------------------------------------------------------------------------------- /src/containers/Modals/ModalClaimReward/api.js: -------------------------------------------------------------------------------- 1 | import { getGnosisConnection } from 'api' 2 | 3 | const calcClaimRewardGasCost = async (contractAddress) => { 4 | const gnosis = await getGnosisConnection() 5 | const rewardContract = await gnosis.contracts.RewardClaimHandler.at(contractAddress) 6 | const gasCost = await rewardContract.claimReward.estimateGas() 7 | return gasCost 8 | } 9 | 10 | export { calcClaimRewardGasCost } 11 | -------------------------------------------------------------------------------- /src/routes/Dashboard/containers/Dashboard/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import Loadable from 'react-loadable' 3 | 4 | import actions from './actions' 5 | import selector from './selectors' 6 | 7 | const LoadableDashboard = Loadable({ 8 | loader: () => import('../../components/Dashboard'), 9 | loading: () => null, 10 | }) 11 | 12 | export default connect( 13 | selector, 14 | actions, 15 | )(LoadableDashboard) 16 | -------------------------------------------------------------------------------- /src/store/reducers/interface.js: -------------------------------------------------------------------------------- 1 | import { handleActions } from 'redux-actions' 2 | import { Map } from 'immutable' 3 | 4 | import { changeUiState } from 'store/actions/interface' 5 | 6 | const reducer = handleActions( 7 | { 8 | [changeUiState]: (state, { payload }) => state.merge(payload), 9 | }, 10 | Map({ 11 | showIntercomReminder: false, 12 | showCookieBanner: false, 13 | }), 14 | ) 15 | 16 | export default reducer 17 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:9.11.1-alpine 2 | RUN apk update && apk --no-cache add git python alpine-sdk 3 | RUN npm install -g webpack babel-cli truffle-contract 4 | ADD package.json /tmp/package.json 5 | RUN cd /tmp && npm install && npm install truffle-contract && npm install --only=dev 6 | 7 | RUN mkdir -p /app && cp -a /tmp/node_modules /app/ 8 | 9 | COPY . /app/ 10 | RUN cd /app && NODE_ENV=development npm run build 11 | 12 | WORKDIR /app 13 | -------------------------------------------------------------------------------- /src/components/layout/Bold/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React, { PureComponent } from 'react' 3 | 4 | class Bold extends PureComponent { 5 | render() { 6 | const { children, ...props } = this.props 7 | 8 | return ( 9 | 10 | { children } 11 | 12 | ) 13 | } 14 | } 15 | 16 | Bold.propTypes = { 17 | children: PropTypes.node, 18 | } 19 | 20 | export default Bold 21 | -------------------------------------------------------------------------------- /src/components/Header/MenuAccountDropdown/List.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import cn from 'classnames/bind' 3 | import PropTypes from 'prop-types' 4 | import style from './dropdown.scss' 5 | 6 | const cx = cn.bind(style) 7 | 8 | const List = ({ children }) => ( 9 |
      10 | {children} 11 |
    12 | ) 13 | 14 | List.propTypes = { 15 | children: PropTypes.node.isRequired, 16 | } 17 | 18 | export default List 19 | -------------------------------------------------------------------------------- /src/containers/LegalCompliance/components/Form.scss: -------------------------------------------------------------------------------- 1 | @import '~style/vars.scss'; 2 | 3 | .checks { 4 | text-align: left; 5 | } 6 | 7 | .annotation { 8 | margin-top: 15px; 9 | } 10 | 11 | .heading { 12 | font-size: 21px; 13 | font-weight: 500; 14 | text-align: center; 15 | color: #333333; 16 | margin-top: 45px; 17 | } 18 | 19 | 20 | .checkBox { 21 | margin: 10px 0; 22 | input { 23 | border: 1px solid #09697b; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/containers/Modals/ModalVerification.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import Verification from 'components/ModalContent/Verification' 3 | 4 | import { closeModal } from 'store/actions/modal' 5 | import { setLegalDocumentsAccepted } from 'integrations/store/actions' 6 | 7 | const mapDispatchToProps = { 8 | setLegalDocumentsAccepted, 9 | closeModal, 10 | } 11 | 12 | export default connect(null, mapDispatchToProps)(Verification) 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/tech-task.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Tech Task 3 | about: Describe a task for techs to implement 4 | 5 | --- 6 | 7 | **Description**: Please set up the configuration for our next Olympia Tournament 8 | 9 | **Additional Information**: 10 | This Tournament we will have more rewards than ever, please be sure to add all following changes to Olympia. 11 | - 12 Reward Groups (1 GNO to 10 GNO) 12 | - Legal Document Updates from our G-Drive update 13 | -------------------------------------------------------------------------------- /src/containers/Modals/ModalRegisterWalletUport.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | 3 | import { closeModal } from 'store/actions/modal' 4 | import { updateMainnetAddress, requestMainnetAddress } from 'store/actions/account' 5 | 6 | import RegisterWalletUport from 'components/ModalContent/RegisterWalletUport' 7 | 8 | export default connect(null, { 9 | updateMainnetAddress, 10 | requestMainnetAddress, 11 | closeModal, 12 | })(RegisterWalletUport) 13 | -------------------------------------------------------------------------------- /src/utils/transactionExplanations.js: -------------------------------------------------------------------------------- 1 | export const DEPOSIT = (amount = '', currency = 'ETH') => `Depositing ${amount} ${currency} to this market's contract` 2 | 3 | export const SELL = (outcomeTokens = '') => `Selling ${outcomeTokens} outcome tokens back to the market` 4 | 5 | export const OUTCOME_TOKENS = 'Transaction of outcome tokens' 6 | 7 | export const SETTING_ALLOWANCE = 'Setting allowance' 8 | 9 | export const REVOKE_TOKENS = 'Revoke of outcome tokens' 10 | -------------------------------------------------------------------------------- /src/assets/content/footerOlympia.md: -------------------------------------------------------------------------------- 1 | Olympia tournament is a testnet alpha for the sole purpose of collecting user experience feedback. Due to the stake of OLY as "play money" no one will face any financial risks. 2 | Please read our full [Privacy Policy](/assets/content/PrivacyPolicy.html), [Cookie Policy](/assets/content/olympia/CookiePolicy.html) and [Terms of Service](/assets/content/olympia/TermsOfService.html) before trading. – [Imprint](/assets/content/olympia/Imprint.html) -------------------------------------------------------------------------------- /src/routes/Scoreboard/store/reducers/users.js: -------------------------------------------------------------------------------- 1 | import { Map } from 'immutable' 2 | import { handleActions } from 'redux-actions' 3 | import { ADD_USERS } from '../actions' 4 | import { UserRecord } from '../models' 5 | 6 | export default handleActions( 7 | { 8 | [ADD_USERS]: (state, { payload }) => 9 | state.withMutations((map) => { 10 | payload.forEach(user => map.set(user.account, new UserRecord(user))) 11 | }), 12 | }, 13 | Map(), 14 | ) 15 | -------------------------------------------------------------------------------- /src/routes/Dashboard/components/Dashboard/Markets/Category.scss: -------------------------------------------------------------------------------- 1 | @import '~style/vars.scss'; 2 | 3 | .marketList { 4 | min-height: 200px; 5 | margin-bottom: 30px; 6 | 7 | > .title { 8 | margin: 0 0 12px 0; 9 | font-size: 12px; 10 | text-transform: uppercase; 11 | color: $font-color-light; 12 | 13 | font-weight: 400; 14 | letter-spacing: 0.5px; 15 | } 16 | 17 | @media (max-width: $screen-sm) { 18 | min-height: auto; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/routes/MarketList/components/Filter/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import Form from './Form' 4 | 5 | const MarketsFilter = ({ userAccount }) => ( 6 |
    7 |
    8 |
    9 | ) 10 | 11 | MarketsFilter.propTypes = { 12 | userAccount: PropTypes.string, 13 | } 14 | 15 | MarketsFilter.defaultProps = { 16 | userAccount: undefined, 17 | } 18 | 19 | export default MarketsFilter 20 | -------------------------------------------------------------------------------- /src/routes/Dashboard/assets/arrows.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/routes/Scoreboard/components/Table/Table.scss: -------------------------------------------------------------------------------- 1 | .ol-account { 2 | display: flex; 3 | flex-direction: row; 4 | align-items: center; 5 | margin-top: 10px; 6 | 7 | .dot { 8 | width: 25px; 9 | height: 25px; 10 | border-radius: 12px; 11 | background-color: #ceedf3; 12 | margin-right: 7px; 13 | } 14 | 15 | .your { 16 | font-size: 10px; 17 | line-height: 1.2; 18 | letter-spacing: 2px; 19 | text-align: left; 20 | margin: 0; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/embedded/index.js: -------------------------------------------------------------------------------- 1 | import 'babel-polyfill' 2 | import 'whatwg-fetch' 3 | 4 | import React from 'react' 5 | import { render } from 'react-dom' 6 | 7 | import 'normalize.css?raw' 8 | import './style/embedded.css?raw' 9 | 10 | import { setMomentRelativeTime, setMomentDurationFormat } from '../setup' 11 | 12 | import RootComponent from './components/Root' 13 | 14 | setMomentRelativeTime() 15 | setMomentDurationFormat() 16 | 17 | render(, document.getElementById('root')) 18 | -------------------------------------------------------------------------------- /src/integrations/store/models/provider.js: -------------------------------------------------------------------------------- 1 | import { Record } from 'immutable' 2 | import { WALLET_STATUS } from 'integrations/constants' 3 | 4 | const ProviderRecord = Record( 5 | { 6 | name: undefined, 7 | network: undefined, 8 | balance: undefined, 9 | account: undefined, 10 | networkId: 0, 11 | mainnetAddress: undefined, 12 | verificationHash: undefined, 13 | status: WALLET_STATUS.REGISTERED, 14 | }, 15 | 'Provider', 16 | ) 17 | 18 | export default ProviderRecord 19 | -------------------------------------------------------------------------------- /src/routes/MarketDetails/store/selectors/index.js: -------------------------------------------------------------------------------- 1 | export { default as getMarketGraph } from './getMarketGraph' 2 | export { default as getMarketTradesForAccount } from './getMarketTradesForAccount' 3 | export { default as getMarketShares } from './getMarketShares' 4 | export { default as getGasCosts } from './getGasCosts' 5 | export { default as getGasPrice } from './getGasPrice' 6 | export { default as isGasCostFetched } from './isGasCostFetched' 7 | export { default as isGasPriceFetched } from './isGasPriceFetched' 8 | -------------------------------------------------------------------------------- /src/verification/onfido/api/utils/checks.js: -------------------------------------------------------------------------------- 1 | export const handleResponse = async (response) => { 2 | if (response.ok) { 3 | return response.json() 4 | } 5 | 6 | let responseBody 7 | try { 8 | responseBody = await response.json() 9 | } catch (err) { 10 | // json parse error, probably not JSON content returned 11 | } 12 | 13 | if (responseBody && responseBody.Message) { 14 | throw new Error(responseBody.Message) 15 | } 16 | 17 | throw new Error(response.statusText) 18 | } 19 | -------------------------------------------------------------------------------- /src/components/layout/Span/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React, { PureComponent } from 'react' 3 | 4 | class Span extends PureComponent { 5 | render() { 6 | const { children, ...props } = this.props 7 | 8 | return ( 9 | 10 | { children } 11 | 12 | ) 13 | } 14 | } 15 | 16 | Span.propTypes = { 17 | children: PropTypes.node, 18 | } 19 | 20 | Span.defaultProps = { 21 | children: null, 22 | } 23 | 24 | export default Span 25 | -------------------------------------------------------------------------------- /src/routes/Scoreboard/components/RewardClaimAddress/AddressSection/AddressSection.scss: -------------------------------------------------------------------------------- 1 | .addressSection { 2 | padding: 26px 18px; 3 | 4 | .rewardClaimTitle { 5 | font-size: 16px; 6 | text-align: left; 7 | font-weight: 500; 8 | padding-bottom: 12px; 9 | line-height: 1; 10 | color: #000; 11 | margin: 0; 12 | } 13 | 14 | .button { 15 | background: transparent; 16 | border: 0; 17 | text-decoration: underline; 18 | padding: 0; 19 | color: #02b1c1; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/components/layout/Hairline/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | 4 | const hairlineStyle = { 5 | width: '100%', 6 | height: '2px', 7 | backgroundColor: '#f0f1f1', 8 | marginBottom: '20px', 9 | } 10 | 11 | const Hairline = ({ style = hairlineStyle }) => ( 12 |
    13 | ) 14 | 15 | Hairline.propTypes = { 16 | style: PropTypes.object, 17 | } 18 | 19 | Hairline.defaultProps = { 20 | style: undefined, 21 | } 22 | 23 | export default Hairline 24 | -------------------------------------------------------------------------------- /src/containers/HeaderContainer/index.js: -------------------------------------------------------------------------------- 1 | import { compose } from 'recompose' 2 | import { connect } from 'react-redux' 3 | import { withRouter } from 'react-router-dom' 4 | import { withNamespaces } from 'react-i18next' 5 | 6 | import Header from 'components/Header' 7 | 8 | import actions from './store/actions' 9 | import selectors from './store/selectors' 10 | 11 | const enhancer = compose( 12 | withRouter, 13 | connect(selectors, actions), 14 | withNamespaces(), 15 | ) 16 | 17 | export default enhancer(Header) 18 | -------------------------------------------------------------------------------- /src/routes/MarketDetails/store/selectors/getGasPrice.js: -------------------------------------------------------------------------------- 1 | import Decimal from 'decimal.js' 2 | 3 | const getGasPrice = (state) => { 4 | const gasPrice = state.blockchain.get('gasPrice', undefined) 5 | 6 | if (typeof gasPrice === 'undefined') { 7 | return undefined 8 | } 9 | 10 | let gasPriceDecimal 11 | try { 12 | gasPriceDecimal = Decimal(gasPrice.toString()) 13 | } catch (e) { 14 | gasPriceDecimal = Decimal(0) 15 | } 16 | 17 | return gasPriceDecimal 18 | } 19 | 20 | export default getGasPrice 21 | -------------------------------------------------------------------------------- /src/routes/Dashboard/containers/Dashboard/actions.js: -------------------------------------------------------------------------------- 1 | import { fetchMarkets } from 'store/actions/market' 2 | import redeemMarket from 'store/actions/market/redeemMarket' 3 | import { requestTrades } from 'store/actions/trades' 4 | import { requestShares } from 'store/actions/shares' 5 | import { fetchTournamentUserData } from 'routes/Scoreboard/store' 6 | 7 | export default { 8 | requestShares, 9 | requestTrades, 10 | fetchMarkets, 11 | fetchTournamentUserData, 12 | redeemWinnings: market => redeemMarket(market), 13 | } 14 | -------------------------------------------------------------------------------- /src/routes/MarketDetails/store/actions/index.js: -------------------------------------------------------------------------------- 1 | export { default as buyMarketShares } from './buyShares' 2 | export { default as sellMarketShares } from './sellShares' 3 | export { default as requestMarketTradesForAccount } from './requestMarketTradesForAccount' 4 | export { default as requestMarketSharesForAccount } from './requestMarketSharesForAccount' 5 | export { default as requestMarket } from './requestMarket' 6 | export { default as requestMarketGraphTrades } from './requestMarketGraphTrades.js' 7 | export * from './requestGasCost' 8 | -------------------------------------------------------------------------------- /src/store/reducers/market.js: -------------------------------------------------------------------------------- 1 | import { Map } from 'immutable' 2 | import { handleActions } from 'redux-actions' 3 | import { addMarkets, updateMarket } from 'store/actions/market' 4 | 5 | export default handleActions( 6 | { 7 | [addMarkets]: (state, { payload }) => state.withMutations((stateMap) => { 8 | payload.forEach(market => stateMap.set(market.address, market)) 9 | }), 10 | [updateMarket]: (state, { payload: { marketAddress, data } }) => state.mergeIn([marketAddress], data), 11 | }, 12 | Map(), 13 | ) 14 | -------------------------------------------------------------------------------- /.bootstraprc: -------------------------------------------------------------------------------- 1 | --- 2 | useFlexbox: true 3 | styles: 4 | grid: true 5 | buttons: true 6 | mixins: true 7 | media: true 8 | tables: true 9 | scripts: false 10 | appStyles: ./src/scss/style.scss 11 | bootstrapVersion: 3 12 | env: 13 | production: 14 | extractStyles: true 15 | styleLoaders: 16 | - css-loader 17 | - postcss-loader 18 | - sass-loader 19 | development: 20 | styleLoaders: 21 | - style-loader 22 | - css-loader?sourceMap 23 | - postcss-loader?sourceMap 24 | - sass-loader?sourceMap 25 | 26 | -------------------------------------------------------------------------------- /src/routes/MarketList/store/test/marketlist.spec.js: -------------------------------------------------------------------------------- 1 | import marketReducerTests from './market.reducer' 2 | import marketTests from './market.selector' 3 | import openMarketTests from './openMarkets.selector' 4 | import endingSoonTests from './endingSoon.selector' 5 | import newMarketsTests from './newMarkets.selector' 6 | 7 | describe('Market List Test suite', () => { 8 | // ACTIONS AND REDUCERS 9 | marketReducerTests() 10 | 11 | // SELECTORS 12 | marketTests() 13 | openMarketTests() 14 | endingSoonTests() 15 | newMarketsTests() 16 | }) 17 | -------------------------------------------------------------------------------- /src/store/actions/market/constants/index.js: -------------------------------------------------------------------------------- 1 | import { TRANSACTION_STATUS } from 'utils/constants' 2 | 3 | /** 4 | * Constant names for marketcreation stages 5 | * @readonly 6 | * @enum {string} 7 | */ 8 | export const TRANSACTION_STAGES = { 9 | GENERIC: 'generic', 10 | } 11 | 12 | /** 13 | * Generic Stage for single-event transactions 14 | */ 15 | export const TRANSACTION_EVENTS_GENERIC = [ 16 | { 17 | event: TRANSACTION_STAGES.GENERIC, 18 | label: 'Sending Transaction', 19 | status: TRANSACTION_STATUS.RUNNING, 20 | }, 21 | ] 22 | -------------------------------------------------------------------------------- /src/components/Form/index.js: -------------------------------------------------------------------------------- 1 | export { default as OutcomeSelection } from './OutcomeSelection' 2 | export { default as RadioButton } from './RadioButton' 3 | export { default as Checkbox } from './Checkbox' 4 | export { default as RadioButtonGroup } from './RadioButtonGroup' 5 | export { default as Select } from './Select' 6 | export { default as Slider } from './Slider' 7 | export { default as TextInput } from './TextInput' 8 | export { default as TextInputAdornment } from './TextInputAdornment' 9 | export { default as MandatoryHint } from './MandatoryHint' 10 | -------------------------------------------------------------------------------- /src/integrations/index.js: -------------------------------------------------------------------------------- 1 | import { WALLET_PROVIDER } from './constants' 2 | 3 | import METAMASK from './metamask' 4 | import PARITY from './parity' 5 | import REMOTE from './remote' 6 | import TRUST from './trust' 7 | import STATUS from './status' 8 | 9 | // eslint-disable-next-line 10 | const providers = { 11 | [WALLET_PROVIDER.METAMASK]: METAMASK, 12 | [WALLET_PROVIDER.PARITY]: PARITY, 13 | [WALLET_PROVIDER.REMOTE]: REMOTE, 14 | [WALLET_PROVIDER.TRUST]: TRUST, 15 | [WALLET_PROVIDER.STATUS]: STATUS, 16 | } 17 | 18 | export default providers 19 | -------------------------------------------------------------------------------- /src/integrations/status/assets/status-logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest a new Feature to be implemented 4 | 5 | --- 6 | 7 | **As a user, I want to view my favorite animal on the site, because I really like dogs** 8 | *Please follow the format of: As a , I want , because * 9 | 10 | **Acceptance Criteria** 11 | - I get to see my favorite animal on every page of the application in the bottom right corner 12 | - The Animal must be a dog 13 | - If I go to `/settings` the dog must wear a hardhat 14 | 15 | **Screenshots/Mockups** 16 | -------------------------------------------------------------------------------- /src/embedded/routes/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { HashRouter, Switch, Route } from 'react-router-dom' 3 | 4 | import EmbeddedView from './EmbeddedView' 5 | 6 | const NoMatch = () => (404) 7 | 8 | const EmbeddedRouter = () => ( 9 | 10 | 11 | {/* Add more Routes here, before the /:address route */} 12 | 13 | 14 | 15 | 16 | ) 17 | 18 | export default EmbeddedRouter 19 | -------------------------------------------------------------------------------- /src/components/layout/PageFrame/index.js: -------------------------------------------------------------------------------- 1 | import classNames from 'classnames/bind' 2 | import Block from 'components/layout/Block' 3 | import PropTypes from 'prop-types' 4 | import React from 'react' 5 | import * as css from './index.scss' 6 | 7 | const cx = classNames.bind(css) 8 | 9 | const PageFrame = ({ width, children }) => 10 | ( 11 | { children } 12 | ) 13 | 14 | PageFrame.propTypes = { 15 | children: PropTypes.node, 16 | width: PropTypes.string, 17 | } 18 | 19 | export default PageFrame 20 | -------------------------------------------------------------------------------- /src/routes/MarketDetails/components/ExpandableViews/MarketMySharesForm/SharesTable/SharesTable.scss: -------------------------------------------------------------------------------- 1 | @import "~style/vars.scss"; 2 | 3 | $indexWidth: 36px; 4 | $groupWidth: 33%; 5 | 6 | .sharesTable { 7 | margin-top: 20px; 8 | table-layout: fixed; 9 | } 10 | 11 | .sharesTableHeading { 12 | font-weight: 400; 13 | text-transform: uppercase; 14 | color: $font-color-muted; 15 | border-bottom: none !important; 16 | 17 | &.group { 18 | width: $groupWidth; 19 | } 20 | 21 | &.index { 22 | width: $indexWidth; 23 | 24 | border-bottom: 0 !important; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/routes/MarketDetails/components/MarketDetail/marketDetail.scss: -------------------------------------------------------------------------------- 1 | @import "~style/vars.scss"; 2 | 3 | $expandable-arrow-size: 15px; 4 | $expandable-margin: 40px; 5 | 6 | .marketTitleHeading { 7 | margin: $page-heading-margins; 8 | } 9 | 10 | .expandable { 11 | position: relative; 12 | z-index: 2; 13 | margin-top: $expandable-margin; 14 | .inner { 15 | padding: 40px 0; 16 | background-color: $bg-color-muted; 17 | 18 | &::before { 19 | visibility: visible; 20 | content: ""; 21 | position: absolute; 22 | margin-bottom: 50px; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/routes/MarketDetails/store/actions/requestMarketTradesForAccount.js: -------------------------------------------------------------------------------- 1 | import { hexWithoutPrefix } from 'utils/helpers' 2 | import { requestFromRestAPI } from 'api/utils/fetch' 3 | import { processTradesResponse } from 'store/actions/trades' 4 | 5 | export default (marketAddress, account) => async (dispatch) => { 6 | const normalizedAccount = hexWithoutPrefix(account) 7 | const normalizedMarket = hexWithoutPrefix(marketAddress) 8 | const response = await requestFromRestAPI(`/markets/${normalizedMarket}/trades/${normalizedAccount}`) 9 | processTradesResponse(response, dispatch) 10 | } 11 | -------------------------------------------------------------------------------- /src/routes/MarketDetails/store/actions/requestMarketSharesForAccount.js: -------------------------------------------------------------------------------- 1 | import { hexWithoutPrefix } from 'utils/helpers' 2 | import { requestFromRestAPI } from 'api/utils/fetch' 3 | import { processSharesResponse } from 'store/actions/shares' 4 | 5 | export default (marketAddress, account) => async (dispatch) => { 6 | const normalizedAccount = hexWithoutPrefix(account) 7 | const normalizedMarket = hexWithoutPrefix(marketAddress) 8 | const response = await requestFromRestAPI(`/markets/${normalizedMarket}/shares/${normalizedAccount}`) 9 | 10 | processSharesResponse(response, dispatch) 11 | } 12 | -------------------------------------------------------------------------------- /src/routes/MarketList/containers/MarketList/selector.js: -------------------------------------------------------------------------------- 1 | import { getCurrentAccount } from 'integrations/store/selectors' 2 | import { createStructuredSelector } from 'reselect' 3 | 4 | import { 5 | marketListSelector, 6 | newMarketsSelector, 7 | endingSoonMarketSelector, 8 | openMarketSelector, 9 | } from '../../store/selectors' 10 | 11 | export default createStructuredSelector({ 12 | markets: marketListSelector, 13 | openMarkets: openMarketSelector, 14 | newMarkets: newMarketsSelector, 15 | endingSoonMarkets: endingSoonMarketSelector, 16 | userAccount: getCurrentAccount, 17 | }) 18 | -------------------------------------------------------------------------------- /src/components/layout/Title/index.js: -------------------------------------------------------------------------------- 1 | import classNames from 'classnames/bind' 2 | import PropTypes from 'prop-types' 3 | import React, { PureComponent } from 'react' 4 | import * as css from './index.scss' 5 | 6 | const cx = classNames.bind(css) 7 | 8 | class Title extends PureComponent { 9 | render() { 10 | const { children, ...props } = this.props 11 | 12 | return ( 13 |

    14 | { children } 15 |

    16 | ) 17 | } 18 | } 19 | 20 | Title.propTypes = { 21 | children: PropTypes.node, 22 | } 23 | 24 | export default Title 25 | -------------------------------------------------------------------------------- /src/containers/LegalCompliance/store/selectors.js: -------------------------------------------------------------------------------- 1 | import { formValueSelector } from 'redux-form' 2 | import { getFeatureConfig } from 'utils/features' 3 | 4 | const { documents } = getFeatureConfig('legalCompliance') 5 | 6 | const getFormValue = formValueSelector('legalCompliance') 7 | 8 | const getLegalDocumentFields = (state) => { 9 | const fields = {} 10 | 11 | documents.forEach((doc) => { 12 | fields[doc.id] = !!getFormValue(state, doc.id) 13 | }) 14 | 15 | return fields 16 | } 17 | 18 | export default state => ({ 19 | fields: getLegalDocumentFields(state), 20 | documents, 21 | }) 22 | -------------------------------------------------------------------------------- /src/api/utils/fetch.js: -------------------------------------------------------------------------------- 1 | /* globals fetch */ 2 | import qs from 'querystring' 3 | import { getConfiguration } from 'utils/features' 4 | 5 | const config = getConfiguration() 6 | 7 | const API_URL = `${config.gnosisdb.protocol}://${config.gnosisdb.host}/api` 8 | 9 | export const requestFromRestAPI = async (endpoint, queryparams) => { 10 | const url = `${API_URL}/${endpoint}?${qs.stringify(queryparams)}` 11 | 12 | let response 13 | 14 | try { 15 | response = await fetch(url) 16 | return response.json() 17 | } catch (e) { 18 | console.error(`GnosisDB: Couldn't fetch ${e}`) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/store/reducers/accountShares.js: -------------------------------------------------------------------------------- 1 | import { Map } from 'immutable' 2 | import { handleActions } from 'redux-actions' 3 | import { addShare, updateShare, redeemShare } from 'store/actions/shares' 4 | 5 | export default handleActions( 6 | { 7 | [addShare]: (state, { payload }) => state.withMutations((map) => { 8 | payload.forEach(share => map.set(share.id, share)) 9 | }), 10 | [redeemShare]: (state, { payload: shareId }) => state.setIn([shareId, 'balance'], '0'), 11 | [updateShare]: (state, { payload: { shareId, data } }) => state.mergeIn([shareId], data), 12 | }, 13 | Map(), 14 | ) 15 | -------------------------------------------------------------------------------- /scripts/configuration.browser.js: -------------------------------------------------------------------------------- 1 | /* globals process */ 2 | const fs = require('fs') 3 | const path = require('path') 4 | 5 | const GNOSIS_ENV = process.argv.splice(-1)[0] 6 | const { GNOSIS_CONFIG } = process.env 7 | 8 | const configLoader = require('./configuration.js') 9 | 10 | const applicationConfiguration = configLoader(GNOSIS_ENV, GNOSIS_CONFIG) 11 | 12 | const configTarget = path.join(__dirname, '..', 'dist', 'config.js') 13 | fs.writeFileSync(configTarget, `window.__GNOSIS_CONFIG__ = ${JSON.stringify(applicationConfiguration, null, 2)}`) 14 | console.log('[PM-UI] Config for env written to dist/config.js') 15 | -------------------------------------------------------------------------------- /.travis/scripts/prepare_production_deployment.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ev 4 | 5 | # Only: 6 | # - Tagged commits 7 | # - Security env variables are available. 8 | if [ -n "$TRAVIS_TAG" ] && [ -n "$PROD_DEPLOYMENT_HOOK_TOKEN" ] && [ -n "$PROD_DEPLOYMENT_HOOK_URL_DOMAIN" ] 9 | then 10 | curl -X POST \ 11 | -F token="$PROD_DEPLOYMENT_HOOK_TOKEN" \ 12 | -F ref=master \ 13 | -F "variables[TRIGGER_RELEASE_COMMIT_TAG]=$TRAVIS_TAG" \ 14 | https://"$PROD_DEPLOYMENT_HOOK_URL_DOMAIN"/api/v4/projects/39/trigger/pipeline 15 | else 16 | echo "[ERROR] Production deployment could not be prepared" 17 | fi 18 | -------------------------------------------------------------------------------- /src/assets/img/icons/icon_checkmark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/assets/img/icons/icon_link.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/components/layout/Paragraph/index.scss: -------------------------------------------------------------------------------- 1 | .default-paragraph { 2 | font-family: Montserrat; 3 | color: #626262; 4 | 5 | line-height: 1.7; 6 | font-weight: 300; 7 | color: #333; 8 | } 9 | 10 | .soft { 11 | color: #888888; 12 | } 13 | 14 | .medium { 15 | color: #686868; 16 | } 17 | 18 | .dark { 19 | color: black; 20 | } 21 | 22 | .primary { 23 | color: #00a6c4; 24 | } 25 | 26 | .no-margin{ 27 | margin-bottom: 5px; 28 | } 29 | 30 | .center { 31 | text-align: center; 32 | } 33 | 34 | .normal { 35 | font-size: 18px; 36 | } 37 | 38 | .small { 39 | font-size: 12px; 40 | } -------------------------------------------------------------------------------- /src/components/layout/Subtitle/index.js: -------------------------------------------------------------------------------- 1 | import classNames from 'classnames/bind' 2 | import PropTypes from 'prop-types' 3 | import React, { PureComponent } from 'react' 4 | import * as css from './index.scss' 5 | 6 | const cx = classNames.bind(css) 7 | 8 | class Subtitle extends PureComponent { 9 | render() { 10 | const { children, ...props } = this.props 11 | 12 | return ( 13 |

    14 | { children } 15 |

    16 | ) 17 | } 18 | } 19 | 20 | Subtitle.propTypes = { 21 | children: PropTypes.node, 22 | } 23 | 24 | export default Subtitle 25 | -------------------------------------------------------------------------------- /src/api/token.js: -------------------------------------------------------------------------------- 1 | import { getROGnosisConnection } from 'api' 2 | 3 | export const getTokenSymbol = async (tokenAddress) => { 4 | const gnosis = await getROGnosisConnection() 5 | const token = await gnosis.contracts.DetailedERC20.at(tokenAddress) 6 | const tokenSymbol = await token.symbol() 7 | return tokenSymbol 8 | } 9 | 10 | export const getTokenBalance = async (tokenAddress, accountAddress) => { 11 | const gnosis = await getROGnosisConnection() 12 | const token = await gnosis.contracts.Token.at(tokenAddress) 13 | const balance = await token.balanceOf(accountAddress) 14 | return balance.toString() 15 | } 16 | -------------------------------------------------------------------------------- /src/assets/img/icons/icon_incomeForecast.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_STORE 3 | node_modules 4 | *~ 5 | *.pyc 6 | static 7 | .grunt 8 | _SpecRunner.html 9 | __benchmarks__ 10 | dist/ 11 | coverage/ 12 | .module-cache 13 | *.gem 14 | docs/.bundle 15 | docs/code 16 | docs/_site 17 | docs/.sass-cache 18 | docs/js/* 19 | docs/downloads/*.zip 20 | docs/vendor/bundle 21 | examples/shared/*.js 22 | examples/**/bundle.js 23 | test/the-files-to-test.generated.js 24 | *.log* 25 | chrome-user-data 26 | *.sublime-project 27 | *.sublime-workspace 28 | .idea 29 | *.iml 30 | .vscode 31 | /semantic.json 32 | /semantic 33 | yarn-error.log 34 | yarn.lock 35 | local.json 36 | production.json 37 | .history -------------------------------------------------------------------------------- /src/integrations/uport/uportQr.js: -------------------------------------------------------------------------------- 1 | export const isValid = cred => !!cred 2 | 3 | const assignSessionProps = (uport, cred) => { 4 | // eslint-disable-next-line 5 | uport.address = cred.address 6 | // eslint-disable-next-line 7 | uport.firstReq = false 8 | } 9 | 10 | const init = async (uport, requestCredentials, getCredential) => { 11 | let credential = getCredential() 12 | if (!isValid(credential)) { 13 | uport.firstReq = true 14 | credential = await requestCredentials() 15 | } 16 | 17 | if (credential) { 18 | assignSessionProps(uport, credential) 19 | } 20 | 21 | return uport 22 | } 23 | 24 | export default init 25 | -------------------------------------------------------------------------------- /src/routes/MarketDetails/components/MarketDetail/Infos/utils/embeddedLink.js: -------------------------------------------------------------------------------- 1 | export default (marketAddress) => { 2 | const path = `${window.location.origin}/embedded/${marketAddress}` 3 | 4 | return ` 5 |
    6 | 7 |
    8 | 21 | ` 22 | } 23 | -------------------------------------------------------------------------------- /src/routes/MarketList/components/MarketsTitle/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { withNamespaces } from 'react-i18next' 4 | import classNames from 'classnames/bind' 5 | 6 | import css from './MarketsTitle.scss' 7 | 8 | const cx = classNames.bind(css) 9 | 10 | const MarketListTitle = ({ t }) => ( 11 |
    12 |
    13 |

    {t('markets.list_title')}

    14 |
    15 |
    16 | ) 17 | 18 | MarketListTitle.propTypes = { 19 | t: PropTypes.func.isRequired, 20 | } 21 | 22 | export default withNamespaces()(MarketListTitle) 23 | -------------------------------------------------------------------------------- /src/containers/BackdropProvider/backdrop.scss: -------------------------------------------------------------------------------- 1 | .below { 2 | height: 100vh; 3 | background-color: #09697b; 4 | opacity: 0.9; 5 | 6 | z-index: 99; 7 | position: fixed; 8 | top: 0; 9 | left: 0; 10 | right: 0; 11 | bottom: 0; 12 | } 13 | 14 | .above { 15 | z-index: 100; 16 | position: fixed; 17 | top: 0; 18 | left: 0; 19 | right: 0; 20 | bottom: 0; 21 | } 22 | 23 | .fade-enter { 24 | opacity: 0.01; 25 | } 26 | .fade-enter-active { 27 | opacity: 1; 28 | transition: all 300ms ease-out; 29 | } 30 | .fade-exit { 31 | opacity: 1; 32 | } 33 | .fade-exit-active { 34 | opacity: 0.01; 35 | transition: all 300ms ease-out; 36 | } 37 | -------------------------------------------------------------------------------- /src/routes/MarketList/store/test/market.selector.js: -------------------------------------------------------------------------------- 1 | import { List } from 'immutable' 2 | import { marketListSelector } from '../selectors' 3 | 4 | const marketTests = () => { 5 | describe('Market List Selector[marketsSelector]', () => { 6 | it('should get empty immutable List when they are not loaded', () => { 7 | // GIVEN 8 | const emptyList = List([]) 9 | const reduxStore = { marketList: emptyList } 10 | 11 | // WHEN 12 | const marketListState = marketListSelector(reduxStore) 13 | 14 | // THEN 15 | expect(marketListState).toEqual(emptyList) 16 | }) 17 | }) 18 | } 19 | 20 | export default marketTests 21 | -------------------------------------------------------------------------------- /src/containers/Modals/ModalClaimReward/action.js: -------------------------------------------------------------------------------- 1 | import { GAS_COST } from 'utils/constants' 2 | import { setGasCost } from 'routes/MarketDetails/store/actions' 3 | import { getFeatureConfig } from 'utils/features' 4 | import { calcClaimRewardGasCost } from './api' 5 | 6 | const contractType = GAS_COST.CLAIM_REWARD 7 | const { claimReward } = getFeatureConfig('rewardClaiming') 8 | 9 | const requestClaimRewardGasCost = () => async (dispatch) => { 10 | const gasCost = await calcClaimRewardGasCost(claimReward.contractAddress) 11 | 12 | dispatch(setGasCost({ entityType: 'gasCosts', contractType, gasCost })) 13 | } 14 | 15 | export { requestClaimRewardGasCost } 16 | -------------------------------------------------------------------------------- /src/utils/analytics/intercom/index.js: -------------------------------------------------------------------------------- 1 | import { getThirdPartyConfig } from 'utils/features' 2 | 3 | export const THIRD_PARTY_ID = 'intercom' 4 | 5 | const { id: APP_ID } = getThirdPartyConfig(THIRD_PARTY_ID) 6 | 7 | export default () => { 8 | const d = document 9 | 10 | const s = d.createElement('script') 11 | s.type = 'text/javascript' 12 | s.async = true 13 | s.src = `https://widget.intercom.io/widget/${APP_ID}` 14 | const x = d.getElementsByTagName('script')[0] 15 | x.parentNode.insertBefore(s, x) 16 | 17 | s.onload = () => { 18 | window.Intercom('boot', { 19 | app_id: APP_ID, 20 | consent: true, 21 | }) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/routes/MarketDetails/components/ExpandableViews/MarketBuySharesForm/SubmitError/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { withNamespaces } from 'react-i18next' 4 | import cn from 'classnames/bind' 5 | import style from '../marketBuySharesForm.scss' 6 | 7 | const cx = cn.bind(style) 8 | 9 | const SubmitError = ({ t }) => ( 10 |
    11 |
    12 | {t('market.submit_error')} 13 |
    14 |
    15 | ) 16 | 17 | SubmitError.propTypes = { 18 | t: PropTypes.func.isRequired, 19 | } 20 | 21 | export default withNamespaces()(SubmitError) 22 | -------------------------------------------------------------------------------- /src/utils/marginPrice.js: -------------------------------------------------------------------------------- 1 | import Decimal from 'decimal.js' 2 | 3 | const allowedRangePrice = (oldP, newP) => { 4 | const oldPrice = new Decimal(oldP) 5 | const newPrice = new Decimal(newP) 6 | 7 | // We calculate the 5% of the latest price applying 18 decimals round up 8 | const allowance = new Decimal(newPrice) 9 | .mul(5) 10 | .div(100) 11 | .toDP(18, Decimal.ROUND_UP) 12 | 13 | // Calculate the abs difference between prices 14 | const diff = new Decimal(newPrice).sub(oldPrice).absoluteValue() 15 | 16 | return diff.lte(allowance) // return true if diff between prices is lower than 5 percent 17 | } 18 | 19 | export default allowedRangePrice 20 | -------------------------------------------------------------------------------- /src/containers/Modals/ModalRegisterWallet/actions.js: -------------------------------------------------------------------------------- 1 | import { GAS_COST } from 'utils/constants' 2 | import { setGasCost } from 'routes/MarketDetails/store/actions' 3 | import { getCurrentAccount } from 'integrations/store/selectors' 4 | import { calcRegistrationGasCost } from './api' 5 | 6 | const contractType = GAS_COST.MAINNET_ADDRESS_REGISTRATION 7 | 8 | const requestRegistrationGasCost = () => async (dispatch, getState) => { 9 | const account = getCurrentAccount(getState()) 10 | const gasCost = await calcRegistrationGasCost(account) 11 | 12 | dispatch(setGasCost({ entityType: 'gasCosts', contractType, gasCost })) 13 | } 14 | 15 | export { requestRegistrationGasCost } 16 | -------------------------------------------------------------------------------- /src/routes/MarketDetails/store/selectors/getMarketTradesForAccount.js: -------------------------------------------------------------------------------- 1 | import { createSelector } from 'reselect' 2 | import moment from 'moment' 3 | import tradeSelector from 'store/selectors/account/trades' 4 | import { normalizeHex } from 'utils/helpers' 5 | 6 | const getMarketTradesForAccount = (eventAddress, accountAddress = '') => createSelector(tradeSelector, trades => trades 7 | .filter( 8 | trade => normalizeHex(trade.eventAddress) === normalizeHex(eventAddress) 9 | && normalizeHex(trade.owner) === normalizeHex(accountAddress), 10 | ) 11 | .sort((a, b) => (moment(a.date).isBefore(b.date) ? 1 : -1))) 12 | 13 | export default getMarketTradesForAccount 14 | -------------------------------------------------------------------------------- /src/routes/MarketList/components/Markets/Market/MarketResolution.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import classNames from 'classnames/bind' 4 | 5 | import Icon from 'components/Icon' 6 | 7 | import css from './Market.scss' 8 | 9 | const cx = classNames.bind(css) 10 | 11 | const MarketResolution = ({ resolution }) => ( 12 |
    13 | 14 |
    15 | {resolution} 16 |
    17 |
    18 | ) 19 | 20 | MarketResolution.propTypes = { 21 | resolution: PropTypes.string.isRequired, 22 | } 23 | 24 | export default MarketResolution 25 | -------------------------------------------------------------------------------- /src/assets/img/icons/icon_share.svg: -------------------------------------------------------------------------------- 1 | 3 | Upload 4 | A line styled icon from Orion Icon Library. 5 | 8 | 11 | -------------------------------------------------------------------------------- /src/routes/MarketDetails/components/MarketGraph/DateAxisTick/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import moment from 'moment' 4 | 5 | const DateAxisTick = ({ x, y, payload }) => ( 6 | 7 | 8 | {moment(payload.value).format('DD/MM/YYYY')} 9 | 10 | 11 | ) 12 | 13 | DateAxisTick.propTypes = { 14 | x: PropTypes.number, 15 | y: PropTypes.number, 16 | payload: PropTypes.string, 17 | } 18 | 19 | DateAxisTick.defaultProps = { 20 | x: 0, 21 | y: 0, 22 | payload: '', 23 | } 24 | 25 | export default DateAxisTick 26 | -------------------------------------------------------------------------------- /src/components/Form/Select.scss: -------------------------------------------------------------------------------- 1 | @import "~style/vars.scss"; 2 | 3 | .formSelect { 4 | .Select-control { 5 | border: 0; 6 | border-bottom: 1px solid $bg-color-muted; 7 | border-radius: unset; 8 | } 9 | 10 | .Select-menu-outer { 11 | border-radius: unset; 12 | } 13 | 14 | label { 15 | margin: 20px 0 6px 0; 16 | display: block; 17 | } 18 | 19 | &.error { 20 | .Select-value span { 21 | color: $active-highlight-error !important; 22 | } 23 | 24 | label { 25 | color: $active-highlight-error; 26 | } 27 | 28 | .Select-control { 29 | border-color: lighten($color: $active-highlight-error, $amount: 30); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/routes/MarketList/components/MarketOverview/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import classNames from 'classnames/bind' 4 | 5 | import css from './MarketOverview.scss' 6 | 7 | const cx = classNames.bind(css) 8 | 9 | const MarketsOverview = ({ children }) => ( 10 |
    11 |
    12 |
    13 | {children} 14 |
    15 |
    16 |
    17 | ) 18 | 19 | MarketsOverview.propTypes = { 20 | children: PropTypes.node, 21 | } 22 | 23 | MarketsOverview.defaultProps = { 24 | children: null, 25 | } 26 | 27 | export default MarketsOverview 28 | -------------------------------------------------------------------------------- /src/store/models/share/index.js: -------------------------------------------------------------------------------- 1 | import { Record } from 'immutable' 2 | 3 | const ShareRecord = Record({ 4 | id: undefined, // string 5 | owner: undefined, // string 6 | eventAddress: undefined, // string 7 | collateralTokenAddress: undefined, // string 8 | balance: undefined, // int 9 | marketTitle: undefined, // string 10 | marketType: undefined, // oneOf OUTCOME_TYPE 11 | marketResolution: undefined, // moment 12 | marketOutcomes: undefined, // List 13 | marginalPrice: undefined, // decimal 14 | outcomeToken: undefined, // OutcomeRecord 15 | market: undefined, // MarketRecord 16 | winnings: undefined, 17 | }, 'Share') 18 | 19 | export default ShareRecord 20 | -------------------------------------------------------------------------------- /src/components/Form/InputError.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | 4 | import className from 'classnames/bind' 5 | 6 | import styles from './InputError.scss' 7 | 8 | const cx = className.bind(styles) 9 | 10 | const InputError = ({ error, style }) => (error ? ( 11 | 12 | {error} 13 | 14 | ) : null) 15 | 16 | InputError.propTypes = { 17 | error: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]), 18 | // eslint-disable-next-line 19 | style: PropTypes.object, 20 | } 21 | 22 | InputError.defaultProps = { 23 | error: undefined, 24 | style: {}, 25 | } 26 | 27 | export default InputError 28 | -------------------------------------------------------------------------------- /src/containers/App/app.scss: -------------------------------------------------------------------------------- 1 | @import "~style/vars.scss"; 2 | 3 | $footer-bottom: 60px; 4 | 5 | .appContainer { 6 | position: relative; 7 | background-color: $bg-color; 8 | height: calc(100vh - #{$footer-bottom}); 9 | overflow-y: scroll; 10 | 11 | .loader-container { 12 | height: 100%; 13 | width: 100%; 14 | display: flex; 15 | justify-content: center; 16 | align-items: center; 17 | flex-direction: column; 18 | 19 | @media (max-width: 767px) { 20 | text-align: center; 21 | 22 | h1 { 23 | font-size: 30px; 24 | line-height: 45px; 25 | } 26 | } 27 | } 28 | 29 | @media (max-width: 992px) { 30 | height: 100vh; 31 | } 32 | } -------------------------------------------------------------------------------- /src/store/models/market/index.js: -------------------------------------------------------------------------------- 1 | import { Record } from 'immutable' 2 | 3 | export const MARKET_STAGES = { 4 | MARKET_CREATED: 0, 5 | MARKET_FUNDED: 1, 6 | MARKET_CLOSED: 2, 7 | } 8 | 9 | export const BoundsRecord = Record({ 10 | lower: undefined, 11 | upper: undefined, 12 | unit: undefined, 13 | decimals: undefined, 14 | }, 'Bound') 15 | 16 | export const OutcomeRecord = Record({ 17 | name: undefined, // string 18 | index: undefined, // int 19 | marginalPrice: undefined, // decimal 20 | outcomeTokensSold: undefined, // int 21 | }, 'Outcome') 22 | 23 | export { default as ScalarMarketRecord } from './scalar' 24 | export { default as CategoricalMarketRecord } from './categorical' 25 | -------------------------------------------------------------------------------- /src/assets/img/icons/icon_next.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/scss/main.scss: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Montserrat'; 3 | font-weight: 300; 4 | src: url('~assets/fonts/Montserrat-Light.ttf') format('truetype'); 5 | } 6 | 7 | @font-face { 8 | font-family: 'Montserrat'; 9 | font-weight: 400; 10 | src: url('~assets/fonts/Montserrat-Regular.ttf') format('truetype'); 11 | } 12 | 13 | @font-face { 14 | font-family: 'Montserrat'; 15 | font-weight: 500; 16 | src: url('~assets/fonts/Montserrat-Medium.ttf') format('truetype'); 17 | } 18 | 19 | * { 20 | box-sizing: border-box; 21 | } 22 | *:before, 23 | *:after { 24 | box-sizing: border-box; 25 | } 26 | 27 | html, 28 | body, 29 | #root { 30 | height: 100%; 31 | font-family: 'Montserrat', sans-serif; 32 | } -------------------------------------------------------------------------------- /src/components/layout/Img/index.js: -------------------------------------------------------------------------------- 1 | import classNames from 'classnames/bind' 2 | import PropTypes from 'prop-types' 3 | import React, { PureComponent } from 'react' 4 | import * as css from './index.css' 5 | 6 | const cx = classNames.bind(css) 7 | 8 | class Img extends PureComponent { 9 | render() { 10 | const { 11 | fullwidth, alt, bordered, className, ...props 12 | } = this.props 13 | 14 | return {alt} 15 | } 16 | } 17 | 18 | Img.propTypes = { 19 | alt: PropTypes.string, 20 | fullwidth: PropTypes.bool, 21 | bordered: PropTypes.bool, 22 | className: PropTypes.string, 23 | } 24 | 25 | export default Img 26 | -------------------------------------------------------------------------------- /src/components/Footer/Footer.scss: -------------------------------------------------------------------------------- 1 | .footer { 2 | position: fixed; 3 | bottom: 0; 4 | left: 0; 5 | width: 100vw; 6 | background: #fff; 7 | padding: 0; 8 | text-align: center; 9 | z-index: 10; 10 | 11 | .footerContainer { 12 | font-size: 12px; 13 | font-weight: 300; 14 | line-height: normal; 15 | color: #686868; 16 | text-align: center; 17 | } 18 | 19 | .version { 20 | padding: 0; 21 | margin: 0; 22 | font-size: 12px; 23 | color: white; 24 | } 25 | 26 | a { 27 | text-decoration: underline; 28 | 29 | &:hover, &:visited, &:active { 30 | color: #00a6c4 31 | } 32 | } 33 | 34 | @media (max-width: 992px) { 35 | position: static; 36 | } 37 | } -------------------------------------------------------------------------------- /src/components/Form/MandatoryHint.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { withNamespaces } from 'react-i18next' 4 | import classnames from 'classnames/bind' 5 | import Tooltip from 'rc-tooltip' 6 | 7 | import styles from './MandatoryHint.scss' 8 | 9 | const cx = classnames.bind(styles) 10 | 11 | const MandatoryHint = ({ t }) => ( 12 | 14 | {t('form.field_required')}; 15 | 16 | )} 17 | > 18 | 19 | * 20 | 21 | 22 | ) 23 | 24 | MandatoryHint.propTypes = { 25 | t: PropTypes.func.isRequired, 26 | } 27 | 28 | export default withNamespaces()(MandatoryHint) 29 | -------------------------------------------------------------------------------- /src/components/Header/MenuAccountDropdown/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Tooltip from 'rc-tooltip' 3 | import cn from 'classnames/bind' 4 | import MenuActions from './MenuActions' 5 | import style from './dropdown.scss' 6 | import './tooltip.scss?raw' 7 | 8 | const cx = cn.bind(style) 9 | 10 | const MenuAccountDropdown = () => ( 11 | } 15 | align={{ 16 | offset: ['10%', 20], 17 | }} 18 | trigger={['click']} 19 | > 20 |
    21 |
    22 |
    23 | 24 | ) 25 | 26 | export default MenuAccountDropdown 27 | -------------------------------------------------------------------------------- /src/routes/MarketDetails/components/ExpandableViews/MarketBuySharesForm/LimitMarginAnnotation/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { withNamespaces } from 'react-i18next' 4 | import cn from 'classnames/bind' 5 | import style from '../marketBuySharesForm.scss' 6 | 7 | const cx = cn.bind(style) 8 | 9 | const LimitMarginAnnotation = ({ t }) => ( 10 |
    11 |
    12 | {t('market.limit_margin_warning')} 13 |
    14 |
    15 | ) 16 | 17 | LimitMarginAnnotation.propTypes = { 18 | t: PropTypes.func.isRequired, 19 | } 20 | 21 | export default withNamespaces()(LimitMarginAnnotation) 22 | -------------------------------------------------------------------------------- /src/components/Header/Layouts/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Loadable from 'react-loadable' 3 | import { Desktop, Tablet, Mobile } from 'components/Responsive' 4 | 5 | const LoadableDesktop = Loadable({ 6 | loader: () => import('./DesktopHeader'), 7 | loading: () => null, 8 | }) 9 | 10 | const LoadableMobile = Loadable({ 11 | loader: () => import('./MobileHeader'), 12 | loading: () => null, 13 | }) 14 | 15 | const Layout = props => ( 16 |
    17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
    27 | ) 28 | 29 | export default Layout 30 | -------------------------------------------------------------------------------- /src/routes/Scoreboard/components/Table/ScoreTable/index.stories.js: -------------------------------------------------------------------------------- 1 | import { text } from '@storybook/addon-knobs' 2 | import { storiesOf } from '@storybook/react' 3 | import * as React from 'react' 4 | import users from 'stories/knobs/scoreboardUsers' 5 | import { host } from 'storybook-host' 6 | import Component from './index' 7 | 8 | storiesOf('Route ScoreBoard components', module) 9 | .addDecorator(host({ 10 | title: 'ScoreBoard', 11 | align: 'center', 12 | height: 650, 13 | width: '100%', 14 | })) 15 | .add('ScoreTable', () => { 16 | const data = users 17 | const myWallet = text('User Account', '0x90F8bf6A479f320ead074411a4B0e7944Ea8ca007') 18 | 19 | return 20 | }) 21 | -------------------------------------------------------------------------------- /src/routes/Scoreboard/containers/actions.js: -------------------------------------------------------------------------------- 1 | import { openModal } from 'store/actions/modal' 2 | import { fetchTournamentUsers, addUsers, fetchTournamentUserData } from '../store/actions' 3 | 4 | const openSetMainnetAddressModal = () => openModal({ modalName: 'ModalRegisterWalletUport' }) 5 | const openClaimRewardModal = () => openModal({ modalName: 'ModalClaimReward' }) 6 | 7 | export default dispatch => ({ 8 | fetchTournamentUsers: () => dispatch(fetchTournamentUsers()), 9 | addUsers: () => dispatch(addUsers()), 10 | openSetMainnetAddressModal: () => dispatch(openSetMainnetAddressModal()), 11 | openClaimRewardModal: () => dispatch(openClaimRewardModal()), 12 | fetchTournamentUserData: account => dispatch(fetchTournamentUserData(account)), 13 | }) 14 | -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | * Example Content 3 | 4 | ### Which Tickets does my PR fix? (Put in title too) 5 | * Fixes task/PM-123 6 | 7 | ### Which PRs are linked to my PR? 8 | * task/PM-123 9 | 10 | ### Which side effects could my PR have? 11 | * Example Content 12 | 13 | ### Which Steps did I take to verify my PR? 14 | 15 | *Case 1* 16 | * Example Content 17 | 18 | *Case 2* 19 | * Example Content 20 | 21 | ### Background Information 22 | * Example Content 23 | 24 | ### Configuration Entries 25 | `/staging/interface.config` 26 | ``` 27 | { 28 | "feature": { 29 | "enabled": false, 30 | } 31 | } 32 | ``` 33 | `/olympia/staging/interface.config` 34 | ``` 35 | { 36 | "feature": { 37 | "enabled" true, 38 | } 39 | } 40 | ``` 41 | -------------------------------------------------------------------------------- /src/components/ModalContent/TransactionsExplanation/TransactionExplanation.scss: -------------------------------------------------------------------------------- 1 | @import "~style/vars.scss"; 2 | 3 | .transactionsExplanation { 4 | display: flex; 5 | justify-content: center; 6 | align-items: center; 7 | flex-direction: column; 8 | min-height: 100vh; 9 | color: #fff; 10 | 11 | @media (max-width: 767px) { 12 | text-align: center; 13 | } 14 | 15 | @media (max-width: 320px) { 16 | font-size: 12px; 17 | } 18 | 19 | 20 | .closeButton { 21 | @include closeButton(32px, 5px); 22 | top: 20px; 23 | right: 10px; 24 | } 25 | 26 | .transactionList { 27 | font-size: 16px; 28 | list-style: none; 29 | margin-top: 20px; 30 | 31 | li + li { 32 | margin-top: 5px; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/embedded/style/embedded.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Montserrat'; 3 | font-weight: 300; 4 | src: url('~assets/fonts/Montserrat-Light.ttf') format('truetype'); 5 | } 6 | 7 | @font-face { 8 | font-family: 'Montserrat'; 9 | font-weight: 400; 10 | src: url('~assets/fonts/Montserrat-Regular.ttf') format('truetype'); 11 | } 12 | 13 | @font-face { 14 | font-family: 'Montserrat'; 15 | font-weight: 500; 16 | src: url('~assets/fonts/Montserrat-Medium.ttf') format('truetype'); 17 | } 18 | 19 | * { 20 | box-sizing: border-box; 21 | } 22 | *:before, 23 | *:after { 24 | box-sizing: border-box; 25 | } 26 | 27 | body { 28 | overflow: hidden; 29 | } 30 | 31 | html, 32 | body, 33 | #root { 34 | height: 100%; 35 | font-family: 'Montserrat', sans-serif; 36 | } -------------------------------------------------------------------------------- /src/components/Header/MenuAccountDropdown/tooltip.scss: -------------------------------------------------------------------------------- 1 | .menuAccountDropdown { 2 | &.rc-tooltip { 3 | filter: drop-shadow(0 4px 4px rgba(0, 0, 0, 0.24)); 4 | box-shadow: none; 5 | } 6 | .rc-tooltip-inner { 7 | background-color: #fafafa; 8 | width: 140px; 9 | border-radius: 2px; 10 | 11 | box-shadow: none; 12 | z-index: 5; 13 | } 14 | .rc-tooltip-inner { 15 | box-shadow: none; 16 | } 17 | .rc-tooltip .rc-tooltip-content .rc-tooltip-arrow { 18 | background: none; 19 | height: 0; 20 | width: 0; 21 | top: -21px; 22 | margin-right: -7.5px; 23 | position: absolute; 24 | pointer-events: none; 25 | border: transparent 15px solid; 26 | border-bottom: #fafafa 15px solid; 27 | 28 | z-index: 1; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Report a Bug for either Gnosis Apollo, Olympia, Sight or Mainnet 4 | 5 | --- 6 | 7 | **Description** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps to reproduce the behavior: 12 | 1. Go to '...' 13 | 2. Click on '....' 14 | 3. Scroll down to '....' 15 | 4. See error 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Screenshots** 21 | If applicable, add screenshots to help explain your problem. 22 | 23 | **Desktop (please complete the following information):** 24 | - System [e.g. Mac with Chrome] 25 | - Build [e.g. 22] 26 | 27 | **Additional context** 28 | Add any other context about the problem here. 29 | -------------------------------------------------------------------------------- /src/components/ModalContent/Verification/Verification.scss: -------------------------------------------------------------------------------- 1 | @import '~style/vars.scss'; 2 | 3 | .verification { 4 | width: 100%; 5 | height: 100%; 6 | display: flex; 7 | flex-direction: column; 8 | justify-content: center; 9 | align-items: center; 10 | color: #fff; 11 | 12 | .heading { 13 | font-size: 21px; 14 | margin: 33px 0px 20px 0px; 15 | font-weight: 500; 16 | } 17 | 18 | .text { 19 | font-size: 14px; 20 | line-height: 1.5; 21 | } 22 | 23 | .closeButton { 24 | @include closeButton(32px, 5px); 25 | top: 20px; 26 | right: 20px; 27 | background: transparent; 28 | border: none; 29 | 30 | &:hover { 31 | &::after, 32 | &::before { 33 | background-color: #fff; 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/routes/Scoreboard/assets/trophy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/components/Header/MenuAccountDropdown/LogOut.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import cn from 'classnames/bind' 4 | import { connect } from 'react-redux' 5 | import Icon from 'components/Icon' 6 | import { logoutProvider } from 'integrations/store/actions' 7 | import style from './dropdown.scss' 8 | 9 | const cx = cn.bind(style) 10 | 11 | const LogOut = ({ logout }) => ( 12 |
  • 13 | 16 |
  • 17 | ) 18 | 19 | LogOut.propTypes = { 20 | logout: PropTypes.func.isRequired, 21 | } 22 | 23 | export default connect( 24 | null, 25 | { 26 | logout: logoutProvider, 27 | }, 28 | )(LogOut) 29 | -------------------------------------------------------------------------------- /src/components/ModalContent/OutcomePriceChanged.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { withNamespaces } from 'react-i18next' 3 | import PropTypes from 'prop-types' 4 | import cn from 'classnames/bind' 5 | import style from './TransactionsExplanation/TransactionExplanation.scss' 6 | 7 | const cx = cn.bind(style) 8 | 9 | const OutcomePriceChanged = ({ closeModal, t }) => ( 10 |
    11 |
    16 | ) 17 | 18 | OutcomePriceChanged.propTypes = { 19 | closeModal: PropTypes.func.isRequired, 20 | t: PropTypes.func.isRequired, 21 | } 22 | 23 | export default withNamespaces()(OutcomePriceChanged) 24 | -------------------------------------------------------------------------------- /src/components/Outcome/WinningOutcome/WinningOutcome.scss: -------------------------------------------------------------------------------- 1 | .winningOutcomeContainer { 2 | display: flex; 3 | margin: 10px 0 10px 3px; 4 | align-items: center; 5 | justify-content: flex-start; 6 | text-transform: uppercase; 7 | font-weight: 500; 8 | } 9 | 10 | .winningOutcomeIcon { 11 | background: url('../../../assets/img/icons/icon_winningOutcome.svg'); 12 | background-size: contain; 13 | width: 40px; 14 | height: 40px; 15 | margin-left: -10px; 16 | } 17 | 18 | .winningOutcomeLabel { 19 | color: #87949c; 20 | font-size: 12px; 21 | } 22 | 23 | .winningOutcomeText { 24 | margin-left: 10px; 25 | background-color: #87949c; 26 | color: #fff; 27 | border-radius: 6px; 28 | padding: 5px 10px; 29 | } 30 | 31 | .winningOutcomeUnit { 32 | text-transform: none; 33 | } 34 | -------------------------------------------------------------------------------- /src/assets/img/icons/icon_cross.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/components/Header/Layouts/MobileHeader/BurgerIcon/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import cn from 'classnames/bind' 4 | import menuIcon from './assets/menu_icon.svg' 5 | import style from './BurgerIcon.scss' 6 | 7 | const cx = cn.bind(style) 8 | 9 | // the prop is called addClass because prop className is overwriteen by react-burger-menu 10 | const BurgerIcon = ({ addClass }) => ( 11 |
    12 | Menu 13 | MENU 14 |
    15 | ) 16 | 17 | BurgerIcon.propTypes = { 18 | addClass: PropTypes.string, 19 | } 20 | 21 | BurgerIcon.defaultProps = { 22 | addClass: '', 23 | } 24 | 25 | export default BurgerIcon 26 | -------------------------------------------------------------------------------- /src/routes/Scoreboard/store/actions/rewards.js: -------------------------------------------------------------------------------- 1 | import { claimRewards } from 'api' 2 | 3 | import { setAccountRewardClaimState } from 'store/actions/account' 4 | import { getCurrentAccount } from 'integrations/store/selectors' 5 | import { getFeatureConfig } from 'utils/features' 6 | 7 | const { claimUntil } = getFeatureConfig('rewards') 8 | 9 | export const claimUserRewards = (contractAddress, rewardClaimAmount) => async (dispatch, getState) => { 10 | const state = getState() 11 | const account = getCurrentAccount(state) 12 | try { 13 | await claimRewards(contractAddress) // These arguments get hashed, this way we can determine if claiming is available again 14 | dispatch(setAccountRewardClaimState(account, claimUntil, rewardClaimAmount)) 15 | } catch (e) { 16 | console.error(e) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/routes/MarketDetails/components/MarketDetail/Controls/Controls.scss: -------------------------------------------------------------------------------- 1 | @import "~style/vars.scss"; 2 | 3 | $expandable-arrow-size: 15px; 4 | $expandable-margin: 40px; 5 | 6 | .marketControls { 7 | &.controlsContainer { 8 | padding-top: 40px; 9 | } 10 | 11 | .button { 12 | margin-right: 20px; 13 | 14 | &.active { 15 | &:after { 16 | content: ''; 17 | position: absolute; 18 | bottom: -$expandable-margin; 19 | left: 50%; 20 | margin-left: -$expandable-arrow-size; 21 | width: 0; 22 | height: 0; 23 | border-left: $expandable-arrow-size solid transparent; 24 | border-right: $expandable-arrow-size solid transparent; 25 | border-bottom: $expandable-arrow-size solid $bg-color-muted; 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/store/middlewares/Storage/index.js: -------------------------------------------------------------------------------- 1 | import StorageLoader from './Load' 2 | import StorageDumper from './Dump' 3 | 4 | export * from './actions' 5 | 6 | const localstorageOptions = { 7 | whitelist: [ 8 | 'transactions.log', 9 | 'integrations.accountSettings', 10 | 'blockchain.targetNetworkId', 11 | 'integrations.documentsAccepted', 12 | ], 13 | } 14 | export const LocalStorageDump = StorageDumper(window.localStorage, localstorageOptions) 15 | export const LocalStorageLoad = StorageLoader(window.localStorage, localstorageOptions) 16 | 17 | const sessionstorageOptions = { 18 | whitelist: ['modal'], 19 | } 20 | export const SessionStorageDump = StorageDumper(window.sessionStorage, sessionstorageOptions) 21 | export const SessionStorageLoad = StorageLoader(window.sessionStorage, sessionstorageOptions) 22 | -------------------------------------------------------------------------------- /src/containers/HeaderContainer/store/actions.js: -------------------------------------------------------------------------------- 1 | import { requestCollateralTokenBalance } from 'store/actions/blockchain' 2 | import { openModal } from 'store/actions/modal' 3 | import { requestMainnetAddress } from 'store/actions/account' 4 | 5 | import { initProviders } from 'integrations/store/actions' 6 | import { WALLET_PROVIDER } from 'integrations/constants' 7 | import { fetchTournamentUserData } from 'routes/Scoreboard/store' 8 | 9 | export default { 10 | requestMainnetAddress, 11 | fetchTournamentUserData: accountAddress => dispatch => dispatch(fetchTournamentUserData(accountAddress)), 12 | requestTokenBalance: requestCollateralTokenBalance, 13 | openModal: modalName => dispatch => dispatch(openModal({ modalName })), 14 | initUport: () => dispatch => dispatch(initProviders({ providers: [WALLET_PROVIDER.UPORT] })), 15 | } 16 | -------------------------------------------------------------------------------- /src/store/models/trade/index.js: -------------------------------------------------------------------------------- 1 | import { Record } from 'immutable' 2 | 3 | export const ORDER_TYPE_BUY = 'BUY' 4 | export const ORDER_TYPE_SELL = 'SELL' 5 | 6 | const TradeRecord = Record({ 7 | id: undefined, // string 8 | date: undefined, // moment 9 | owner: undefined, // string 10 | price: undefined, // string (Decimal) 11 | eventAddress: undefined, // string 12 | collateralTokenAddress: undefined, // string 13 | orderType: undefined, // string oneOf 'BUY', 'SELL' 14 | marketType: undefined, // string 15 | marketTitle: undefined, // string 16 | marketResolution: undefined, // moment 17 | marketOutcomes: undefined, // List 18 | marginalPrices: undefined, // List 19 | outcomeToken: undefined, // OutcomeRecord 20 | market: undefined, // MarketRecord 21 | }, 'Trade') 22 | 23 | export default TradeRecord 24 | -------------------------------------------------------------------------------- /src/containers/Modals/ModalSelectProvider.js: -------------------------------------------------------------------------------- 1 | import SelectProvider from 'components/ModalContent/SelectProvider' 2 | import { connect } from 'react-redux' 3 | import { getProvidersList } from 'integrations/store/selectors' 4 | import { initProviders } from 'integrations/store/actions' 5 | import { getTargetNetworkId } from 'store/selectors/blockchain' 6 | import { requestTargetNetworkId } from 'store/actions/blockchain' 7 | 8 | const mapStateToProps = state => ({ 9 | providersList: getProvidersList(state), 10 | targetNetworkId: getTargetNetworkId(state), 11 | }) 12 | 13 | const mapDispatchToProps = dispatch => ({ 14 | requestTargetNetworkId: () => dispatch(requestTargetNetworkId()), 15 | initProviders: provider => dispatch(initProviders({ provider })), 16 | }) 17 | 18 | export default connect(mapStateToProps, mapDispatchToProps)(SelectProvider) 19 | -------------------------------------------------------------------------------- /src/routes/Dashboard/components/Dashboard/UserSection/Category.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | 4 | import IndefiniteSpinner from 'components/Spinner/Indefinite' 5 | 6 | import classnames from 'classnames/bind' 7 | import styles from './Category.scss' 8 | 9 | const cx = classnames.bind(styles) 10 | 11 | const Category = ({ children, className, isLoading }) => ( 12 |
    13 | {isLoading ? : children} 14 |
    15 | ) 16 | 17 | Category.propTypes = { 18 | children: PropTypes.node.isRequired, 19 | className: PropTypes.oneOfType([PropTypes.string, PropTypes.array]), 20 | isLoading: PropTypes.bool, 21 | } 22 | 23 | Category.defaultProps = { 24 | className: '', 25 | isLoading: false, 26 | } 27 | 28 | export default Category 29 | -------------------------------------------------------------------------------- /src/components/Root/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { I18nextProvider } from 'react-i18next' 3 | import { BrowserRouter } from 'react-router-dom' 4 | import { hot } from 'react-hot-loader' 5 | import BackdropProvider from 'containers/BackdropProvider' 6 | import AppContainer from 'containers/App' 7 | import store from 'store' 8 | import { Provider } from 'react-redux' 9 | import AppRouter from 'routes' 10 | import i18n from 'i18n' 11 | 12 | const RootComponent = () => ( 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | ) 25 | 26 | export default hot(module)(RootComponent) 27 | -------------------------------------------------------------------------------- /src/integrations/metamask/components/UnlockMetamask/UnlockMetamask.scss: -------------------------------------------------------------------------------- 1 | @import '~style/vars.scss'; 2 | 3 | .unlockMetamask { 4 | width: 100%; 5 | height: 100%; 6 | display: flex; 7 | flex-direction: column; 8 | justify-content: center; 9 | align-items: center; 10 | color: #fff; 11 | 12 | @media (max-width: 767px) { 13 | text-align: center; 14 | } 15 | 16 | .heading { 17 | font-size: 21px; 18 | margin: 33px 0px 20px 0px; 19 | font-weight: 500; 20 | } 21 | 22 | .text { 23 | font-size: 14px; 24 | line-height: 1.5; 25 | } 26 | 27 | .closeButton { 28 | @include closeButton(32px, 5px); 29 | top: 20px; 30 | right: 20px; 31 | background: transparent; 32 | border: none; 33 | 34 | &:hover { 35 | &::after, 36 | &::before { 37 | background-color: #fff; 38 | } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /src/components/ModalContent/InitialisationError/InitialisationError.scss: -------------------------------------------------------------------------------- 1 | @import '~style/vars.scss'; 2 | 3 | .initialisationError { 4 | width: 100%; 5 | height: 100%; 6 | display: flex; 7 | flex-direction: column; 8 | justify-content: center; 9 | align-items: center; 10 | color: #fff; 11 | 12 | @media (max-width: 767px) { 13 | text-align: center; 14 | } 15 | 16 | .heading { 17 | font-size: 21px; 18 | margin: 33px 0px 20px 0px; 19 | font-weight: 500; 20 | } 21 | 22 | .text { 23 | font-size: 14px; 24 | line-height: 1.5; 25 | } 26 | 27 | .closeButton { 28 | @include closeButton(32px, 5px); 29 | top: 20px; 30 | right: 20px; 31 | background: transparent; 32 | border: none; 33 | 34 | &:hover { 35 | &::after, 36 | &::before { 37 | background-color: #fff; 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/routes/MarketDetails/api/sellShares.js: -------------------------------------------------------------------------------- 1 | import * as api from 'api' 2 | import Decimal from 'decimal.js' 3 | import { hexWithPrefix } from 'utils/helpers' 4 | 5 | const sellShares = async (marketAddress, outcomeTokenIndex, outcomeTokenCount, earnings, approvalResetAmount) => { 6 | const gnosis = await api.getGnosisConnection() 7 | 8 | const outcomeTokenCountWei = Decimal(outcomeTokenCount) 9 | .mul(1e18) 10 | .toString() 11 | const minProfit = Decimal(earnings) 12 | .mul(1e18) 13 | .round() 14 | .toString() 15 | 16 | const collateralTokensReceived = await gnosis.sellOutcomeTokens({ 17 | market: hexWithPrefix(marketAddress), 18 | outcomeTokenIndex, 19 | outcomeTokenCount: outcomeTokenCountWei, 20 | minProfit, 21 | approvalResetAmount, 22 | }) 23 | 24 | return collateralTokensReceived 25 | } 26 | 27 | export default sellShares 28 | -------------------------------------------------------------------------------- /src/routes/GameGuide/components/LayoutMetamask.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PageFrame from 'components/layout/PageFrame' 3 | import Title from 'components/layout/Title' 4 | import SignUp from './metamaskComponents/SignUp' 5 | import MarketOverview from './metamaskComponents/MarketOverview' 6 | import DashboardOverview from './metamaskComponents/DashboardOverview' 7 | import MakePrediction from './metamaskComponents/MakePrediction' 8 | import Profits from './metamaskComponents/ProfitsAndScoreboard' 9 | import ClaimRewards from './metamaskComponents/ClaimRewards' 10 | 11 | const GameGuide = () => ( 12 | 13 | GAME GUIDE 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ) 22 | 23 | export default GameGuide 24 | -------------------------------------------------------------------------------- /src/containers/Modals/index.js: -------------------------------------------------------------------------------- 1 | export { default as ModalOutcomePriceChanged } from './ModalOutcomePriceChanged' 2 | export { default as ModalTransactionExplanation } from './ModalTransactionExplanation' 3 | export { default as ModalInstallProvider } from './ModalInstallProvider' 4 | export { default as ModalRegisterWallet } from './ModalRegisterWallet' 5 | export { default as ModalRegisterWalletUport } from './ModalRegisterWalletUport' 6 | export { default as ModalClaimReward } from './ModalClaimReward' 7 | export { default as ModalAcceptTOS } from './ModalAcceptTOS' 8 | export { default as ModalVerification } from './ModalVerification' 9 | export { default as ModalSelectProvider } from './ModalSelectProvider' 10 | export { default as ModalInitialisationError } from './ModalInitialisationError' 11 | export { default as ModalUnlockMetamask } from 'integrations/metamask/components/UnlockMetamask' 12 | -------------------------------------------------------------------------------- /src/routes/Scoreboard/components/Layout.scss: -------------------------------------------------------------------------------- 1 | @import '~style/vars.scss'; 2 | 3 | .rewardContainer { 4 | display: flex; 5 | 6 | @media (max-width: $screen-sm) { 7 | flex-direction: column; 8 | } 9 | } 10 | 11 | .trophy { 12 | display: flex; 13 | flex-direction: row; 14 | flex-wrap: nowrap; 15 | align-items: center; 16 | 17 | & img { 18 | width: 48px; 19 | height: 46px; 20 | } 21 | 22 | & p { 23 | font-size: 44px; 24 | margin: 0 0 0 10px; 25 | font-family: Montserrat; 26 | font-size: 42px; 27 | font-weight: 300; 28 | text-align: left; 29 | color: #333333; 30 | } 31 | } 32 | 33 | .explanation { 34 | font-size: 12px; 35 | line-height: 14px; 36 | text-align: left; 37 | } 38 | 39 | .norows { 40 | text-align: center; 41 | font-family: Montserrat; 42 | font-size: 18px; 43 | color: #626262; 44 | margin: 10px 0px; 45 | } 46 | -------------------------------------------------------------------------------- /src/routes/Dashboard/components/Dashboard/Title/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { withNamespaces } from 'react-i18next' 4 | 5 | import classname from 'classnames/bind' 6 | import style from './DashboardTitle.scss' 7 | 8 | const cx = classname.bind(style) 9 | 10 | const Title = ({ t }) => ( 11 |
    12 |
    13 |
    14 |
    15 |
    16 |

    {t('header.dashboard')}

    17 |
    18 |
    19 |
    20 |
    21 |
    22 | ) 23 | 24 | Title.propTypes = { 25 | t: PropTypes.func.isRequired, 26 | } 27 | 28 | export default withNamespaces()(Title) 29 | -------------------------------------------------------------------------------- /src/store/models/market/scalar.js: -------------------------------------------------------------------------------- 1 | import { Record } from 'immutable' 2 | import { OUTCOME_TYPES } from 'utils/constants' 3 | 4 | const ScalarMarketRecord = Record({ 5 | type: OUTCOME_TYPES.SCALAR, 6 | address: undefined, 7 | title: undefined, // string 8 | description: undefined, // string 9 | resolution: undefined, // moment 10 | volume: undefined, // decimal 11 | bounds: undefined, // BoundRecord 12 | eventAddress: undefined, // string 13 | winningOutcome: undefined, // int 14 | funding: undefined, // int 15 | creation: undefined, // moment 16 | stage: undefined, 17 | fee: undefined, // int 18 | resolved: undefined, // boolean 19 | closed: undefined, // boolean 20 | creator: undefined, // string 21 | collateralToken: undefined, // string 22 | outcomeTokensSold: undefined, // List 23 | outcomes: undefined, 24 | }, 'Market') 25 | 26 | export default ScalarMarketRecord 27 | -------------------------------------------------------------------------------- /src/components/Header/Layouts/DesktopHeader/components/WrongNetwork/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import Icon from 'components/Icon' 4 | import classnames from 'classnames/bind' 5 | import Tooltip from 'rc-tooltip' 6 | 7 | import styles from './WrongNetwork.scss' 8 | 9 | const cx = classnames.bind(styles) 10 | 11 | const wrongNetworkIconStyle = { 12 | width: 20, 13 | height: 20, 14 | } 15 | 16 | const WrongNetwork = ({ targetNetwork }) => ( 17 | You're connected to the wrong network. Please connect to the {targetNetwork} network.} 20 | > 21 | 22 | 23 | ) 24 | 25 | WrongNetwork.propTypes = { 26 | targetNetwork: PropTypes.string.isRequired, 27 | } 28 | 29 | export default WrongNetwork 30 | -------------------------------------------------------------------------------- /src/components/Outcome/OutcomeColorBox/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import cn from 'classnames/bind' 3 | import PropTypes from 'prop-types' 4 | 5 | import { COLOR_SCHEME_DEFAULT, COLOR_SCHEME_SCALAR, OUTCOME_TYPES } from 'utils/constants' 6 | 7 | import styles from './OutcomeColorBox.scss' 8 | 9 | const cx = cn.bind(styles) 10 | 11 | const COLOR_SCHEMES = { 12 | [OUTCOME_TYPES.SCALAR]: COLOR_SCHEME_SCALAR, 13 | [OUTCOME_TYPES.CATEGORICAL]: COLOR_SCHEME_DEFAULT, 14 | } 15 | 16 | const OutcomeColorBox = ({ outcomeIndex, scheme }) => (
    ) 17 | 18 | OutcomeColorBox.propTypes = { 19 | outcomeIndex: PropTypes.number.isRequired, 20 | scheme: PropTypes.string, 21 | } 22 | 23 | OutcomeColorBox.defaultProps = { 24 | scheme: OUTCOME_TYPES.CATEGORICAL, 25 | } 26 | 27 | export default OutcomeColorBox 28 | -------------------------------------------------------------------------------- /src/components/layout/Block/index.js: -------------------------------------------------------------------------------- 1 | import classNames from 'classnames/bind' 2 | import PropTypes from 'prop-types' 3 | import React, { PureComponent } from 'react' 4 | import css from './index.scss' 5 | 6 | const cx = classNames.bind(css) 7 | 8 | class Block extends PureComponent { 9 | get blockStyle() { 10 | return { 11 | width: this.props.width, 12 | } 13 | } 14 | 15 | render() { 16 | const { 17 | margin, center, children, className, ...props 18 | } = this.props 19 | 20 | return ( 21 |
    22 | {children} 23 |
    24 | ) 25 | } 26 | } 27 | 28 | Block.propTypes = { 29 | width: PropTypes.string, 30 | margin: PropTypes.string, 31 | center: PropTypes.bool, 32 | children: PropTypes.node, 33 | className: PropTypes.string, 34 | } 35 | 36 | export default Block 37 | -------------------------------------------------------------------------------- /src/routes/MarketList/components/Markets/Market/MarketTrading.js: -------------------------------------------------------------------------------- 1 | import CurrencyName from 'components/CurrencyName' 2 | import PropTypes from 'prop-types' 3 | import React from 'react' 4 | import classNames from 'classnames/bind' 5 | import { hexWithPrefix } from 'utils/helpers' 6 | 7 | import Icon from 'components/Icon' 8 | 9 | import css from './Market.scss' 10 | 11 | const cx = classNames.bind(css) 12 | 13 | const MarketTrading = ({ volume, collateralToken }) => ( 14 |
    15 | 16 |
    17 | {volume} {collateralToken && } Volume 18 |
    19 |
    20 | ) 21 | 22 | MarketTrading.propTypes = { 23 | volume: PropTypes.string.isRequired, 24 | collateralToken: PropTypes.string.isRequired, 25 | } 26 | 27 | export default MarketTrading 28 | -------------------------------------------------------------------------------- /src/store/models/market/categorical.js: -------------------------------------------------------------------------------- 1 | import { Record } from 'immutable' 2 | import { OUTCOME_TYPES } from 'utils/constants' 3 | 4 | const CategoricalMarketRecord = Record({ 5 | type: OUTCOME_TYPES.CATEGORICAL, 6 | address: undefined, 7 | title: undefined, // string 8 | description: undefined, // string 9 | resolution: undefined, // moment 10 | volume: undefined, // decimal 11 | outcomes: undefined, // List 12 | eventAddress: undefined, // string 13 | winningOutcome: undefined, // OutcomeRecord 14 | funding: undefined, // int 15 | creation: undefined, // moment 16 | stage: undefined, 17 | fee: undefined, // int 18 | resolved: undefined, // boolean 19 | closed: undefined, // boolean 20 | creator: undefined, // string 21 | collateralToken: undefined, // string 22 | outcomeTokensSold: undefined, // List 23 | }, 'Market') 24 | 25 | export default CategoricalMarketRecord 26 | -------------------------------------------------------------------------------- /src/components/Outcome/OutcomeScalar/TrendingOutcomeScalar/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import Decimal from 'decimal.js' 4 | import DecimalValue from 'components/DecimalValue' 5 | 6 | const TrendingOutcomeScalar = ({ predictedValue, unit, decimals }) => ( 7 |
    8 |
    9 | 10 |  {unit} 11 |
    12 |
    13 | ) 14 | 15 | TrendingOutcomeScalar.propTypes = { 16 | predictedValue: PropTypes.instanceOf(Decimal), 17 | unit: PropTypes.string, 18 | decimals: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), 19 | } 20 | 21 | TrendingOutcomeScalar.defaultProps = { 22 | predictedValue: Decimal(0), 23 | unit: '', 24 | decimals: 0, 25 | } 26 | 27 | export default TrendingOutcomeScalar 28 | -------------------------------------------------------------------------------- /src/routes/MarketDetails/components/ExpandableViews/MarketMyTrades/marketMyTrades.scss: -------------------------------------------------------------------------------- 1 | @import '~style/vars.scss'; 2 | 3 | $indexWidth: 36px; 4 | $groupWidth: 20%; 5 | 6 | .marketMyTrades { 7 | .shareTable { 8 | margin-top: 20px; 9 | table-layout: fixed; 10 | } 11 | 12 | .shareTableRow { 13 | vertical-align: middle; 14 | 15 | td { 16 | vertical-align: middle !important; 17 | border-top: 1px solid #ddd; 18 | 19 | &:first-of-type { 20 | border-top: 0; 21 | } 22 | } 23 | } 24 | } 25 | 26 | .shareOutcomeColor { 27 | display: inline-block; 28 | vertical-align: middle; 29 | 30 | width: 20px; 31 | height: 20px; 32 | 33 | border-radius: 4px; 34 | } 35 | 36 | .tableHeading { 37 | &.first { 38 | width: 36px; 39 | } 40 | 41 | font-weight: 400; 42 | text-transform: uppercase; 43 | color: #a3adb3; 44 | border-bottom: none !important; 45 | } 46 | -------------------------------------------------------------------------------- /src/routes/Transactions/components/Transactions/Transaction/DetailLabel/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import cn from 'classnames/bind' 4 | import moment from 'moment' 5 | import { RESOLUTION_TIME } from 'utils/constants' 6 | import style from './DetailLabel.scss' 7 | 8 | const cx = cn.bind(style) 9 | 10 | const DetailLabel = ({ label, date, children }) => ( 11 |
    12 |
    {label}
    13 | {children || moment(date).format(RESOLUTION_TIME.ABSOLUTE_FORMAT)} 14 |
    15 | ) 16 | 17 | DetailLabel.propTypes = { 18 | label: PropTypes.string, 19 | date: PropTypes.string, 20 | children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]), 21 | } 22 | 23 | DetailLabel.defaultProps = { 24 | label:
    , 25 | date: undefined, 26 | children: undefined, 27 | } 28 | 29 | export default DetailLabel 30 | -------------------------------------------------------------------------------- /src/routes/Transactions/containers/TransactionsPage/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { withRouter } from 'react-router-dom' 3 | import { compose, withProps } from 'recompose' 4 | 5 | import { getRunningTransactions, getCompletedTransactions } from 'routes/Transactions/store/selectors/transactions' 6 | import { getCurrentAccount } from 'integrations/store/selectors' 7 | import Transactions from '../../components/Transactions' 8 | 9 | const mapStateToProps = state => ({ 10 | currentAccount: getCurrentAccount(state), 11 | runningTransactions: getRunningTransactions(state), 12 | completedTransactions: getCompletedTransactions(state), 13 | }) 14 | 15 | const enhancer = compose( 16 | withRouter, 17 | withProps(({ history }) => ({ 18 | changeUrl: url => history.push(url), 19 | })), 20 | connect( 21 | mapStateToProps, 22 | ), 23 | ) 24 | 25 | export default enhancer(Transactions) 26 | -------------------------------------------------------------------------------- /src/routes/Scoreboard/components/Layout.stories.js: -------------------------------------------------------------------------------- 1 | import { text } from '@storybook/addon-knobs' 2 | import { storiesOf } from '@storybook/react' 3 | import * as React from 'react' 4 | import users from 'stories/knobs/scoreboardUsers' 5 | import { host } from 'storybook-host' 6 | import Layout from './Layout' 7 | 8 | storiesOf('Route ScoreBoard', module) 9 | .addDecorator(host({ 10 | title: 'ScoreBoard ', 11 | align: 'center', 12 | height: 720, 13 | })) 14 | .add('Account in the first 10 positions ', () => { 15 | const data = users 16 | const myWallet = text('User account', '0x90F8bf6A479f320ead074411a4B0e7944Ea8ca007') 17 | 18 | return ( 19 | 20 | ) 21 | }) 22 | .add('Account NOT in the first 10 positions ', () => { 23 | const data = users 24 | 25 | return ( 26 | 27 | ) 28 | }) 29 | -------------------------------------------------------------------------------- /src/components/Header/BadgeIcon.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Tooltip from 'rc-tooltip' 3 | import PropTypes from 'prop-types' 4 | import Icon from 'components/Icon' 5 | import { badgeOf } from 'routes/Scoreboard/components/Table/ScoreTable/table' 6 | 7 | const BadgeIcon = ({ userTournamentInfo }) => { 8 | let predictionsAmount = 0 9 | 10 | if (userTournamentInfo) { 11 | predictionsAmount = userTournamentInfo.predictions 12 | } 13 | 14 | const badge = badgeOf(predictionsAmount) 15 | 16 | if (!badge) { 17 | return null 18 | } 19 | 20 | return ( 21 | 22 | 23 | 24 | ) 25 | } 26 | 27 | BadgeIcon.propTypes = { 28 | userTournamentInfo: PropTypes.shape({}), 29 | } 30 | 31 | BadgeIcon.defaultProps = { 32 | userTournamentInfo: {}, 33 | } 34 | 35 | export default BadgeIcon 36 | -------------------------------------------------------------------------------- /src/routes/Dashboard/assets/shape.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/routes/MarketDetails/components/ExpandableViews/MarketBuySharesForm/OutcomesSection/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { marketShape } from 'utils/shapes' 3 | import { OUTCOME_TYPES } from 'utils/constants' 4 | import OutcomesSectionCategorical from './OutcomesSectionCategorical' 5 | import OutcomesSectionScalar from './OutcomeSectionScalar' 6 | 7 | const BuySharesOutcomeSection = (props) => { 8 | const { 9 | market: { type }, 10 | } = props 11 | if (type === OUTCOME_TYPES.CATEGORICAL) { 12 | return 13 | } 14 | 15 | if (type === OUTCOME_TYPES.SCALAR) { 16 | return 17 | } 18 | 19 | return
    20 | } 21 | 22 | BuySharesOutcomeSection.propTypes = { 23 | market: marketShape, 24 | } 25 | 26 | BuySharesOutcomeSection.defaultProps = { 27 | market: { 28 | event: {}, 29 | }, 30 | } 31 | 32 | export default BuySharesOutcomeSection 33 | -------------------------------------------------------------------------------- /src/components/Form/TextInputAdornment.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import className from 'classnames/bind' 4 | 5 | import styles from './TextInputAdornment.scss' 6 | 7 | const cx = className.bind(styles) 8 | 9 | const TextInputAdornment = ({ children, position, style }) => { 10 | const textInputAdornmentClasses = cx('adornment', { 11 | end: position === 'end', 12 | start: position === 'start', 13 | }) 14 | 15 | return ( 16 |

    17 | {children} 18 |

    19 | ) 20 | } 21 | 22 | TextInputAdornment.propTypes = { 23 | children: PropTypes.node, 24 | position: PropTypes.oneOf(['end', 'start']), 25 | // eslint-disable-next-line 26 | style: PropTypes.object, 27 | } 28 | 29 | TextInputAdornment.defaultProps = { 30 | children: undefined, 31 | position: undefined, 32 | style: {}, 33 | } 34 | 35 | export default TextInputAdornment 36 | -------------------------------------------------------------------------------- /src/api/market.js: -------------------------------------------------------------------------------- 1 | import Gnosis from '@gnosis.pm/pm-js/' 2 | import { OUTCOME_TYPES } from 'utils/constants' 3 | import { getGnosisConnection } from 'api' 4 | 5 | export const resolveEvent = async (event, selectedOutcomeIndex) => { 6 | const gnosis = await getGnosisConnection() 7 | 8 | await gnosis.resolveEvent({ event: event.address, outcome: parseInt(selectedOutcomeIndex, 10) }) 9 | } 10 | 11 | export const redeemWinnings = async (eventType, eventAddress) => { 12 | const gnosis = await getGnosisConnection() 13 | 14 | const eventContract = eventType === OUTCOME_TYPES.CATEGORICAL 15 | ? await gnosis.contracts.CategoricalEvent.at(eventAddress) 16 | : await gnosis.contracts.ScalarEvent.at(eventAddress) 17 | 18 | if (eventContract) { 19 | return Gnosis.requireEventFromTXResult(await eventContract.redeemWinnings(), 'WinningsRedemption') 20 | } 21 | throw new Error("Invalid Event - can't find the specified Event, invalid Eventtype?") 22 | } 23 | -------------------------------------------------------------------------------- /src/utils/analytics/google/index.js: -------------------------------------------------------------------------------- 1 | /* globals ga */ 2 | import { getThirdPartyConfig } from 'utils/features' 3 | 4 | export const THIRD_PARTY_ID = 'googleAnalytics' 5 | 6 | const { id } = getThirdPartyConfig(THIRD_PARTY_ID) 7 | 8 | const GOOGLE_ANALYTICS_URL = 'https://www.google-analytics.com/analytics.js' 9 | 10 | export const ga = (...args) => (window.ga && window.ga.q && window.ga.q(...args)) 11 | || (window.ga && window.ga(...args)) 12 | || (() => {})(...args) // no-op 13 | 14 | const loadGoogleAnalytics = () => new Promise((resolve) => { 15 | const script = document.createElement('script') 16 | script.src = GOOGLE_ANALYTICS_URL 17 | script.type = 'text/javascript' 18 | 19 | document.head.appendChild(script) 20 | 21 | script.onload = () => { 22 | ga('create', id, 'auto') 23 | ga('send', 'pageview') 24 | 25 | resolve() 26 | } 27 | }) 28 | 29 | export const gaSend = (...args) => ga(id, ...args) 30 | 31 | export default loadGoogleAnalytics 32 | -------------------------------------------------------------------------------- /src/setup.js: -------------------------------------------------------------------------------- 1 | import moment from 'moment' 2 | import momentDurationFormatSetup from 'moment-duration-format' 3 | 4 | export const setMomentRelativeTime = () => { 5 | moment.updateLocale('en', { 6 | relativeTime: { 7 | future: '%s', 8 | past: '%s ago', 9 | s: '< 59s', 10 | ss: '> %d s', 11 | m: '< 59m', 12 | mm: '> %d m', 13 | h: '< 1h', 14 | hh: '> %d h', 15 | d: '< 1d', 16 | dd: '< %d d', 17 | M: 'a month', 18 | MM: '%d months', 19 | y: 'a year', 20 | yy: '%d years', 21 | }, 22 | }) 23 | 24 | // Set new thresholds 25 | moment.relativeTimeThreshold('ss', 3) 26 | moment.relativeTimeThreshold('s', 59) 27 | moment.relativeTimeThreshold('m', 59) 28 | moment.relativeTimeThreshold('h', 20) 29 | moment.relativeTimeThreshold('d', 25) 30 | moment.relativeTimeThreshold('M', 10) 31 | } 32 | 33 | export const setMomentDurationFormat = () => { 34 | momentDurationFormatSetup(moment) 35 | } 36 | -------------------------------------------------------------------------------- /src/routes/MarketList/components/MarketStats/MarketStats.scss: -------------------------------------------------------------------------------- 1 | @import '~style/vars.scss'; 2 | 3 | .marketStats { 4 | width: 100%; 5 | margin-bottom: 96px; 6 | 7 | .inner { 8 | width: 100%; 9 | max-width: 100%; 10 | display: flex; 11 | flex-flow: row wrap; 12 | justify-content: space-between; 13 | 14 | @media (max-width: $screen-sm) { 15 | flex-direction: column; 16 | align-items: baseline; 17 | } 18 | 19 | .stat { 20 | margin-bottom: 12px; 21 | width: auto; 22 | 23 | .content { 24 | margin-left: 20px; 25 | float: left; 26 | } 27 | 28 | .value { 29 | font-size: 28px; 30 | font-weight: 300; 31 | letter-spacing: 1px; 32 | } 33 | 34 | .label { 35 | color: $font-color-light; 36 | opacity: .6; 37 | text-transform: uppercase; 38 | font-size: 10px; 39 | letter-spacing: .5px; 40 | } 41 | } 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /src/routes/Dashboard/components/Dashboard/Markets/Category.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import classnames from 'classnames/bind' 4 | 5 | import { marketRecordListShape } from 'utils/shapes' 6 | import ConditionalList from './ConditionalList' 7 | 8 | import style from './Category.scss' 9 | 10 | const cx = classnames.bind(style) 11 | 12 | const Category = ({ 13 | markets, title, viewMarket, component: MarketComponent, 14 | }) => ( 15 |
    16 |
    {title}
    17 | 18 |
    19 | ) 20 | 21 | Category.propTypes = { 22 | title: PropTypes.string.isRequired, 23 | viewMarket: PropTypes.func.isRequired, 24 | component: PropTypes.func.isRequired, 25 | markets: marketRecordListShape, 26 | } 27 | 28 | Category.defaultProps = { 29 | markets: undefined, 30 | } 31 | 32 | export default Category 33 | -------------------------------------------------------------------------------- /src/utils/analytics/index.js: -------------------------------------------------------------------------------- 1 | import { isThirdPartyIntegrationEnabled, getThirdPartyConfig } from 'utils/features' 2 | 3 | import loadGoogleAnalytics, { THIRD_PARTY_ID as GOOGLE_ANALYTICS } from './google' 4 | import loadIntercom, { THIRD_PARTY_ID as INTERCOM } from './intercom' 5 | 6 | export const THIRD_PARTY_INTEGRATIONS = { 7 | [GOOGLE_ANALYTICS]: loadGoogleAnalytics, 8 | [INTERCOM]: loadIntercom, 9 | } 10 | 11 | const initAnalytics = () => { 12 | Object.keys(THIRD_PARTY_INTEGRATIONS).forEach((THIRD_PARTY_ID) => { 13 | if (isThirdPartyIntegrationEnabled(THIRD_PARTY_ID)) { 14 | const init = THIRD_PARTY_INTEGRATIONS[THIRD_PARTY_ID] 15 | const thirdPartyConfig = getThirdPartyConfig(THIRD_PARTY_ID) 16 | 17 | // console.info(`Loading third party: ${THIRD_PARTY_ID}`) 18 | init(thirdPartyConfig).then(() => { 19 | // console.info(`Finished loading third party: ${THIRD_PARTY_ID}`) 20 | }) 21 | } 22 | }) 23 | } 24 | 25 | export default initAnalytics 26 | -------------------------------------------------------------------------------- /src/store/reducers/notifications/index.js: -------------------------------------------------------------------------------- 1 | import { handleActions } from 'redux-actions' 2 | import { Map, List } from 'immutable' 3 | import { showNotification, fadeOutNotification, hideAllNotifications } from 'store/actions/notifications' 4 | import NotificationRecord from 'store/reducers/notifications/models/notification' 5 | 6 | const reducer = handleActions( 7 | { 8 | [showNotification]: (state, action) => 9 | state.withMutations((stateMap) => { 10 | stateMap.update('currentVisible', value => value.push(action.payload.id)) 11 | stateMap.setIn(['log', action.payload.id], new NotificationRecord(action.payload)) 12 | }), 13 | [fadeOutNotification]: (state, action) => 14 | state.update('currentVisible', value => value.filter(id => id !== action.payload.id)), 15 | [hideAllNotifications]: state => state.set('currentVisible', List()), 16 | }, 17 | Map({ 18 | log: Map(), 19 | currentVisible: List(), 20 | }), 21 | ) 22 | 23 | export default reducer 24 | -------------------------------------------------------------------------------- /src/assets/img/icons/icon_winningOutcome.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/components/Header/Layouts/MobileHeader/AccountOverview/AccountOverview.scss: -------------------------------------------------------------------------------- 1 | .overviewContainer { 2 | text-align: center; 3 | margin-bottom: 30px; 4 | 5 | .identicon { 6 | width: 90px; 7 | height: 90px; 8 | 9 | border-radius: 50%; 10 | border: 1px solid white; 11 | } 12 | 13 | .networkBalanceWrapper { 14 | display: flex; 15 | margin-bottom: 10px; 16 | 17 | & > div { 18 | line-height: 1; 19 | margin-top: -1px; 20 | } 21 | 22 | span { 23 | font-size: 15px; 24 | font-weight: bold; 25 | } 26 | 27 | .network { 28 | margin-right: auto; 29 | } 30 | } 31 | 32 | .addressWrapper { 33 | margin-top: 10px; 34 | .address { 35 | padding: 0; 36 | border: 0; 37 | background: transparent; 38 | color: #b8b7ad; 39 | font-size: 16px; 40 | 41 | &:focus, 42 | &:hover { 43 | color: darken($color: #b8b7ad, $amount: 20); 44 | outline: 0; 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/routes/MarketDetails/store/actions/requestGasCost.js: -------------------------------------------------------------------------------- 1 | import { GAS_COST } from 'utils/constants' 2 | import { createAction } from 'redux-actions' 3 | import { calcBuySharesGasCost, calcSellSharesGasCost, calcRedeemWinningsGasCost } from '../../api' 4 | 5 | const setGasCost = createAction('SET_GAS_COST') 6 | 7 | const requestGasCost = (contractType, opts) => async (dispatch) => { 8 | if (contractType === GAS_COST.BUY_SHARES) { 9 | const gasCost = await calcBuySharesGasCost() 10 | dispatch(setGasCost({ entityType: 'gasCosts', contractType, gasCost })) 11 | } else if (contractType === GAS_COST.SELL_SHARES) { 12 | const gasCost = await calcSellSharesGasCost() 13 | dispatch(setGasCost({ entityType: 'gasCosts', contractType, gasCost })) 14 | } else if (contractType === GAS_COST.REDEEM_WINNINGS) { 15 | const gasCost = await calcRedeemWinningsGasCost(opts) 16 | dispatch(setGasCost({ entityType: 'gasCosts', contractType, gasCost })) 17 | } 18 | } 19 | 20 | export { requestGasCost, setGasCost } 21 | -------------------------------------------------------------------------------- /src/routes/Scoreboard/components/RewardClaimAddress/RewardClaim.scss: -------------------------------------------------------------------------------- 1 | @import '~style/vars.scss'; 2 | 3 | .rewardClaim { 4 | width: 350px; 5 | height: 110px; 6 | border-radius: 2px; 7 | background-color: #ffffff; 8 | box-shadow: 0 0 6px 0 rgba(0, 0, 0, 0.11); 9 | word-break: break-all; 10 | margin-bottom: 20px; 11 | 12 | display: flex; 13 | 14 | @media (max-width: $screen-sm) { 15 | width: 100%; 16 | } 17 | 18 | .iconSection { 19 | background-color: #f0f1f1; 20 | width: 60px; 21 | flex-shrink: 0; 22 | flex-grow: 0; 23 | 24 | display: flex; 25 | justify-content: center; 26 | align-items: center; 27 | } 28 | 29 | p { 30 | font-size: 14px; 31 | margin: 0; 32 | } 33 | 34 | .loadingSection { 35 | display: flex; 36 | justify-content: center; 37 | align-items: center; 38 | width: 100%; 39 | height: 118px; 40 | } 41 | 42 | a, 43 | a:link, 44 | a:visited { 45 | color: #00a6c4; 46 | text-decoration: underline; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/store/utils/marketStatus.js: -------------------------------------------------------------------------------- 1 | import moment from 'moment' 2 | import { MARKET_STAGES } from 'store/models' 3 | 4 | export const isMarketClosed = ({ stage, resolution }) => { 5 | const stageClosed = stage !== MARKET_STAGES.MARKET_FUNDED 6 | const marketExpired = moment.utc(resolution).isBefore(moment.utc()) 7 | 8 | const marketClosed = stageClosed || marketExpired 9 | return marketClosed 10 | } 11 | 12 | export const isMarketEndingSoon = (resolutionDate) => { 13 | const threeDays = moment.utc().add(3, 'days') 14 | return moment.utc(resolutionDate).isSameOrBefore(threeDays) 15 | } 16 | 17 | export const isNewMarket = (creation) => { 18 | const threeDaysAgo = moment.utc().subtract(3, 'days') 19 | 20 | return threeDaysAgo.isBefore(creation) 21 | } 22 | 23 | export const isMarketResolved = ({ resolved }) => resolved 24 | 25 | export const isMarketClosedOrResolved = market => isMarketClosed(market) || isMarketResolved(market) 26 | 27 | export const isMarketFunded = stage => stage > MARKET_STAGES.MARKET_CREATED 28 | -------------------------------------------------------------------------------- /src/store/middlewares/Storage/Load.js: -------------------------------------------------------------------------------- 1 | import * as actions from './actions' 2 | import { NOOP_MIDDLEWARE, STORAGE_KEY } from './constants' 3 | 4 | const middleware = (storage) => { 5 | const storageIsValid = storage instanceof Storage 6 | 7 | if (!storageIsValid) { 8 | console.warn('StorageLoader: Storage is either not supported or invalid') 9 | return NOOP_MIDDLEWARE 10 | } 11 | 12 | return store => next => (action) => { 13 | const { type } = action 14 | if (type === 'INIT') { 15 | const stringPayload = storage.getItem(STORAGE_KEY) 16 | if (stringPayload) { 17 | let payload 18 | try { 19 | const decoded = Buffer.from(stringPayload, 'base64').toString('ascii') 20 | payload = JSON.parse(decoded) 21 | store.dispatch(actions.loadStorage(payload)) 22 | } catch (e) { 23 | console.error('Could not load saved storage: ', e) 24 | } 25 | } 26 | } 27 | 28 | next(action) 29 | } 30 | } 31 | 32 | export default middleware 33 | -------------------------------------------------------------------------------- /src/routes/MarketDetails/components/MarketDetail/Details/RedeemWinnings/RedeemWinnings.scss: -------------------------------------------------------------------------------- 1 | @import '~style/vars.scss'; 2 | 3 | .redeemWinning { 4 | display: flex; 5 | flex-direction: column; 6 | max-width: 267px; 7 | margin: 20px 0; 8 | 9 | .detailsContainer { 10 | display: flex; 11 | align-items: center; 12 | 13 | .details { 14 | padding-left: 10px; 15 | } 16 | 17 | .heading { 18 | font-size: 30px; 19 | } 20 | 21 | .label { 22 | text-transform: uppercase; 23 | color: $font-color-muted; 24 | font-size: 10px; 25 | font-weight: 500; 26 | letter-spacing: 0.5px; 27 | } 28 | } 29 | 30 | .action { 31 | text-align: center; 32 | margin-top: 20px; 33 | .redeemButton { 34 | padding: 10px; 35 | height: auto; 36 | width: 100%; 37 | text-align: center; 38 | line-height: 1; 39 | } 40 | } 41 | 42 | .gasCost { 43 | margin-top: 5px; 44 | display: inline-block; 45 | color: $font-color-muted; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/routes/MarketDetails/store/selectors/getMarketShares.js: -------------------------------------------------------------------------------- 1 | import { getCurrentAccount } from 'integrations/store/selectors' 2 | import Decimal from 'decimal.js' 3 | import { createSelector } from 'reselect' 4 | import { sharesWithMarketsSelector } from 'store/selectors/account/shares' 5 | import { hexWithoutPrefix } from 'utils/helpers' 6 | import { calcShareWinnings } from 'routes/Dashboard/containers/Dashboard/utils' 7 | 8 | const getMarketShares = marketAddress => createSelector(sharesWithMarketsSelector, getCurrentAccount, (shares, account) => shares 9 | .filter( 10 | share => Decimal(share.balance).gt(0) 11 | && share.owner === hexWithoutPrefix(account) 12 | && share.market?.address === marketAddress, 13 | ) 14 | .map((share) => { 15 | let shareWinnings = '0' 16 | 17 | if (share.market.resolved) { 18 | shareWinnings = calcShareWinnings(share, share.market) 19 | } 20 | 21 | return share.set('winnings', shareWinnings) 22 | }) 23 | .toList()) 24 | 25 | export default getMarketShares 26 | -------------------------------------------------------------------------------- /src/routes/MarketDetails/components/ExpandableViews/MarketMyTrades/TableHeader/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import cn from 'classnames/bind' 3 | import PropTypes from 'prop-types' 4 | import { withNamespaces } from 'react-i18next' 5 | import style from '../marketMyTrades.scss' 6 | 7 | const cx = cn.bind(style) 8 | 9 | const TableHeader = ({ t }) => ( 10 | 11 | 12 | 13 | {t('market.order_type')} 14 | {t('market.outcome')} 15 | {t('market.outcome_count')} 16 | {t('market.avg_price')} 17 | {t('market.date')} 18 | {t('market.cost')} 19 | 20 | 21 | ) 22 | 23 | TableHeader.propTypes = { 24 | t: PropTypes.func.isRequired, 25 | } 26 | 27 | export default withNamespaces()(TableHeader) 28 | -------------------------------------------------------------------------------- /src/assets/verification/onfido/id-type-driverlicense.svg: -------------------------------------------------------------------------------- 1 | 2 | drivers-licence-hover 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/components/ModalContent/InstallProvider/InstallProvider.scss: -------------------------------------------------------------------------------- 1 | @import '~style/vars.scss'; 2 | 3 | .installProvider { 4 | width: 100%; 5 | height: 100%; 6 | display: flex; 7 | flex-direction: column; 8 | justify-content: center; 9 | align-items: center; 10 | color: #fff; 11 | 12 | @media (max-width: 767px) { 13 | text-align: center; 14 | } 15 | 16 | .installText { 17 | font-size: 21px; 18 | margin: 33px 0px 20px 0px; 19 | font-weight: 500; 20 | } 21 | 22 | .downloadText { 23 | font-size: 14px; 24 | line-height: 1.5; 25 | 26 | .downloadLink { 27 | &:hover { 28 | color: #fff; 29 | opacity: 0.6; 30 | } 31 | 32 | text-decoration: underline; 33 | } 34 | } 35 | 36 | .closeButton { 37 | @include closeButton(32px, 5px); 38 | top: 20px; 39 | right: 20px; 40 | background: transparent; 41 | border: none; 42 | 43 | &:hover { 44 | &::after, 45 | &::before { 46 | background-color: #fff; 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/assets/badges/crystal-gazer.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/components/ModalContent/Verification/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { withNamespaces } from 'react-i18next' 4 | 5 | import VerificationHandler from 'verification' 6 | 7 | import classnames from 'classnames/bind' 8 | import styles from './Verification.scss' 9 | 10 | const cx = classnames.bind(styles) 11 | 12 | const ErrorComponent = ({ closeModal, t }) => ( 13 | <> 14 |

    {t('verification.errors.not_loaded')}

    15 |
    19 | ) 20 | 21 | TransactionsExplanation.propTypes = { 22 | transactions: PropTypes.arrayOf(PropTypes.string).isRequired, 23 | closeModal: PropTypes.func.isRequired, 24 | t: PropTypes.func.isRequired, 25 | } 26 | 27 | export default withNamespaces()(TransactionsExplanation) 28 | -------------------------------------------------------------------------------- /src/routes/Dashboard/assets/badges/crystal-gazer.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/containers/LegalCompliance/components/DocumentExplanation.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | 4 | const TOS_DOCUMENT = 'TOS_DOCUMENT' 5 | const TOS_TEXT = 'TOS_TEXT' 6 | 7 | const DOCUMENT_TYPES = { 8 | FILE: TOS_DOCUMENT, 9 | TEXT: TOS_TEXT, 10 | } 11 | 12 | const LegalDocumentTitle = ({ 13 | type, file, id, t, 14 | }) => { 15 | if (type === DOCUMENT_TYPES.FILE) { 16 | return ( 17 | 18 | 19 | {t(`legal.documents.${id}`)} 20 | 21 | 22 | ) 23 | } 24 | if (type === DOCUMENT_TYPES.TEXT) { 25 | return {t(`legal.documents.${id}_short`)} 26 | } 27 | 28 | return null 29 | } 30 | 31 | LegalDocumentTitle.propTypes = { 32 | type: PropTypes.string.isRequired, 33 | id: PropTypes.string.isRequired, 34 | t: PropTypes.func.isRequired, 35 | file: PropTypes.string, 36 | } 37 | 38 | LegalDocumentTitle.defaultProps = { 39 | file: '', 40 | } 41 | 42 | export default LegalDocumentTitle 43 | -------------------------------------------------------------------------------- /src/routes/Transactions/store/selectors/transactions.spec.js: -------------------------------------------------------------------------------- 1 | import { transactionSelector } from 'routes/Transactions/store/selectors/transactions' 2 | import { Map } from 'immutable' 3 | 4 | // import { TRANSACTION_STATUS, TRANSACTION_COMPLETE_STATUS } from 'utils/constants' 5 | 6 | describe('transactionsSelector', () => { 7 | test('it should return a transaction object', () => { 8 | const state = { 9 | transactions: Map({ 10 | log: Map({ 11 | test123: { 12 | id: 'test123', 13 | }, 14 | }), 15 | }), 16 | } 17 | 18 | expect(transactionSelector(state, 'test123')).toMatchObject(state.transactions.getIn(['log', 'test123'])) 19 | }) 20 | 21 | test('it should return an empty object for an invalid transaction id', () => { 22 | const state = { 23 | transactions: Map({ 24 | log: { 25 | test123: { 26 | id: 'test123', 27 | }, 28 | }, 29 | }), 30 | } 31 | 32 | expect(transactionSelector(state, 'test123')).toMatchObject({}) 33 | }) 34 | }) 35 | -------------------------------------------------------------------------------- /src/routes/GameGuide/components/uPortComponents/SignUp/index.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import Block from 'components/layout/Block' 3 | import Subtitle from 'components/layout/Subtitle' 4 | import Paragraph from 'components/layout/Paragraph' 5 | 6 | const SignUp = () => ( 7 | 8 | Sign-up 9 | 10 | To participate in our two-week tournament, verify your identity by signing up via the uPort app on Android or iOS.{' '} 11 |
    12 |
    13 | uPort is a secure, easy-to-use system for self-sovereign identity, built on Ethereum. uPort identities are fully 14 | owned and controlled by the creator, and don't rely on centralized third-parties for creation or validation. 15 | Via uPort, you can own and control your personal identity; securely and selectively disclose your data to 16 | counterparties, and interact with decentralized applications and smart contracts such as Gnosis. 17 |
    18 |
    19 | ) 20 | 21 | export default SignUp 22 | -------------------------------------------------------------------------------- /config/mainnet/development.json: -------------------------------------------------------------------------------- 1 | { 2 | "gnosisdb": { 3 | "protocol": "https", 4 | "host": "tradingdb.staging.gnosisdev.com", 5 | "port": 443 6 | }, 7 | "ethereum":{ 8 | "protocol":"https", 9 | "host":"rinkeby.infura.io/v3/5e7a225e60184afaa7b888303def93b8", 10 | "port":443 11 | }, 12 | "htmlConfig": { 13 | "title": "Gnosis Trading Interface" 14 | }, 15 | "whitelist": { 16 | "0x9eab578556de5782445ec036f25a41902ba19eeb": "Gnosis", 17 | "0xb2e87b8ce41184e0688027f370a972a436abe77e": "Giacomo", 18 | "0xb00a24c899f88e5514583cfa8c40e4cdab6c473e": "Andre", 19 | "0x65039084cc6f4773291a6ed7dcf5bc3a2e894ff3": "Denis", 20 | "0x4b07f5a08639bcde3b7275a98dae265cbda608ca": "Lama", 21 | "0xe7e3272a84cf3fe180345b9f7234ba705eb5e2ca": "Mikhail", 22 | "0x95db47d3e9d574cd15b0f02c845bc2971b0fc3e1": "Lauti" 23 | }, 24 | "thirdparty": { 25 | "googleAnalytics": { 26 | "enabled": false 27 | } 28 | }, 29 | "providers": { 30 | "default": "METAMASK" 31 | }, 32 | "legalCompliance": { 33 | "enabled": true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/containers/LegalCompliance/components/DocumentField.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { Field } from 'redux-form' 4 | import { Checkbox } from 'components/Form' 5 | 6 | const DocumentField = ({ 7 | id, type, className, file, t, 8 | }) => ( 9 | 10 | {type === 'TOS_DOCUMENT' && ( 11 | 12 | {t('legal.read_and_understood')}  13 | 14 | {t(`legal.documents.${id}`)} 15 | 16 | 17 | )} 18 | {type === 'TOS_TEXT' && {t(`legal.documents.${id}_description`)}} 19 | 20 | ) 21 | 22 | DocumentField.propTypes = { 23 | t: PropTypes.func.isRequired, 24 | id: PropTypes.string.isRequired, 25 | type: PropTypes.string.isRequired, 26 | file: PropTypes.string, 27 | className: PropTypes.string, 28 | } 29 | 30 | DocumentField.defaultProps = { 31 | className: '', 32 | file: '', 33 | } 34 | 35 | export default DocumentField 36 | -------------------------------------------------------------------------------- /src/assets/img/icons/icon_currency.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/components/Notifications/Notifications.scss: -------------------------------------------------------------------------------- 1 | @import '~style/vars.scss'; 2 | @keyframes slideInFromRight { 3 | 0% { 4 | transform: translateX(400px); 5 | } 6 | 7 | 100% { 8 | transform: translateX(0); 9 | } 10 | } 11 | 12 | .notification { 13 | animation: slideInFromRight 1s ease-out 0s 1; 14 | background-color: $bg-color; 15 | 16 | padding: 4px; 17 | width: 100%; 18 | position: relative; 19 | 20 | color: $font-color-dark; 21 | border: none; 22 | 23 | &:hover { 24 | color: $active-highlight; 25 | } 26 | 27 | .notificationHeaderContainer { 28 | display: flex; 29 | align-items: center; 30 | 31 | .iconContainer { 32 | height: 100%; 33 | vertical-align: middle; 34 | margin-left: 4px; 35 | display: inline-block; 36 | } 37 | 38 | .title { 39 | text-transform: uppercase; 40 | font-weight: 500; 41 | margin-bottom: 8px; 42 | color: inherit; 43 | display: inline-block; 44 | } 45 | } 46 | 47 | .message { 48 | color: inherit; 49 | padding-left: 24px; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/routes/MarketDetails/store/actions/requestMarket.js: -------------------------------------------------------------------------------- 1 | import { requestFromRestAPI } from 'api/utils/fetch' 2 | import { addMarkets, extractMarkets } from 'store/actions/market' 3 | import { getCollateralToken } from 'store/selectors/blockchain' 4 | import { hexWithoutPrefix } from 'utils/helpers' 5 | 6 | export const processMarketResponse = (dispatch, state, response) => { 7 | if (!response) { 8 | dispatch(addMarkets([])) 9 | return 10 | } 11 | 12 | const applicationCollateralToken = getCollateralToken(state) 13 | 14 | let marketRecords = extractMarkets([response]) 15 | 16 | if (applicationCollateralToken.address) { 17 | marketRecords = marketRecords.filter(({ collateralToken }) => collateralToken === hexWithoutPrefix(applicationCollateralToken.address)) 18 | } 19 | 20 | dispatch(addMarkets(marketRecords)) 21 | } 22 | 23 | export default marketAddress => async (dispatch, getState) => { 24 | const response = await requestFromRestAPI(`markets/${marketAddress}`) 25 | const state = getState() 26 | 27 | return processMarketResponse(dispatch, state, response) 28 | } 29 | -------------------------------------------------------------------------------- /src/routes/MarketDetails/api/calculateGasCost.js: -------------------------------------------------------------------------------- 1 | import { getGnosisConnection } from 'api' 2 | 3 | /* 4 | * Gas Calculation functions 5 | */ 6 | 7 | export const calcBuySharesGasCost = async () => { 8 | const gnosis = await getGnosisConnection() 9 | const gasCost = await gnosis.buyOutcomeTokens.estimateGas({ using: 'stats' }) 10 | return gasCost 11 | } 12 | 13 | export const calcSellSharesGasCost = async () => { 14 | const gnosis = await getGnosisConnection() 15 | const gasCost = await gnosis.sellOutcomeTokens.estimateGas({ using: 'stats' }) 16 | return gasCost 17 | } 18 | 19 | /** 20 | * Returns gas cost for redeem winnings 21 | * @param {*object} opts options 22 | * @param {*string} opts.eventAddress Address for the event 23 | */ 24 | 25 | export const calcRedeemWinningsGasCost = async ({ eventAddress }) => { 26 | if (!eventAddress) { 27 | return undefined 28 | } 29 | 30 | const gnosis = await getGnosisConnection() 31 | const event = await gnosis.contracts.Event.at(eventAddress) 32 | 33 | const gasGost = await event.redeemWinnings.estimateGas() 34 | return gasGost 35 | } 36 | -------------------------------------------------------------------------------- /src/components/layout/Paragraph/index.js: -------------------------------------------------------------------------------- 1 | import classNames from 'classnames/bind' 2 | import PropTypes from 'prop-types' 3 | import React, { PureComponent } from 'react' 4 | import * as css from './index.scss' 5 | 6 | const cx = classNames.bind(css) 7 | 8 | class Paragraph extends PureComponent { 9 | render() { 10 | const { 11 | children, color, center, size, nomargin, ...props 12 | } = this.props 13 | const noMargin = nomargin ? 'no-margin' : undefined 14 | 15 | return ( 16 |

    17 | { children } 18 |

    19 | ) 20 | } 21 | } 22 | 23 | Paragraph.propTypes = { 24 | size: PropTypes.oneOf(['normal', 'small']), 25 | nomargin: PropTypes.bool, 26 | center: PropTypes.bool, 27 | color: PropTypes.oneOf(['soft', 'medium', 'dark', 'primary']), 28 | children: PropTypes.node, 29 | } 30 | 31 | Paragraph.defaultProps = { 32 | size: 'normal', 33 | center: false, 34 | color: undefined, 35 | children: undefined, 36 | nomargin: false, 37 | } 38 | 39 | export default Paragraph 40 | -------------------------------------------------------------------------------- /src/routes/Scoreboard/containers/selector.js: -------------------------------------------------------------------------------- 1 | import { createSelector, createStructuredSelector } from 'reselect' 2 | import { getCurrentAccount, getRegisteredMainnetAddress } from 'integrations/store/selectors' 3 | import { rankSelector } from 'routes/Scoreboard/store/selectors' 4 | import { hasClaimedReward } from 'containers/Modals/ModalClaimReward/selectors' 5 | import { firstTournamentUsersSelectorAsList, meSelector } from '../store/selectors' 6 | 7 | const usersSelector = createSelector(firstTournamentUsersSelectorAsList, meSelector, (firstUsers, me) => { 8 | if (!me) { 9 | return firstUsers 10 | } 11 | 12 | if (!firstUsers) { 13 | return undefined 14 | } 15 | 16 | const foundUser = firstUsers ? firstUsers.find(user => user.account === me.account) : undefined 17 | const dataTable = foundUser ? firstUsers : firstUsers.push(me) 18 | 19 | return dataTable 20 | }) 21 | 22 | export default createStructuredSelector({ 23 | data: usersSelector, 24 | mainnetAddress: getRegisteredMainnetAddress, 25 | myAccount: getCurrentAccount, 26 | rank: rankSelector, 27 | hasClaimedReward, 28 | }) 29 | -------------------------------------------------------------------------------- /src/components/TransactionFloater/Notifications/Notifications.scss: -------------------------------------------------------------------------------- 1 | @import '~style/vars.scss'; 2 | 3 | @keyframes slideInFromRight { 4 | 0% { 5 | transform: translateX(400px); 6 | } 7 | 8 | 100% { 9 | transform: translateX(0); 10 | } 11 | } 12 | 13 | .notification { 14 | animation: slideInFromRight 1s ease-out 0s 1; 15 | background-color: $bg-color; 16 | 17 | padding: 4px; 18 | width: 100%; 19 | position: relative; 20 | 21 | color: $font-color-dark; 22 | border: none; 23 | 24 | &:hover { 25 | color: $active-highlight; 26 | } 27 | 28 | .notificationHeaderContainer { 29 | display: flex; 30 | align-items: center; 31 | 32 | .iconContainer { 33 | height: 100%; 34 | vertical-align: middle; 35 | margin-left: 4px; 36 | display: inline-block; 37 | } 38 | 39 | .title { 40 | text-transform: uppercase; 41 | font-weight: 500; 42 | margin-bottom: 8px; 43 | color: inherit; 44 | display: inline-block; 45 | } 46 | } 47 | 48 | .message { 49 | color: inherit; 50 | padding-left: 24px; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/components/Header/ProviderIcon.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import Tooltip from 'rc-tooltip' 4 | import { withNamespaces } from 'react-i18next' 5 | 6 | import Icon from 'components/Icon' 7 | 8 | import { providerPropType } from 'utils/shapes' 9 | import { upperFirst } from 'lodash' 10 | 11 | import { WALLET_PROVIDER } from 'integrations/constants' 12 | 13 | const PROVIDER_ICONS = { 14 | ...WALLET_PROVIDER, 15 | [WALLET_PROVIDER.REMOTE]: 'etherTokens', 16 | } 17 | 18 | const providerIconStyle = { 19 | marginLeft: 10, 20 | } 21 | 22 | const ProviderIcon = ({ provider, t }) => ( 23 | 24 | 25 | 26 | ) 27 | 28 | ProviderIcon.propTypes = { 29 | provider: providerPropType, 30 | t: PropTypes.func.isRequired, 31 | } 32 | 33 | ProviderIcon.defaultProps = { 34 | provider: {}, 35 | } 36 | 37 | export default withNamespaces()(ProviderIcon) 38 | -------------------------------------------------------------------------------- /src/assets/img/icons/icon_enddate.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 11 | 12 | -------------------------------------------------------------------------------- /src/store/middlewares/Notifications.js: -------------------------------------------------------------------------------- 1 | import { 2 | createNotificationFromTransaction, 3 | hideAllNotifications, 4 | } from 'store/actions/notifications' 5 | 6 | let isModalOpen = false 7 | 8 | export default store => next => (action) => { 9 | const handledAction = next(action) 10 | 11 | const { type, payload } = action 12 | 13 | if (type === 'SHOW_MODAL') { 14 | isModalOpen = true 15 | } 16 | 17 | if (type === 'CLOSE_MODAL') { 18 | isModalOpen = false 19 | } 20 | 21 | if (!isModalOpen) { 22 | if (type === 'CLOSE_TRANSACTION_LOG') { 23 | // intercept close log messages, fire notification handler 24 | store.dispatch(createNotificationFromTransaction(payload.id, 'CLOSE')) 25 | } 26 | 27 | if (type === 'START_TRANSACTION_LOG') { 28 | store.dispatch(createNotificationFromTransaction(payload.id, 'START')) 29 | } 30 | 31 | // disable/hide all notifications while menu is open 32 | if (type === 'SHOW_TRANSACTION_LOG' || type === 'HIDE_TRANSACTION_LOG') { 33 | store.dispatch(hideAllNotifications()) 34 | } 35 | } 36 | 37 | return handledAction 38 | } 39 | -------------------------------------------------------------------------------- /src/routes/Dashboard/assets/icon_outstandingPredictions.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Gnosis Ltd 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/routes/Dashboard/components/Dashboard/Metrics/Metric.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | 4 | import IndefiniteSpinner from 'components/Spinner/Indefinite' 5 | 6 | import classnames from 'classnames/bind' 7 | import style from './Metrics.scss' 8 | 9 | const cx = classnames.bind(style) 10 | 11 | const Metric = ({ 12 | src, explanation, children, isLoading, 13 | }) => ( 14 |
    15 | {explanation} 16 | {isLoading ? ( 17 | 18 | ) : ( 19 |
    20 | {children} 21 | {explanation} 22 |
    23 | )} 24 |
    25 | ) 26 | 27 | Metric.propTypes = { 28 | src: PropTypes.string.isRequired, 29 | explanation: PropTypes.string, 30 | children: PropTypes.node, 31 | isLoading: PropTypes.bool, 32 | } 33 | 34 | Metric.defaultProps = { 35 | explanation: 'N/A', 36 | children: , 37 | isLoading: false, 38 | } 39 | 40 | export default Metric 41 | -------------------------------------------------------------------------------- /src/assets/img/icons/gno_token.svg: -------------------------------------------------------------------------------- 1 | gno_token_bw -------------------------------------------------------------------------------- /src/components/Header/Layouts/MobileHeader/assets/icon_copy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "parser": "babel-eslint", 4 | "plugins": ["jest"], 5 | "rules": { 6 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }], 7 | "react/forbid-prop-types": [1, { "forbid": ["object", "any"] }], 8 | "class-methods-use-this": 0, 9 | "semi": ["error", "never"], 10 | "max-len": [ 11 | "error", 12 | 120, 13 | 2, 14 | { 15 | "ignoreUrls": true, 16 | "ignoreComments": false, 17 | "ignoreRegExpLiterals": true, 18 | "ignoreStrings": true, 19 | "ignoreTemplateLiterals": true 20 | } 21 | ], 22 | "import/no-unresolved": 0, 23 | "import/no-extraneous-dependencies": 0, 24 | "import/extensions": 0, 25 | "import/prefer-default-export": 0, 26 | "react/jsx-one-expression-per-line": "off", 27 | "jsx-a11y/label-has-for": 0, 28 | "jsx-a11y/anchor-is-valid": ["error", { 29 | "components": [] 30 | }], 31 | "indent": ["error", 2], 32 | "no-console": ["error", { "allow": ["warn", "error"] }] 33 | }, 34 | "env": { 35 | "jest/globals": true, 36 | "browser": true 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/integrations/uport/uportNotifications.js: -------------------------------------------------------------------------------- 1 | import { decodeToken } from 'jsontokens' 2 | 3 | export const isValid = (cred) => { 4 | if (cred === null) { 5 | return false 6 | } 7 | 8 | const pushToken = decodeToken(cred.pushToken) 9 | if (!pushToken) { 10 | return false 11 | } 12 | 13 | const expiration = pushToken.payload.exp // When the uPort credential will expire 14 | const oneDay = 24 * 60 * 6 // one day in seconds 15 | const now = new Date() / 1000 // in seconds 16 | const valid = expiration - oneDay > now 17 | 18 | return valid 19 | } 20 | 21 | const assignSessionProps = (uport, cred) => { 22 | /* eslint-disable */ 23 | uport.address = cred.address 24 | uport.pushToken = cred.pushToken 25 | uport.publicEncKey = cred.publicEncKey 26 | /* eslint-enable */ 27 | } 28 | 29 | const init = async (uport, requestCredentials, getCredential) => { 30 | let credential = getCredential() 31 | if (!isValid(credential)) { 32 | credential = await requestCredentials() 33 | } 34 | 35 | if (credential) { 36 | assignSessionProps(uport, credential) 37 | } 38 | 39 | return uport 40 | } 41 | 42 | export default init 43 | -------------------------------------------------------------------------------- /src/containers/TransactionFloaterContainer/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import TransactionFloater from 'components/TransactionFloater' 3 | import { showTransactionLog, hideTransactionLog } from 'routes/Transactions/store/actions/transactions' 4 | import { 5 | getRunningTransactions, 6 | getCompletedTransactions, 7 | getRunningTransactionsProgress, 8 | areLogsVisible, 9 | } from 'routes/Transactions/store/selectors/transactions' 10 | import { getVisibleNotifications } from 'store/selectors/notifications' 11 | 12 | const LIMIT_COUNT_RUNNING_TRANSACTIONS = 3 13 | const LIMIT_COUNT_COMPLETED_TRANSACTIONS = 3 14 | 15 | const mapStateToProps = state => ({ 16 | runningTransactions: getRunningTransactions(state).takeLast(LIMIT_COUNT_RUNNING_TRANSACTIONS), 17 | completedTransactions: getCompletedTransactions(state).takeLast(LIMIT_COUNT_COMPLETED_TRANSACTIONS), 18 | progress: getRunningTransactionsProgress(state), 19 | notifications: getVisibleNotifications(state), 20 | showLogs: areLogsVisible(state), 21 | }) 22 | 23 | export default connect(mapStateToProps, { 24 | showTransactionLog, 25 | hideTransactionLog, 26 | })(TransactionFloater) 27 | -------------------------------------------------------------------------------- /src/components/Spinner/Transaction.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import Icon from 'components/Icon' 4 | import { TRANSACTION_COMPLETE_STATUS } from 'utils/constants' 5 | 6 | import IndefiniteSpinner from './Indefinite' 7 | 8 | const ProgressIndicator = ({ completed, completionStatus, progress }) => { 9 | const iconType = completionStatus === TRANSACTION_COMPLETE_STATUS.NO_ERROR ? 'checkmark' : 'cross' 10 | const iconStyle = { 11 | top: '50%', 12 | marginTop: -24, 13 | } 14 | 15 | return completed ? ( 16 | 17 | ) : ( 18 | 26 | ) 27 | } 28 | 29 | ProgressIndicator.propTypes = { 30 | completed: PropTypes.bool, 31 | completionStatus: PropTypes.string, 32 | progress: PropTypes.number, 33 | } 34 | 35 | ProgressIndicator.defaultProps = { 36 | completed: false, 37 | completionStatus: undefined, 38 | progress: 0, 39 | } 40 | 41 | export default ProgressIndicator 42 | -------------------------------------------------------------------------------- /src/store/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux' 2 | import { reducer as formReducer } from 'redux-form' 3 | import { isFeatureEnabled } from 'utils/features' 4 | 5 | // Reducers 6 | import integrations from 'integrations/store/reducers' 7 | import users from 'routes/Scoreboard/store/reducers/users' 8 | import transactions from 'routes/Transactions/store/reducers/transactions' 9 | import modal from './modal' 10 | import blockchain from './blockchain' 11 | import notifications from './notifications' 12 | import marketList from './market' 13 | import accountShares from './accountShares' 14 | import accountTrades from './accountTrades' 15 | import interfaceState from './interface' 16 | 17 | const tournamentEnabled = isFeatureEnabled('tournament') 18 | 19 | const reducers = { 20 | form: formReducer, 21 | modal, 22 | transactions, 23 | blockchain, 24 | notifications, 25 | integrations, 26 | marketList, 27 | accountShares, 28 | accountTrades, 29 | interfaceState, 30 | } 31 | 32 | if (tournamentEnabled) { 33 | reducers.tournament = combineReducers({ 34 | ranking: users, 35 | }) 36 | } 37 | 38 | export default combineReducers(reducers) 39 | --------------------------------------------------------------------------------