1
0
mirror of https://github.com/dap-ps/discover.git synced 2025-03-04 02:40:38 +00:00

Merge pull request #16 from dap-ps/fetching-dapps-flow

Fetching dapps flow
This commit is contained in:
George Spasov 2019-07-20 15:39:20 +03:00 committed by GitHub
commit fc7e1d50d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 454 additions and 255 deletions

View File

@ -1,158 +1,179 @@
const DAppMetadata = require('./../models/dapps-metadata-model');
const DAppMetadata = require('./../models/dapps-metadata-model')
const TemplateParser = require('./../inputs/template-parser');
const DAppsMetadataInputTemplates = require('./../inputs/templates/dapps-metadata');
const TemplateParser = require('./../inputs/template-parser')
const DAppsMetadataInputTemplates = require('./../inputs/templates/dapps-metadata')
const IPFSService = require('./../services/ipfs-service');
const DiscoverService = require('./../services/discover-service');
const DAppImageService = require('./../services/dapp-image-service');
const DAppMetadataService = require('./../services/dapp-metadata-service');
const IPFSService = require('./../services/ipfs-service')
const DiscoverService = require('./../services/discover-service')
const DAppImageService = require('./../services/dapp-image-service')
const DAppMetadataService = require('./../services/dapp-metadata-service')
const ApprovalEmail = require('./../emails/approval-email');
const BadRequestError = require('./../errors/bad-request-error');
const ApprovalEmail = require('./../emails/approval-email')
const BadRequestError = require('./../errors/bad-request-error')
const DAPP_METADATA_STATUSES = require('./../constants/dapp-metadata-statuses');
const DAPP_METADATA_STATUSES = require('./../constants/dapp-metadata-statuses')
const web3 = require('./../blockchain/web3');
const logger = require('./../logger/logger').getLoggerFor('DApps-Metadata-Controller');
const web3 = require('./../blockchain/web3')
const logger = require('./../logger/logger').getLoggerFor(
'DApps-Metadata-Controller',
)
class DAppsMetadataController {
static async uploadDAppMetadata(req, res) {
try {
const parsedMetadata = TemplateParser.parse(req.body, DAppsMetadataInputTemplates.UploadingTemplate);
const uploadedMetadata = await DAppMetadataService.upload(req, parsedMetadata);
const parsedInput = TemplateParser.parse(
req.body,
DAppsMetadataInputTemplates.UploadingTemplate,
)
logger.info(`A dapp metadata with hash [${uploadedMetadata.hash}] has been uploaded successfully`);
const uploadedMetadata = await DAppMetadataService.upload(
req,
parsedInput,
)
res.status(200).json({ hash: uploadedMetadata.hash });
logger.info(
`A dapp metadata with hash [${uploadedMetadata.hash}] has been uploaded successfully`,
)
res.status(200).json({ hash: uploadedMetadata.hash })
} catch (error) {
logger.error(error.message);
throw new BadRequestError(error);
logger.error(error.message)
throw new BadRequestError(error)
}
}
static async sendApprovalEmail(req, res) {
const dappMetadata = await DAppMetadata.findOne({ 'hash': req.params.hash });
const dappMetadata = await DAppMetadata.findOne({ hash: req.params.hash })
if (!dappMetadata) {
return void res.status(404).send();
return void res.status(404).send()
}
if (dappMetadata.status == DAPP_METADATA_STATUSES.NEW) {
const approvalEmail = new ApprovalEmail(dappMetadata.details);
approvalEmail.send();
const approvalEmail = new ApprovalEmail(dappMetadata)
approvalEmail.send()
}
res.status(200).send();
res.status(200).send()
}
static async setMetadataStatus(req, res) {
waitToBeMined(req.body.txHash, async () => {
const dapp = await DiscoverService.retrieveDApp(req.params.dappId);
const dappMetadata = await DAppMetadata.findByBytes32Hash(dapp.metadata);
const initialDAppMetadata = await DAppMetadata.findOne({ 'compressedMetadata': req.params.dappId });
const dapp = await DiscoverService.retrieveDApp(req.params.dappId)
const dappMetadata = await DAppMetadata.findByBytes32Hash(dapp.metadata)
const initialDAppMetadata = await DAppMetadata.findOne({
compressedMetadata: req.params.dappId,
})
if (dappMetadata && initialDAppMetadata && initialDAppMetadata.status == DAPP_METADATA_STATUSES.APPROVED) {
dappMetadata.status = DAPP_METADATA_STATUSES.APPROVED;
await dappMetadata.save();
if (
dappMetadata &&
initialDAppMetadata &&
initialDAppMetadata.status == DAPP_METADATA_STATUSES.APPROVED
) {
dappMetadata.status = DAPP_METADATA_STATUSES.APPROVED
await dappMetadata.save()
}
});
})
res.status(200).send();
res.status(200).send()
}
static async getDAppMetadata(req, res) {
try {
const dappMetadata = await DAppMetadata.findOne({ 'hash': req.params.hash });
const dappMetadata = await DAppMetadata.findOne({ hash: req.params.hash })
if (dappMetadata) {
return void res.status(200).jsonCutSensitives(dappMetadata, ['_id', '__v']);
return void res
.status(200)
.jsonCutSensitives(dappMetadata, ['_id', '__v'])
}
res.status(404).send();
res.status(404).send()
} catch (error) {
logger.error(error.message);
res.status(404).send();
logger.error(error.message)
res.status(404).send()
}
}
static async getDAppImage(req, res) {
try {
const dappImage = await DAppImageService.retrieveImage(req.params.hash);
const dappImage = await DAppImageService.retrieveImage(req.params.hash)
if (dappImage) {
const imageBuffer = Buffer.from(dappImage.content, 'base64');
const imageBuffer = Buffer.from(dappImage.content, 'base64')
res.writeHead(200, {
'Content-Type': 'image/png',
'Content-Length': imageBuffer.length
});
return void res.end(imageBuffer);
'Content-Length': imageBuffer.length,
})
return void res.end(imageBuffer)
}
res.status(404).send();
res.status(404).send()
} catch (error) {
logger.error(error.message);
res.status(404).send();
logger.error(error.message)
res.status(404).send()
}
}
static async getAllDappsMetadata(req, res) {
const dappsMetadata = await DAppMetadata.find();
const dappsMetadata = await DAppMetadata.find()
const dappsFormatedMetadata = {}
for (let i = 0; i < dappsMetadata.length; i++) {
const metadataHash = dappsMetadata[i].hash;
dappsFormatedMetadata[metadataHash] = dappsMetadata[i];
const metadataHash = dappsMetadata[i].hash
dappsFormatedMetadata[metadataHash] = dappsMetadata[i]
}
res.status(200).json(dappsFormatedMetadata);
res.status(200).json(dappsFormatedMetadata)
}
static async approveDApp(req, res) {
let dappMetadata = await DAppMetadata.findOne({ 'hash': req.params.hash });
const dappMetadata = await DAppMetadata.findOne({ hash: req.params.hash })
if (dappMetadata) {
dappMetadata.status = DAPP_METADATA_STATUSES.APPROVED;
dappMetadata.status = DAPP_METADATA_STATUSES.APPROVED
const hasStaked = await DiscoverService.hasStaked(dappMetadata.compressedMetadata);
const hasStaked = await DiscoverService.hasStaked(
dappMetadata.compressedMetadata,
)
if (hasStaked) {
dappMetadata.ipfsHash = await IPFSService.addContent(dappMetadata.details);
dappMetadata.ipfsHash = await IPFSService.addContent(
dappMetadata.details,
)
}
await dappMetadata.save();
await dappMetadata.save()
logger.info(`A dapp with hash [${dappMetadata.hash}] has been approved`);
return void res.status(200).send();
logger.info(`A dapp with hash [${dappMetadata.hash}] has been approved`)
return void res.status(200).send()
}
res.status(404).send();
res.status(404).send()
}
static async rejectDApp(req, res) {
const dappMetadata = await DAppMetadata.findOne({ 'hash': req.params.hash });
const dappMetadata = await DAppMetadata.findOne({ hash: req.params.hash })
if (dappMetadata) {
await dappMetadata.remove();
return void res.status(200).send();
await dappMetadata.remove()
return void res.status(200).send()
}
res.status(404).send();
res.status(404).send()
}
}
const waitToBeMined = async function(txHash, callback) {
const updateMetadataTx = await web3.eth.getTransaction(txHash);
const updateMetadataTx = await web3.eth.getTransaction(txHash)
if (!updateMetadataTx.blockNumber) {
setTimeout(() => {
waitToBeMined(txHash, callback);
}, 10000);
}
else {
callback();
waitToBeMined(txHash, callback)
}, 10000)
} else {
callback()
}
}
module.exports = DAppsMetadataController;
module.exports = DAppsMetadataController

View File

@ -2,7 +2,7 @@ const Email = require('./base-email');
class ApprovalEmail extends Email {
constructor(dapp) {
const emailBody = `A DApp metadata ${JSON.stringify(dapp.details)} has been uploaded`;
const emailBody = `A DApp metadata ${JSON.stringify(dapp.details)} has been uploaded. You can connect with the Dapp owner at email: ${dapp.email}`;
super(process.env.APPROVE_NOTIFIER_MAIL, process.env.APPROVER_MAIL, `Uploaded DApp Metadata. Hash - ${dapp.hash}`, emailBody);
}
}

View File

@ -1,5 +1,7 @@
{
"UploadingTemplate": {
"email": true,
"metadata": {
"name": true,
"url": true,
"description": true,
@ -9,3 +11,4 @@
"uploader": true
}
}
}

View File

@ -9,3 +9,32 @@
[2019-06-04 11:39:00]-[ERROR]-[Base-Email]: Email service verification failed due to Error: connect ECONNREFUSED 127.0.0.1:587
[2019-06-04 11:42:55]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmXpVWSYayBYPzjiPdhTjmjCcbuY3Qr6ZYteWGaB6fDm4m] has been uploaded successfully
[2019-06-04 14:15:12]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmTmHntVv6ixcQwtFEivSQ1kY4N5mzjmHVPEfhBRcUD6AC] has been uploaded successfully
[2019-07-20 10:23:51]-[ERROR]-[DApps-Metadata-Controller]: metadata is not defined
[2019-07-20 10:27:21]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmeJKQtcEASSbmUgqEco4wXcpTVA21jWuEsnkGADEWZyFe] has been uploaded successfully
[2019-07-20 10:55:32]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmaviKASDQ9Bc1ntwnPkVr2Kds4zXSrhud1hGj7Mc4NdGv] has been uploaded successfully
[2019-07-20 10:57:31]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmNUSXTixR4DZtPQ5vuBoEAZtv5Pe6CQdkgpRyPYfsbVs6] has been uploaded successfully
[2019-07-20 10:59:15]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmVv5G6UvVBAFsMQtff8Sk9p12Hn29g959wUeE3WjsdGUv] has been uploaded successfully
[2019-07-20 11:00:45]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmQiiVYUTtpg1DtiKnVKVfkfKkM7Brt7JHVFLcVf3H1yDV] has been uploaded successfully
[2019-07-20 11:04:34]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmNMPu9ykeAmmjBoN4g3zBC5HGypr6K4MFb3Tjkmd78i5B] has been uploaded successfully
[2019-07-20 11:06:41]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmScorFHZqFYze8RYNXpXuJPTh4ptwTcLeGPE5TodC6gnw] has been uploaded successfully
[2019-07-20 11:06:50]-[ERROR]-[Base-Email]: Email service verification failed due to Error: connect ECONNREFUSED 127.0.0.1:587
[2019-07-20 11:09:14]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmeyTjkdgSA2M28xugPNRXCjSmsQNHWfsNeYyCfK1FyqV9] has been uploaded successfully
[2019-07-20 11:10:55]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmQDFjSnY5pTo2k8uHgvYBFYKB1C9RtrNFxt4enLizP9Hp] has been uploaded successfully
[2019-07-20 11:12:14]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmZ4yiDhHmWf1tTsio4vrTzZrE51XKbtm8NzYUV68cxXZz] has been uploaded successfully
[2019-07-20 11:12:14]-[ERROR]-[Base-Email]: Email service verification failed due to Error: connect ECONNREFUSED 127.0.0.1:587
[2019-07-20 11:32:31]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [Qmf5RuGyCJFVVtCq7KLXgWwmgRVhTi7oKyiN1Nqk7Fw7Rv] has been uploaded successfully
[2019-07-20 11:32:31]-[ERROR]-[Base-Email]: Email service verification failed due to Error: connect ECONNREFUSED 127.0.0.1:587
[2019-07-20 11:35:27]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmcsiJkjcfuGvVYK55j9RC2DCBwvHPjrcBrG7UztM3G9xw] has been uploaded successfully
[2019-07-20 11:35:27]-[ERROR]-[Base-Email]: Email service verification failed due to Error: connect ECONNREFUSED 127.0.0.1:587
[2019-07-20 11:38:06]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmbJ1t7GmMujpvVcFpdGQ58dTxFAtNYaUxNNEXrXS9hnHJ] has been uploaded successfully
[2019-07-20 11:38:06]-[ERROR]-[Base-Email]: Email service verification failed due to Error: connect ECONNREFUSED 127.0.0.1:587
[2019-07-20 11:39:17]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmPheif9S68kEo4hzuszveWMk5LMEsUb2f5MR8nStkiZBs] has been uploaded successfully
[2019-07-20 11:39:17]-[ERROR]-[Base-Email]: Email service verification failed due to Error: connect ECONNREFUSED 127.0.0.1:587
[2019-07-20 11:45:48]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmcFPhH8yLG7ERjbEv6kyWsPEGMu2JufXud7Regdn4KNHz] has been uploaded successfully
[2019-07-20 11:45:48]-[ERROR]-[Base-Email]: Email service verification failed due to Error: connect ECONNREFUSED 127.0.0.1:587
[2019-07-20 11:47:31]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmWvNbgnR82ZkjWmAC7SMisA7k7zKCz7Fqu9HKVwyhJqFY] has been uploaded successfully
[2019-07-20 11:47:31]-[ERROR]-[Base-Email]: Email service verification failed due to Error: connect ECONNREFUSED 127.0.0.1:587
[2019-07-20 11:49:43]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmRtZmATHLNgxSZPbsDXaDiRe7hURagzCWYqbG7rdtS9T1] has been uploaded successfully
[2019-07-20 11:50:02]-[ERROR]-[Base-Email]: Email service verification failed due to Error: connect ECONNREFUSED 127.0.0.1:587
[2019-07-20 12:10:07]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmYA7iGvK4641Fu2uPSKe5ahUmrMxrksFDtigvQb4VDtXd] has been uploaded successfully
[2019-07-20 12:10:07]-[ERROR]-[Base-Email]: Email service verification failed due to Error: connect ECONNREFUSED 127.0.0.1:587

View File

@ -2,6 +2,7 @@ let mongoose = require('mongoose');
let Schema = mongoose.Schema;
const bs58 = require('bs58');
const validator = require('validator');
const dappCategories = require('./../constants/dapp-categories').ALL_CATEGORIES;
const metadataStatuses = require('./../constants/dapp-metadata-statuses').ALL_STATUSES;
@ -41,6 +42,16 @@ let DAppsMetadataSchema = new Schema({
required: true
},
},
email: {
type: String,
required: true,
validate: {
validator: function (value) {
return validator.isEmail(value);
},
message: props => `${props.value} is not a valid email!`
}
},
hash: {
type: String,
unique: true,

View File

@ -1,37 +1,45 @@
const DAppMetadata = require('./../models/dapps-metadata-model');
const validator = require('validator')
const web3Utils = require('web3-utils')
const DAppMetadata = require('./../models/dapps-metadata-model')
const DAppImageService = require('./../services/dapp-image-service');
const validator = require('validator');
const web3Utils = require('web3-utils');
const DAppImageService = require('./../services/dapp-image-service')
class DAppMetadataService {
static async upload(req, metadata) {
static async upload(req, details) {
try {
if (!validator.isURL(metadata.url, { require_protocol: true })) {
throw new Error(`Invalid url: ${metadata.url}`);
if (!validator.isURL(details.metadata.url, { require_protocol: true })) {
throw new Error(`Invalid url: ${details.metadata.url}`)
}
if (!web3Utils.isAddress(metadata.uploader)) {
throw new Error(`Metadata uploader [${metadata.url}] is not a valid address`);
if (!web3Utils.isAddress(details.metadata.uploader)) {
throw new Error(
`Metadata uploader [${details.metadata.uploader}] is not a valid address`,
)
}
const compressedMetadata = web3Utils.keccak256(JSON.stringify(metadata));
metadata.image = await DAppImageService.upload(req, metadata.image);
const dappMetadata = await DAppMetadata.create({ details: metadata, compressedMetadata: compressedMetadata });
const compressedMetadata = web3Utils.keccak256(
JSON.stringify(details.metadata),
)
details.metadata.image = await DAppImageService.upload(
req,
details.metadata.image,
)
const dappMetadata = await DAppMetadata.create({
details: details.metadata,
compressedMetadata,
email: details.email,
})
return dappMetadata;
return dappMetadata
} catch (error) {
// Code 11000 is because of uniqueness, so just return the already existing document
if (error.code == 11000) {
return DAppMetadata.findByPlainMetadata(metadata);
return DAppMetadata.findByPlainMetadata(details.metadata)
}
throw new Error(error.message);
throw new Error(error.message)
}
}
}
module.exports = DAppMetadataService;
module.exports = DAppMetadataService

View File

@ -74,7 +74,7 @@ module.exports = {
SafeMath: { deploy: false },
TestBancorFormula: { deploy: false },
MiniMeToken: {
address: '0x25B1bD06fBfC2CbDbFc174e10f1B78b1c91cc77B'
address: '0x25B1bD06fBfC2CbDbFc174e10f1B78b1c91cc77B',
},
Discover: { address: '0x17e7a7330d23fc6a2ab8578a627408f815396662' },
// MiniMeToken: {
@ -112,9 +112,11 @@ module.exports = {
// used with "embark run testnet"
testnet: {
deployment: {
accounts: [{
accounts: [
{
mnemonic: wallet.mnemonic,
}],
},
],
host: `ropsten.infura.io/v3/8675214b97b44e96b70d05326c61fd6a`,
port: false,
type: 'rpc',
@ -124,7 +126,7 @@ module.exports = {
'$WEB3',
'https://ropsten.infura.io/v3/8675214b97b44e96b70d05326c61fd6a',
],
dappAutoEnable: false
dappAutoEnable: false,
},
// merges with the settings in default

View File

@ -8,6 +8,7 @@
"@trailofbits/embark-contract-info": "^1.0.0",
"axios": "^0.18.0",
"bignumber.js": "^8.1.1",
"bn.js": "^5.0.0",
"bs58": "^4.0.1",
"connected-react-router": "^6.3.2",
"debounce": "^1.2.0",
@ -15,6 +16,7 @@
"embark": "4.0.1",
"embark-solium": "0.0.1",
"history": "^4.7.2",
"idb": "4.0.3",
"moment": "^2.24.0",
"node-sass": "^4.11.0",
"prop-types": "^15.7.2",
@ -31,11 +33,10 @@
"redux": "^4.0.1",
"redux-thunk": "^2.3.0",
"reselect": "^4.0.0",
"web3-utils": "^1.0.0-beta.35",
"webpack": "4.28.3",
"idb": "4.0.3",
"validator": "^11.1.0",
"web3": "1.0.0-beta.34",
"validator": "latest"
"web3-utils": "^1.0.0-beta.35",
"webpack": "4.28.3"
},
"scripts": {
"start": "react-scripts start",

View File

@ -9,6 +9,20 @@ import DiscoverContract from '../../../../embarkArtifacts/contracts/Discover'
const BN = require('bn.js')
const EMPTY_METADATA = {
developer: '',
id: '',
metadata: {
status: 'EMPTY',
},
balance: 0,
rate: 0,
available: 0,
votesMinted: 0,
votesCast: 0,
effectiveBalance: 0,
}
class DiscoverService extends BlockchainService {
constructor(sharedContext) {
super(sharedContext, DiscoverContract, DiscoverValidator)
@ -17,10 +31,11 @@ class DiscoverService extends BlockchainService {
// View methods
async upVoteEffect(id, amount) {
await this.validator.validateUpVoteEffect(id, amount)
const tokenAmount = new BN(amount, 10)
await this.validator.validateUpVoteEffect(id, tokenAmount)
return DiscoverContract.methods
.upvoteEffect(id, amount)
.upvoteEffect(id, tokenAmount.toString())
.call({ from: this.sharedContext.account })
}
@ -32,9 +47,56 @@ class DiscoverService extends BlockchainService {
}
async getDAppsCount() {
return DiscoverContract.methods
return MetadataClient.getDappsCount()
}
async getAllDappsWithMetadata() {
try {
const contractDappsCount = await DiscoverContract.methods
.getDAppsCount()
.call({ from: this.sharedContext.account })
const dappsCache = JSON.parse(
JSON.stringify(await MetadataClient.retrieveMetadataCache()),
)
const dapps = []
for (let i = 0; i < contractDappsCount; i++) {
const dapp = await DiscoverContract.methods
.dapps(i)
.call({ from: this.sharedContext.account })
const dappMetadata = dappsCache[dapp.metadata]
delete dappsCache[dapp.metadata]
dapp.metadata = dappMetadata.details
dapp.metadata.status = dappMetadata.status
dapps.push(dapp)
}
Object.keys(dappsCache).forEach(metadataHash => {
const dappMetadata = dappsCache[metadataHash]
dapps.push({
developer: '',
id: dappMetadata.compressedMetadata,
metadata: {
...dappMetadata.details,
status: dappMetadata.status,
},
balance: 0,
rate: 0,
available: 0,
votesMinted: 0,
votesCast: 0,
effectiveBalance: 0,
})
})
return dapps
} catch (error) {
throw new Error(`Error fetching dapps. Details: ${error.message}`)
}
}
async getDAppByIndexWithMetadata(index) {
@ -43,9 +105,10 @@ class DiscoverService extends BlockchainService {
.dapps(index)
.call({ from: this.sharedContext.account })
const dappMetadata = await MetadataClient.retrieveMetadataCache(
const dappMetadata = await MetadataClient.retrieveDAppFromCache(
dapp.metadata,
)
if (dappMetadata === null) return null
dapp.metadata = dappMetadata.details
dapp.metadata.status = dappMetadata.status
@ -56,7 +119,10 @@ class DiscoverService extends BlockchainService {
}
async getDAppById(id) {
let dapp
let dapp = EMPTY_METADATA
const dappExists = await this.isDAppExists(id)
if (dappExists) {
try {
const dappId = await DiscoverContract.methods
.id2index(id)
@ -72,16 +138,18 @@ class DiscoverService extends BlockchainService {
if (dapp.id != id) {
throw new Error('Error fetching correct data from contract')
}
}
return dapp
}
async getDAppDataById(id) {
const dapp = await this.getDAppById(id)
if (dapp.metadata.status == 'EMPTY') return EMPTY_METADATA
try {
const dappMetadata = await MetadataClient.retrieveMetadata(dapp.metadata)
if (dappMetadata === null) return null
if (dappMetadata === null) return EMPTY_METADATA
dapp.metadata = dappMetadata.details
dapp.metadata.status = dappMetadata.status
@ -105,17 +173,16 @@ class DiscoverService extends BlockchainService {
async checkIfCreatorOfDApp(id) {
const dapp = await this.getDAppById(id)
if (dapp.metadata.status == 'EMPTY') return false
this.sharedContext.account = await super.getAccount()
return dapp.developer.toLowerCase() == this.sharedContext.account
}
// Transaction methods
async createDApp(amount, metadata) {
async createDApp(amount, metadata, email) {
const tokenAmount = this.decimalMultiplier.mul(new BN(amount, 10))
console.log(tokenAmount)
const ConnectedDiscoverContract = await super.__unlockServiceAccount(
DiscoverContract,
)
@ -126,17 +193,21 @@ class DiscoverService extends BlockchainService {
const dappId = web3.utils.keccak256(JSON.stringify(dappMetadata))
await this.validator.validateDAppCreation(dappId, tokenAmount)
const uploadedMetadata = await MetadataClient.upload(dappMetadata)
const uploadedMetadata = await MetadataClient.upload(dappMetadata, email)
let createdTx = ''
if (tokenAmount.gt(new BN(0, 10))) {
const callData = ConnectedDiscoverContract.methods
.createDApp(dappId, tokenAmount, uploadedMetadata)
.createDApp(dappId, tokenAmount.toString(), uploadedMetadata)
.encodeABI()
const createdTx = await this.sharedContext.SNTService.approveAndCall(
createdTx = await this.sharedContext.SNTService.approveAndCall(
this.contract,
tokenAmount,
callData,
)
}
await MetadataClient.requestApproval(uploadedMetadata)
@ -149,7 +220,7 @@ class DiscoverService extends BlockchainService {
await this.validator.validateUpVoting(id, tokenAmount)
const callData = DiscoverContract.methods
.upvote(id, tokenAmount)
.upvote(id, tokenAmount.toString())
.encodeABI()
return this.sharedContext.SNTService.approveAndCall(
this.contract,
@ -167,7 +238,7 @@ class DiscoverService extends BlockchainService {
const tokenAmount = this.decimalMultiplier.mul(amountBN)
const callData = DiscoverContract.methods
.downvote(dapp.id, tokenAmount)
.downvote(dapp.id, tokenAmount.toString())
.encodeABI()
return this.sharedContext.SNTService.approveAndCall(
this.contract,
@ -185,7 +256,8 @@ class DiscoverService extends BlockchainService {
try {
return broadcastContractFn(
ConnectedDiscoverContract.methods.withdraw(id, tokenAmount).send,
ConnectedDiscoverContract.methods.withdraw(id, tokenAmount.toString())
.send,
this.sharedContext.account,
)
} catch (error) {

View File

@ -27,12 +27,6 @@ class DiscoverValidator {
throw new Error('You must submit a unique ID')
}
if (amount.lte(0)) {
throw new Error(
'You must spend some SNT to submit a ranking in order to avoid spam',
)
}
const safeMax = await this.service.safeMax()
if (amount.div(this.decimalMultiplier).toNumber() > safeMax) {
throw new Error('You cannot stake more SNT than the ceiling dictates')

View File

@ -40,7 +40,11 @@ class SNTService extends BlockchainService {
const ConnectedSNTToken = await super.__unlockServiceAccount(SNTToken)
await this.validator.validateApproveAndCall(spender, amount)
return broadcastContractFn(
ConnectedSNTToken.methods.approveAndCall(spender, amount, callData).send,
ConnectedSNTToken.methods.approveAndCall(
spender,
amount.toString(),
callData,
).send,
this.sharedContext.account,
)
}

View File

@ -20,6 +20,10 @@ const waitOneMoreBlock = async function(prevBlockNumber) {
export default {
getTxStatus: async txHash => {
if (!txHash) {
return TRANSACTION_STATUSES.Successful
}
const txReceipt = await web3.eth.getTransactionReceipt(txHash)
if (txReceipt) {
await waitOneMoreBlock(txReceipt.blockNumber)

View File

@ -6,11 +6,11 @@ import metadataClientEndpoints from './endpoints/metadata-client-endpoints'
let metadataCache = null
class MetadataClient {
static async upload(metadata) {
static async upload(metadata, email) {
try {
const uploadedDataResponse = await HTTPClient.postRequest(
metadataClientEndpoints.UPLOAD,
metadata,
{ metadata, email },
)
return helpers.getBytes32FromIpfsHash(uploadedDataResponse.data.hash)
@ -76,7 +76,20 @@ class MetadataClient {
return formatedDappsMetadata
}
static async retrieveMetadataCache(metadataBytes32) {
static async getDappsCount() {
if (metadataCache === null)
metadataCache = await MetadataClient.retrieveAllDappsMetadata()
return Object.keys(metadataCache).length
}
static async retrieveMetadataCache() {
if (metadataCache === null)
metadataCache = await MetadataClient.retrieveAllDappsMetadata()
return metadataCache
}
static async retrieveDAppFromCache(metadataBytes32) {
if (metadataCache === null)
metadataCache = await MetadataClient.retrieveAllDappsMetadata()
const result = metadataCache[metadataBytes32]

View File

@ -64,6 +64,7 @@ const DappListItem = props => {
<img src={sntIcon} alt="SNT" width="16" height="16" />
{dapp.sntValue}
</span>
{dapp.sntValue > 0 && (
<div className={styles.voteTriggers}>
<span className={styles.vote} onClick={handleUpVote}>
<img src={upvoteArrowIcon} alt="" />
@ -74,6 +75,7 @@ const DappListItem = props => {
Downvote
</span>
</div>
)}
</div>
)}
</div>

View File

@ -7,6 +7,7 @@ export default class DappModel {
this.sntValue = 0
// metadata
this.email = ''
this.name = ''
this.image = ''
this.desc = ''

View File

@ -2,6 +2,7 @@ const submit = {
visible_submit: false,
visible_rating: false,
id: '',
email: '',
name: '',
desc: '',
url: '',

View File

@ -67,16 +67,14 @@ embarkJSConnectorWeb3.getNetworkId = function() {
EmbarkJS.Blockchain.registerProvider('web3', embarkJSConnectorWeb3)
EmbarkJS.Blockchain.setProvider('web3', {})
if (!global.__Web3) {
const web3ConnectionConfig = require('/Users/georgispasov/Development/LimeLabs/status/discover/src/embarkArtifacts/config/blockchain.json')
const web3ConnectionConfig = require('./config/blockchain.json')
EmbarkJS.Blockchain.connect(web3ConnectionConfig, err => {
if (err) {
console.error(err)
}
})
}
const namehash =
global.namehash ||
require('/Users/georgispasov/Development/LimeLabs/status/discover/src/embarkArtifacts/modules/eth-ens-namehash')
const namehash = global.namehash || require('./modules/eth-ens-namehash')
;('use strict')
/*global namehash*/

View File

@ -32,26 +32,16 @@ export const fetchAllDappsAction = () => {
}
const { transactionStatus } = state
let dappSource = await discoverService.getDAppByIndexWithMetadata(0)
if (dappSource !== null) {
const dappModel = DappModel.instanceFromBlockchainWithMetadata(
dappSource,
)
dappState = dappState.creditDapp(dappModel)
if (
dappModel.id !== transactionStatus.dappId ||
transactionStatus.type !== TYPE_SUBMIT
) {
dispatch(onUpdateDappsAction(dappState))
Database.creditDapp(dappModel)
}
}
for (let i = N - 1; i >= 1; i -= 1) {
dappSource = await discoverService.getDAppByIndexWithMetadata(i)
let dappSource = ''
const allDapps = await discoverService.getAllDappsWithMetadata()
for (let i = 0; i < allDapps.length; i++) {
dappSource = allDapps[i]
if (dappSource !== null) {
const dappModel = DappModel.instanceFromBlockchainWithMetadata(
dappSource,
)
dappState = dappState.creditDapp(dappModel)
if (
dappModel.id !== transactionStatus.dappId ||

View File

@ -18,6 +18,7 @@ import {
switchToRatingAction,
onInputSntValueAction,
updateAction,
onInputEmailAction,
} from './Submit.reducer'
import { showAlertAction } from '../Alert/Alert.reducer';
@ -25,6 +26,7 @@ const mapStateToProps = state =>
Object.assign(state.submit, { dappState: state.dapps })
const mapDispatchToProps = dispatch => ({
onClickClose: () => dispatch(closeSubmitAction()),
onInputEmail: name => dispatch(onInputEmailAction(name)),
onInputName: name => dispatch(onInputNameAction(name)),
onInputDesc: name => dispatch(onInputDescAction(name)),
onInputUrl: name => dispatch(onInputUrlAction(name)),

View File

@ -23,6 +23,7 @@ class Submit extends React.Component {
this.imgCanvas = React.createRef()
this.previousMoveX = 0
this.previousMoveY = 0
this.onInputEmail = this.onInputEmail.bind(this)
this.onInputName = this.onInputName.bind(this)
this.onInputDesc = this.onInputDesc.bind(this)
this.onInputUrl = this.onInputUrl.bind(this)
@ -71,6 +72,11 @@ class Submit extends React.Component {
imgNode.src = img
}
onInputEmail(e) {
const { onInputEmail } = this.props
onInputEmail(e.target.value)
}
onInputName(e) {
const { onInputName } = this.props
onInputName(e.target.value)
@ -169,6 +175,7 @@ class Submit extends React.Component {
onSubmit,
onUpdate,
id,
email,
name,
desc,
url,
@ -178,6 +185,7 @@ class Submit extends React.Component {
} = this.props
const metadata = {
email,
name,
url,
image: img,
@ -214,6 +222,8 @@ class Submit extends React.Component {
visible_submit,
visible_rating,
onClickClose,
email,
id,
name,
desc,
url,
@ -265,6 +275,19 @@ class Submit extends React.Component {
{visible_submit && (
<div className={imgControl ? styles.cntWithImgControl : ''}>
<div className={imgControl ? styles.withImgControl : ''}>
{id === '' && (
<div className={styles.block}>
<div className={styles.labelRow}>
<span>Your eMail</span>
</div>
<input
className={styles.input}
placeholder="eMail"
value={email}
onChange={this.onInputEmail}
/>
</div>
)}
<div className={styles.block}>
<div className={styles.labelRow}>
<span>Name of your Ðapp</span>
@ -473,6 +496,7 @@ class Submit extends React.Component {
Submit.propTypes = {
visible_submit: PropTypes.bool.isRequired,
visible_rating: PropTypes.bool.isRequired,
email: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
desc: PropTypes.string.isRequired,
url: PropTypes.string.isRequired,
@ -485,6 +509,7 @@ Submit.propTypes = {
imgControlY: PropTypes.number.isRequired,
sntValue: PropTypes.string.isRequired,
onClickClose: PropTypes.func.isRequired,
onInputEmail: PropTypes.func.isRequired,
onInputName: PropTypes.func.isRequired,
onInputDesc: PropTypes.func.isRequired,
onInputUrl: PropTypes.func.isRequired,

View File

@ -16,6 +16,7 @@ import BlockchainSDK from '../../common/blockchain'
const SHOW_SUBMIT_AFTER_CHECK = 'SUBMIT_SHOW_SUBMIT_AFTER_CHECK'
const CLOSE_SUBMIT = 'SUBMIT_CLOSE_SUBMIT'
const ON_INPUT_EMAIL = 'SUBMIT_ON_INPUT_EMAIL'
const ON_INPUT_NAME = 'SUBMIT_ON_INPUT_NAME'
const ON_INPUT_DESC = 'SUBMIT_ON_INPUT_DESC'
const ON_INPUT_URL = 'SUBMIT_ON_INPUT_URL'
@ -81,6 +82,11 @@ export const closeSubmitAction = () => {
}
}
export const onInputEmailAction = email => ({
type: ON_INPUT_EMAIL,
payload: email,
})
export const onInputNameAction = name => ({
type: ON_INPUT_NAME,
payload: name,
@ -144,14 +150,18 @@ export const submitAction = (dapp, sntValue) => {
)
try {
const blockchain = await BlockchainSDK.getInstance()
const { tx, id } = await blockchain.DiscoverService.createDApp(sntValue, {
const { tx, id } = await blockchain.DiscoverService.createDApp(
sntValue,
{
name: dapp.name,
url: dapp.url,
description: dapp.description,
category: dapp.category,
image: dapp.image,
dateAdded: dapp.dateAdded,
})
},
dapp.email,
)
dispatch(onReceiveTransactionInfoAction(id, tx))
dispatch(checkTransactionStatusAction(tx))
} catch (e) {
@ -199,6 +209,7 @@ const showSubmitAfterCheck = (state, dapp) => {
visible_submit: true,
visible_rating: false,
id: dapp !== undefined ? dapp.id : '',
email: dapp !== undefined ? dapp.email : '',
name: dapp !== undefined ? dapp.name : '',
desc: dapp !== undefined ? dapp.description : '',
url: dapp !== undefined ? dapp.url : '',
@ -219,6 +230,12 @@ const closeSubmit = state => {
})
}
const onInputEmail = (state, email) => {
return Object.assign({}, state, {
email,
})
}
const onInputName = (state, name) => {
return Object.assign({}, state, {
name,
@ -303,6 +320,7 @@ const onInputSntValue = (state, sntValue) => {
const map = {
[SHOW_SUBMIT_AFTER_CHECK]: showSubmitAfterCheck,
[CLOSE_SUBMIT]: closeSubmit,
[ON_INPUT_EMAIL]: onInputEmail,
[ON_INPUT_NAME]: onInputName,
[ON_INPUT_DESC]: onInputDesc,
[ON_INPUT_URL]: onInputUrl,