mirror of
https://github.com/status-im/discover-dapps.git
synced 2025-03-03 19:40:50 +00:00
Add IPFS data uploading
This commit is contained in:
parent
a26091f59e
commit
c3920055bb
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,5 +1,6 @@
|
||||
.embark
|
||||
chains.json
|
||||
config/development/mnemonic
|
||||
config/livenet/password
|
||||
config/production/password
|
||||
coverage
|
||||
|
@ -29,11 +29,6 @@ module.exports = {
|
||||
// Below are additional accounts that will count as `nodeAccounts` in the `deployment` section of your contract config
|
||||
// Those will not be unlocked in the node itself
|
||||
// {
|
||||
// privateKey:
|
||||
// '0xEFA9DB87A755C9D2B96F77BBCB9EF06CBDDFC01DB1A5129CE2649F73E9C2739C',
|
||||
// balance: '100 ether',
|
||||
// },
|
||||
// {
|
||||
// privateKeyFile: 'path/to/file', // Either a keystore or a list of keys, separated by , or ;
|
||||
// password: 'passwordForTheKeystore', // Needed to decrypt the keystore file
|
||||
// },
|
||||
|
@ -1,3 +1,5 @@
|
||||
const wallet = require('./development/mnemonic')
|
||||
|
||||
module.exports = {
|
||||
// default applies to all environments
|
||||
default: {
|
||||
@ -31,9 +33,8 @@ module.exports = {
|
||||
|
||||
accounts: [
|
||||
{
|
||||
privateKey:
|
||||
'0xEFA9DB87A755C9D2B96F77BBCB9EF06CBDDFC01DB1A5129CE2649F73E9C2739C',
|
||||
balance: '100 ether',
|
||||
mnemonic: wallet.mnemonic,
|
||||
balance: '1534983463450 ether',
|
||||
},
|
||||
],
|
||||
},
|
||||
@ -72,7 +73,6 @@ module.exports = {
|
||||
TestBancorFormula: { deploy: false },
|
||||
MiniMeTokenFactory: {},
|
||||
SNT: {
|
||||
from: '0x68C864373C6631984B646453138557A81224ACf6',
|
||||
instanceOf: 'MiniMeToken',
|
||||
args: [
|
||||
'$MiniMeTokenFactory',
|
||||
@ -85,7 +85,6 @@ module.exports = {
|
||||
],
|
||||
},
|
||||
Discover: {
|
||||
from: '0x68C864373C6631984B646453138557A81224ACf6',
|
||||
args: ['$SNT'],
|
||||
},
|
||||
},
|
||||
|
2
config/development/mnemonic.js
Normal file
2
config/development/mnemonic.js
Normal file
@ -0,0 +1,2 @@
|
||||
module.exports.mnemonic =
|
||||
'artefact rebuild liquid honey sport clean candy motor cereal job gap series'
|
@ -237,6 +237,15 @@ contract Discover is ApproveAndCallFallBack, BancorFormula {
|
||||
return (mEBalance.sub(d.effectiveBalance));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @dev Used in UI in order to fetch all dapps
|
||||
* @return dapps count
|
||||
*/
|
||||
function getDAppsCount() external view returns(uint) {
|
||||
return dapps.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Downvotes always remove 1% of the current ranking.
|
||||
* @param _id bytes32 unique identifier.
|
||||
|
@ -1,24 +0,0 @@
|
||||
import EmbarkJS from '../../embarkArtifacts/embarkjs'
|
||||
|
||||
class BlockchainService {
|
||||
constructor(sharedContext, contractAddress, Validator) {
|
||||
this.contract = contractAddress
|
||||
this.sharedContext = sharedContext
|
||||
this.validator = new Validator(this)
|
||||
}
|
||||
|
||||
async __unlockServiceAccount() {
|
||||
try {
|
||||
const accounts = await EmbarkJS.Blockchain.Providers.web3.getAccounts()
|
||||
if (accounts.length > 0) {
|
||||
this.sharedContext.account = accounts[0]
|
||||
}
|
||||
|
||||
this.sharedContext.account = (await EmbarkJS.enableEthereum())[0]
|
||||
} catch (error) {
|
||||
throw new Error('Could not unlock an account or web3 is missing')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default BlockchainService
|
@ -1,8 +1,13 @@
|
||||
import SNTService from './snt-services/snt-service'
|
||||
import DiscoverService from './discover-services/discover-service'
|
||||
import utils from './utils'
|
||||
import SNTService from './sdk/snt-services/snt-service'
|
||||
import DiscoverService from './sdk/discover-services/discover-service'
|
||||
|
||||
const init = async function() {
|
||||
import BlockchainConfig from './sdk/config'
|
||||
|
||||
const init = function() {
|
||||
try {
|
||||
BlockchainConfig()
|
||||
|
||||
const sharedContext = {
|
||||
account: '',
|
||||
}
|
||||
@ -13,10 +18,11 @@ const init = async function() {
|
||||
return {
|
||||
SNTService: sharedContext.SNTService,
|
||||
DiscoverService: sharedContext.DiscoverService,
|
||||
utils,
|
||||
}
|
||||
} catch (error) {
|
||||
throw new Error(error.message)
|
||||
}
|
||||
}
|
||||
|
||||
export default { init }
|
||||
export default { init, utils }
|
||||
|
11
src/common/blockchain/ipfs/helpers.js
Normal file
11
src/common/blockchain/ipfs/helpers.js
Normal file
@ -0,0 +1,11 @@
|
||||
export const base64ToBlob = base64Text => {
|
||||
const byteString = atob(base64Text.split(',')[1])
|
||||
|
||||
const arrayBuffer = new ArrayBuffer(byteString.length)
|
||||
const uintArray = new Uint8Array(arrayBuffer)
|
||||
for (let i = 0; i < byteString.length; i++) {
|
||||
uintArray[i] = byteString.charCodeAt(i)
|
||||
}
|
||||
|
||||
return new Blob([arrayBuffer])
|
||||
}
|
50
src/common/blockchain/ipfs/index.js
Normal file
50
src/common/blockchain/ipfs/index.js
Normal file
@ -0,0 +1,50 @@
|
||||
import { base64ToBlob } from './helpers'
|
||||
|
||||
// Todo: EmbarkJS -> setup it in init
|
||||
// Todo: Should check for isAvailable
|
||||
import EmbarkJS from '../../../embarkArtifacts/embarkjs'
|
||||
|
||||
EmbarkJS.Storage.setProvider('ipfs')
|
||||
|
||||
export const uploadMetadata = async metadata => {
|
||||
try {
|
||||
const hash = await EmbarkJS.Storage.saveText(metadata)
|
||||
return hash
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Uploading DApp metadata to IPFS failed. Details: ${error.message}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Todo: should convert base64 image into binary data in order to upload it on IPFS
|
||||
export const uploadImage = async base64Image => {
|
||||
try {
|
||||
const imageFile = [
|
||||
{
|
||||
files: [base64ToBlob(base64Image)],
|
||||
},
|
||||
]
|
||||
const hash = await EmbarkJS.Storage.uploadFile(imageFile)
|
||||
return hash
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Uploading DApp image to IPFS failed. Details: ${error.message}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export const retrieveMetadata = async metadataHash => {
|
||||
try {
|
||||
const metadata = await EmbarkJS.Storage.get(metadataHash)
|
||||
return metadata
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Fetching metadata from IPFS failed. Details: ${error.message}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export const retrieveImageUrl = async imageHash => {
|
||||
return EmbarkJS.Storage.getUrl(imageHash)
|
||||
}
|
31
src/common/blockchain/sdk/blockchain-service.js
Normal file
31
src/common/blockchain/sdk/blockchain-service.js
Normal file
@ -0,0 +1,31 @@
|
||||
import EmbarkJS from '../../../embarkArtifacts/embarkjs'
|
||||
|
||||
class BlockchainService {
|
||||
constructor(sharedContext, contract, Validator) {
|
||||
this.contract = contract.address
|
||||
contract.setProvider(global.web3.currentProvider)
|
||||
|
||||
this.sharedContext = sharedContext
|
||||
this.validator = new Validator(this)
|
||||
}
|
||||
|
||||
async __unlockServiceAccount() {
|
||||
const accounts = await EmbarkJS.Blockchain.Providers.web3.getAccounts()
|
||||
// if (accounts.length > 0) {
|
||||
this.sharedContext.account = accounts[0]
|
||||
// } else {
|
||||
// const provider = global.web3.currentProvider
|
||||
// Check for undefined
|
||||
// console.log(await global.web3.eth.getAccounts())
|
||||
// const accounts = await EmbarkJS.enableEthereum()
|
||||
// if (accounts) {
|
||||
// this.sharedContext.account = accounts[0]
|
||||
// }
|
||||
// global.web3.setProvider(provider)
|
||||
// }
|
||||
|
||||
// throw new Error('Could not unlock an account or web3 is missing')
|
||||
}
|
||||
}
|
||||
|
||||
export default BlockchainService
|
8
src/common/blockchain/sdk/config.js
Normal file
8
src/common/blockchain/sdk/config.js
Normal file
@ -0,0 +1,8 @@
|
||||
import Web3 from '../../../embarkArtifacts/modules/web3'
|
||||
|
||||
// Should be moved to .env
|
||||
const RPC_URL = 'http://localhost:8545'
|
||||
|
||||
export default function() {
|
||||
global.web3 = new Web3(new Web3.providers.HttpProvider(RPC_URL))
|
||||
}
|
@ -1,19 +1,17 @@
|
||||
import broadcastContractFn from '../helpers'
|
||||
|
||||
import * as ipfsSDK from '../../ipfs'
|
||||
import BlockchainService from '../blockchain-service'
|
||||
|
||||
import DiscoverValidator from './discover-validator'
|
||||
import DiscoverContract from '../../../embarkArtifacts/contracts/Discover'
|
||||
|
||||
// TODO: Validators ? - YUP
|
||||
// TODO: check for unlocked account: If it is not -> request unlocking - YUP
|
||||
// TODO: Make transfer failed an Error object ?
|
||||
import DiscoverContract from '../../../../embarkArtifacts/contracts/Discover'
|
||||
|
||||
class DiscoverService extends BlockchainService {
|
||||
constructor(sharedContext) {
|
||||
super(sharedContext, DiscoverContract.address, DiscoverValidator)
|
||||
super(sharedContext, DiscoverContract, DiscoverValidator)
|
||||
}
|
||||
|
||||
// TODO: Amount -> string/bigInt/number ?
|
||||
// TODO: Maybe we can get id from a DApp name ?
|
||||
// TODO: formatBigNumberToNumber
|
||||
|
||||
// View methods
|
||||
@ -31,6 +29,16 @@ class DiscoverService extends BlockchainService {
|
||||
return DiscoverContract.methods.upvoteEffect(id).call()
|
||||
}
|
||||
|
||||
// Todo: Should be implemented
|
||||
// async getDApps() {
|
||||
// const dapps = []
|
||||
// const dappsCount = await DiscoverContract.methods.getDAppsCount().call()
|
||||
|
||||
// for (let i = 0; i < dappsCount; i++) {
|
||||
// const dapp = await DiscoverContract.methods.dapps(i).call()
|
||||
// }
|
||||
// }
|
||||
|
||||
async getDAppById(id) {
|
||||
try {
|
||||
const dappId = await DiscoverContract.methods.id2index(id).call()
|
||||
@ -51,14 +59,22 @@ class DiscoverService extends BlockchainService {
|
||||
}
|
||||
|
||||
// Transaction methods
|
||||
async createDApp(id, amount, metadata) {
|
||||
await this.validator.validateDAppCreation(id, amount)
|
||||
async createDApp(amount, metadata) {
|
||||
const dappMetadata = JSON.parse(JSON.stringify(metadata))
|
||||
const dappId = global.web3.keccak256(JSON.stringify(dappMetadata))
|
||||
|
||||
await this.validator.validateDAppCreation(dappId, amount)
|
||||
|
||||
dappMetadata.image = await ipfsSDK.uploadImage(dappMetadata.image)
|
||||
const metadataHash = await ipfsSDK.uploadMetadata(
|
||||
JSON.stringify(dappMetadata),
|
||||
)
|
||||
|
||||
const callData = DiscoverContract.methods
|
||||
.createDApp(id, amount, metadata)
|
||||
.createDApp(dappId, amount, metadataHash)
|
||||
.encodeABI()
|
||||
|
||||
await this.sharedContext.SNTService.approveAndCall(
|
||||
return this.sharedContext.SNTService.approveAndCall(
|
||||
this.contract,
|
||||
amount,
|
||||
callData,
|
||||
@ -69,7 +85,7 @@ class DiscoverService extends BlockchainService {
|
||||
await this.validator.validateUpVoting(id, amount)
|
||||
|
||||
const callData = DiscoverContract.methods.upvote(id, amount).encodeABI()
|
||||
await this.sharedContext.SNTService.approveAndCall(
|
||||
return this.sharedContext.SNTService.approveAndCall(
|
||||
this.contract,
|
||||
amount,
|
||||
callData,
|
||||
@ -80,7 +96,7 @@ class DiscoverService extends BlockchainService {
|
||||
await this.validator.validateDownVoting(id, amount)
|
||||
|
||||
const callData = DiscoverContract.methods.downvote(id, amount).encodeABI()
|
||||
await this.sharedContext.SNTService.approveAndCall(
|
||||
return this.sharedContext.SNTService.approveAndCall(
|
||||
this.contract,
|
||||
amount,
|
||||
callData,
|
||||
@ -88,25 +104,32 @@ class DiscoverService extends BlockchainService {
|
||||
}
|
||||
|
||||
async withdraw(id, amount) {
|
||||
await super.__unlockServiceAccount(this.service)
|
||||
await super.__unlockServiceAccount()
|
||||
await this.validator.validateWithdrawing(id, amount)
|
||||
|
||||
try {
|
||||
await DiscoverContract.methods
|
||||
.withdraw(id, amount)
|
||||
.send({ from: this.sharedContext.account })
|
||||
return broadcastContractFn(
|
||||
DiscoverContract.methods.withdraw(id, amount).send,
|
||||
this.sharedContext.account,
|
||||
)
|
||||
} catch (error) {
|
||||
throw new Error('Transfer on withdraw failed')
|
||||
throw new Error(`Transfer on withdraw failed. Details: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
// Todo: Should we upload the metadata to IPFS
|
||||
async setMetadata(id, metadata) {
|
||||
await super.__unlockServiceAccount(this.service)
|
||||
await super.__unlockServiceAccount()
|
||||
await this.validator.validateMetadataSet(id)
|
||||
|
||||
await DiscoverContract.methods
|
||||
.setMetadata(id, metadata)
|
||||
.send({ from: this.sharedContext.account })
|
||||
try {
|
||||
return broadcastContractFn(
|
||||
DiscoverContract.methods.setMetadata(id, metadata).send,
|
||||
this.sharedContext.account,
|
||||
)
|
||||
} catch (error) {
|
||||
throw new Error(`Uploading metadata failed. Details: ${error.message}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
9
src/common/blockchain/sdk/helpers.js
Normal file
9
src/common/blockchain/sdk/helpers.js
Normal file
@ -0,0 +1,9 @@
|
||||
export default {
|
||||
broadcastContractFn: (contractMethod, account) => {
|
||||
return new Promise(resolve => {
|
||||
contractMethod({ from: account }).on('transactionHash', hash => {
|
||||
resolve(hash)
|
||||
})
|
||||
})
|
||||
},
|
||||
}
|
@ -1,11 +1,13 @@
|
||||
import broadcastContractFn from '../helpers'
|
||||
|
||||
import BlockchainService from '../blockchain-service'
|
||||
|
||||
import SNTValidator from './snt-validator'
|
||||
import SNTToken from '../../../embarkArtifacts/contracts/SNT'
|
||||
import SNTToken from '../../../../embarkArtifacts/contracts/SNT'
|
||||
|
||||
class SNTService extends BlockchainService {
|
||||
constructor(sharedContext) {
|
||||
super(sharedContext, SNTToken.address, SNTValidator)
|
||||
super(sharedContext, SNTToken, SNTValidator)
|
||||
}
|
||||
|
||||
async allowance(from, to) {
|
||||
@ -25,21 +27,22 @@ class SNTService extends BlockchainService {
|
||||
}
|
||||
|
||||
async approveAndCall(spender, amount, callData) {
|
||||
await super.__unlockServiceAccount(this.service)
|
||||
await super.__unlockServiceAccount()
|
||||
await this.validator.validateApproveAndCall(spender, amount)
|
||||
|
||||
await SNTToken.methods
|
||||
.approveAndCall(spender, amount, callData)
|
||||
.send({ from: this.sharedContext.account })
|
||||
return broadcastContractFn(
|
||||
SNTToken.methods.approveAndCall(spender, amount, callData).send,
|
||||
this.sharedContext.account,
|
||||
)
|
||||
}
|
||||
|
||||
// This is for testing purpose only
|
||||
async generateTokens() {
|
||||
await super.__unlockServiceAccount(this.service)
|
||||
await super.__unlockServiceAccount()
|
||||
|
||||
await SNTToken.methods
|
||||
.generateTokens(this.sharedContext.account, 10000)
|
||||
.send()
|
||||
.send({ from: this.sharedContext.account })
|
||||
}
|
||||
}
|
||||
|
18
src/common/blockchain/utils.js
Normal file
18
src/common/blockchain/utils.js
Normal file
@ -0,0 +1,18 @@
|
||||
const TRANSACTION_STATUSES = {
|
||||
Failed: 0,
|
||||
Successful: 1,
|
||||
Pending: 2,
|
||||
}
|
||||
|
||||
export default {
|
||||
getTxStatus: async txHash => {
|
||||
const txReceipt = await global.web3.eth.getTransactionReceipt(txHash)
|
||||
if (txReceipt) {
|
||||
return txReceipt.status
|
||||
? TRANSACTION_STATUSES.Successful
|
||||
: TRANSACTION_STATUSES.Failed
|
||||
}
|
||||
|
||||
return TRANSACTION_STATUSES.Pending
|
||||
},
|
||||
}
|
@ -3,17 +3,21 @@ import BlockchainSDK from '../../common/blockchain'
|
||||
|
||||
class Example extends React.Component {
|
||||
async logDiscoverMethod() {
|
||||
const services = await BlockchainSDK.init()
|
||||
|
||||
console.log(await services.SNTService.controller())
|
||||
// const services = await BlockchainSDK.init()
|
||||
// console.log(await services.SNTService.controller())
|
||||
// await services.SNTService.generateTokens()
|
||||
// await services.DiscoverService.createDApp('0x2', 10000, '0x2')
|
||||
// console.log(await services.DiscoverService.getDAppById('0x2'))
|
||||
}
|
||||
|
||||
render() {
|
||||
return <h1 onLoad={this.logDiscoverMethod()} />
|
||||
return (
|
||||
<div>
|
||||
<h1 onLoad={this.logDiscoverMethod()} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Example
|
||||
// QmZGzoAEEZoFP9jYXoVfhkDqXHxVrFCSMxSU8eGQpcDNHw
|
||||
|
Loading…
x
Reference in New Issue
Block a user