29 | ))
30 | );
31 |
--------------------------------------------------------------------------------
/src/js/pages/MyTrades/components/__snapshots__/Trades.test.jsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Trades should render correctly 1`] = `
4 |
7 |
10 |
23 |
36 |
37 |
38 |
39 | `;
40 |
41 | exports[`Trades should render when empty 1`] = `
42 |
45 |
50 |
51 | `;
52 |
--------------------------------------------------------------------------------
/src/images/limits.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/src/js/components/Loading/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
4 | import {faCircleNotch} from "@fortawesome/free-solid-svg-icons";
5 | import {withTranslation} from "react-i18next";
6 | import TxHash from '../../ui/TxHash';
7 |
8 | import "./index.scss";
9 |
10 | const Loading = ({t, mining, initial, page, value, txHash}) => (
11 |
12 |
13 | {value}
14 | {mining && t('loading.mining')}
15 | {initial && t('loading.initial')}
16 | {page && t('loading.page')}
17 |
18 |
19 | {txHash &&
{t('transaction.hash')}:
}
20 |
21 | );
22 |
23 | Loading.propTypes = {
24 | t: PropTypes.func,
25 | mining: PropTypes.bool,
26 | initial: PropTypes.bool,
27 | page: PropTypes.bool,
28 | value: PropTypes.string,
29 | txHash: PropTypes.string
30 | };
31 |
32 | export default withTranslation()(Loading);
33 |
--------------------------------------------------------------------------------
/src/images/pencil.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/src/js/features/emailNotifications/actions.js:
--------------------------------------------------------------------------------
1 | import {CHECK_EMAIL_SUBSCRIPTION, SUBSCRIBE_EMAIL, UNSUBSCRIBE_EMAIL,
2 | HIDE_ERROR, VERIFY_EMAIL, HIDE_SUCCESS, SET_REDIRECT_TARGET,
3 | REFUSE_EMAIL_NOTIFICATIONS, RESET_NOTIFICATION_WARNINGS} from './constants';
4 |
5 | export const checkEmailSubscription = () => {
6 | return {type: CHECK_EMAIL_SUBSCRIPTION};
7 | };
8 |
9 | export const setRedirectTarget = (redirectTarget) => {
10 | return {type: SET_REDIRECT_TARGET, redirectTarget};
11 | };
12 |
13 | export const subscribeToEmail = (email) => {
14 | return {type: SUBSCRIBE_EMAIL, email};
15 | };
16 |
17 | export const unsubscribeToEmail = () => {
18 | return {type: UNSUBSCRIBE_EMAIL};
19 | };
20 |
21 | export const hideError = () => {
22 | return {type: HIDE_ERROR};
23 | };
24 |
25 | export const hideSuccess = () => {
26 | return {type: HIDE_SUCCESS};
27 | };
28 |
29 | export const verifyEmail = (token) => {
30 | return {type: VERIFY_EMAIL, token};
31 | };
32 |
33 | export const refuseEmailNotifications = () => {
34 | return {type: REFUSE_EMAIL_NOTIFICATIONS};
35 | };
36 |
37 | export const resetNotificationWarnings = () => ({type: RESET_NOTIFICATION_WARNINGS});
38 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { ConnectedRouter } from "connected-react-router";
4 | import { Provider } from 'react-redux';
5 | import { I18nextProvider } from 'react-i18next';
6 | import { LastLocationProvider } from 'react-router-last-location';
7 | import i18n from './js/i18n';
8 | import { PersistGate } from 'redux-persist/integration/react';
9 |
10 | import './css/fonts/Inter/inter.css';
11 | import './css/bootstrap-overrides.scss';
12 | import 'flag-icon-css/css/flag-icon.min.css';
13 | import './index.scss';
14 | import './css/Form.scss';
15 |
16 | import App from './js/layout/App';
17 | import history from './js/history';
18 | import {store, persistor} from './js/store';
19 |
20 | ReactDOM.render(
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | ,
32 | document.getElementById('root')
33 | );
34 |
--------------------------------------------------------------------------------
/src/images/change.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/src/js/components/NoLicense/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Button} from 'reactstrap';
3 | import {Link} from "react-router-dom";
4 | import PropTypes from 'prop-types';
5 | import {withTranslation} from "react-i18next";
6 |
7 | const NoLicense = ({t, arbitratorPage}) => (
8 |
9 |
10 | {arbitratorPage && t('license.noArbiLicense')}
11 | {!arbitratorPage && t('license.noSellerLicense')}
12 |
13 | {arbitratorPage &&
14 |
{t('license.onceArbi')}
}
15 | {!arbitratorPage &&
{t('license.onceSeller')}
}
16 |
17 | {arbitratorPage && }
18 | {!arbitratorPage && }
19 |
20 |
21 | );
22 |
23 | NoLicense.defaultProps = {
24 | arbitratorPage: false
25 | };
26 |
27 | NoLicense.propTypes = {
28 | t: PropTypes.func,
29 | arbitratorPage: PropTypes.bool
30 | };
31 |
32 | export default withTranslation()(NoLicense);
33 |
--------------------------------------------------------------------------------
/src/images/bank.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/js/pages/License/components/Balance.jsx:
--------------------------------------------------------------------------------
1 | import React, {Component, Fragment} from 'react';
2 | import PropTypes from 'prop-types';
3 | import {withTranslation} from 'react-i18next';
4 | import classnames from 'classnames';
5 |
6 | import SNTIcon from '../../../../../node_modules/cryptocurrency-icons/svg/color/snt.svg';
7 |
8 | class YourSNTBalance extends Component {
9 | render() {
10 | const t = this.props.t;
11 | return (
12 |
13 | {t('yourSNTBalance.label')}
14 |
15 |
16 |
17 | {(this.props.value || this.props.value === 0) && {this.props.value} SNT}
18 | {!this.props.value && this.props.value !== 0 && t('general.loading')}
19 |
20 |
21 |
22 | );
23 | }
24 | }
25 |
26 | YourSNTBalance.propTypes = {
27 | t: PropTypes.func,
28 | value: PropTypes.string,
29 | disabled: PropTypes.bool
30 | };
31 |
32 | export default withTranslation()(YourSNTBalance);
33 |
--------------------------------------------------------------------------------
/Landing/images/twitter-icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
21 |
--------------------------------------------------------------------------------
/src/images/landing/twitter-icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
21 |
--------------------------------------------------------------------------------
/src/js/components/ConfirmDialog/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Modal, ModalHeader, ModalBody, ModalFooter, Button} from 'reactstrap';
3 | import PropTypes from 'prop-types';
4 | import {withTranslation} from "react-i18next";
5 |
6 | const ConfirmDialog = ({t, display, onCancel, title, content, onConfirm, cancelText, confirmText}) => (
7 |
8 |
9 | {title}
10 |
11 |
12 | {content}
13 |
14 |
15 |
16 |
17 |
18 |
19 | );
20 |
21 | ConfirmDialog.defaultProps = {
22 | display: false
23 | };
24 |
25 | ConfirmDialog.propTypes = {
26 | t: PropTypes.func,
27 | onCancel: PropTypes.func,
28 | onConfirm: PropTypes.func,
29 | title: PropTypes.string,
30 | content: PropTypes.string,
31 | display: PropTypes.bool,
32 | cancelText: PropTypes.string,
33 | confirmText: PropTypes.string
34 | };
35 |
36 | export default withTranslation()(ConfirmDialog);
37 |
--------------------------------------------------------------------------------
/src/js/pages/License/components/Info.jsx:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {Row, Col} from 'reactstrap';
3 | import PropTypes from 'prop-types';
4 | import {withTranslation} from 'react-i18next';
5 |
6 | import "./Info.scss";
7 |
8 | class LicenseInfo extends Component {
9 | render() {
10 | const t = this.props.t;
11 | return (
12 |
13 |
14 |
15 | {t('sellerLicenseInfo.title')}
16 |
17 |
18 |
19 |
20 | {t('sellerLicenseInfo.fee')}
{t('sellerLicenseInfo.fee2')}
21 |
22 |
23 |
24 | {t('sellerLicenseInfo.stake', {price: this.props.price})}
{t('sellerLicenseInfo.stake2')}
25 |
26 |
27 | );
28 | }
29 | }
30 |
31 | LicenseInfo.propTypes = {
32 | t: PropTypes.func,
33 | price: PropTypes.oneOfType([
34 | PropTypes.string,
35 | PropTypes.number
36 | ])
37 | };
38 |
39 | export default withTranslation()(LicenseInfo);
40 |
--------------------------------------------------------------------------------
/src/js/pages/ProfileSettings/index.jsx:
--------------------------------------------------------------------------------
1 | import React, {Fragment} from "react";
2 | import {withTranslation} from "react-i18next";
3 | import PropTypes from "prop-types";
4 | import ProfileButton from "../MyProfile/components/ProfileButton";
5 | import iconChat from "../../../images/read-chat.svg";
6 | import iconBell from "../../../images/bell.svg";
7 | import iconSettings from "../../../images/settings.svg";
8 | import { ReactComponent as iconLocation } from "../../../images/location.svg";
9 |
10 | const ProfileSettings = ({t}) => (
11 | {t('profileSettings.title')}
12 |
13 |
14 |
15 |
16 | );
17 |
18 |
19 | ProfileSettings.propTypes = {
20 | t: PropTypes.func
21 | };
22 |
23 | export default withTranslation()(ProfileSettings);
24 |
--------------------------------------------------------------------------------
/embarkConfig/storage.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | // default applies to all environments
3 | default: {
4 | enabled: false,
5 | ipfs_bin: "ipfs",
6 | available_providers: ["ipfs"],
7 | upload: {
8 | provider: "ipfs",
9 | host: "localhost",
10 | port: 5001
11 | },
12 | dappConnection: [
13 | {
14 | provider: "ipfs",
15 | host: "localhost",
16 | port: 5001,
17 | getUrl: "http://localhost:8080/ipfs/"
18 | }
19 | ]
20 | },
21 |
22 | development: {
23 | upload: {
24 | provider: "ipfs",
25 | host: "localhost",
26 | port: 5001,
27 | getUrl: "http://localhost:8080/ipfs/"
28 | }
29 | },
30 |
31 | // merges with the settings in default
32 | // used with "embark run privatenet"
33 | privatenet: {
34 | },
35 |
36 | // merges with the settings in default
37 | // used with "embark run testnet"
38 | testnet: {
39 | enabled: false
40 | },
41 |
42 | // merges with the settings in default
43 | // used with "embark run livenet"
44 | livenet: {
45 | },
46 |
47 | // you can name an environment with specific settings and then specify with
48 | // "embark run custom_name"
49 | //custom_name: {
50 | //}
51 | };
52 |
--------------------------------------------------------------------------------
/src/js/features/newBuy/reducer.js:
--------------------------------------------------------------------------------
1 | import {SET_CONTACT_INFO, SET_TRADE, SET_OFFER_ID, RESET_NEW_BUY} from './constants';
2 | import {RESET_STATE, PURGE_STATE} from "../network/constants";
3 | import {getContactData} from "../../utils/strings";
4 |
5 | const DEFAULT_STATE = {
6 | currencyQuantity: 0,
7 | assetQuantity: 0
8 | };
9 |
10 | function reducer(state = DEFAULT_STATE, action) {
11 | switch (action.type) {
12 | case SET_OFFER_ID:
13 | return {
14 | ...state, offerId: parseInt(action.offerId, 10)
15 | };
16 | case SET_CONTACT_INFO:
17 | return {
18 | ...state,
19 | username: action.username,
20 | contactData: action.contactMethod && action.contactUsername ? getContactData(action.contactMethod, action.contactUsername) : state.contactData
21 | };
22 | case SET_TRADE:
23 | return {
24 | ...state,
25 | currencyQuantity: action.currencyQuantity,
26 | assetQuantity: action.assetQuantity,
27 | price: action.price
28 | };
29 | case RESET_NEW_BUY:
30 | case PURGE_STATE:
31 | case RESET_STATE: {
32 | return DEFAULT_STATE;
33 | }
34 | default:
35 | return state;
36 | }
37 | }
38 |
39 | export default reducer;
40 |
--------------------------------------------------------------------------------
/src/js/pages/Escrow/components/OpenDispute.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Row, Col} from 'reactstrap';
3 | import PropTypes from 'prop-types';
4 | import exclamationCircle from "../../../../images/exclamation-circle.png";
5 | import RoundedIcon from "../../../ui/RoundedIcon";
6 | import escrow from '../../../features/escrow';
7 | import {Link} from "react-router-dom";
8 | import {zeroAddress} from '../../../utils/address';
9 | import {withTranslation} from "react-i18next";
10 |
11 | const OpenDispute = ({t, trade}) => {
12 | const shouldDisplay = trade.status === escrow.helpers.tradeStates.paid && trade.arbitrator !== zeroAddress;
13 | return shouldDisplay && (
14 |
15 |
16 |
17 | {t('escrow.openDispute.open')}
18 | {t('escrow.openDispute.havingProblem')}
19 |
20 |
21 | );
22 | };
23 |
24 | OpenDispute.propTypes = {
25 | t: PropTypes.func,
26 | trade: PropTypes.object
27 | };
28 |
29 | export default withTranslation()(OpenDispute);
30 |
--------------------------------------------------------------------------------
/stories/components/userInformation.stories.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import {storiesOf} from '@storybook/react';
4 | import {withInfo} from "@storybook/addon-info";
5 | import { withKnobs, text, boolean } from '@storybook/addon-knobs';
6 |
7 | import UserInformation from '../../src/js/components/UserInformation';
8 | import Address from '../../src/js/components/UserInformation/Address';
9 |
10 | storiesOf('Components/UserInformation', module)
11 | .addDecorator(withKnobs)
12 | .add(
13 | "Default",
14 | withInfo({inline: true})(() => (
15 |
16 | ))
17 | )
18 | .add(
19 | "Address",
20 | withInfo({inline: true})(() => (
21 |
22 | ))
23 | )
24 | .add(
25 | "Address Compact",
26 | withInfo({inline: true})(() => (
27 |
28 | ))
29 | );
30 |
--------------------------------------------------------------------------------
/src/images/beta-tag.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/js/pages/OffersList/components/Modals/SortModal.jsx:
--------------------------------------------------------------------------------
1 | import {ButtonGroup, Modal, ModalBody} from "reactstrap";
2 | import React, {Fragment} from "react";
3 | import CheckButton from "../../../../ui/CheckButton";
4 | import Separator from "../../../MyProfile/components/Separator";
5 | import PropTypes from "prop-types";
6 |
7 | const SorterModal = ({onClose, sortTypes, setSortType, sortType}) => (
8 |
9 |
10 |
11 | {sortTypes.map((_sortType, index) => (
12 |
13 | {
14 | setSortType(index);
15 | onClose();
16 | }} active={index === sortType}>
17 | {_sortType}
18 |
19 | {index !== sortTypes.length - 1 && }
20 |
21 | ))}
22 |
23 |
24 |
25 | );
26 |
27 | SorterModal.propTypes = {
28 | onClose: PropTypes.func,
29 | setSortType: PropTypes.func,
30 | sortTypes: PropTypes.array,
31 | sortType: PropTypes.number
32 | };
33 |
34 | export default SorterModal;
35 |
--------------------------------------------------------------------------------
/Landing/images/beta-tag.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/js/reducer.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux';
2 | import { connectRouter } from 'connected-react-router';
3 |
4 | import history from './history';
5 |
6 | import prices from './features/prices';
7 | import license from './features/license';
8 | import escrow from './features/escrow';
9 | import network from './features/network';
10 | import signature from './features/signature';
11 | import arbitration from './features/arbitration';
12 | import newSeller from './features/newSeller';
13 | import newBuy from './features/newBuy';
14 | import metadata from './features/metadata';
15 | import approval from './features/approval';
16 | import events from './features/events';
17 | import emailNotifications from './features/emailNotifications';
18 |
19 | const rootReducer = combineReducers({
20 | router: connectRouter(history),
21 | prices: prices.reducer,
22 | license: license.reducer,
23 | network: network.reducer,
24 | escrow: escrow.reducer,
25 | signature: signature.reducer,
26 | arbitration: arbitration.reducer,
27 | newSeller: newSeller.reducer,
28 | newBuy: newBuy.reducer,
29 | metadata: metadata.reducer,
30 | approval: approval.reducer,
31 | events: events.reducer,
32 | emailNotifications: emailNotifications.reducer
33 | });
34 |
35 | export default rootReducer;
36 |
--------------------------------------------------------------------------------
/src/js/services/embarkjs.js:
--------------------------------------------------------------------------------
1 | /*global web3*/
2 | import EmbarkJS from '../../embarkArtifacts/embarkjs';
3 | import {contactCodeRegExp} from '../utils/address';
4 | import TellerProvider from '../provider';
5 | import tabookey from 'tabookey-gasless';
6 | import Subspace from '@embarklabs/subspace';
7 |
8 | export function onReady() {
9 | return new Promise((resolve, reject) => {
10 | EmbarkJS.onReady((err) => {
11 | if (err) {
12 | return reject(err);
13 | }
14 |
15 | const relayProvider = new tabookey.RelayProvider(web3.currentProvider);
16 | const customProvider = new TellerProvider(relayProvider);
17 | customProvider.startProvider(web3);
18 |
19 | global.subspace = new Subspace(web3);
20 | global.subspace.init().then(resolve);
21 | });
22 | });
23 | }
24 |
25 | export async function getEnsAddress(name) {
26 | // TODO check if an address is not correct and we only want contact codes, we need to validate that ENS returns a contact code
27 | if (contactCodeRegExp.test(name) || web3.utils.isAddress(name)) {
28 | return name;
29 | }
30 | if (name.indexOf('.') === -1) {
31 | name += '.stateofus.eth';
32 | }
33 | return EmbarkJS.Names.resolve(name);
34 | }
35 |
36 | export async function enableEthereum() {
37 | return EmbarkJS.enableEthereum();
38 | }
39 |
--------------------------------------------------------------------------------
/src/js/features/signature/reducer.js:
--------------------------------------------------------------------------------
1 | import {
2 | INCLUDE_SIGNATURE,
3 | INCLUDE_SIGNATURE_PRE_SUCCESS,
4 | INCLUDE_SIGNATURE_SUCCEEDED,
5 | INCLUDE_SIGNATURE_FAILED
6 | } from './constants';
7 | import {RESET_STATE, PURGE_STATE} from "../network/constants";
8 |
9 | const DEFAULT_STATE = {message: null, type: null, escrowId: null, loading: false};
10 |
11 | function reducer(state = DEFAULT_STATE, action) {
12 | switch (action.type) {
13 | case INCLUDE_SIGNATURE:
14 | return {
15 | ...state, ...{
16 | loading: true
17 | }
18 | };
19 | case INCLUDE_SIGNATURE_PRE_SUCCESS:
20 | return {
21 | ...state, ...{
22 | txHash: action.txHash
23 | }
24 | };
25 | case INCLUDE_SIGNATURE_FAILED:
26 | return {
27 | ...state, ...{
28 | error: action.error,
29 | receipt: null,
30 | loading: false
31 | }
32 | };
33 | case INCLUDE_SIGNATURE_SUCCEEDED:
34 | return {
35 | ...state, ...{
36 | receipt: action.receipt,
37 | error: '',
38 | loading: false
39 | }
40 | };
41 | case PURGE_STATE:
42 | case RESET_STATE: {
43 | return DEFAULT_STATE;
44 | }
45 | default:
46 | return state;
47 | }
48 | }
49 |
50 | export default reducer;
51 |
--------------------------------------------------------------------------------
/src/js/pages/Settings/index.js:
--------------------------------------------------------------------------------
1 | import React, {Component, Fragment} from 'react';
2 | import PropTypes from 'prop-types';
3 | import {Button} from "reactstrap";
4 | import network from '../../features/network';
5 | import {connect} from "react-redux";
6 | import {withRouter} from "react-router-dom";
7 | import {withTranslation} from "react-i18next";
8 |
9 |
10 | class Settings extends Component {
11 | clearCache = () => {
12 | this.props.clearCache();
13 | setTimeout(() => {
14 | window.location.reload();
15 | }, 500);
16 | };
17 |
18 | render() {
19 | const t = this.props.t;
20 | return (
21 | {t('profileSettings.cacheSettings.title')}
22 | {t('profileSettings.cacheSettings.pressToReset')}
23 | {t('profileSettings.cacheSettings.willDelete')}
24 | {t('profileSettings.cacheSettings.noPermanentLoss')}
25 |
26 | );
27 | }
28 | }
29 |
30 | Settings.propTypes = {
31 | t: PropTypes.func,
32 | clearCache: PropTypes.func,
33 | history: PropTypes.object
34 | };
35 |
36 | export default connect(
37 | null,
38 | {
39 | clearCache: network.actions.clearCache
40 | }
41 | )(withRouter(withTranslation()(Settings)));
42 |
--------------------------------------------------------------------------------
/contracts/common/Pausable.sol:
--------------------------------------------------------------------------------
1 | pragma solidity >=0.5.0 <0.6.0;
2 |
3 | import "./Ownable.sol";
4 |
5 | /**
6 | * @title Pausable
7 | * @dev Makes contract functions pausable by the owner
8 | */
9 | contract Pausable is Ownable {
10 |
11 | event Paused();
12 | event Unpaused();
13 |
14 | bool public paused;
15 |
16 | constructor () internal {
17 | paused = false;
18 | }
19 |
20 | modifier whenNotPaused() {
21 | require(!paused, "Contract must be unpaused");
22 | _;
23 | }
24 |
25 | modifier whenPaused() {
26 | require(paused, "Contract must be paused");
27 | _;
28 | }
29 |
30 | /**
31 | * @dev Disables contract functions marked with "whenNotPaused" and enables the use of functions marked with "whenPaused"
32 | * Only the owner of the contract can invoke this function
33 | */
34 | function pause() external onlyOwner whenNotPaused {
35 | paused = true;
36 | emit Paused();
37 | }
38 |
39 | /**
40 | * @dev Enables contract functions marked with "whenNotPaused" and disables the use of functions marked with "whenPaused"
41 | * Only the owner of the contract can invoke this function
42 | */
43 | function unpause() external onlyOwner whenPaused {
44 | paused = false;
45 | emit Unpaused();
46 | }
47 | }
--------------------------------------------------------------------------------