1
0
mirror of https://github.com/oceanprotocol-archive/squid-js.git synced 2024-02-02 15:31:51 +01:00
squid-js/src/ocean/Order.ts

192 lines
7.1 KiB
TypeScript
Raw Normal View History

2018-10-02 10:06:26 +02:00
import * as EthCrypto from "eth-crypto"
import EthEcies from "eth-ecies"
import * as EthjsUtil from "ethereumjs-util"
import JWT from "jsonwebtoken"
import Asset from "../models/Asset"
import OrderModel from "../models/Order"
import Logger from "../utils/Logger"
2018-10-09 10:55:53 +02:00
import OceanBase from "./OceanBase"
2018-10-02 10:06:26 +02:00
declare var fetch
2018-10-09 10:55:53 +02:00
export default class Order extends OceanBase {
private static create(asset: Asset, args, key): OrderModel {
2018-10-02 10:06:26 +02:00
const accessId = args._id
Logger.log("got new access request id: ", accessId)
return {
id: accessId,
assetId: asset.assetId,
asset,
timeout: args._timeout,
pubkey: args._pubKey,
key,
2018-10-02 10:06:26 +02:00
} as OrderModel
}
public async getOrdersByConsumer(consumerAddress: string) {
2018-10-02 10:06:26 +02:00
const {auth, market} = this.keeper
2018-10-04 13:14:03 +02:00
2018-10-09 10:55:53 +02:00
Logger.log("Getting orders")
2018-10-09 10:55:53 +02:00
const accessConsentRequestedData = await auth.getEventData(
"AccessConsentRequested", {
filter: {
_consumer: consumerAddress,
},
fromBlock: 0,
toBlock: "latest",
})
2018-10-04 13:14:03 +02:00
const orders = await Promise.all(
accessConsentRequestedData
2018-10-09 10:55:53 +02:00
.filter((event: any) => {
return event.returnValues._consumer === consumerAddress
})
2018-10-04 13:14:03 +02:00
.map(async (event: any) => ({
2018-10-09 10:55:53 +02:00
...event.returnValues,
timeout: parseInt(event.returnValues._timeout, 10),
status: await auth.getOrderStatus(event.returnValues._id),
paid: await market.verifyOrderPayment(event.returnValues._id),
2018-10-04 13:14:03 +02:00
key: null,
} as Order
),
),
)
2018-10-09 10:55:53 +02:00
// Logger.log("Got orders:", JSON.stringify(orders, null, 2))
Logger.log(`Got ${Object.keys(orders).length} orders`)
2018-10-02 10:06:26 +02:00
return orders
}
public async purchaseAsset(asset: Asset, timeout: number, buyerAddress: string): Promise<OrderModel> {
2018-10-02 10:06:26 +02:00
const {token, market, auth} = this.keeper
2018-10-02 10:06:26 +02:00
const key = EthCrypto.createIdentity()
const publicKey = EthjsUtil.privateToPublic(key.privateKey).toString("hex")
const price = await market.getAssetPrice(asset.assetId)
const isValid = await market.isAssetActive(asset.assetId)
2018-10-02 10:06:26 +02:00
Logger.log("The asset:", asset.assetId, "is it valid?", isValid, "it's price is:", price)
if (!isValid) {
2018-10-02 10:06:26 +02:00
throw new Error("asset not valid")
}
try {
// Allow market contract to transfer funds on the consumer"s behalf
2018-10-02 10:06:26 +02:00
await token.approve(market.getAddress(), price, buyerAddress)
} catch (err) {
2018-10-09 10:55:53 +02:00
Logger.error("token.approve failed", err)
}
2018-10-09 10:55:53 +02:00
let order: OrderModel
try {
// Submit the access request
2018-10-09 10:55:53 +02:00
const initiateAccessRequestReceipt = await auth.initiateAccessRequest(asset,
publicKey, timeout, buyerAddress)
const args = initiateAccessRequestReceipt.events.AccessConsentRequested.returnValues
Logger.log("keeper AccessConsentRequested event received on asset: ", asset.assetId, "\nevent:", args)
order = Order.create(asset, args, key)
Logger.log("Created order", order)
} catch (err) {
2018-10-09 10:55:53 +02:00
Logger.error("auth.initiateAccessRequest failed", err)
}
2018-10-04 13:14:03 +02:00
2018-10-09 10:55:53 +02:00
return order
if (false) {
// todo: AccessRequestCommitted event is not emitted in this flow
const finalOrder: OrderModel = await auth.listenToEventOnce(
"AccessRequestCommitted", {
2018-10-04 13:14:03 +02:00
filter: {
_id: order.id,
},
})
2018-10-09 10:55:53 +02:00
.then((accessRequestCommittedResult) => {
Logger.log("Got AccessRequestCommitted Event")
return this.payAsset(asset, accessRequestCommittedResult.returnValues, order, buyerAddress)
2018-10-04 13:14:03 +02:00
})
2018-10-09 10:55:53 +02:00
.then((payAssetReceipt) => {
return auth.listenToEventOnce(
"EncryptedTokenPublished", {
filter: {
_id: order.id,
},
})
})
.then((result) => {
Logger.log("Got EncryptedTokenPublished Event")
2018-10-09 10:55:53 +02:00
return this.finalizePurchaseAsset(
result, order, key, buyerAddress,
)
})
}
}
private async payAsset(asset: Asset, args, order, buyerAddress) {
2018-10-02 10:06:26 +02:00
const {market} = this.keeper
// send payment
2018-10-02 10:06:26 +02:00
Logger.log("Sending payment: ", order.id, args._id, asset.publisherId, asset.price, order.timeout)
return market.payAsset(asset, order, buyerAddress)
}
private async finalizePurchaseAsset(args, order, key, buyerAddress): Promise<OrderModel> {
2018-10-02 10:06:26 +02:00
const {auth, web3Helper} = this.keeper
2018-10-02 10:06:26 +02:00
const encryptedAccessToken = await auth.getEncryptedAccessToken(args._id, buyerAddress)
// grab the access token from acl contract
2018-10-02 10:06:26 +02:00
const tokenNo0x = encryptedAccessToken.slice(2)
const encryptedTokenBuffer = Buffer.from(tokenNo0x, "hex")
2018-10-02 10:06:26 +02:00
const privateKey = key.privateKey.slice(2)
const accessTokenEncoded = EthEcies.Decrypt(Buffer.from(privateKey, "hex"), encryptedTokenBuffer)
const accessToken = JWT.decode(accessTokenEncoded) // Returns a json object
// sign it
2018-10-02 10:06:26 +02:00
const hexEncrToken = `0x${encryptedTokenBuffer.toString("hex")}`
2018-10-02 10:06:26 +02:00
const signature = web3Helper.sign(buyerAddress, hexEncrToken)
const fixedMsgSha = web3Helper.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: buyerAddress,
fixed_msg: fixedMsgSha,
sigEncJWT: signature,
jwt: accessTokenEncoded,
2018-10-02 10:06:26 +02:00
})
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) {
2018-10-02 10:06:26 +02:00
return response.text()
}
2018-10-02 10:06:26 +02:00
Logger.log("Failed: ", response.status, response.statusText)
})
.then((consumptionUrl: string) => {
2018-10-02 10:06:26 +02:00
Logger.log("Success accessing consume endpoint: ", consumptionUrl)
return consumptionUrl
})
.catch((error) => {
2018-10-02 10:06:26 +02:00
Logger.error("Error fetching the data asset consumption url: ", error)
})
Logger.log("consume url: ", accessUrl)
order.accessUrl = accessUrl
2018-10-02 10:06:26 +02:00
return order
}
}