Browse Source

Merge branch 'develop' into feature/ui-enhancements

# Conflicts:
#	packages/concordia-app/src/components/PostList/PostListRow/index.jsx
#	packages/concordia-app/src/components/PostList/index.jsx
#	packages/concordia-app/src/components/TopicList/TopicListRow/index.jsx
#	packages/concordia-app/src/components/TopicList/index.jsx
#	packages/concordia-app/src/views/Topic/TopicCreate/index.jsx
#	packages/concordia-app/src/views/Topic/TopicView/index.jsx
develop
Apostolos Fanakis 4 years ago
parent
commit
b249c96b51
  1. 2
      .gitignore
  2. 1
      packages/concordia-app/package.json
  3. 0
      packages/concordia-app/patches/web3-eth+1.3.4.patch
  4. 2
      packages/concordia-app/src/components/InitializationScreen/index.jsx
  5. 6
      packages/concordia-app/src/components/PostCreate/index.jsx
  6. 4
      packages/concordia-app/src/components/PostList/PostListRow/index.jsx
  7. 2
      packages/concordia-app/src/components/PostList/index.jsx
  8. 4
      packages/concordia-app/src/components/TopicList/TopicListRow/index.jsx
  9. 2
      packages/concordia-app/src/components/TopicList/index.jsx
  10. 2
      packages/concordia-app/src/components/UsernameSelector.jsx
  11. 16
      packages/concordia-app/src/constants/configuration/defaults.js
  12. 11
      packages/concordia-app/src/constants/contracts/ContractNames.js
  13. 13
      packages/concordia-app/src/constants/contracts/events/ForumContractEvents.js
  14. 8
      packages/concordia-app/src/constants/contracts/events/index.js
  15. 40
      packages/concordia-app/src/options/breezeOptions.js
  16. 9
      packages/concordia-app/src/options/drizzleOptions.js
  17. 29
      packages/concordia-app/src/options/web3Options.js
  18. 2
      packages/concordia-app/src/redux/actions/contractEventActions.js
  19. 2
      packages/concordia-app/src/redux/sagas/orbitSaga.js
  20. 2
      packages/concordia-app/src/redux/sagas/peerDbReplicationSaga.js
  21. 2
      packages/concordia-app/src/redux/sagas/userSaga.js
  22. 9
      packages/concordia-app/src/redux/store.js
  23. 28
      packages/concordia-app/src/utils/drizzleUtils.js
  24. 2
      packages/concordia-app/src/views/Home/index.jsx
  25. 4
      packages/concordia-app/src/views/Profile/GeneralTab/EditInformationModal/index.jsx
  26. 2
      packages/concordia-app/src/views/Profile/GeneralTab/index.jsx
  27. 2
      packages/concordia-app/src/views/Profile/index.jsx
  28. 2
      packages/concordia-app/src/views/Register/PersonalInformationStep/index.jsx
  29. 2
      packages/concordia-app/src/views/Register/SignUpStep/index.jsx
  30. 6
      packages/concordia-app/src/views/Topic/TopicCreate/index.jsx
  31. 5
      packages/concordia-app/src/views/Topic/TopicView/index.jsx
  32. 4
      packages/concordia-contracts-provider/package.json
  33. 2
      packages/concordia-contracts-provider/src/constants.js
  34. 6
      packages/concordia-contracts-provider/src/index.js
  35. 21
      packages/concordia-contracts/constants/config/defaults.js
  36. 16
      packages/concordia-contracts/contracts/Forum.sol
  37. 5
      packages/concordia-contracts/package.json
  38. 19
      packages/concordia-contracts/truffle-config.js
  39. 8
      packages/concordia-contracts/utils/contractsProviderUtils.js
  40. 60
      packages/concordia-pinner/.eslintrc.js
  41. 10
      packages/concordia-pinner/.gitattributes
  42. 40
      packages/concordia-pinner/.gitignore
  43. 39
      packages/concordia-pinner/package.json
  44. 63
      packages/concordia-pinner/src/app.js
  45. 6
      packages/concordia-pinner/src/constants.js
  46. 80
      packages/concordia-pinner/src/index.js
  47. 22
      packages/concordia-pinner/src/options/ipfsOptions.js
  48. 90
      packages/concordia-pinner/src/options/libp2pBundle.js
  49. 46
      packages/concordia-pinner/src/utils/orbitUtils.js
  50. 60
      packages/concordia-shared/.eslintrc.js
  51. 16
      packages/concordia-shared/package.json
  52. 33
      packages/concordia-shared/src/configuration/breezeConfiguration.js
  53. 25
      packages/concordia-shared/src/configuration/web3Configuration.js
  54. 46
      packages/concordia-shared/src/constants/configuration/defaults.js
  55. 16
      packages/concordia-shared/src/constants/contracts/ContractNames.js
  56. 19
      packages/concordia-shared/src/constants/contracts/events/ForumContractEvents.js
  57. 8
      packages/concordia-shared/src/constants/contracts/events/index.js
  58. 13
      packages/concordia-shared/src/constants/orbit/OrbitDatabases.js
  59. 14
      packages/concordia-shared/src/environment/contractsProviderEnv.js
  60. 21
      packages/concordia-shared/src/environment/interpolated/contractsProvider.js
  61. 12
      packages/concordia-shared/src/environment/interpolated/pinner.js
  62. 15
      packages/concordia-shared/src/environment/interpolated/rendezvous.js
  63. 9
      packages/concordia-shared/src/environment/interpolated/shared.js
  64. 37
      packages/concordia-shared/src/environment/interpolated/web3.js
  65. 7
      packages/concordia-shared/src/environment/pinnerEnv.js
  66. 9
      packages/concordia-shared/src/environment/rendezvousEnv.js
  67. 9
      packages/concordia-shared/src/environment/sharedEnv.js
  68. 24
      packages/concordia-shared/src/environment/web3Env.js
  69. 5
      packages/concordia-shared/src/utils/rendezvous.js
  70. 6
      packages/concordia-shared/src/utils/web3.js
  71. 564
      yarn.lock

2
.gitignore

@ -36,3 +36,5 @@ docker/env/contracts.env
# Lerna
*.lerna_backup
yarn-clean.sh

1
packages/concordia-app/package.json

@ -30,6 +30,7 @@
"@reduxjs/toolkit": "~1.4.0",
"@welldone-software/why-did-you-render": "^6.0.0-rc.1",
"concordia-contracts": "~0.1.0",
"concordia-shared": "~0.1.0",
"i18next": "^19.8.3",
"i18next-browser-languagedetector": "^6.0.1",
"i18next-http-backend": "^1.0.21",

0
packages/concordia-app/patches/web3-eth+1.3.3.patch → packages/concordia-app/patches/web3-eth+1.3.4.patch

2
packages/concordia-app/src/components/InitializationScreen/index.jsx

@ -1,11 +1,11 @@
import React, { Children } from 'react';
import { breezeConstants } from '@ezerous/breeze';
import { useSelector } from 'react-redux';
import { FORUM_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames';
import CustomLoader from './CustomLoader';
// CSS
import '../../assets/css/loading-component.css';
import { FORUM_CONTRACT } from '../../constants/contracts/ContractNames';
const InitializationLoader = ({ children }) => {
const initializing = useSelector((state) => state.drizzleStatus.initializing);

6
packages/concordia-app/src/components/PostCreate/index.jsx

@ -7,15 +7,15 @@ import {
import PropTypes from 'prop-types';
import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux';
import { FORUM_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames';
import { POSTS_DATABASE, USER_DATABASE } from 'concordia-shared/src/constants/orbit/OrbitDatabases';
import { POST_CREATED_EVENT } from 'concordia-shared/src/constants/contracts/events/ForumContractEvents';
import determineKVAddress from '../../utils/orbitUtils';
import { POSTS_DATABASE, USER_DATABASE } from '../../constants/orbit/OrbitDatabases';
import { FETCH_USER_DATABASE } from '../../redux/actions/peerDbReplicationActions';
import { breeze, drizzle } from '../../redux/store';
import './styles.css';
import { TRANSACTION_ERROR, TRANSACTION_SUCCESS } from '../../constants/TransactionStatus';
import { POST_CONTENT } from '../../constants/orbit/PostsDatabaseKeys';
import { FORUM_CONTRACT } from '../../constants/contracts/ContractNames';
import { POST_CREATED_EVENT } from '../../constants/contracts/events/ForumContractEvents';
const { contracts: { [FORUM_CONTRACT]: { methods: { createPost } } } } = drizzle;
const { orbit } = breeze;

4
packages/concordia-app/src/components/PostList/PostListRow/index.jsx

@ -7,13 +7,13 @@ import { useTranslation } from 'react-i18next';
import TimeAgo from 'react-timeago';
import { useDispatch, useSelector } from 'react-redux';
import { Link } from 'react-router-dom';
import { FORUM_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames';
import { POSTS_DATABASE, USER_DATABASE } from 'concordia-shared/src/constants/orbit/OrbitDatabases';
import { FETCH_USER_DATABASE } from '../../../redux/actions/peerDbReplicationActions';
import { breeze } from '../../../redux/store';
import './styles.css';
import { POSTS_DATABASE, USER_DATABASE } from '../../../constants/orbit/OrbitDatabases';
import determineKVAddress from '../../../utils/orbitUtils';
import { POST_CONTENT } from '../../../constants/orbit/PostsDatabaseKeys';
import { FORUM_CONTRACT } from '../../../constants/contracts/ContractNames';
import ProfileImage from '../../ProfileImage';
import PostVoting from '../PostVoting';

2
packages/concordia-app/src/components/PostList/index.jsx

@ -6,9 +6,9 @@ import { useSelector } from 'react-redux';
import {
Dimmer, Feed, Loader,
} from 'semantic-ui-react';
import { FORUM_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames';
import PostListRow from './PostListRow';
import { drizzle } from '../../redux/store';
import { FORUM_CONTRACT } from '../../constants/contracts/ContractNames';
const { contracts: { [FORUM_CONTRACT]: { methods: { getPost: { cacheCall: getPostChainData } } } } } = drizzle;

4
packages/concordia-app/src/components/TopicList/TopicListRow/index.jsx

@ -11,13 +11,13 @@ import { useHistory } from 'react-router';
import { useDispatch, useSelector } from 'react-redux';
import { Link } from 'react-router-dom';
import ProfileImage from '../../ProfileImage';
import { FORUM_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames';
import { TOPICS_DATABASE, USER_DATABASE } from 'concordia-shared/src/constants/orbit/OrbitDatabases';
import { FETCH_USER_DATABASE } from '../../../redux/actions/peerDbReplicationActions';
import { breeze } from '../../../redux/store';
import './styles.css';
import { TOPICS_DATABASE, USER_DATABASE } from '../../../constants/orbit/OrbitDatabases';
import determineKVAddress from '../../../utils/orbitUtils';
import { TOPIC_SUBJECT } from '../../../constants/orbit/TopicsDatabaseKeys';
import { FORUM_CONTRACT } from '../../../constants/contracts/ContractNames';
const { orbit } = breeze;

2
packages/concordia-app/src/components/TopicList/index.jsx

@ -4,9 +4,9 @@ import React, {
import PropTypes from 'prop-types';
import { useSelector } from 'react-redux';
import { List } from 'semantic-ui-react';
import { FORUM_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames';
import TopicListRow from './TopicListRow';
import { drizzle } from '../../redux/store';
import { FORUM_CONTRACT } from '../../constants/contracts/ContractNames';
import './styles.css';
const { contracts: { [FORUM_CONTRACT]: { methods: { getTopic: { cacheCall: getTopicChainData } } } } } = drizzle;

2
packages/concordia-app/src/components/UsernameSelector.jsx

@ -6,8 +6,8 @@ import throttle from 'lodash/throttle';
import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux';
import PropTypes from 'prop-types';
import { FORUM_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames';
import { drizzle } from '../redux/store';
import { FORUM_CONTRACT } from '../constants/contracts/ContractNames';
const { contracts: { [FORUM_CONTRACT]: { methods: { isUserNameTaken } } } } = drizzle;

16
packages/concordia-app/src/constants/configuration/defaults.js

@ -1,14 +1,2 @@
export const WEB3_HOST_DEFAULT = '127.0.0.1';
export const WEB3_PORT_DEFAULT = '8545';
export const WEB3_PORT_SOCKET_TIMEOUT_DEFAULT = 30000;
export const WEB3_PORT_SOCKET_CONNECT_MAX_ATTEMPTS_DEFAULT = 3;
export const REACT_APP_CONCORDIA_HOST_DEFAULT = '127.0.0.1';
export const REACT_APP_CONCORDIA_PORT_DEFAULT = '7000';
export const REACT_APP_RENDEZVOUS_HOST_DEFAULT = '127.0.0.1';
export const REACT_APP_RENDEZVOUS_PORT_DEFAULT = '9090';
export const REACT_APP_CONTRACTS_SUPPLIER_HOST_DEFAULT = '127.0.0.1';
export const REACT_APP_CONTRACTS_SUPPLIER_PORT_DEFAULT = '8400';
export const REACT_APP_CONTRACTS_VERSION_HASH_DEFAULT = 'latest';
export const CONCORDIA_HOST_DEFAULT = '127.0.0.1';
export const CONCORDIA_PORT_DEFAULT = '7000';

11
packages/concordia-app/src/constants/contracts/ContractNames.js

@ -1,11 +0,0 @@
export const FORUM_CONTRACT = 'Forum';
export const POST_VOTING_CONTRACT = 'PostVoting';
export const VOTING_CONTRACT = 'Voting';
const CONTRACTS = [
FORUM_CONTRACT,
POST_VOTING_CONTRACT,
VOTING_CONTRACT,
];
export default CONTRACTS;

13
packages/concordia-app/src/constants/contracts/events/ForumContractEvents.js

@ -1,13 +0,0 @@
export const USER_SIGNED_UP_EVENT = 'UserSignedUp';
export const USERNAME_UPDATED_EVENT = 'UsernameUpdated';
export const TOPIC_CREATED_EVENT = 'TopicCreated';
export const POST_CREATED_EVENT = 'PostCreated';
const forumContractEvents = [
USER_SIGNED_UP_EVENT,
USERNAME_UPDATED_EVENT,
TOPIC_CREATED_EVENT,
POST_CREATED_EVENT,
];
export default forumContractEvents;

8
packages/concordia-app/src/constants/contracts/events/index.js

@ -1,8 +0,0 @@
import { FORUM_CONTRACT } from '../ContractNames';
import forumContractEvents from './ForumContractEvents';
const appEvents = {
[FORUM_CONTRACT]: forumContractEvents,
};
export default appEvents;

40
packages/concordia-app/src/options/breezeOptions.js

@ -1,40 +0,0 @@
import { EthereumContractIdentityProvider } from '@ezerous/eth-identity-provider';
import databases from '../constants/orbit/OrbitDatabases';
import {
REACT_APP_RENDEZVOUS_HOST_DEFAULT,
REACT_APP_RENDEZVOUS_PORT_DEFAULT,
} from '../constants/configuration/defaults';
const REACT_APP_RENDEZVOUS_HOST = process.env.REACT_APP_RENDEZVOUS_HOST || REACT_APP_RENDEZVOUS_HOST_DEFAULT;
const REACT_APP_RENDEZVOUS_PORT = process.env.REACT_APP_RENDEZVOUS_PORT || REACT_APP_RENDEZVOUS_PORT_DEFAULT;
const breezeOptions = {
ipfs: {
repo: 'concordia',
config: {
Addresses: {
Swarm: [
// Use local signaling server (see also rendezvous script in package.json)
// For more information: https://github.com/libp2p/js-libp2p-webrtc-star
`/ip4/${REACT_APP_RENDEZVOUS_HOST}/tcp/${REACT_APP_RENDEZVOUS_PORT}/wss/p2p-webrtc-star`,
// Use the following public servers if needed
// '/dns4/wrtc-star1.par.dwebops.pub/tcp/443/wss/p2p-webrtc-star',
// '/dns4/ wrtc-star2.sjc.dwebops.pub/tcp/443/wss/p2p-webrtc-star'
],
},
},
preload: {
enabled: false,
},
init: {
emptyRepo: true,
},
},
orbit: {
identityProvider: EthereumContractIdentityProvider,
databases,
},
};
export default breezeOptions;

9
packages/concordia-app/src/options/drizzleOptions.js

@ -1,17 +1,18 @@
// Check out the documentation: https://truffleframework.com/docs/drizzle/reference/drizzle-options
import { contracts } from 'concordia-contracts';
import web3Options from './web3Options';
import appEvents from '../constants/contracts/events';
import { getWeb3Configuration } from 'concordia-shared/src/configuration/web3Configuration';
import Web3 from 'web3';
import appEvents from 'concordia-shared/src/constants/contracts/events';
import downloadContractArtifactsSync from '../utils/drizzleUtils';
const drizzleOptions = {
web3: web3Options,
web3: getWeb3Configuration(Web3),
events: { ...appEvents },
reloadWindowOnNetworkChange: true,
reloadWindowOnAccountChange: true, // We need it to reinitialize breeze and create new Orbit databases
};
if (process.env.REACT_APP_USE_EXTERNAL_CONTRACTS_SUPPLIER) {
if (process.env.REACT_APP_USE_EXTERNAL_CONTRACTS_PROVIDER) {
drizzleOptions.contracts = downloadContractArtifactsSync();
} else {
drizzleOptions.contracts = contracts;

29
packages/concordia-app/src/options/web3Options.js

@ -1,29 +0,0 @@
import Web3 from 'web3';
import {
WEB3_HOST_DEFAULT,
WEB3_PORT_DEFAULT,
WEB3_PORT_SOCKET_CONNECT_MAX_ATTEMPTS_DEFAULT,
WEB3_PORT_SOCKET_TIMEOUT_DEFAULT,
} from '../constants/configuration/defaults';
const { WEB3_HOST, WEB3_PORT, WEBSOCKET_TIMEOUT } = process.env;
const web3WebsocketOptions = {
keepAlive: true,
timeout: WEBSOCKET_TIMEOUT !== undefined ? WEBSOCKET_TIMEOUT : WEB3_PORT_SOCKET_TIMEOUT_DEFAULT,
reconnect: {
maxAttempts: WEB3_PORT_SOCKET_CONNECT_MAX_ATTEMPTS_DEFAULT,
},
};
const web3 = (WEB3_HOST !== undefined && WEB3_PORT !== undefined)
? new Web3(new Web3.providers.WebsocketProvider(`ws://${WEB3_HOST}:${WEB3_PORT}`))
: new Web3(Web3.givenProvider || new Web3.providers.WebsocketProvider(
`ws://${WEB3_HOST_DEFAULT}:${WEB3_PORT_DEFAULT}`, web3WebsocketOptions,
));
const web3Options = {
customProvider: web3,
};
export default web3Options;

2
packages/concordia-app/src/redux/actions/contractEventActions.js

@ -3,7 +3,7 @@ import {
TOPIC_CREATED_EVENT,
USER_SIGNED_UP_EVENT,
USERNAME_UPDATED_EVENT,
} from '../../constants/contracts/events/ForumContractEvents';
} from 'concordia-shared/src/constants/contracts/events/ForumContractEvents';
export const FORUM_EVENT_USER_SIGNED_UP = 'FORUM_EVENT_USER_SIGNED_UP';
export const FORUM_EVENT_USERNAME_UPDATED = 'FORUM_EVENT_USERNAME_UPDATED';

2
packages/concordia-app/src/redux/sagas/orbitSaga.js

@ -7,7 +7,7 @@ import { drizzleActions } from '@ezerous/drizzle';
import { contracts } from 'concordia-contracts';
import { EthereumContractIdentityProvider } from '@ezerous/eth-identity-provider';
import { FORUM_CONTRACT } from '../../constants/contracts/ContractNames';
import { FORUM_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames';
function* initOrbitDatabases(action) {
const { account, breeze } = action;

2
packages/concordia-app/src/redux/sagas/peerDbReplicationSaga.js

@ -7,9 +7,9 @@ import {
ORBIT_DB_REPLICATED,
ORBIT_DB_WRITE,
} from '@ezerous/breeze/src/orbit/orbitActions';
import { POSTS_DATABASE, TOPICS_DATABASE, USER_DATABASE } from 'concordia-shared/src/constants/orbit/OrbitDatabases';
import determineKVAddress from '../../utils/orbitUtils';
import { FETCH_USER_DATABASE, UPDATE_ORBIT_DATA } from '../actions/peerDbReplicationActions';
import { POSTS_DATABASE, TOPICS_DATABASE, USER_DATABASE } from '../../constants/orbit/OrbitDatabases';
import userDatabaseKeys from '../../constants/orbit/UserDatabaseKeys';
import { TOPIC_SUBJECT } from '../../constants/orbit/TopicsDatabaseKeys';
import { POST_CONTENT } from '../../constants/orbit/PostsDatabaseKeys';

2
packages/concordia-app/src/redux/sagas/userSaga.js

@ -3,9 +3,9 @@ import {
all, call, put, take, takeLatest,
} from 'redux-saga/effects';
import { drizzleActions } from '@ezerous/drizzle';
import { FORUM_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames';
import { USER_DATA_UPDATED, USER_DATA_ERROR } from '../actions/userActions';
import { FORUM_EVENT_USER_SIGNED_UP } from '../actions/contractEventActions';
import { FORUM_CONTRACT } from '../../constants/contracts/ContractNames';
function* fetchUserData({ drizzle, account }) {
const contract = drizzle.contracts[FORUM_CONTRACT];

9
packages/concordia-app/src/redux/store.js

@ -4,11 +4,12 @@ import {
} from '@ezerous/drizzle';
import { Breeze, breezeReducers } from '@ezerous/breeze';
import createSagaMiddleware from 'redux-saga';
import getBreezeConfiguration from 'concordia-shared/src/configuration/breezeConfiguration';
import { EthereumContractIdentityProvider } from '@ezerous/eth-identity-provider';
import userReducer from './reducers/userReducer';
import rootSaga from './sagas/rootSaga';
import drizzleOptions from '../options/drizzleOptions';
import peerDbReplicationReducer from './reducers/peerDbReplicationReducer';
import breezeOptions from '../options/breezeOptions';
const initialState = {
contracts: generateContractsInitialState(drizzleOptions),
@ -27,8 +28,12 @@ const store = configureStore({
preloadedState: initialState,
});
const breezeConfiguration = getBreezeConfiguration(EthereumContractIdentityProvider,
process.env.REACT_APP_RENDEZVOUS_HOST,
process.env.REACT_APP_RENDEZVOUS_PORT);
export const drizzle = new Drizzle(drizzleOptions, store);
export const breeze = new Breeze(breezeOptions, store);
export const breeze = new Breeze(breezeConfiguration, store);
sagaMiddleware.run(rootSaga);
export default store;

28
packages/concordia-app/src/utils/drizzleUtils.js

@ -1,26 +1,22 @@
import { CONTRACTS } from 'concordia-shared/src/constants/contracts/ContractNames';
import {
REACT_APP_CONCORDIA_HOST_DEFAULT,
REACT_APP_CONCORDIA_PORT_DEFAULT,
REACT_APP_CONTRACTS_SUPPLIER_HOST_DEFAULT,
REACT_APP_CONTRACTS_SUPPLIER_PORT_DEFAULT,
REACT_APP_CONTRACTS_VERSION_HASH_DEFAULT,
contractsProviderHost,
contractsProviderPort,
contractsVersionHash,
} from 'concordia-shared/src/environment/interpolated/contractsProvider';
import {
CONCORDIA_HOST_DEFAULT,
CONCORDIA_PORT_DEFAULT,
} from '../constants/configuration/defaults';
import CONTRACTS from '../constants/contracts/ContractNames';
function getContractsDownloadRequest() {
const CONTRACTS_SUPPLIER_HOST = process.env.REACT_APP_CONTRACTS_SUPPLIER_HOST
|| REACT_APP_CONTRACTS_SUPPLIER_HOST_DEFAULT;
const CONTRACTS_SUPPLIER_PORT = process.env.REACT_APP_CONTRACTS_SUPPLIER_PORT
|| REACT_APP_CONTRACTS_SUPPLIER_PORT_DEFAULT;
const CONTRACTS_VERSION_HASH = process.env.REACT_APP_CONTRACTS_VERSION_HASH
|| REACT_APP_CONTRACTS_VERSION_HASH_DEFAULT;
const HOST = process.env.REACT_APP_CONCORDIA_HOST || REACT_APP_CONCORDIA_HOST_DEFAULT;
const PORT = process.env.REACT_APP_CONCORDIA_PORT || REACT_APP_CONCORDIA_PORT_DEFAULT;
const HOST = process.env.REACT_APP_CONCORDIA_HOST || CONCORDIA_HOST_DEFAULT;
const PORT = process.env.REACT_APP_CONCORDIA_PORT || CONCORDIA_PORT_DEFAULT;
const xhrRequest = new XMLHttpRequest();
xhrRequest.open('GET',
`http://${CONTRACTS_SUPPLIER_HOST}:${CONTRACTS_SUPPLIER_PORT}/contracts/${CONTRACTS_VERSION_HASH}`,
`http://${contractsProviderHost}:${contractsProviderPort}/contracts/${contractsVersionHash}`,
false);
xhrRequest.setRequestHeader('Access-Control-Allow-Origin', `${HOST}:${PORT}`);
xhrRequest.setRequestHeader('Access-Control-Allow-Credentials', 'true');
@ -40,7 +36,7 @@ function validateRemoteContracts(remoteContracts) {
}));
if (contractsPresentStatus.reduce((accumulator, contract) => accumulator && contract.present, true)) {
throw new Error(`Contracts missing from artifacts. Supplier didn't bring ${contractsPresentStatus
throw new Error(`Contracts missing from artifacts. Provider didn't bring ${contractsPresentStatus
.filter((contractPresentStatus) => contractPresentStatus.present === false)
.map((contractPresentStatus) => contractPresentStatus.contract)
.join(', ')}.`);

2
packages/concordia-app/src/views/Home/index.jsx

@ -3,10 +3,10 @@ import React, {
} from 'react';
import { Container } from 'semantic-ui-react';
import { useSelector } from 'react-redux';
import { FORUM_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames';
import Board from './Board';
import './styles.css';
import { drizzle } from '../../redux/store';
import { FORUM_CONTRACT } from '../../constants/contracts/ContractNames';
const { contracts: { [FORUM_CONTRACT]: { methods: { numTopics } } } } = drizzle;

4
packages/concordia-app/src/views/Profile/GeneralTab/EditInformationModal/index.jsx

@ -6,12 +6,12 @@ import {
} from 'semantic-ui-react';
import PropTypes from 'prop-types';
import { useTranslation } from 'react-i18next';
import { FORUM_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames';
import { USER_DATABASE } from 'concordia-shared/src/constants/orbit/OrbitDatabases';
import checkUrlValid from '../../../../utils/urlUtils';
import { USER_LOCATION, USER_PROFILE_PICTURE } from '../../../../constants/orbit/UserDatabaseKeys';
import { USER_DATABASE } from '../../../../constants/orbit/OrbitDatabases';
import { breeze, drizzle } from '../../../../redux/store';
import UsernameSelector from '../../../../components/UsernameSelector';
import { FORUM_CONTRACT } from '../../../../constants/contracts/ContractNames';
const { orbit: { stores } } = breeze;
const { contracts: { [FORUM_CONTRACT]: { methods: { updateUsername } } } } = drizzle;

2
packages/concordia-app/src/views/Profile/GeneralTab/index.jsx

@ -5,8 +5,8 @@ import {
import PropTypes from 'prop-types';
import { useDispatch, useSelector } from 'react-redux';
import { useTranslation } from 'react-i18next';
import { USER_DATABASE, databases } from 'concordia-shared/src/constants/orbit/OrbitDatabases';
import determineKVAddress from '../../../utils/orbitUtils';
import databases, { USER_DATABASE } from '../../../constants/orbit/OrbitDatabases';
import { FETCH_USER_DATABASE } from '../../../redux/actions/peerDbReplicationActions';
import { breeze } from '../../../redux/store';
import { USER_LOCATION, USER_PROFILE_PICTURE } from '../../../constants/orbit/UserDatabaseKeys';

2
packages/concordia-app/src/views/Profile/index.jsx

@ -5,8 +5,8 @@ import { Container, Header, Tab } from 'semantic-ui-react';
import { useSelector } from 'react-redux';
import { useHistory, useRouteMatch } from 'react-router';
import { useTranslation } from 'react-i18next';
import { FORUM_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames';
import { drizzle } from '../../redux/store';
import { FORUM_CONTRACT } from '../../constants/contracts/ContractNames';
import CustomLoadingTabPane from '../../components/CustomLoadingTabPane';
import TopicList from '../../components/TopicList';
import PostList from '../../components/PostList';

2
packages/concordia-app/src/views/Register/PersonalInformationStep/index.jsx

@ -7,10 +7,10 @@ import {
import { useTranslation } from 'react-i18next';
import PropTypes from 'prop-types';
import { useHistory } from 'react-router';
import { USER_DATABASE } from 'concordia-shared/src/constants/orbit/OrbitDatabases';
import checkUrlValid from '../../../utils/urlUtils';
import { breeze } from '../../../redux/store';
import './styles.css';
import { USER_DATABASE } from '../../../constants/orbit/OrbitDatabases';
import { USER_LOCATION, USER_PROFILE_PICTURE } from '../../../constants/orbit/UserDatabaseKeys';
const { orbit: { stores } } = breeze;

2
packages/concordia-app/src/views/Register/SignUpStep/index.jsx

@ -6,9 +6,9 @@ import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux';
import { useHistory } from 'react-router';
import PropTypes from 'prop-types';
import { FORUM_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames';
import { drizzle } from '../../../redux/store';
import { TRANSACTION_ERROR, TRANSACTION_SUCCESS } from '../../../constants/TransactionStatus';
import { FORUM_CONTRACT } from '../../../constants/contracts/ContractNames';
import UsernameSelector from '../../../components/UsernameSelector';
const { contracts: { [FORUM_CONTRACT]: { methods: { signUp } } } } = drizzle;

6
packages/concordia-app/src/views/Topic/TopicCreate/index.jsx

@ -7,13 +7,13 @@ import {
import { useTranslation } from 'react-i18next';
import { useHistory } from 'react-router';
import { useSelector } from 'react-redux';
import { FORUM_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames';
import { TOPIC_CREATED_EVENT } from 'concordia-shared/src/constants/contracts/events/ForumContractEvents';
import { POSTS_DATABASE, TOPICS_DATABASE } from 'concordia-shared/src/constants/orbit/OrbitDatabases';
import { drizzle, breeze } from '../../../redux/store';
import { TRANSACTION_ERROR, TRANSACTION_SUCCESS } from '../../../constants/TransactionStatus';
import { POSTS_DATABASE, TOPICS_DATABASE } from '../../../constants/orbit/OrbitDatabases';
import { TOPIC_SUBJECT } from '../../../constants/orbit/TopicsDatabaseKeys';
import { POST_CONTENT } from '../../../constants/orbit/PostsDatabaseKeys';
import { FORUM_CONTRACT } from '../../../constants/contracts/ContractNames';
import { TOPIC_CREATED_EVENT } from '../../../constants/contracts/events/ForumContractEvents';
import './styles.css';
const { contracts: { [FORUM_CONTRACT]: { methods: { createTopic } } } } = drizzle;

5
packages/concordia-app/src/views/Topic/TopicView/index.jsx

@ -6,16 +6,15 @@ import {
} from 'semantic-ui-react';
import { Link } from 'react-router-dom';
import { useHistory } from 'react-router';
import { FORUM_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames';
import { TOPICS_DATABASE, USER_DATABASE } from 'concordia-shared/src/constants/orbit/OrbitDatabases';
import { breeze, drizzle } from '../../../redux/store';
import { FETCH_USER_DATABASE } from '../../../redux/actions/peerDbReplicationActions';
import './styles.css';
import PostList from '../../../components/PostList';
import { TOPICS_DATABASE, USER_DATABASE } from '../../../constants/orbit/OrbitDatabases';
import determineKVAddress from '../../../utils/orbitUtils';
import { TOPIC_SUBJECT } from '../../../constants/orbit/TopicsDatabaseKeys';
import PostCreate from '../../../components/PostCreate';
import { FORUM_CONTRACT } from '../../../constants/contracts/ContractNames';
const { contracts: { [FORUM_CONTRACT]: { methods: { getTopic: { cacheCall: getTopicChainData } } } } } = drizzle;
const { orbit } = breeze;

4
packages/concordia-contracts-provider/package.json

@ -5,10 +5,12 @@
"private": true,
"main": "src/index.js",
"scripts": {
"start": "node -r esm src/index.js"
"start": "node -r esm src/index.js",
"lint": "eslint --ext js,jsx . --format table"
},
"license": "MIT",
"dependencies": {
"concordia-shared": "~0.1.0",
"cors": "^2.8.5",
"esm": "~3.2.25",
"express": "^4.17.1",

2
packages/concordia-contracts-provider/src/constants.js

@ -1,11 +1,9 @@
import path from 'path';
const PROVIDER_PORT = '8400';
const UPLOAD_CONTRACTS_DIRECTORY = path.join(__dirname, '..', 'contracts-uploads');
const CORS_ALLOWED_ORIGINS = ['http://127.0.0.1:7000', 'http://localhost:7000'];
export default {
port: PROVIDER_PORT,
uploadsDirectory: UPLOAD_CONTRACTS_DIRECTORY,
corsAllowedOrigins: CORS_ALLOWED_ORIGINS,
};

6
packages/concordia-contracts-provider/src/index.js

@ -1,9 +1,9 @@
import express from 'express';
import cors from 'cors';
import { contractsProviderPort } from 'concordia-shared/src/environment/interpolated/contractsProvider';
import initRoutes from './routes/web';
import constants from './constants';
const PROVIDER_PORT = process.env.CONTRACTS_PROVIDER_PORT || constants.port;
const ALLOWED_ORIGINS = process.env.CORS_ALLOWED_ORIGINS
? process.env.CORS_ALLOWED_ORIGINS.split(';')
: constants.corsAllowedOrigins;
@ -20,6 +20,6 @@ app.use(cors(corsOptions));
initRoutes(app);
app.listen(PROVIDER_PORT, () => {
console.log(`Contracts provider listening at http://127.0.0.1:${PROVIDER_PORT}`);
app.listen(contractsProviderPort, () => {
console.log(`Contracts provider listening at http://127.0.0.1:${contractsProviderPort}`);
});

21
packages/concordia-contracts/constants/config/defaults.js

@ -1,21 +0,0 @@
const DEVELOP_CHAIN_HOST_DEFAULT = '127.0.0.1';
const DEVELOP_CHAIN_PORT_DEFAULT = '8545';
const TEST_CHAIN_HOST_DEFAULT = '127.0.0.1';
const TEST_CHAIN_PORT_DEFAULT = '8546';
const CONTRACTS_PROVIDER_HOST_DEFAULT = '127.0.0.1';
const CONTRACTS_PROVIDER_PORT_DEFAULT = '8400';
module.exports = {
develop: {
chainHost: DEVELOP_CHAIN_HOST_DEFAULT,
chainPort: DEVELOP_CHAIN_PORT_DEFAULT,
},
test: {
chainHost: TEST_CHAIN_HOST_DEFAULT,
chainPort: TEST_CHAIN_PORT_DEFAULT,
},
contractsProviderHost: CONTRACTS_PROVIDER_HOST_DEFAULT,
contractsProviderPort: CONTRACTS_PROVIDER_PORT_DEFAULT,
};

16
packages/concordia-contracts/contracts/Forum.sol

@ -18,7 +18,8 @@ contract Forum {
}
mapping(address => User) users;
mapping(string => address) userAddresses;
mapping(string => address) usernameAddresses;
address[] userAddresses;
event UserSignedUp(string username, address userAddress);
event UsernameUpdated(string newName, string oldName, address userAddress);
@ -27,7 +28,8 @@ contract Forum {
require(!hasUserSignedUp(msg.sender), USER_HAS_NOT_SIGNED_UP);
require(!isUserNameTaken(username), USERNAME_TAKEN);
users[msg.sender] = User(username, new uint[](0), new uint[](0), block.timestamp, true);
userAddresses[username] = msg.sender;
usernameAddresses[username] = msg.sender;
userAddresses.push(msg.sender);
emit UserSignedUp(username, msg.sender);
return true;
}
@ -36,9 +38,9 @@ contract Forum {
require(hasUserSignedUp(msg.sender), USER_HAS_NOT_SIGNED_UP);
require(!isUserNameTaken(newUsername), USERNAME_TAKEN);
string memory oldUsername = getUsername(msg.sender);
delete userAddresses[users[msg.sender].username];
delete usernameAddresses[users[msg.sender].username];
users[msg.sender].username = newUsername;
userAddresses[newUsername] = msg.sender;
usernameAddresses[newUsername] = msg.sender;
emit UsernameUpdated(newUsername, oldUsername, msg.sender);
return true;
}
@ -49,7 +51,7 @@ contract Forum {
}
function getUserAddress(string memory username) public view returns (address) {
return userAddresses[username];
return usernameAddresses[username];
}
function hasUserSignedUp(address userAddress) public view returns (bool) {
@ -82,6 +84,10 @@ contract Forum {
return users[userAddress];
}
function getUserAddresses() public view returns (address[] memory) {
return userAddresses;
}
//----------------------------------------POSTING----------------------------------------
struct Topic {
uint topicID;

5
packages/concordia-contracts/package.json

@ -16,8 +16,9 @@
"upload": "node ./utils/contractsProviderUtils.js ${npm_package_version}-dev latest"
},
"dependencies": {
"@openzeppelin/contracts": "~3.2.0",
"truffle": "~5.1.55",
"@openzeppelin/contracts": "~3.3.0",
"concordia-shared": "~0.1.0",
"truffle": "~5.1.58",
"unirest": "^0.6.0"
},
"devDependencies": {

19
packages/concordia-contracts/truffle-config.js

@ -1,9 +1,6 @@
const path = require('path');
const defaults = require('./constants/config/defaults');
const {
CHAIN_HOST, CHAIN_PORT,
} = process.env;
const web3EnvInterpolated = require('concordia-shared/src/environment/interpolated/web3');
const configurationDefaults = require('concordia-shared/src/constants/configuration/defaults');
module.exports = {
// See <http://truffleframework.com/docs/advanced/configuration>
@ -16,18 +13,18 @@ module.exports = {
contracts_build_directory: path.join(__dirname, 'build/'),
networks: {
develop: {
host: defaults.develop.chainHost,
port: defaults.develop.chainPort,
host: configurationDefaults.web3.develop.chainHost,
port: configurationDefaults.web3.develop.chainPort,
network_id: '*',
},
test: {
host: defaults.test.chainHost,
port: defaults.test.chainPort,
host: configurationDefaults.web3.test.chainHost,
port: configurationDefaults.web3.test.chainPort,
network_id: '*',
},
env: {
host: CHAIN_HOST,
port: CHAIN_PORT,
host: web3EnvInterpolated.web3Host,
port: web3EnvInterpolated.web3Port,
network_id: '*',
},
},

8
packages/concordia-contracts/utils/contractsProviderUtils.js

@ -1,13 +1,11 @@
const path = require('path');
const unirest = require('unirest');
const { contractsProviderHost } = require('concordia-shared/src/environment/interpolated/contractsProvider');
const { contractsProviderPort } = require('concordia-shared/src/environment/interpolated/contractsProvider');
const { contracts } = require('../index');
const defaults = require('../constants/config/defaults');
const uploadContractsToProviderUnirest = (versionHash, tag) => {
const CONTRACTS_PROVIDER_HOST = process.env.CONTRACTS_PROVIDER_HOST || defaults.contractsProviderHost;
const CONTRACTS_PROVIDER_PORT = process.env.CONTRACTS_PROVIDER_PORT || defaults.contractsProviderPort;
const uploadPath = `http://${CONTRACTS_PROVIDER_HOST}:${CONTRACTS_PROVIDER_PORT}/contracts/${versionHash}`;
const uploadPath = `http://${contractsProviderHost}:${contractsProviderPort}/contracts/${versionHash}`;
const request = unirest('POST', uploadPath)
.field('tag', tag);

60
packages/concordia-pinner/.eslintrc.js

@ -0,0 +1,60 @@
module.exports = {
env: {
browser: true,
es6: true,
jest: true,
},
extends: [
'plugin:react/recommended',
'airbnb',
],
globals: {
Atomics: 'readonly',
SharedArrayBuffer: 'readonly',
},
parser: 'babel-eslint',
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 2018,
sourceType: 'module',
},
plugins: [
'react',
'react-hooks',
],
rules: {
'react/jsx-props-no-spreading': 'off',
'import/extensions': 'off',
'react/jsx-indent': [
'error',
4,
{
checkAttributes: true,
indentLogicalExpressions: true,
},
],
'react/require-default-props': 'off',
'react/prop-types': 'off',
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'error',
'max-len': ['warn', { code: 120, tabWidth: 4 }],
'no-unused-vars': 'warn',
'no-console': 'off',
'no-shadow': 'warn',
'no-multi-str': 'warn',
'jsx-a11y/label-has-associated-control': [2, {
labelAttributes: ['label'],
controlComponents: ['Input'],
depth: 3,
}],
},
settings: {
'import/resolver': {
node: {
extensions: ['.js', '.jsx'],
},
},
},
};

10
packages/concordia-pinner/.gitattributes

@ -0,0 +1,10 @@
# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto eol=lf
# Denote all files that are truly binary and should not be modified.
*.png binary
*.jpg binary
*.ico binary
# Solidity
*.sol linguist-language=Solidity

40
packages/concordia-pinner/.gitignore

@ -0,0 +1,40 @@
# Node
/node_modules
packages/*/node_modules
packages/concordia-contracts/build
# IDE
.DS_Store
.idea
# Build Directories
/build
/src/build
/packages/concordia-app/build
/packages/concordia-contracts/build
# Logs
/log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Docker volumes
docker/volumes
docker/ganache/volumes
docker/reports
# Env var files
docker/env/concordia.env
docker/env/contracts.env
# Misc
.env.local
.env.development.local
.env.test.local
.env.production.local
# IPFS & OrbitDB Storage
ipfs
orbitdb

39
packages/concordia-pinner/package.json

@ -0,0 +1,39 @@
{
"name": "concordia-pinner",
"description": "An OrbitDB pinning service for Concordia.",
"version": "0.1.0",
"private": true,
"main": "src/index.js",
"scripts": {
"start": "node -r esm src/index.js",
"clean": "rimraf ipfs orbitdb",
"lint": "eslint --ext js,jsx . --format table"
},
"license": "MIT",
"dependencies": {
"@ezerous/eth-identity-provider": "~0.1.2",
"concordia-contracts": "~0.1.0",
"concordia-shared": "~0.1.0",
"esm": "~3.2.25",
"express": "^4.17.1",
"ipfs": "~0.52.1",
"is-reachable": "^5.0.0",
"level": "~6.0.1",
"libp2p": "~0.30.0",
"libp2p-bootstrap": "~0.12.1",
"libp2p-gossipsub": "~0.8.0",
"libp2p-kad-dht": "~0.20.1",
"libp2p-mdns": "~0.15.0",
"libp2p-mplex": "~0.10.0",
"libp2p-noise": "~2.0.1",
"libp2p-tcp": "~0.15.1",
"libp2p-webrtc-star": "~0.20.2",
"lodash": "^4.17.20",
"orbit-db": "~0.26.0",
"orbit-db-identity-provider": "~0.3.1",
"rimraf": "~3.0.2",
"web3": "~1.3.0",
"web3-eth-contract": "^1.3.1",
"wrtc": "~0.4.6"
}
}

63
packages/concordia-pinner/src/app.js

@ -0,0 +1,63 @@
import express from 'express';
import _ from 'lodash';
import isReachable from 'is-reachable';
import { pinnerApiPort } from 'concordia-shared/src/environment/interpolated/pinner';
import getWeb3ProviderUrl from 'concordia-shared/src/utils/web3';
import getRendezvousUrl from 'concordia-shared/src/utils/rendezvous';
const POLLING_INTERVAL = 1000;
const responseBody = {
ipfs: {
id: '', localAddresses: [], peers: [], totalPeers: 0, repoStats: {},
},
orbit: { identity: {}, databases: [] },
web3: { url: getWeb3ProviderUrl(), reachable: false },
rendezvous: { url: getRendezvousUrl(), reachable: false },
timestamp: 0,
};
async function getStats(orbit) {
try {
// eslint-disable-next-line no-underscore-dangle
const ipfs = orbit._ipfs;
const { id } = await ipfs.id();
const peers = await ipfs.swarm.peers();
const localAddresses = await ipfs.swarm.localAddrs();
const repoStats = await ipfs.stats.repo();
const uniquePeers = _.uniqBy(peers, 'peer');
const orbitIdentity = orbit.identity;
const databases = Object.keys(orbit.stores);
const isWeb3Reachable = await isReachable(getWeb3ProviderUrl());
const isRendezvousReachable = await isReachable(getRendezvousUrl());
const timestamp = +new Date();
responseBody.ipfs.id = id;
responseBody.ipfs.peers = uniquePeers;
responseBody.ipfs.totalPeers = uniquePeers.length;
responseBody.ipfs.localAddresses = localAddresses;
responseBody.ipfs.repoStats = repoStats;
responseBody.orbit.identity = orbitIdentity;
responseBody.orbit.databases = databases;
responseBody.web3.reachable = isWeb3Reachable;
responseBody.rendezvous.reachable = isRendezvousReachable;
responseBody.timestamp = timestamp;
} catch (err) {
console.error('Error while getting stats:', err);
}
}
const startAPI = (orbit) => {
const app = express();
app.get('/', async (req, res) => {
res.send(responseBody);
});
app.listen(pinnerApiPort, () => {
console.log(`Pinner API at http://localhost:${pinnerApiPort}!`);
});
setInterval(getStats, POLLING_INTERVAL, orbit);
};
export default startAPI;

6
packages/concordia-pinner/src/constants.js

@ -0,0 +1,6 @@
import path from 'path';
import getBreezeConfiguration from 'concordia-shared/src/configuration/breezeConfiguration';
export const swarmAddresses = getBreezeConfiguration().ipfs.config.Addresses.Swarm;
export const ORBIT_DIRECTORY_DEFAULT = path.join(__dirname, '..', 'orbitdb');

80
packages/concordia-pinner/src/index.js

@ -0,0 +1,80 @@
import Web3 from 'web3';
import Contract from 'web3-eth-contract';
import IPFS from 'ipfs';
import { contracts } from 'concordia-contracts';
import { FORUM_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames';
import getWeb3ProviderUrl from 'concordia-shared/src/utils/web3';
import { createOrbitInstance, getPeerDatabases, openKVDBs } from './utils/orbitUtils';
import ipfsOptions from './options/ipfsOptions';
import startAPI from './app';
process.on('unhandledRejection', (error) => {
// This happens when attempting to initialize without any available Swarm addresses (e.g. Rendezvous)
if (error.code === 'ERR_NO_VALID_ADDRESSES') {
console.error('unhandledRejection', error.message);
process.exit(1);
}
// Don't swallow other errors
console.error(error);
throw error;
});
const getDeployedContract = async (web3) => {
const forumContract = contracts.find((contract) => contract.contractName === FORUM_CONTRACT);
return web3.eth.net.getId()
.then((networkId) => forumContract.networks[networkId].address)
.then((contractAddress) => {
Contract.setProvider(getWeb3ProviderUrl());
const contract = new Contract(forumContract.abi, contractAddress);
return { contract, contractAddress };
});
};
// Open & replicate databases of existing users
const openExistingUsersDatabases = async (contract, orbit) => contract.methods.getUserAddresses().call()
.then((userAddresses) => getPeerDatabases(orbit, userAddresses))
.then((peerDBs) => openKVDBs(orbit, peerDBs));
const handleWeb3LogEvent = (web3, eventJsonInterface, orbit) => (error, result) => {
if (!error) {
const eventObj = web3.eth.abi.decodeLog(
eventJsonInterface.inputs,
result.data,
result.topics.slice(1),
);
const userAddress = eventObj[1];
console.log('User signed up:', userAddress);
getPeerDatabases(orbit, [userAddress])
.then((peerDBs) => openKVDBs(orbit, peerDBs));
}
};
const main = async () => {
console.log('Initializing...');
const web3 = new Web3(new Web3.providers.WebsocketProvider(getWeb3ProviderUrl()));
getDeployedContract(web3)
.then(({ contract, contractAddress }) => IPFS.create(ipfsOptions)
.then((ipfs) => createOrbitInstance(ipfs, contractAddress))
.then((orbit) => openExistingUsersDatabases(contract, orbit)
.then(() => {
// Listen for new users and subscribe to their databases
const eventJsonInterface = web3.utils._.find(
// eslint-disable-next-line no-underscore-dangle
contract._jsonInterface,
(obj) => obj.name === 'UserSignedUp' && obj.type === 'event',
);
web3.eth.subscribe('logs', {
address: contractAddress,
topics: [eventJsonInterface.signature],
}, handleWeb3LogEvent(web3, eventJsonInterface, orbit));
startAPI(orbit);
})));
};
main();

22
packages/concordia-pinner/src/options/ipfsOptions.js

@ -0,0 +1,22 @@
import libp2pBundle from './libp2pBundle';
import { swarmAddresses } from '../constants';
export default {
repo: 'ipfs',
config: {
Profile: 'server',
Addresses: {
Swarm: swarmAddresses,
},
},
libp2p: libp2pBundle,
EXPERIMENTAL: {
pubsub: true,
},
preload: {
enabled: false,
},
init: {
emptyRepo: true,
},
};

90
packages/concordia-pinner/src/options/libp2pBundle.js

@ -0,0 +1,90 @@
import Libp2p from 'libp2p';
import wrtc from 'wrtc';
import MulticastDNS from 'libp2p-mdns';
import WebrtcStar from 'libp2p-webrtc-star';
import Bootstrap from 'libp2p-bootstrap';
import Gossipsub from 'libp2p-gossipsub';
import KadDHT from 'libp2p-kad-dht';
import MPLEX from 'libp2p-mplex';
import { NOISE } from 'libp2p-noise';
import { swarmAddresses } from '../constants';
// See also: https://github.com/libp2p/js-libp2p/blob/master/doc/CONFIGURATION.md
export default (opts) => new Libp2p({
peerId: opts.peerId,
addresses: {
listen: swarmAddresses,
},
connectionManager: {
minPeers: 25,
maxPeers: 100,
pollInterval: 5000,
},
modules: {
transport: [
WebrtcStar,
],
streamMuxer: [
MPLEX,
],
connEncryption: [
NOISE,
],
peerDiscovery: [
MulticastDNS,
Bootstrap,
],
dht: KadDHT,
pubsub: Gossipsub,
},
config: {
transport: {
[WebrtcStar.prototype[Symbol.toStringTag]]: {
wrtc,
},
},
peerDiscovery: {
autoDial: true,
mdns: {
enabled: true,
interval: 10000,
},
bootstrap: {
enabled: true,
interval: 30e3,
list: opts.config.Bootstrap,
},
},
relay: {
enabled: true,
hop: {
enabled: true,
active: true,
},
},
dht: {
enabled: true,
kBucketSize: 20,
randomWalk: {
enabled: true,
interval: 10e3,
timeout: 2e3,
},
},
pubsub: {
enabled: true,
emitself: true,
},
},
metrics: {
enabled: true,
computeThrottleMaxQueueSize: 1000,
computeThrottleTimeout: 2000,
movingAverageIntervals: [
60 * 1000, // 1 minute
5 * 60 * 1000, // 5 minutes
15 * 60 * 1000, // 15 minutes
],
maxOldPeersRetention: 50,
},
});

46
packages/concordia-pinner/src/utils/orbitUtils.js

@ -0,0 +1,46 @@
import OrbitDB from 'orbit-db';
import Identities from 'orbit-db-identity-provider';
import { EthereumContractIdentityProvider } from '@ezerous/eth-identity-provider';
import Web3 from 'web3';
import { ORBIT_DIRECTORY_DEFAULT } from '../constants';
// TODO: share code below with frontend (?)
const determineDBAddress = async ({
orbit, dbName, type, identityId,
}) => orbit.determineAddress(dbName, type, { accessController: { write: [identityId] } })
.then((orbitAddress) => {
const ipfsMultihash = orbitAddress.root;
return `/orbitdb/${ipfsMultihash}/${dbName}`;
});
const determineKVAddress = async ({ orbit, dbName, userAddress }) => determineDBAddress({
orbit, dbName, type: 'keyvalue', identityId: userAddress + EthereumContractIdentityProvider.contractAddress,
});
export const createOrbitInstance = async (ipfs, contractAddress) => {
Identities.addIdentityProvider(EthereumContractIdentityProvider);
EthereumContractIdentityProvider.setWeb3(new Web3()); // We need a fully-featured new Web3 for signature verification
EthereumContractIdentityProvider.setContractAddress(contractAddress);
const ORBIT_DIRECTORY = process.env.ORBIT_DIRECTORY || ORBIT_DIRECTORY_DEFAULT;
return OrbitDB.createInstance(ipfs, { directory: ORBIT_DIRECTORY });
};
export const getPeerDatabases = async (orbit, userAddresses) => Promise.all(userAddresses
.flatMap((userAddress) => [
determineKVAddress({ orbit, dbName: 'user', userAddress }),
determineKVAddress({ orbit, dbName: 'posts', userAddress }),
determineKVAddress({ orbit, dbName: 'topics', userAddress }),
]));
export const openKVDBs = async (orbit, databases) => {
databases
.forEach((database) => {
orbit
.keyvalue(database)
.then((store) => store.events.on('replicated', (address) => console.log(`Replicated ${address}`)));
console.log(`Opened ${database}`);
});
};

60
packages/concordia-shared/.eslintrc.js

@ -0,0 +1,60 @@
module.exports = {
'env': {
'browser': true,
'es6': true,
'jest': true
},
'extends': [
'plugin:react/recommended',
'airbnb'
],
'globals': {
'Atomics': 'readonly',
'SharedArrayBuffer': 'readonly'
},
parser: 'babel-eslint',
'parserOptions': {
'ecmaFeatures': {
'jsx': true
},
'ecmaVersion': 2018,
'sourceType': 'module'
},
'plugins': [
'react',
'react-hooks',
],
'rules': {
'react/jsx-props-no-spreading': 'off',
'import/extensions': 'off',
"react/jsx-indent": [
'error',
4,
{
checkAttributes: true,
indentLogicalExpressions: true
}
],
'react/require-default-props': 'off',
'react/prop-types': 'off',
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'error',
'max-len': ['warn', {'code': 120, 'tabWidth': 4}],
'no-unused-vars': 'warn',
'no-console': 'warn',
'no-shadow': 'warn',
"no-multi-str": "warn",
"jsx-a11y/label-has-associated-control": [ 2, {
"labelAttributes": ["label"],
"controlComponents": ["Input"],
"depth": 3,
}],
},
'settings': {
'import/resolver': {
'node': {
'extensions': ['.js', '.jsx']
}
}
},
};

16
packages/concordia-shared/package.json

@ -0,0 +1,16 @@
{
"name": "concordia-shared",
"version": "0.1.0",
"private": true,
"scripts": {
"lint": "eslint --ext js,jsx . --format table"
},
"devDependencies": {
"eslint": "^6.8.0",
"eslint-config-airbnb": "^18.1.0",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-react": "^7.19.0",
"eslint-plugin-react-hooks": "^4.2.0"
}
}

33
packages/concordia-shared/src/configuration/breezeConfiguration.js

@ -0,0 +1,33 @@
const { databases } = require('../constants/orbit/OrbitDatabases');
const { rendezvousHost, rendezvousPort } = require('../environment/interpolated/rendezvous');
const getBreezeConfiguration = (identityProvider) => ({
ipfs: {
repo: 'concordia',
config: {
Addresses: {
Swarm: [
// Use local signaling server (see also rendezvous script in package.json)
// For more information: https://github.com/libp2p/js-libp2p-webrtc-star
`/ip4/${rendezvousHost}/tcp/${rendezvousPort}/wss/p2p-webrtc-star`,
// Use the following public servers if needed
// '/dns4/wrtc-star1.par.dwebops.pub/tcp/443/wss/p2p-webrtc-star',
// '/dns4/ wrtc-star2.sjc.dwebops.pub/tcp/443/wss/p2p-webrtc-star'
],
},
},
preload: {
enabled: false,
},
init: {
emptyRepo: true,
},
},
orbit: {
identityProvider,
databases,
},
});
module.exports = getBreezeConfiguration;

25
packages/concordia-shared/src/configuration/web3Configuration.js

@ -0,0 +1,25 @@
const getWeb3ProviderUrl = require('../utils/web3');
const { web3PortSocketConnectMaxAttempts, web3PortSocketTimeout } = require('../environment/interpolated/web3');
const { web3HostEnv, web3PortEnv } = require('../environment/web3Env');
const getWeb3Configuration = (Web3) => {
const web3WebsocketOptions = {
keepAlive: true,
timeout: web3PortSocketTimeout,
reconnect: {
maxAttempts: web3PortSocketConnectMaxAttempts,
},
};
const web3 = (web3HostEnv !== undefined && web3PortEnv !== undefined)
? new Web3(new Web3.providers.WebsocketProvider(getWeb3ProviderUrl()))
: new Web3(Web3.givenProvider || new Web3.providers.WebsocketProvider(getWeb3ProviderUrl(), web3WebsocketOptions));
return {
customProvider: web3,
};
};
module.exports = {
getWeb3Configuration,
};

46
packages/concordia-shared/src/constants/configuration/defaults.js

@ -0,0 +1,46 @@
// Contracts provider
const CONTRACTS_PROVIDER_HOST_DEFAULT = '127.0.0.1';
const CONTRACTS_PROVIDER_PORT_DEFAULT = '8400';
const CONTRACTS_VERSION_HASH_DEFAULT = 'latest';
// Pinner
const PINNER_API_PORT_DEFAULT = 4444;
// Rendezvous
const RENDEZVOUS_HOST_DEFAULT = '127.0.0.1';
const RENDEZVOUS_PORT_DEFAULT = '9090';
// Web3 (probably ganache)
const WEB3_HOST_DEFAULT = '127.0.0.1';
const WEB3_PORT_DEFAULT = '8545';
const WEB3_HOST_TEST_DEFAULT = '127.0.0.1';
const WEB3_PORT_TEST_DEFAULT = '8546';
const WEB3_PORT_SOCKET_TIMEOUT_DEFAULT = 30000;
const WEB3_PORT_SOCKET_CONNECT_MAX_ATTEMPTS_DEFAULT = 3;
module.exports = Object.freeze({
contractsProvider: {
host: CONTRACTS_PROVIDER_HOST_DEFAULT,
port: CONTRACTS_PROVIDER_PORT_DEFAULT,
hash: CONTRACTS_VERSION_HASH_DEFAULT,
},
pinner: {
port: PINNER_API_PORT_DEFAULT,
},
rendezvous: {
host: RENDEZVOUS_HOST_DEFAULT,
port: RENDEZVOUS_PORT_DEFAULT,
},
web3: {
develop: {
chainHost: WEB3_HOST_DEFAULT,
chainPort: WEB3_PORT_DEFAULT,
},
test: {
chainHost: WEB3_HOST_TEST_DEFAULT,
chainPort: WEB3_PORT_TEST_DEFAULT,
},
socketTimeout: WEB3_PORT_SOCKET_TIMEOUT_DEFAULT,
socketConnectMaxAttempts: WEB3_PORT_SOCKET_CONNECT_MAX_ATTEMPTS_DEFAULT,
},
});

16
packages/concordia-shared/src/constants/contracts/ContractNames.js

@ -0,0 +1,16 @@
const FORUM_CONTRACT = 'Forum';
const POST_VOTING_CONTRACT = 'PostVoting';
const VOTING_CONTRACT = 'Voting';
const CONTRACTS = [
FORUM_CONTRACT,
POST_VOTING_CONTRACT,
VOTING_CONTRACT,
];
module.exports = Object.freeze({
FORUM_CONTRACT,
POST_VOTING_CONTRACT,
VOTING_CONTRACT,
CONTRACTS,
});

19
packages/concordia-shared/src/constants/contracts/events/ForumContractEvents.js

@ -0,0 +1,19 @@
const USER_SIGNED_UP_EVENT = 'UserSignedUp';
const USERNAME_UPDATED_EVENT = 'UsernameUpdated';
const TOPIC_CREATED_EVENT = 'TopicCreated';
const POST_CREATED_EVENT = 'PostCreated';
const forumContractEvents = Object.freeze([
USER_SIGNED_UP_EVENT,
USERNAME_UPDATED_EVENT,
TOPIC_CREATED_EVENT,
POST_CREATED_EVENT,
]);
module.exports = {
USER_SIGNED_UP_EVENT,
USERNAME_UPDATED_EVENT,
TOPIC_CREATED_EVENT,
POST_CREATED_EVENT,
forumContractEvents,
};

8
packages/concordia-shared/src/constants/contracts/events/index.js

@ -0,0 +1,8 @@
const forumContractEvents = require('./ForumContractEvents');
const { FORUM_CONTRACT } = require('../ContractNames');
const appEvents = Object.freeze({
[FORUM_CONTRACT]: forumContractEvents,
});
module.exports = appEvents;

13
packages/concordia-app/src/constants/orbit/OrbitDatabases.js → packages/concordia-shared/src/constants/orbit/OrbitDatabases.js

@ -1,6 +1,6 @@
export const USER_DATABASE = 'user';
export const TOPICS_DATABASE = 'topics';
export const POSTS_DATABASE = 'posts';
const USER_DATABASE = 'user';
const TOPICS_DATABASE = 'topics';
const POSTS_DATABASE = 'posts';
const databases = [
{
@ -17,4 +17,9 @@ const databases = [
},
];
export default databases;
module.exports = Object.freeze({
USER_DATABASE,
TOPICS_DATABASE,
POSTS_DATABASE,
databases,
});

14
packages/concordia-shared/src/environment/contractsProviderEnv.js

@ -0,0 +1,14 @@
// Depending on the package user (app in contrast to any of the other packages) the env var names should either include
// the REACT_APP_ prefix or not
const contractsProviderHostEnv = process.env.REACT_APP_CONTRACTS_PROVIDER_HOST
|| process.env.CONTRACTS_PROVIDER_HOST;
const contractsProviderPortEnv = process.env.REACT_APP_CONTRACTS_PROVIDER_PORT
|| process.env.CONTRACTS_PROVIDER_PORT;
const contractsVersionHashEnv = process.env.REACT_APP_CONTRACTS_VERSION_HASH
|| process.env.CONTRACTS_VERSION_HASH;
module.exports = {
contractsProviderHostEnv,
contractsProviderPortEnv,
contractsVersionHashEnv,
};

21
packages/concordia-shared/src/environment/interpolated/contractsProvider.js

@ -0,0 +1,21 @@
const {
contractsProviderHostEnv, contractsProviderPortEnv, contractsVersionHashEnv,
} = require('../contractsProviderEnv');
const {
contractsProvider: {
host: CONTRACTS_PROVIDER_HOST_DEFAULT,
port: CONTRACTS_PROVIDER_PORT_DEFAULT,
hash: CONTRACTS_VERSION_HASH_DEFAULT,
},
} = require('../../constants/configuration/defaults');
const contractsProviderHost = contractsProviderHostEnv || CONTRACTS_PROVIDER_HOST_DEFAULT;
const contractsProviderPort = contractsProviderPortEnv || CONTRACTS_PROVIDER_PORT_DEFAULT;
const contractsVersionHash = contractsVersionHashEnv || CONTRACTS_VERSION_HASH_DEFAULT;
module.exports = {
contractsProviderHost,
contractsProviderPort,
contractsVersionHash,
};

12
packages/concordia-shared/src/environment/interpolated/pinner.js

@ -0,0 +1,12 @@
const {
pinner: {
port: PINNER_API_PORT_DEFAULT,
},
} = require('../../constants/configuration/defaults');
const { pinnerApiPortEnv } = require('../pinnerEnv');
const pinnerApiPort = pinnerApiPortEnv || PINNER_API_PORT_DEFAULT;
module.exports = {
pinnerApiPort,
};

15
packages/concordia-shared/src/environment/interpolated/rendezvous.js

@ -0,0 +1,15 @@
const { rendezvousHostEnv, rendezvousPortEnv } = require('../rendezvousEnv');
const {
rendezvous: {
host: RENDEZVOUS_HOST_DEFAULT,
port: RENDEZVOUS_PORT_DEFAULT,
},
} = require('../../constants/configuration/defaults');
const rendezvousHost = rendezvousHostEnv || RENDEZVOUS_HOST_DEFAULT;
const rendezvousPort = rendezvousPortEnv || RENDEZVOUS_PORT_DEFAULT;
module.exports = {
rendezvousHost,
rendezvousPort,
};

9
packages/concordia-shared/src/environment/interpolated/shared.js

@ -0,0 +1,9 @@
const contractsProvider = require('./contractsProvider');
const rendezvous = require('./rendezvous');
const web3 = require('./web3');
module.exports = {
contractsProvider,
rendezvous,
web3,
};

37
packages/concordia-shared/src/environment/interpolated/web3.js

@ -0,0 +1,37 @@
const {
web3: {
develop: {
chainHost: WEB3_HOST_DEFAULT,
chainPort: WEB3_PORT_DEFAULT,
},
test: {
chainHost: WEB3_HOST_TEST_DEFAULT,
chainPort: WEB3_PORT_TEST_DEFAULT,
},
socketConnectMaxAttempts: WEB3_PORT_SOCKET_CONNECT_MAX_ATTEMPTS_DEFAULT,
socketTimeout: WEB3_PORT_SOCKET_TIMEOUT_DEFAULT,
},
} = require('../../constants/configuration/defaults');
const {
web3HostEnv, web3HostTestEnv, web3PortEnv, web3PortSocketConnectMaxAttemptsEnv, web3PortSocketTimeoutEnv,
web3PortTestEnv,
} = require('../web3Env');
const web3Host = web3HostEnv || WEB3_HOST_DEFAULT;
const web3Port = web3PortEnv || WEB3_PORT_DEFAULT;
const web3HostTest = web3HostTestEnv || WEB3_HOST_TEST_DEFAULT;
const web3PortTest = web3PortTestEnv || WEB3_PORT_TEST_DEFAULT;
const web3PortSocketTimeout = web3PortSocketTimeoutEnv || WEB3_PORT_SOCKET_TIMEOUT_DEFAULT;
const web3PortSocketConnectMaxAttempts = web3PortSocketConnectMaxAttemptsEnv
|| WEB3_PORT_SOCKET_CONNECT_MAX_ATTEMPTS_DEFAULT;
module.exports = {
web3Host,
web3Port,
web3HostTest,
web3PortTest,
web3PortSocketTimeout,
web3PortSocketConnectMaxAttempts,
};

7
packages/concordia-shared/src/environment/pinnerEnv.js

@ -0,0 +1,7 @@
// Depending on the package user (app in contrast to any of the other packages) the env var names should either include
// the REACT_APP_ prefix or not
const pinnerApiPortEnv = process.env.REACT_APP_PINNER_API_PORT || process.env.PINNER_API_PORT;
module.exports = {
pinnerApiPortEnv,
};

9
packages/concordia-shared/src/environment/rendezvousEnv.js

@ -0,0 +1,9 @@
// Depending on the package user (app in contrast to any of the other packages) the env var names should either include
// the REACT_APP_ prefix or not
const rendezvousHostEnv = process.env.REACT_APP_RENDEZVOUS_HOST || process.env.RENDEZVOUS_HOST;
const rendezvousPortEnv = process.env.REACT_APP_RENDEZVOUS_PORT || process.env.RENDEZVOUS_PORT;
module.exports = {
rendezvousHostEnv,
rendezvousPortEnv,
};

9
packages/concordia-shared/src/environment/sharedEnv.js

@ -0,0 +1,9 @@
const contractsProvider = require('./contractsProviderEnv');
const rendezvous = require('./rendezvousEnv');
const web3 = require('./web3Env');
module.exports = {
contractsProvider,
rendezvous,
web3,
};

24
packages/concordia-shared/src/environment/web3Env.js

@ -0,0 +1,24 @@
// Depending on the package user (app in contrast to any of the other packages) the env var names should either include
// the REACT_APP_ prefix or not
const web3HostEnv = process.env.REACT_APP_WEB3_HOST
|| process.env.WEB3_HOST;
const web3PortEnv = process.env.REACT_APP_WEB3_PORT
|| process.env.WEB3_PORT;
// Web3 test environment shouldn't be available to the react app
const web3HostTestEnv = process.env.WEB3_HOST_TEST;
const web3PortTestEnv = process.env.WEB3_PORT_TEST;
const web3PortSocketTimeoutEnv = process.env.REACT_APP_WEB3_PORT_SOCKET_TIMEOUT
|| process.env.WEB3_PORT_SOCKET_TIMEOUT;
const web3PortSocketConnectMaxAttemptsEnv = process.env.REACT_APP_WEB3_PORT_SOCKET_CONNECT_MAX_ATTEMPTS
|| process.env.WEB3_PORT_SOCKET_CONNECT_MAX_ATTEMPTS;
module.exports = {
web3HostEnv,
web3PortEnv,
web3HostTestEnv,
web3PortTestEnv,
web3PortSocketTimeoutEnv,
web3PortSocketConnectMaxAttemptsEnv,
};

5
packages/concordia-shared/src/utils/rendezvous.js

@ -0,0 +1,5 @@
const { rendezvousHost, rendezvousPort } = require('../environment/interpolated/rendezvous');
const getRendezvousUrl = () => `http://${rendezvousHost}:${rendezvousPort}`;
module.exports = getRendezvousUrl;

6
packages/concordia-shared/src/utils/web3.js

@ -0,0 +1,6 @@
const { web3Port } = require('../environment/interpolated/web3');
const { web3Host } = require('../environment/interpolated/web3');
const getWeb3ProviderUrl = () => `ws://${web3Host}:${web3Port}`;
module.exports = getWeb3ProviderUrl;

564
yarn.lock

File diff suppressed because it is too large
Loading…
Cancel
Save