Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update marketplace to single output #987

Merged
merged 4 commits into from
May 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions systemservices/marketplace/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion systemservices/marketplace/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"bignumber.js": "^8.1.1",
"ipfs-http-client": "^30.1.3",
"jsonschema": "^1.2.4",
"mesg-js": "github:mesg-foundation/mesg-js#next",
"mesg-js": "^3.0.0-beta.0",
"request": "^2.88.0",
"request-promise-native": "^1.0.7",
"web3": "1.0.0-beta.37"
Expand Down
32 changes: 13 additions & 19 deletions systemservices/marketplace/src/tasks/getService.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,23 @@
import { TaskInputs, TaskOutputs } from "mesg-js/lib/service"
import { TaskInputs } from "mesg-js/lib/service"
import { Marketplace } from "../contracts/Marketplace"
import { getService } from "../contracts/service";
import { getManifest } from "../contracts/manifest";
import { getServiceVersions } from "../contracts/version";
import { getServiceOffers } from "../contracts/offer";
import { getServicePurchases } from "../contracts/purchase";

export default (contract: Marketplace) => async (inputs: TaskInputs, outputs: TaskOutputs): Promise<void> => {
try {
const [ service, versions, offers, purchases ] = await Promise.all([
getService(contract, inputs.sid),
getServiceVersionWithManifest(contract, inputs.sid),
getServiceOffers(contract, inputs.sid),
getServicePurchases(contract, inputs.sid),
])
return outputs.success({
...service,
offers,
purchases,
versions,
})
}
catch (error) {
console.error('error in getService', error)
return outputs.error({ message: error.message })
export default (contract: Marketplace) => async (inputs: TaskInputs): Promise<object> => {
const [service, versions, offers, purchases] = await Promise.all([
getService(contract, inputs.sid),
getServiceVersionWithManifest(contract, inputs.sid),
getServiceOffers(contract, inputs.sid),
getServicePurchases(contract, inputs.sid),
])
return {
...service,
offers,
purchases,
versions,
}
}

Expand Down
8 changes: 4 additions & 4 deletions systemservices/marketplace/src/tasks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ export default (
publishCreateServiceOffer: publishCreateServiceOffer(web3, marketplace),
isAuthorized: isAuthorized(marketplace),
})
.on('error', error => {
console.error('catch listenTask', error)
process.exit(1)
})
.on('error', error => {
console.error('catch listenTask', error)
process.exit(1)
})
}
100 changes: 47 additions & 53 deletions systemservices/marketplace/src/tasks/isAuthorized.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { TaskInputs, TaskOutputs } from "mesg-js/lib/service"
import { TaskInputs } from "mesg-js/lib/service"
import { Marketplace } from "../contracts/Marketplace"
import { getServiceVersion } from "../contracts/version";
import { hexToString, stringToHex, hashToHex, hexToHash } from "../contracts/utils";
Expand All @@ -8,64 +8,58 @@ import { requireServiceExist } from "../contracts/service";

export default (
contract: Marketplace,
) => async (inputs: TaskInputs, outputs: TaskOutputs): Promise<void> => {
try {
let sid = ""
let versionHash = ""
if (inputs.versionHash) {
versionHash = inputs.versionHash
// get service from version hash
const sidHash = await contract.methods.versionHashToService(hashToHex(versionHash)).call()
if (Number(sidHash) === 0) {
throw new Error('service with hash ' + versionHash + ' does not exist')
}
const service = await contract.methods.services(sidHash).call()
sid = hexToString(service.sid)
) => async (inputs: TaskInputs): Promise<object> => {
let sid = ""
let versionHash = ""
if (inputs.versionHash) {
versionHash = inputs.versionHash
// get service from version hash
const sidHash = await contract.methods.versionHashToService(hashToHex(versionHash)).call()
if (Number(sidHash) === 0) {
throw new Error('service with hash ' + versionHash + ' does not exist')
}
else if (inputs.sid) {
// get version hash from sid
sid = inputs.sid
const versionsLength = new BigNumber(await contract.methods.serviceVersionsLength(stringToHex(sid)).call())
if (versionsLength.isEqualTo(0)) {
throw new Error('service with sid ' + sid + ' does not have any version')
}
versionHash = hexToHash(await contract.methods.serviceVersionHash(stringToHex(sid), versionsLength.minus(1).toString()).call())
}
else {
throw new Error('input should have sid or hash set')
const service = await contract.methods.services(sidHash).call()
sid = hexToString(service.sid)
}
else if (inputs.sid) {
// get version hash from sid
sid = inputs.sid
const versionsLength = new BigNumber(await contract.methods.serviceVersionsLength(stringToHex(sid)).call())
if (versionsLength.isEqualTo(0)) {
throw new Error('service with sid ' + sid + ' does not have any version')
}
versionHash = hexToHash(await contract.methods.serviceVersionHash(stringToHex(sid), versionsLength.minus(1).toString()).call())
}
else {
throw new Error('input should have sid or hash set')
}

await requireServiceExist(contract, sid)

// Hack to allow user with no address to have access to services with free offers
const addresses = inputs.addresses.length > 0
? [...inputs.addresses]
: ['0x0000000000000000000000000000000000000000'] // Service with free offer will always return true for whatever address
await requireServiceExist(contract, sid)

// check if at least one of the provided addresses is authorized
const authorizations = await Promise.all(addresses.map((address: string) => {
return contract.methods.isAuthorized(stringToHex(sid), address).call()
}) as Promise<boolean>[])
const authorized = authorizations.reduce((p, c) => p || c, false)
if (!authorized) {
return outputs.success({
authorized,
sid: sid,
})
}
// Hack to allow user with no address to have access to services with free offers
const addresses = inputs.addresses.length > 0
? [...inputs.addresses]
: ['0x0000000000000000000000000000000000000000'] // Service with free offer will always return true for whatever address

// get version's manifest data
const version = await getServiceVersion(contract, versionHash)
const manifest = await getManifest(version.manifestProtocol, version.manifest)
return outputs.success({
authorized: authorized,
// check if at least one of the provided addresses is authorized
const authorizations = await Promise.all(addresses.map((address: string) => {
return contract.methods.isAuthorized(stringToHex(sid), address).call()
}) as Promise<boolean>[])
const authorized = authorizations.reduce((p, c) => p || c, false)
if (!authorized) {
return {
authorized,
sid: sid,
type: manifest.service.deployment.type,
source: manifest.service.deployment.source,
})
}
}
catch (error) {
console.error('error in isAuthorized', error)
return outputs.error({ message: error.message })

// get version's manifest data
const version = await getServiceVersion(contract, versionHash)
const manifest = await getManifest(version.manifestProtocol, version.manifest)
return {
authorized: authorized,
sid: sid,
type: manifest.service.deployment.type,
source: manifest.service.deployment.source,
}
}
14 changes: 4 additions & 10 deletions systemservices/marketplace/src/tasks/listServices.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
import { TaskInputs, TaskOutputs } from "mesg-js/lib/service"
import { TaskInputs } from "mesg-js/lib/service"
import { Marketplace } from "../contracts/Marketplace"
import { getAllServices } from "../contracts/service";

export default (contract: Marketplace) => async (inputs: TaskInputs, outputs: TaskOutputs): Promise<void> => {
try {
const services = await getAllServices(contract)
return outputs.success({ services })
}
catch (error) {
console.error('error in listServices', error)
return outputs.error({ message: error.message })
}
export default (contract: Marketplace) => async (inputs: TaskInputs): Promise<object> => {
const services = await getAllServices(contract)
return { services }
}
46 changes: 20 additions & 26 deletions systemservices/marketplace/src/tasks/prepareCreateServiceOffer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { TaskInputs, TaskOutputs } from "mesg-js/lib/service"
import { TaskInputs } from "mesg-js/lib/service"
import { Marketplace } from "../contracts/Marketplace"
import { toUnit, stringToHex, CreateTransaction } from "../contracts/utils";
import BigNumber from "bignumber.js";
Expand All @@ -9,33 +9,27 @@ import { getServiceVersionCount } from "../contracts/version";
export default (
marketplace: Marketplace,
createTransaction: CreateTransaction
) => async (inputs: TaskInputs, outputs: TaskOutputs): Promise<void> => {
try {
// check inputs
const sid = inputs.sid
const duration = new BigNumber(inputs.duration)
assert.ok(duration.isPositive() && !duration.isZero(), 'duration must be strictly positive')
) => async (inputs: TaskInputs): Promise<object> => {
// check inputs
const sid = inputs.sid
const duration = new BigNumber(inputs.duration)
assert.ok(duration.isPositive() && !duration.isZero(), 'duration must be strictly positive')

// check service
const service = await getService(marketplace, sid)
// check service
const service = await getService(marketplace, sid)

// check ownership
assert.strictEqual(inputs.from.toLowerCase(), service.owner.toLowerCase(), `service's owner is different`)
// check ownership
assert.strictEqual(inputs.from.toLowerCase(), service.owner.toLowerCase(), `service's owner is different`)

// check service version
const versionsLength = await getServiceVersionCount(marketplace, sid)
assert.ok(!versionsLength.isEqualTo(0), 'cannot create an offer on a service with no version')
// check service version
const versionsLength = await getServiceVersionCount(marketplace, sid)
assert.ok(!versionsLength.isEqualTo(0), 'cannot create an offer on a service with no version')

// create transaction
const transactionData = marketplace.methods.createServiceOffer(
stringToHex(sid),
toUnit(inputs.price),
duration.toString()
).encodeABI()
return outputs.success(await createTransaction(marketplace, inputs, transactionData))
}
catch (error) {
console.error('error in prepareCreateServiceOffer', error)
return outputs.error({ message: error.message })
}
// create transaction
const transactionData = marketplace.methods.createServiceOffer(
stringToHex(sid),
toUnit(inputs.price),
duration.toString()
).encodeABI()
return createTransaction(marketplace, inputs, transactionData)
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { TaskInputs, TaskOutputs } from "mesg-js/lib/service"
import { TaskInputs } from "mesg-js/lib/service"
import { Marketplace } from "../contracts/Marketplace"
import { stringToHex, CreateTransaction } from "../contracts/utils";
import { Manifest } from "../types/manifest";
Expand All @@ -12,50 +12,44 @@ const manifestProtocol = 'ipfs'
export default (
marketplace: Marketplace,
createTransaction: CreateTransaction
) => async (inputs: TaskInputs, outputs: TaskOutputs): Promise<void> => {
try {
// check inputs
const sid = inputs.service.definition.sid
assert.ok(sid.length >= 1 && sid.length <= 63, 'sid\'s length must be 1 at min and 63 at max') // See Core service validation (https://github.com/mesg-foundation/core)
assert.ok(isDomainName(sid), 'sid must respect domain-style notation, eg author.name')

if(await isServiceExist(marketplace, sid)) {
// get service
const service = await getService(marketplace, sid)

// check ownership
assert.strictEqual(inputs.from.toLowerCase(), service.owner.toLowerCase(), `service's owner is different`)
}

// upload manifest
const manifestHash = await uploadManifest({
version: '1',
service: inputs.service
})

// check if version already exist on marketplace
const versionHash = computeVersionHash(inputs.from, sid, manifestHash, manifestProtocol)
assert.ok(!(await isVersionExist(marketplace, versionHash)), `service version already exist`)

// create transaction
const transactionData = marketplace.methods.publishServiceVersion(
stringToHex(sid),
stringToHex(manifestHash),
stringToHex(manifestProtocol)
).encodeABI()
return outputs.success(await createTransaction(marketplace, inputs, transactionData))
}
catch (error) {
console.error('error in preparePublishServiceVersion', error)
return outputs.error({ message: error.message })
) => async (inputs: TaskInputs): Promise<object> => {
// check inputs
const sid = inputs.service.definition.sid
assert.ok(sid.length >= 1 && sid.length <= 63, 'sid\'s length must be 1 at min and 63 at max') // See Core service validation (https://github.com/mesg-foundation/core)
assert.ok(isDomainName(sid), 'sid must respect domain-style notation, eg author.name')

if (await isServiceExist(marketplace, sid)) {
// get service
const service = await getService(marketplace, sid)

// check ownership
assert.strictEqual(inputs.from.toLowerCase(), service.owner.toLowerCase(), `service's owner is different`)
}

// upload manifest
const manifestHash = await uploadManifest({
version: '1',
service: inputs.service
})

// check if version already exist on marketplace
const versionHash = computeVersionHash(inputs.from, sid, manifestHash, manifestProtocol)
assert.ok(!(await isVersionExist(marketplace, versionHash)), `service version already exist`)

// create transaction
const transactionData = marketplace.methods.publishServiceVersion(
stringToHex(sid),
stringToHex(manifestHash),
stringToHex(manifestProtocol)
).encodeABI()
return createTransaction(marketplace, inputs, transactionData)
}

const uploadManifest = async (manifest: Manifest): Promise<string> => {
const ipfsClient = require('ipfs-http-client')
const IPFS = ipfsClient(process.env.IPFS_PROVIDER)
const buffer = Buffer.from(JSON.stringify(manifest))
const res = await IPFS.add(buffer, {pin: false})
const res = await IPFS.add(buffer, { pin: false })
if (!res.length) {
throw new Error('error while uploading manifest')
}
Expand Down
Loading