mirror of
https://github.com/oceanprotocol-archive/squid-js.git
synced 2024-02-02 15:31:51 +01:00
added purchase functiuonality
This commit is contained in:
parent
9fb6f296f3
commit
5719a667ea
5
package-lock.json
generated
5
package-lock.json
generated
@ -4181,6 +4181,11 @@
|
||||
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
|
||||
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.2.0.tgz",
|
||||
"integrity": "sha512-OayFWziIxiHY8bCUyLX6sTpDH8Jsbp4FfYd1j1f7vZyfgkcOnAyM4oQR16f8a0s7Gl/viMGRey8eScYk4V4EZA=="
|
||||
},
|
||||
"node-libs-browser": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.1.0.tgz",
|
||||
|
@ -55,6 +55,7 @@
|
||||
"eth-ecies": "^1.0.3",
|
||||
"ethereumjs-util": "^5.2.0",
|
||||
"jsonwebtoken": "^8.3.0",
|
||||
"node-fetch": "^2.2.0",
|
||||
"web3": "1.0.0-beta.36",
|
||||
"web3-utils": "1.0.0-beta.36"
|
||||
},
|
||||
|
@ -1,5 +1,7 @@
|
||||
import {Receipt} from "web3-utils"
|
||||
import AccessStatus from "../models/AccessStatus"
|
||||
import Asset from "../ocean/Asset"
|
||||
import Order from "../ocean/Order"
|
||||
import ContractBaseWrapper from "./ContractWrapperBase"
|
||||
|
||||
export default class OceanAuth extends ContractBaseWrapper {
|
||||
@ -10,34 +12,36 @@ export default class OceanAuth extends ContractBaseWrapper {
|
||||
return auth
|
||||
}
|
||||
|
||||
public async getOrderStatus(orderId: string): Promise<number> {
|
||||
return this.contract.methods.statusOfAccessRequest(orderId)
|
||||
.call()
|
||||
.then((status: string) => parseInt(status, 10))
|
||||
}
|
||||
|
||||
public async cancelAccessRequest(orderId: string, senderAddress: string): Promise<Receipt> {
|
||||
return this.contract.methods.cancelAccessRequest(orderId)
|
||||
.send({
|
||||
from: senderAddress,
|
||||
public async getOrderStatus(orderId: string): Promise<AccessStatus> {
|
||||
return this.call("statusOfAccessRequest", [orderId])
|
||||
.then((status: string) => {
|
||||
const statusInt = parseInt(status, 10)
|
||||
const statusString = AccessStatus[statusInt]
|
||||
return AccessStatus[statusString]
|
||||
})
|
||||
}
|
||||
|
||||
public async getEncryptedAccessToken(orderId: string, senderAddress: string): Promise<Receipt> {
|
||||
return this.contract.methods.getEncryptedAccessToken(orderId)
|
||||
.send({
|
||||
from: senderAddress,
|
||||
})
|
||||
public async getEncryptedAccessToken(orderId: string, consumerAddress: string): Promise<Receipt> {
|
||||
return this.call("getEncryptedAccessToken", [orderId], consumerAddress)
|
||||
}
|
||||
|
||||
public async initiateAccessRequest(asset: Asset, publicKey: string,
|
||||
timeout: number, buyerAddress: string): Promise<Receipt> {
|
||||
|
||||
const args = [asset.getId(), asset.publisher.getId(), publicKey, timeout]
|
||||
return this.sendTransaction("initiateAccessRequest", buyerAddress, args)
|
||||
}
|
||||
|
||||
public async commitAccessRequest() {
|
||||
// todo
|
||||
public async commitAccessRequest(order: Order, publisherAddress: string) {
|
||||
const args = [order.getId(), true, 9999999999, "discovery", "read", "slaLink", "slaType"]
|
||||
return this.sendTransaction("commitAccessRequest", publisherAddress, args)
|
||||
}
|
||||
|
||||
public async getTempPubKey(orderId: string) {
|
||||
return this.call("getTempPubKey", [orderId])
|
||||
}
|
||||
|
||||
public async deliverAccessToken(orderId: string, accessToken: string, publisherAddress: string) {
|
||||
return this.sendTransaction("deliverAccessToken", publisherAddress, [orderId, accessToken])
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,7 +8,13 @@ const contracts: Map<string, Contract> = new Map<string, Contract>()
|
||||
export default class ContractHandler {
|
||||
|
||||
public static async get(what: string): Contract {
|
||||
return contracts.get(what) || await ContractHandler.load(what)
|
||||
const where = (await (await Keeper.getInstance()).getNetworkName()).toLowerCase()
|
||||
try {
|
||||
return contracts.get(what) || await ContractHandler.load(what, where)
|
||||
} catch (err) {
|
||||
Logger.error("Failed to load", what, "from", where, err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
public static async deployContracts() {
|
||||
@ -48,21 +54,21 @@ export default class ContractHandler {
|
||||
})
|
||||
}
|
||||
|
||||
private static async load(what: string): Promise<Contract> {
|
||||
private static async load(what: string, where: string): Promise<Contract> {
|
||||
const web3 = Web3Provider.getWeb3()
|
||||
const where = (await (await Keeper.getInstance()).getNetworkName()).toLowerCase()
|
||||
Logger.log("Loading", what, "from", where)
|
||||
try {
|
||||
const artifact = require(`@oceanprotocol/keeper-contracts/artifacts/${what}.${where}`)
|
||||
// Logger.log('Loaded artifact', artifact)
|
||||
// Logger.log("Getting instance of", what, "from", where, "at", artifact.address)
|
||||
const contract = new web3.eth.Contract(artifact.abi, artifact.address)
|
||||
Logger.log("Loaded", what, "from", where)
|
||||
contracts.set(what, contract)
|
||||
return contracts.get(what)
|
||||
} catch (err) {
|
||||
Logger.error("Failed to load", what, "from", where, err)
|
||||
// Logger.log("Loading", what, "from", where)
|
||||
const artifact = require(`@oceanprotocol/keeper-contracts/artifacts/${what}.${where}`)
|
||||
// Logger.log('Loaded artifact', artifact)
|
||||
const code = await web3.eth.getCode(artifact.address)
|
||||
if (code === "0x0") {
|
||||
// no code in the blockchain dude
|
||||
throw new Error(`No code deployed at address ${artifact.address}, sorry.`)
|
||||
}
|
||||
// Logger.log("Getting instance of", what, "from", where, "at", artifact.address)
|
||||
const contract = new web3.eth.Contract(artifact.abi, artifact.address)
|
||||
Logger.log("Loaded", what, "from", where)
|
||||
contracts.set(what, contract)
|
||||
return contracts.get(what)
|
||||
}
|
||||
|
||||
private static replaceTokens(bytecode: string, tokens: any[]) {
|
||||
|
@ -1,12 +1,13 @@
|
||||
import Event from "web3"
|
||||
import Contract from "web3-eth-contract"
|
||||
import Logger from "../utils/Logger"
|
||||
import ContractHandler from "./ContractHandler"
|
||||
|
||||
export default abstract class ContractWrapperBase {
|
||||
|
||||
protected static instance = null
|
||||
|
||||
protected contract: Contract = null
|
||||
private contract: Contract = null
|
||||
private contractName: string
|
||||
|
||||
constructor(contractName) {
|
||||
@ -46,14 +47,34 @@ export default abstract class ContractWrapperBase {
|
||||
if (!this.contract.methods[name]) {
|
||||
throw new Error(`Method ${name} is not part of contract ${this.contractName}`)
|
||||
}
|
||||
const tx = this.contract.methods[name](...args)
|
||||
const gas = await tx.estimateGas(args, {
|
||||
from,
|
||||
})
|
||||
return tx.send({
|
||||
from,
|
||||
gas,
|
||||
})
|
||||
try {
|
||||
const tx = this.contract.methods[name](...args)
|
||||
const gas = await tx.estimateGas(args, {
|
||||
from,
|
||||
})
|
||||
return tx.send({
|
||||
from,
|
||||
gas,
|
||||
})
|
||||
} catch (err) {
|
||||
const argString = JSON.stringify(args, null, 2)
|
||||
Logger.error(`Sending transaction ${name} on contract ${this.contractName} failed.`)
|
||||
Logger.error(`Args: ${argString} From: ${from}`)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
protected async call(name: string, args: any[], from?: string) {
|
||||
if (!this.contract.methods[name]) {
|
||||
throw new Error(`Method ${name} is not part of contract ${this.contractName}`)
|
||||
}
|
||||
try {
|
||||
const method = this.contract.methods[name](...args)
|
||||
return method.call(from ? {from} : null)
|
||||
} catch (err) {
|
||||
Logger.error(`Calling method ${name} on contract ${this.contractName} failed. Args: ${args}`, err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import BigNumber from "bignumber.js"
|
||||
import {Receipt} from "web3-utils"
|
||||
import ConfigProvider from "../ConfigProvider"
|
||||
import Order from "../ocean/Order"
|
||||
import ContractWrapperBase from "./ContractWrapperBase"
|
||||
|
||||
@ -14,50 +13,34 @@ export default class OceanMarket extends ContractWrapperBase {
|
||||
|
||||
// call functions (costs no gas)
|
||||
public async isAssetActive(assetId: string): Promise<boolean> {
|
||||
return this.contract.methods.checkAsset(assetId).call()
|
||||
return this.call("checkAsset", [assetId])
|
||||
}
|
||||
|
||||
public async verifyOrderPayment(orderId: string): Promise<boolean> {
|
||||
return this.contract.methods.verifyPaymentReceived(orderId).call()
|
||||
return this.call("verifyPaymentReceived", [orderId])
|
||||
}
|
||||
|
||||
public async getAssetPrice(assetId: string): Promise<number> {
|
||||
return this.contract.methods.getAssetPrice(assetId)
|
||||
.call()
|
||||
return this.call("getAssetPrice", [assetId])
|
||||
.then((price: string) => new BigNumber(price).toNumber())
|
||||
}
|
||||
|
||||
public async requestTokens(amount: number, receiverAddress: string): Promise<Receipt> {
|
||||
return this.contract.methods.requestTokens(amount)
|
||||
.send({
|
||||
from: receiverAddress,
|
||||
})
|
||||
return this.sendTransaction("requestTokens", receiverAddress, [amount])
|
||||
}
|
||||
|
||||
public async generateId(input: string): Promise<string> {
|
||||
return await this.contract.methods.generateId(input).call()
|
||||
return this.call("generateId", [input])
|
||||
}
|
||||
|
||||
public async register(assetId: string, price: number, publisherAddress: string): Promise<Receipt> {
|
||||
return await this.contract.methods.register(assetId, price)
|
||||
.send({
|
||||
from: publisherAddress,
|
||||
gas: ConfigProvider.getConfig().defaultGas,
|
||||
})
|
||||
return this.sendTransaction("register", publisherAddress, [assetId, price])
|
||||
}
|
||||
|
||||
public async payOrder(order: Order, payerAddreess: string): Promise<Receipt> {
|
||||
|
||||
const args = [
|
||||
order.getId(), order.getAsset().publisher.getId(),
|
||||
order.getAsset().price, order.getTimeout(),
|
||||
]
|
||||
|
||||
return this.sendTransaction("sendPayment", payerAddreess, args)
|
||||
}
|
||||
|
||||
public getAssetPublisher(assetId: string): Promise<string> {
|
||||
return this.contract.methods.getAssetPublisher(assetId)
|
||||
.call()
|
||||
public async payOrder(order: Order, publisherAddress: string,
|
||||
price: number, consumerAddress: string): Promise<Receipt> {
|
||||
return this.sendTransaction("sendPayment", consumerAddress, [
|
||||
order.getId(), publisherAddress, price, order.getTimeout(),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import BigNumber from "bignumber.js"
|
||||
import {Receipt} from "web3-utils"
|
||||
import ConfigProvider from "../ConfigProvider"
|
||||
import ContractBaseWrapper from "./ContractWrapperBase"
|
||||
|
||||
export default class OceanToken extends ContractBaseWrapper {
|
||||
@ -12,16 +11,11 @@ export default class OceanToken extends ContractBaseWrapper {
|
||||
}
|
||||
|
||||
public async approve(marketAddress: string, price: number, buyerAddress: string): Promise<Receipt> {
|
||||
return this.contract.methods.approve(marketAddress, price)
|
||||
.send({
|
||||
from: buyerAddress,
|
||||
gas: ConfigProvider.getConfig().defaultGas,
|
||||
})
|
||||
return this.sendTransaction("approve", buyerAddress, [marketAddress, price])
|
||||
}
|
||||
|
||||
public async balanceOf(address: string): Promise<number> {
|
||||
return this.contract.methods.balanceOf(address)
|
||||
.call()
|
||||
return this.call("balanceOf", [address])
|
||||
.then((balance: string) => new BigNumber(balance).toNumber())
|
||||
}
|
||||
}
|
||||
|
9
src/models/AccessStatus.ts
Normal file
9
src/models/AccessStatus.ts
Normal file
@ -0,0 +1,9 @@
|
||||
enum AccessStatus {
|
||||
Requested,
|
||||
Committed,
|
||||
Delivered,
|
||||
Verified,
|
||||
Revoked,
|
||||
}
|
||||
|
||||
export default AccessStatus
|
@ -1,5 +1,4 @@
|
||||
export default class Config {
|
||||
public defaultGas: number = 300000
|
||||
public providerUri: string
|
||||
public nodeUri: string
|
||||
public web3Provider: any
|
||||
|
@ -1,30 +1,17 @@
|
||||
import * as EthCrypto from "eth-crypto"
|
||||
import EthEcies from "eth-ecies"
|
||||
import * as EthEcies from "eth-ecies"
|
||||
import * as EthjsUtil from "ethereumjs-util"
|
||||
import JWT from "jsonwebtoken"
|
||||
import * as JWT from "jsonwebtoken"
|
||||
import Keeper from "../keeper/Keeper"
|
||||
import Web3Provider from "../keeper/Web3Provider"
|
||||
import ProviderProvider from "../provider/ProviderProvider"
|
||||
import Logger from "../utils/Logger"
|
||||
import Account from "./Account"
|
||||
import OceanBase from "./OceanBase"
|
||||
import Order from "./Order"
|
||||
|
||||
declare var fetch
|
||||
|
||||
export default class Asset extends OceanBase {
|
||||
|
||||
public static async load(assetId): Promise<Asset> {
|
||||
const {market} = await Keeper.getInstance()
|
||||
|
||||
const asset = new Asset("unknown", "unknown",
|
||||
await market.getAssetPrice(assetId),
|
||||
new Account(await market.getAssetPublisher(assetId)))
|
||||
|
||||
asset.setId(assetId)
|
||||
|
||||
return asset
|
||||
}
|
||||
|
||||
constructor(public name: string,
|
||||
public description: string,
|
||||
public price: number,
|
||||
@ -37,7 +24,7 @@ export default class Asset extends OceanBase {
|
||||
return market.isAssetActive(this.getId())
|
||||
}
|
||||
|
||||
public async purchase(account: Account, timeout: number): Promise<Order> {
|
||||
public async purchase(consumer: Account, timeout: number): Promise<Order> {
|
||||
const {token, market, auth} = await Keeper.getInstance()
|
||||
|
||||
const key = EthCrypto.createIdentity()
|
||||
@ -53,7 +40,7 @@ export default class Asset extends OceanBase {
|
||||
try {
|
||||
const marketAddr = market.getAddress()
|
||||
// Allow market contract to transfer funds on the consumer"s behalf
|
||||
await token.approve(marketAddr, price, account.getId())
|
||||
await token.approve(marketAddr, price, consumer.getId())
|
||||
Logger.log(`${price} tokens approved on market with id: ${marketAddr}`)
|
||||
} catch (err) {
|
||||
Logger.error("token.approve failed", err)
|
||||
@ -62,7 +49,7 @@ export default class Asset extends OceanBase {
|
||||
try {
|
||||
// Submit the access request
|
||||
const initiateAccessRequestReceipt = await auth.initiateAccessRequest(this,
|
||||
publicKey, timeout, account.getId())
|
||||
publicKey, timeout, consumer.getId())
|
||||
|
||||
const {returnValues} = initiateAccessRequestReceipt.events.AccessConsentRequested
|
||||
Logger.log(`Keeper AccessConsentRequested event received on asset: ${this.getId()}`)
|
||||
@ -73,91 +60,44 @@ export default class Asset extends OceanBase {
|
||||
}
|
||||
|
||||
return order
|
||||
if (false) {
|
||||
// todo: AccessRequestCommitted event is not emitted in this flow
|
||||
await auth.listenToEventOnce(
|
||||
"AccessRequestCommitted", {
|
||||
filter: {
|
||||
_id: order.getId(),
|
||||
},
|
||||
})
|
||||
.then((accessRequestCommittedResult) => {
|
||||
Logger.log("Got AccessRequestCommitted Event")
|
||||
|
||||
return order.pay(account)
|
||||
})
|
||||
.then((payAssetReceipt) => {
|
||||
return auth.listenToEventOnce(
|
||||
"EncryptedTokenPublished", {
|
||||
filter: {
|
||||
_id: order.getId(),
|
||||
},
|
||||
})
|
||||
})
|
||||
.then((encryptedTokenPublishedResult) => {
|
||||
Logger.log("Got EncryptedTokenPublished Event")
|
||||
|
||||
const {returnValues} = encryptedTokenPublishedResult
|
||||
|
||||
return this.finalizePurchaseAsset(
|
||||
returnValues._id, order, key, account,
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
public async finalizePurchaseAsset(accessId: string, order: Order, key: any, account: Account): Promise<Order> {
|
||||
public async consume(order: Order, consumer: Account): Promise<string> {
|
||||
const {auth} = await Keeper.getInstance()
|
||||
|
||||
const encryptedAccessToken = await auth.getEncryptedAccessToken(accessId, this.getId())
|
||||
const encryptedAccessToken = await auth.getEncryptedAccessToken(order.getId(), consumer.getId())
|
||||
|
||||
// grab the access token from acl contract
|
||||
const tokenNo0x = encryptedAccessToken.slice(2)
|
||||
const encryptedTokenBuffer = Buffer.from(tokenNo0x, "hex")
|
||||
|
||||
const privateKey = key.privateKey.slice(2)
|
||||
const accessTokenEncoded = EthEcies.Decrypt(Buffer.from(privateKey, "hex"), encryptedTokenBuffer)
|
||||
const privateKey = order.getKey().privateKey.slice(2)
|
||||
const accessTokenEncoded: string =
|
||||
EthEcies.decrypt(Buffer.from(privateKey, "hex"), encryptedTokenBuffer).toString()
|
||||
const accessToken = JWT.decode(accessTokenEncoded) // Returns a json object
|
||||
|
||||
// sign it
|
||||
const hexEncrToken = `0x${encryptedTokenBuffer.toString("hex")}`
|
||||
if (!accessToken) {
|
||||
throw new Error(`AccessToken is not an jwt: ${accessTokenEncoded}`)
|
||||
}
|
||||
|
||||
const signature = Web3Provider.getWeb3().eth.sign(account.getId(), hexEncrToken)
|
||||
const fixedMsgSha = Web3Provider.getWeb3().utils.sha3(encryptedAccessToken)
|
||||
const signature = Web3Provider.getWeb3().eth.sign(encryptedAccessToken, consumer.getId())
|
||||
const encryptedAccessTokenSha3 = Web3Provider.getWeb3().utils.sha3(encryptedAccessToken)
|
||||
|
||||
// Download the data set from the provider using the url in the access token
|
||||
// decode the access token, grab the service_endpoint, request_id,
|
||||
|
||||
// payload keys: ['consumerId', 'fixed_msg', 'sigEncJWT', 'jwt']
|
||||
const payload = JSON.stringify({
|
||||
consumerId: account.getId(),
|
||||
fixed_msg: fixedMsgSha,
|
||||
consumerId: consumer.getId(),
|
||||
fixed_msg: encryptedAccessTokenSha3,
|
||||
sigEncJWT: signature,
|
||||
jwt: accessTokenEncoded,
|
||||
})
|
||||
const accessUrl = await fetch(`${accessToken.service_endpoint}/${accessToken.resource_id}`, {
|
||||
method: "POST",
|
||||
body: payload,
|
||||
headers: {
|
||||
"Content-type": "application/json",
|
||||
},
|
||||
})
|
||||
.then((response: any) => {
|
||||
if (response.ok) {
|
||||
return response.text()
|
||||
}
|
||||
Logger.log("Failed: ", response.status, response.statusText)
|
||||
})
|
||||
.then((consumptionUrl: string) => {
|
||||
Logger.log("Success accessing consume endpoint: ", consumptionUrl)
|
||||
return consumptionUrl
|
||||
})
|
||||
.catch((error) => {
|
||||
Logger.error("Error fetching the data asset consumption url: ", error)
|
||||
})
|
||||
Logger.log("consume url: ", accessUrl)
|
||||
order.setAccessUrl(accessUrl)
|
||||
|
||||
return order
|
||||
const accessUrl = await ProviderProvider.getProvider().getAccessUrl(accessToken, payload)
|
||||
|
||||
Logger.log("consume url: ", accessUrl)
|
||||
|
||||
return accessUrl
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
import ConfigProvider from "../ConfigProvider"
|
||||
import Keeper from "../keeper/Keeper"
|
||||
import Web3Provider from "../keeper/Web3Provider"
|
||||
import Provider from "../provider/Provider"
|
||||
import ProviderProvider from "../provider/ProviderProvider"
|
||||
import Logger from "../utils/Logger"
|
||||
import Account from "./Account"
|
||||
import Asset from "./Asset"
|
||||
@ -12,6 +14,7 @@ export default class Ocean {
|
||||
|
||||
if (!Ocean.instance) {
|
||||
ConfigProvider.configure(config)
|
||||
ProviderProvider.setProvider(Provider)
|
||||
Ocean.instance = new Ocean(await Keeper.getInstance())
|
||||
}
|
||||
|
||||
@ -38,12 +41,16 @@ export default class Ocean {
|
||||
|
||||
// generate an id
|
||||
const assetId = await market.generateId(asset.name + asset.description)
|
||||
Logger.log(`Registering: ${assetId} with price ${asset.price}`)
|
||||
Logger.log(`Registering: ${assetId} with price ${asset.price} for ${asset.publisher.getId()}`)
|
||||
asset.setId(assetId)
|
||||
const isAssetActive = await market.isAssetActive(assetId)
|
||||
// register asset in the market
|
||||
const result = await market.register(asset.getId(), asset.price, asset.publisher.getId())
|
||||
Logger.log("Registered:", assetId, "in block", result.blockNumber)
|
||||
|
||||
if (!isAssetActive) {
|
||||
const result = await market.register(asset.getId(), asset.price, asset.publisher.getId())
|
||||
Logger.log("Registered:", assetId, "in block", result.blockNumber)
|
||||
} else {
|
||||
throw new Error("Asset already registered")
|
||||
}
|
||||
return assetId
|
||||
}
|
||||
|
||||
@ -68,12 +75,11 @@ export default class Ocean {
|
||||
const {returnValues} = event
|
||||
|
||||
const order: Order = new Order(
|
||||
await Asset.load(returnValues._resourceId),
|
||||
null,
|
||||
parseInt(returnValues._timeout, 10),
|
||||
null, null)
|
||||
|
||||
order.setId(returnValues._id)
|
||||
order.setStatus(await auth.getOrderStatus(returnValues._id))
|
||||
order.setPaid(await market.verifyOrderPayment(returnValues._id))
|
||||
|
||||
return order
|
||||
|
@ -1,4 +1,6 @@
|
||||
import * as EthEcies from "eth-ecies"
|
||||
import Keeper from "../keeper/Keeper"
|
||||
import AccessStatus from "../models/AccessStatus"
|
||||
import Logger from "../utils/Logger"
|
||||
import Account from "./Account"
|
||||
import Asset from "./Asset"
|
||||
@ -7,33 +9,15 @@ import OceanBase from "./OceanBase"
|
||||
export default class Order extends OceanBase {
|
||||
|
||||
private paid: boolean
|
||||
private status: number
|
||||
private accessUrl: string
|
||||
private accessId: string
|
||||
|
||||
constructor(private asset: Asset, private timeout: number,
|
||||
private pubkey: string, private key: any) {
|
||||
super()
|
||||
}
|
||||
|
||||
public setAccessUrl(url: string) {
|
||||
this.accessUrl = url
|
||||
}
|
||||
|
||||
public getAccessUrl() {
|
||||
return this.accessUrl
|
||||
}
|
||||
|
||||
public setStatus(status: number) {
|
||||
this.status = status
|
||||
}
|
||||
|
||||
public setAccessId(accessId: string) {
|
||||
this.accessId = accessId
|
||||
}
|
||||
|
||||
public getStatus() {
|
||||
return this.status
|
||||
public async getStatus(): Promise<AccessStatus> {
|
||||
const {auth} = await Keeper.getInstance()
|
||||
return auth.getOrderStatus(this.id)
|
||||
}
|
||||
|
||||
public setPaid(paid: boolean) {
|
||||
@ -44,14 +28,6 @@ export default class Order extends OceanBase {
|
||||
return this.paid
|
||||
}
|
||||
|
||||
public getAsset() {
|
||||
return this.asset
|
||||
}
|
||||
|
||||
public getPubkey() {
|
||||
return this.pubkey
|
||||
}
|
||||
|
||||
public getTimeout() {
|
||||
return this.timeout
|
||||
}
|
||||
@ -60,12 +36,34 @@ export default class Order extends OceanBase {
|
||||
return this.key
|
||||
}
|
||||
|
||||
public async pay(account: Account): Promise<string> {
|
||||
public async pay(consumer: Account): Promise<string> {
|
||||
const {market} = await Keeper.getInstance()
|
||||
Logger.log(`Sending payment: ${this.getId()} ${this.accessId}
|
||||
${this.asset.publisher.getId()} ${this.asset.price} ${this.timeout}`)
|
||||
const payReceipt = await market.payOrder(this, account.getId())
|
||||
Logger.log(
|
||||
`Sending payment: ${this.getId()} ${this.asset.publisher.getId()} ${this.asset.price} ${this.timeout}`,
|
||||
)
|
||||
const payReceipt = await market.payOrder(this, this.asset.publisher.getId(), this.asset.price, consumer.getId())
|
||||
|
||||
return payReceipt.events.PaymentReceived.returnValues._paymentId
|
||||
}
|
||||
|
||||
public async commit(accessToken: string) {
|
||||
const {auth} = await Keeper.getInstance()
|
||||
const commitAccessRequestReceipt = await auth.commitAccessRequest(this, this.asset.publisher.getId())
|
||||
if (commitAccessRequestReceipt.events.AccessRequestRejected) {
|
||||
|
||||
const {returnValues} = commitAccessRequestReceipt.events.AccessRequestRejected
|
||||
throw new Error(`commitAccessRequest failed ${JSON.stringify(returnValues, null, 2)}`)
|
||||
}
|
||||
|
||||
const pubKey = await auth.getTempPubKey(this.getId())
|
||||
|
||||
if (this.pubkey !== pubKey) {
|
||||
throw new Error("Pubkey missmatch")
|
||||
}
|
||||
|
||||
const encryptedAccessToken =
|
||||
EthEcies.encrypt(new Buffer(pubKey, "hex"), new Buffer(accessToken)).toString("hex")
|
||||
|
||||
await auth.deliverAccessToken(this.getId(), `0x${encryptedAccessToken}`, this.asset.publisher.getId())
|
||||
}
|
||||
}
|
||||
|
30
src/provider/Provider.ts
Normal file
30
src/provider/Provider.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import fetch from "node-fetch"
|
||||
import Logger from "../utils/Logger"
|
||||
|
||||
export default class Provider {
|
||||
public static async getAccessUrl(accessToken: any, payload: any): Promise<string> {
|
||||
|
||||
const accessUrl = await fetch(`${accessToken.service_endpoint}/${accessToken.resource_id}`, {
|
||||
method: "POST",
|
||||
body: payload,
|
||||
headers: {
|
||||
"Content-type": "application/json",
|
||||
},
|
||||
})
|
||||
.then((response: any) => {
|
||||
if (response.ok) {
|
||||
return response.text()
|
||||
}
|
||||
Logger.log("Failed: ", response.status, response.statusText)
|
||||
})
|
||||
.then((consumptionUrl: string) => {
|
||||
Logger.log("Success accessing consume endpoint: ", consumptionUrl)
|
||||
return consumptionUrl
|
||||
})
|
||||
.catch((error) => {
|
||||
Logger.error("Error fetching the data asset consumption url: ", error)
|
||||
})
|
||||
|
||||
return accessUrl
|
||||
}
|
||||
}
|
14
src/provider/ProviderProvider.ts
Normal file
14
src/provider/ProviderProvider.ts
Normal file
@ -0,0 +1,14 @@
|
||||
export default class ProviderProvider {
|
||||
|
||||
public static setProvider(provider) {
|
||||
|
||||
ProviderProvider.provider = provider
|
||||
}
|
||||
|
||||
public static getProvider() {
|
||||
|
||||
return ProviderProvider.provider
|
||||
}
|
||||
|
||||
private static provider
|
||||
}
|
8
test/MockProvider.ts
Normal file
8
test/MockProvider.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import Provider from "../src/provider/Provider"
|
||||
|
||||
export default class MockProvider extends Provider {
|
||||
|
||||
public static async getAccessUrl(accessToken: any, payload: any): Promise<string> {
|
||||
return "http://test/test"
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ describe("ContractHandler", () => {
|
||||
describe("#get()", () => {
|
||||
|
||||
it("should load and get OceanToken correctly", async () => {
|
||||
assert(await ContractHandler.get("OceanTokewn") !== null)
|
||||
assert(await ContractHandler.get("OceanToken") !== null)
|
||||
})
|
||||
|
||||
})
|
||||
|
@ -41,9 +41,9 @@ describe("Account", () => {
|
||||
|
||||
describe("#getEthBalance()", () => {
|
||||
|
||||
it("should get initial balance", async () => {
|
||||
it("should get initial ether balance", async () => {
|
||||
|
||||
const account: Account = accounts[1]
|
||||
const account: Account = accounts[9]
|
||||
const balance = await account.getEthBalance()
|
||||
const web3 = Web3Provider.getWeb3()
|
||||
|
||||
@ -55,7 +55,7 @@ describe("Account", () => {
|
||||
|
||||
it("should get initial balance", async () => {
|
||||
|
||||
const account: Account = accounts[1]
|
||||
const account: Account = accounts[9]
|
||||
const balance = await account.getBalance()
|
||||
const web3 = Web3Provider.getWeb3()
|
||||
|
||||
|
@ -5,11 +5,15 @@ import Account from "../../src/ocean/Account"
|
||||
import Asset from "../../src/ocean/Asset"
|
||||
import Ocean from "../../src/ocean/Ocean"
|
||||
import Order from "../../src/ocean/Order"
|
||||
import ProviderProvider from "../../src/provider/ProviderProvider"
|
||||
import config from "../config"
|
||||
import MockProvider from "../MockProvider"
|
||||
|
||||
const testName = "Test Asset 2"
|
||||
const testDescription = "This asset is pure owange"
|
||||
const testPrice = 100
|
||||
const timeout = 100000
|
||||
const accessToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE1Mzk3ODcxMDEsImV4cCI6NDcyNjk5NjcwNCwiYXVkIjoiIiwic3ViIjoiIiwic2VydmljZV9lbmRwb2ludCI6Imh0dHA6Ly9hZGFzZCIsInJlc291cmNlX2lkIjoiMTIzNDUifQ.2H3TRC3CAToVE9divSckwHi_HNvgOHKrtJPo8128qrKBHTk7YYb0UNfVCuYqwhGR"
|
||||
|
||||
let ocean: Ocean
|
||||
let testAsset: Asset
|
||||
@ -18,6 +22,8 @@ let testPublisher: Account
|
||||
|
||||
before(async () => {
|
||||
ConfigProvider.configure(config)
|
||||
ProviderProvider.setProvider(MockProvider)
|
||||
|
||||
await ContractHandler.deployContracts()
|
||||
ocean = await Ocean.getInstance(config)
|
||||
accounts = await ocean.getAccounts()
|
||||
@ -50,16 +56,25 @@ describe("Asset", () => {
|
||||
it("should purchase an asset", async () => {
|
||||
|
||||
// todo
|
||||
const order: Order = await testAsset.purchase(accounts[5], 10000)
|
||||
const consumerAccount = accounts[5]
|
||||
const order: Order = await testAsset.purchase(consumerAccount, timeout)
|
||||
assert(order)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#purchase()", () => {
|
||||
describe("#consume()", () => {
|
||||
|
||||
it("should purchase an asset", async () => {
|
||||
// todo
|
||||
// await testAsset.finalizePurchaseAsset()
|
||||
it("should consume an asset", async () => {
|
||||
const consumerAccount = accounts[5]
|
||||
await consumerAccount.requestTokens(testAsset.price)
|
||||
// place order - consumer
|
||||
const order: Order = await testAsset.purchase(consumerAccount, timeout)
|
||||
// commit order - provider
|
||||
await order.commit(accessToken)
|
||||
// pay order - consumer
|
||||
await order.pay(consumerAccount)
|
||||
const url = await testAsset.consume(order, consumerAccount)
|
||||
assert(url)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -4,17 +4,27 @@ import ContractHandler from "../../src/keeper/ContractHandler"
|
||||
import Account from "../../src/ocean/Account"
|
||||
import Asset from "../../src/ocean/Asset"
|
||||
import Ocean from "../../src/ocean/Ocean"
|
||||
import Logger from "../../src/utils/Logger"
|
||||
import Order from "../../src/ocean/Order"
|
||||
import config from "../config"
|
||||
|
||||
let ocean: Ocean
|
||||
let accounts: Account[]
|
||||
let testAsset: Asset
|
||||
let testPublisher: Account
|
||||
|
||||
const name = "Test Asset 3"
|
||||
const description = "This asset is pure owange"
|
||||
const price = 100
|
||||
const timeout = 100000000
|
||||
|
||||
before(async () => {
|
||||
ConfigProvider.configure(config)
|
||||
await ContractHandler.deployContracts()
|
||||
ocean = await Ocean.getInstance(config)
|
||||
accounts = await ocean.getAccounts()
|
||||
|
||||
testPublisher = accounts[0]
|
||||
testAsset = new Asset(name, description, price, testPublisher)
|
||||
})
|
||||
|
||||
describe("Ocean", () => {
|
||||
@ -36,15 +46,7 @@ describe("Ocean", () => {
|
||||
|
||||
it("should register an asset", async () => {
|
||||
|
||||
const publisher: Account = accounts[0]
|
||||
|
||||
const name = "Test Asset 3"
|
||||
const description = "This asset is pure owange"
|
||||
const price = 100
|
||||
|
||||
const asset = new Asset(name, description, price, publisher)
|
||||
|
||||
const assetId: string = await ocean.register(asset)
|
||||
const assetId: string = await ocean.register(testAsset)
|
||||
|
||||
assert(assetId.length === 66)
|
||||
assert(assetId.startsWith("0x"))
|
||||
@ -55,9 +57,17 @@ describe("Ocean", () => {
|
||||
|
||||
it("should list orders", async () => {
|
||||
|
||||
// todo
|
||||
const orders = await ocean.getOrdersByConsumer(accounts[1])
|
||||
Logger.log(orders)
|
||||
const testConsumer = accounts[1]
|
||||
const asset: Asset = new Asset("getOrdersByConsumer test", description, price, testPublisher)
|
||||
|
||||
await ocean.register(asset)
|
||||
|
||||
const order: Order = await asset.purchase(testConsumer, timeout)
|
||||
const orders = await ocean.getOrdersByConsumer(testConsumer)
|
||||
|
||||
assert(orders.length === 1)
|
||||
assert(orders[0].getId() === order.getId())
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
@ -1,21 +1,24 @@
|
||||
import * as assert from "assert"
|
||||
import ConfigProvider from "../../src/ConfigProvider"
|
||||
import ContractHandler from "../../src/keeper/ContractHandler"
|
||||
import AccessStatus from "../../src/models/AccessStatus"
|
||||
import Account from "../../src/ocean/Account"
|
||||
import Asset from "../../src/ocean/Asset"
|
||||
import Ocean from "../../src/ocean/Ocean"
|
||||
import Order from "../../src/ocean/Order"
|
||||
import Logger from "../../src/utils/Logger"
|
||||
import config from "../config"
|
||||
|
||||
const testName = "Test Asset 333"
|
||||
const testName = "Order Test Asset"
|
||||
const testDescription = "This asset is pure owange"
|
||||
const testPrice = 100
|
||||
const timeout = 1000000
|
||||
const accessToken = "eyJhbGciOiJIUzI1"
|
||||
|
||||
let ocean: Ocean
|
||||
let testAsset: Asset
|
||||
let accounts: Account[]
|
||||
let testPublisher: Account
|
||||
let testConsumer: Account
|
||||
|
||||
before(async () => {
|
||||
ConfigProvider.configure(config)
|
||||
@ -23,6 +26,7 @@ before(async () => {
|
||||
ocean = await Ocean.getInstance(config)
|
||||
accounts = await ocean.getAccounts()
|
||||
testPublisher = accounts[0]
|
||||
testConsumer = accounts[1]
|
||||
// register an asset to play around with
|
||||
testAsset = new Asset(testName, testDescription, testPrice, testPublisher)
|
||||
await ocean.register(testAsset)
|
||||
@ -30,17 +34,53 @@ before(async () => {
|
||||
|
||||
describe("Order", () => {
|
||||
|
||||
describe("#pay()", () => {
|
||||
describe("#pay()", async () => {
|
||||
|
||||
it("should pay for the order", async () => {
|
||||
it("should pay for an order", async () => {
|
||||
|
||||
const order: Order = await testAsset.purchase(accounts[0], 10000)
|
||||
const order: Order = await testAsset.purchase(testConsumer, timeout)
|
||||
assert(order)
|
||||
|
||||
const paymentId: string = await order.pay(accounts[0])
|
||||
Logger.log("paymentId", paymentId)
|
||||
await order.commit(accessToken)
|
||||
await testConsumer.requestTokens(testAsset.price)
|
||||
const paymentId: string = await order.pay(testConsumer)
|
||||
assert(paymentId)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe("#commit()", async () => {
|
||||
|
||||
it("should commit the order", async () => {
|
||||
|
||||
const order: Order = await testAsset.purchase(testConsumer, timeout)
|
||||
assert(order)
|
||||
|
||||
await order.commit(accessToken)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getStatus()", async () => {
|
||||
|
||||
it("should get status Requested on new order", async () => {
|
||||
|
||||
const order: Order = await testAsset.purchase(testConsumer, timeout)
|
||||
assert(order)
|
||||
|
||||
const status: AccessStatus = await order.getStatus()
|
||||
assert(status === AccessStatus.Requested)
|
||||
})
|
||||
|
||||
it("should get status Delivered on commited order", async () => {
|
||||
|
||||
const order: Order = await testAsset.purchase(testConsumer, timeout)
|
||||
assert(order)
|
||||
|
||||
await order.commit(accessToken)
|
||||
|
||||
const status: AccessStatus = await order.getStatus()
|
||||
assert(status === AccessStatus.Delivered)
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
Loading…
x
Reference in New Issue
Block a user