mirror of
https://github.com/oceanprotocol-archive/squid-js.git
synced 2024-02-02 15:31:51 +01:00
Clean and simplify template related typings.
This commit is contained in:
parent
76c4b2b1fb
commit
51aa0fbf64
@ -1,4 +1,5 @@
|
|||||||
import Config from "./models/Config"
|
import Config from "./models/Config"
|
||||||
|
import Logger, { LogLevel } from "./utils/Logger"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores the configuration of the library.
|
* Stores the configuration of the library.
|
||||||
@ -16,6 +17,12 @@ export default class ConfigProvider {
|
|||||||
* @param {Config} Library config.
|
* @param {Config} Library config.
|
||||||
*/
|
*/
|
||||||
public static setConfig(config: Config) {
|
public static setConfig(config: Config) {
|
||||||
|
Logger.setLevel(
|
||||||
|
typeof config.verbose !== "number"
|
||||||
|
? (config.verbose ? LogLevel.Log : LogLevel.None)
|
||||||
|
: config.verbose as LogLevel,
|
||||||
|
)
|
||||||
|
|
||||||
ConfigProvider.config = config
|
ConfigProvider.config = config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
import { Event } from "./Event"
|
|
||||||
|
|
||||||
export interface Parameter {
|
|
||||||
name: string
|
|
||||||
type: string
|
|
||||||
value: any
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Dependency {
|
|
||||||
/**
|
|
||||||
* @example "lockPayment"
|
|
||||||
*/
|
|
||||||
name: string
|
|
||||||
/**
|
|
||||||
* @example 0
|
|
||||||
*/
|
|
||||||
timeout: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Condition {
|
|
||||||
name: string
|
|
||||||
/**
|
|
||||||
* @example "AccessCondition"
|
|
||||||
*/
|
|
||||||
contractName: string
|
|
||||||
/**
|
|
||||||
* @example "lockPayment"
|
|
||||||
*/
|
|
||||||
functionName: string
|
|
||||||
/**
|
|
||||||
* @example 0
|
|
||||||
*/
|
|
||||||
timeout: number
|
|
||||||
/**
|
|
||||||
* @example "0x12122434"
|
|
||||||
*/
|
|
||||||
conditionKey: string
|
|
||||||
parameters: Parameter[]
|
|
||||||
events: Event[]
|
|
||||||
/**
|
|
||||||
* @example []
|
|
||||||
*/
|
|
||||||
dependencies: Dependency[]
|
|
||||||
/**
|
|
||||||
* @example false
|
|
||||||
*/
|
|
||||||
isTerminalCondition: boolean
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
import { Event } from "./Event"
|
|
||||||
|
|
||||||
export interface Contract {
|
|
||||||
contractName: string
|
|
||||||
fulfillmentOperator: number
|
|
||||||
events: Event[]
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
export interface EventHandler {
|
|
||||||
/**
|
|
||||||
* @example "serviceAgreement"
|
|
||||||
*/
|
|
||||||
moduleName: string
|
|
||||||
/**
|
|
||||||
* @example "fulfillAgreement"
|
|
||||||
*/
|
|
||||||
functionName: string
|
|
||||||
/**
|
|
||||||
* @example "0.1"
|
|
||||||
*/
|
|
||||||
version: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Event {
|
|
||||||
name: string
|
|
||||||
actorType: string
|
|
||||||
handler: EventHandler
|
|
||||||
}
|
|
@ -1,6 +1,7 @@
|
|||||||
import { Condition } from "./Condition"
|
import { Condition } from "./Condition"
|
||||||
import { Contract } from "./Contract"
|
import { Contract } from "./Contract"
|
||||||
import { MetaData } from "./MetaData"
|
import { MetaData } from "./MetaData"
|
||||||
|
import { ServiceAgreementTemplate } from "./ServiceAgreementTemplate"
|
||||||
|
|
||||||
export type ServiceType = "Authorization" | "Metadata" | "Access" | "Compute" | "FitchainCompute"
|
export type ServiceType = "Authorization" | "Metadata" | "Access" | "Compute" | "FitchainCompute"
|
||||||
|
|
||||||
@ -22,11 +23,12 @@ export interface ServiceMetadata extends ServiceCommon {
|
|||||||
|
|
||||||
export interface ServiceAccess extends ServiceCommon {
|
export interface ServiceAccess extends ServiceCommon {
|
||||||
type: "Access"
|
type: "Access"
|
||||||
|
name?: string,
|
||||||
|
description?: string
|
||||||
|
creator?: string
|
||||||
templateId?: string
|
templateId?: string
|
||||||
purchaseEndpoint?: string
|
purchaseEndpoint?: string
|
||||||
description?: string
|
serviceAgreementTemplate?: ServiceAgreementTemplate
|
||||||
serviceAgreementContract?: Contract
|
|
||||||
conditions?: Condition[]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ServiceCompute extends ServiceCommon {
|
export interface ServiceCompute extends ServiceCommon {
|
||||||
|
33
src/ddo/ServiceAgreementTemplate.ts
Normal file
33
src/ddo/ServiceAgreementTemplate.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
export interface ServiceAgreementTemplateParameter {
|
||||||
|
name: string
|
||||||
|
type: string
|
||||||
|
value: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ServiceAgreementTemplateEvent {
|
||||||
|
name: string
|
||||||
|
actorType: string
|
||||||
|
handler: {
|
||||||
|
moduleName: string
|
||||||
|
functionName: string
|
||||||
|
version: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ServiceAgreementTemplateCondition {
|
||||||
|
name: string
|
||||||
|
timelock: number
|
||||||
|
timeout: number
|
||||||
|
contractName: string
|
||||||
|
functionName: string
|
||||||
|
parameters: ServiceAgreementTemplateParameter[]
|
||||||
|
events: ServiceAgreementTemplateEvent[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ServiceAgreementTemplate {
|
||||||
|
contractName: string
|
||||||
|
events: ServiceAgreementTemplateEvent[]
|
||||||
|
fulfillmentOrder: string[]
|
||||||
|
conditionDependency: {[condition: string]: string[]}
|
||||||
|
conditions: ServiceAgreementTemplateCondition[]
|
||||||
|
}
|
@ -14,7 +14,7 @@ import Web3Provider from "./Web3Provider"
|
|||||||
* - Ocean Tokens: the intrinsic tokens circulated inside Ocean network, which is used in the voting of TCRs.
|
* - Ocean Tokens: the intrinsic tokens circulated inside Ocean network, which is used in the voting of TCRs.
|
||||||
* - Marketplace: the core marketplace where people can transact with each other with Ocean tokens.
|
* - Marketplace: the core marketplace where people can transact with each other with Ocean tokens.
|
||||||
*/
|
*/
|
||||||
export default class Keeper {
|
export class Keeper {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns Keeper instance.
|
* Returns Keeper instance.
|
||||||
@ -150,3 +150,5 @@ export default class Keeper {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default Keeper
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { LogLevel } from "../utils/Logger"
|
import { LogLevel } from "../utils/Logger"
|
||||||
|
export { LogLevel } from "../utils/Logger"
|
||||||
|
|
||||||
export default class Config {
|
export class Config {
|
||||||
/* Aquarius Config */
|
/* Aquarius Config */
|
||||||
// the url to the aquarius
|
// the url to the aquarius
|
||||||
public aquariusUri: string
|
public aquariusUri: string
|
||||||
@ -30,3 +31,5 @@ export default class Config {
|
|||||||
/* Squid config */
|
/* Squid config */
|
||||||
public verbose: boolean | LogLevel
|
public verbose: boolean | LogLevel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default Config
|
||||||
|
@ -16,7 +16,7 @@ import { Service } from "../ddo/Service"
|
|||||||
import ContractEvent from "../keeper/Event"
|
import ContractEvent from "../keeper/Event"
|
||||||
import Config from "../models/Config"
|
import Config from "../models/Config"
|
||||||
import SecretStoreProvider from "../secretstore/SecretStoreProvider"
|
import SecretStoreProvider from "../secretstore/SecretStoreProvider"
|
||||||
import Logger, { LogLevel } from "../utils/Logger"
|
import { Logger, LogLevel } from "../utils/Logger"
|
||||||
import Account from "./Account"
|
import Account from "./Account"
|
||||||
import DID from "./DID"
|
import DID from "./DID"
|
||||||
import ServiceAgreement from "./ServiceAgreements/ServiceAgreement"
|
import ServiceAgreement from "./ServiceAgreements/ServiceAgreement"
|
||||||
@ -36,6 +36,7 @@ export default class Ocean {
|
|||||||
*/
|
*/
|
||||||
public static async getInstance(config: Config): Promise<Ocean> {
|
public static async getInstance(config: Config): Promise<Ocean> {
|
||||||
// Must be defined on instance level, right now, calling getInstance twice is going to rewrite that
|
// Must be defined on instance level, right now, calling getInstance twice is going to rewrite that
|
||||||
|
// WARN: is called on ConfigProvider.setConfig too (to work fine on test)
|
||||||
Logger.setLevel(
|
Logger.setLevel(
|
||||||
typeof config.verbose !== "number"
|
typeof config.verbose !== "number"
|
||||||
? (config.verbose ? LogLevel.Log : LogLevel.None)
|
? (config.verbose ? LogLevel.Log : LogLevel.None)
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
import { Event } from "../../ddo/Event"
|
|
||||||
import MethodReflection from "../../models/MethodReflection"
|
|
||||||
import Parameter from "./Parameter"
|
|
||||||
|
|
||||||
export default class Condition {
|
|
||||||
public methodReflection: MethodReflection
|
|
||||||
public condtionKey: string
|
|
||||||
public dependencies: string[]
|
|
||||||
public dependencyTimeoutFlags: number[]
|
|
||||||
public isTerminalCondition: boolean
|
|
||||||
public timeout: number
|
|
||||||
public events: Event[]
|
|
||||||
public parameters: Parameter[]
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
import EventHandler from "./EventHandler"
|
|
||||||
|
|
||||||
export default class Event {
|
|
||||||
public name: string = "PaymentLocked"
|
|
||||||
public actorType: string = "publisher"
|
|
||||||
public handler: EventHandler
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
export default class EventHandler {
|
|
||||||
public moduleName: string = "accessControl"
|
|
||||||
public functionName: string = "grantAccess"
|
|
||||||
public version: string = "0.1"
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
import Event from "./Event"
|
|
||||||
import Parameter from "./Parameter"
|
|
||||||
|
|
||||||
export default class Method {
|
|
||||||
public name: string
|
|
||||||
public contractName: string
|
|
||||||
public methodName: string
|
|
||||||
public timeout: number
|
|
||||||
public parameters: Parameter[]
|
|
||||||
public events: Event[]
|
|
||||||
public dependencies: string[]
|
|
||||||
public dependencyTimeoutFlags: number[]
|
|
||||||
public isTerminalCondition: boolean
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
export default class Parameter {
|
|
||||||
public name: string
|
|
||||||
public type: string
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
import { Condition } from "../../ddo/Condition"
|
import { ServiceAgreementTemplateCondition } from "../../ddo/ServiceAgreementTemplate"
|
||||||
import { DDO } from "../../ddo/DDO"
|
import { DDO } from "../../ddo/DDO"
|
||||||
import { ServiceAccess } from "../../ddo/Service"
|
import { ServiceAccess } from "../../ddo/Service"
|
||||||
import Keeper from "../../keeper/Keeper"
|
import Keeper from "../../keeper/Keeper"
|
||||||
@ -7,21 +7,22 @@ import ValuePair from "../../models/ValuePair"
|
|||||||
import Logger from "../../utils/Logger"
|
import Logger from "../../utils/Logger"
|
||||||
import Account from "../Account"
|
import Account from "../Account"
|
||||||
import DID from "../DID"
|
import DID from "../DID"
|
||||||
import OceanBase from "../OceanBase"
|
import { signText } from "../../utils"
|
||||||
|
|
||||||
export default class ServiceAgreement extends OceanBase {
|
|
||||||
|
// TODO: move this class to helpers, it only contains pure functions
|
||||||
|
export default class ServiceAgreement {
|
||||||
|
|
||||||
public static async signServiceAgreement(
|
public static async signServiceAgreement(
|
||||||
ddo: DDO,
|
ddo: DDO,
|
||||||
serviceDefinitionId: string,
|
serviceDefinitionId: string,
|
||||||
serviceAgreementId: string,
|
serviceAgreementId: string,
|
||||||
|
valuesMap: {[value: string]: string},
|
||||||
consumer: Account,
|
consumer: Account,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
|
|
||||||
Logger.log("Signing SA with serviceAgreementId", serviceAgreementId)
|
|
||||||
|
|
||||||
const service = ddo.findServiceById<"Access">(serviceDefinitionId)
|
const service = ddo.findServiceById<"Access">(serviceDefinitionId)
|
||||||
const values: ValuePair[][] = ServiceAgreement.getValuesFromService(service, serviceAgreementId)
|
const values: ValuePair[][] = ServiceAgreement.getValuesFromService(service, valuesMap)
|
||||||
const valueHashes: string[] = ServiceAgreement.createValueHashes(values)
|
const valueHashes: string[] = ServiceAgreement.createValueHashes(values)
|
||||||
const timeoutValues: number[] = ServiceAgreement.getTimeoutValuesFromService(service)
|
const timeoutValues: number[] = ServiceAgreement.getTimeoutValuesFromService(service)
|
||||||
|
|
||||||
@ -38,31 +39,6 @@ export default class ServiceAgreement extends OceanBase {
|
|||||||
return serviceAgreementHashSignature
|
return serviceAgreementHashSignature
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async executeServiceAgreement(
|
|
||||||
did: DID,
|
|
||||||
ddo: DDO,
|
|
||||||
serviceDefinitionId: string,
|
|
||||||
serviceAgreementId: string,
|
|
||||||
serviceAgreementHashSignature: string,
|
|
||||||
consumer: Account,
|
|
||||||
publisher: Account,
|
|
||||||
): Promise<ServiceAgreement> {
|
|
||||||
|
|
||||||
Logger.log("Executing SA with serviceAgreementId", serviceAgreementId)
|
|
||||||
|
|
||||||
const service = ddo.findServiceById<"Access">(serviceDefinitionId)
|
|
||||||
const values: ValuePair[][] = ServiceAgreement.getValuesFromService(service, serviceAgreementId)
|
|
||||||
const valueHashes: string[] = ServiceAgreement.createValueHashes(values)
|
|
||||||
const timeoutValues: number[] = ServiceAgreement.getTimeoutValuesFromService(service)
|
|
||||||
|
|
||||||
// todo get consumer from ddo
|
|
||||||
const serviceAgreement: ServiceAgreement = await ServiceAgreement.executeAgreement(did, ddo,
|
|
||||||
serviceDefinitionId, serviceAgreementId, valueHashes, timeoutValues, serviceAgreementHashSignature,
|
|
||||||
consumer.getId(), publisher)
|
|
||||||
|
|
||||||
return serviceAgreement
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async createSAHashSignature(
|
private static async createSAHashSignature(
|
||||||
service: ServiceAccess,
|
service: ServiceAccess,
|
||||||
serviceAgreementId: string,
|
serviceAgreementId: string,
|
||||||
@ -75,88 +51,20 @@ export default class ServiceAgreement extends OceanBase {
|
|||||||
throw new Error("TemplateId not found in ddo.")
|
throw new Error("TemplateId not found in ddo.")
|
||||||
}
|
}
|
||||||
|
|
||||||
const conditionKeys: string[] = service.conditions.map((condition) => {
|
|
||||||
return condition.conditionKey
|
|
||||||
})
|
|
||||||
|
|
||||||
if (conditionKeys.length !== valueHashes.length) {
|
|
||||||
throw new Error("Hashing SA failed!")
|
|
||||||
}
|
|
||||||
|
|
||||||
const serviceAgreementHash = ServiceAgreement.hashServiceAgreement(
|
const serviceAgreementHash = ServiceAgreement.hashServiceAgreement(
|
||||||
service.templateId,
|
service.templateId,
|
||||||
serviceAgreementId,
|
serviceAgreementId,
|
||||||
conditionKeys,
|
|
||||||
valueHashes,
|
valueHashes,
|
||||||
timeoutValues)
|
timeoutValues)
|
||||||
|
|
||||||
let serviceAgreementHashSignature: string
|
let serviceAgreementHashSignature = await signText(serviceAgreementHash, consumer.getId(), consumer.getPassword())
|
||||||
const web3 = Web3Provider.getWeb3()
|
|
||||||
if ((web3 as any).currentProvider.isMetaMask) {
|
|
||||||
// password is injected by metamask, dont try to set it!
|
|
||||||
serviceAgreementHashSignature = await web3.eth.personal.sign(serviceAgreementHash, consumer.getId(), null)
|
|
||||||
} else {
|
|
||||||
serviceAgreementHashSignature = await web3.eth.sign(serviceAgreementHash, consumer.getId())
|
|
||||||
}
|
|
||||||
|
|
||||||
return serviceAgreementHashSignature
|
return serviceAgreementHashSignature
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async executeAgreement(
|
|
||||||
did: DID,
|
|
||||||
ddo: DDO,
|
|
||||||
serviceDefinitionId: string,
|
|
||||||
serviceAgreementId: string,
|
|
||||||
valueHashes: string[],
|
|
||||||
timeoutValues: number[],
|
|
||||||
serviceAgreementHashSignature: string,
|
|
||||||
consumerAddress: string,
|
|
||||||
publisher: Account,
|
|
||||||
): Promise<ServiceAgreement> {
|
|
||||||
|
|
||||||
const {serviceAgreement} = <any>await Keeper.getInstance()
|
|
||||||
|
|
||||||
const service = ddo.findServiceById<"Access">(serviceDefinitionId)
|
|
||||||
|
|
||||||
if (!service.templateId) {
|
|
||||||
throw new Error(`TemplateId not found in service "${service.type}" ddo.`)
|
|
||||||
}
|
|
||||||
|
|
||||||
const templateActive = await serviceAgreement.getTemplateStatus(service.templateId)
|
|
||||||
|
|
||||||
if (!templateActive) {
|
|
||||||
throw new Error(`Template with id ${service.templateId} is not active.`)
|
|
||||||
}
|
|
||||||
|
|
||||||
const executeAgreementReceipt = await serviceAgreement
|
|
||||||
.initializeAgreement(
|
|
||||||
service.templateId,
|
|
||||||
serviceAgreementHashSignature,
|
|
||||||
consumerAddress,
|
|
||||||
valueHashes,
|
|
||||||
timeoutValues,
|
|
||||||
serviceAgreementId,
|
|
||||||
did,
|
|
||||||
publisher.getId(),
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!executeAgreementReceipt.status) {
|
|
||||||
throw new Error("executing service agreement failed.")
|
|
||||||
}
|
|
||||||
return new ServiceAgreement(
|
|
||||||
executeAgreementReceipt.events.AgreementInitialized.returnValues.agreementId,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private static createValueHashes(parameterValuePairs: ValuePair[][]): string[] {
|
private static createValueHashes(parameterValuePairs: ValuePair[][]): string[] {
|
||||||
|
return parameterValuePairs
|
||||||
const hashes: string[] = []
|
.map((valuePairs: ValuePair[]) => ServiceAgreement.hashValuePairArray(valuePairs))
|
||||||
parameterValuePairs.map((valuePairs: ValuePair[]) => {
|
|
||||||
|
|
||||||
hashes.push(ServiceAgreement.hashValuePairArray(valuePairs))
|
|
||||||
})
|
|
||||||
|
|
||||||
return hashes
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static hashValuePairArray(valuePairs: ValuePair[]): string {
|
private static hashValuePairArray(valuePairs: ValuePair[]): string {
|
||||||
@ -178,70 +86,35 @@ export default class ServiceAgreement extends OceanBase {
|
|||||||
private static hashServiceAgreement(
|
private static hashServiceAgreement(
|
||||||
serviceAgreementTemplateId: string,
|
serviceAgreementTemplateId: string,
|
||||||
serviceAgreementId: string,
|
serviceAgreementId: string,
|
||||||
conditionKeys: string[],
|
|
||||||
valueHashes: string[],
|
valueHashes: string[],
|
||||||
timeouts: number[],
|
timeouts: number[],
|
||||||
): string {
|
): string {
|
||||||
|
|
||||||
const args = [
|
const args = [
|
||||||
{type: "bytes32", value: serviceAgreementTemplateId} as ValuePair,
|
{type: "bytes32", value: serviceAgreementTemplateId},
|
||||||
{type: "bytes32[]", value: conditionKeys} as ValuePair,
|
{type: "bytes32[]", value: valueHashes},
|
||||||
{type: "bytes32[]", value: valueHashes} as ValuePair,
|
{type: "uint256[]", value: timeouts},
|
||||||
{type: "uint256[]", value: timeouts} as ValuePair,
|
{type: "bytes32", value: "0x" + serviceAgreementId},
|
||||||
{type: "bytes32", value: "0x" + serviceAgreementId} as ValuePair,
|
|
||||||
]
|
]
|
||||||
|
|
||||||
return (Web3Provider as any).getWeb3().utils.soliditySha3(...args).toString("hex")
|
return (Web3Provider as any).getWeb3().utils.soliditySha3(...args).toString("hex")
|
||||||
}
|
}
|
||||||
|
|
||||||
private static getTimeoutValuesFromService(service: ServiceAccess): number[] {
|
private static getTimeoutValuesFromService(service: ServiceAccess): number[] {
|
||||||
const timeoutValues: number[] = service.conditions.map((condition: Condition) => {
|
const timeoutValues: number[] = service.serviceAgreementTemplate.conditions
|
||||||
return condition.timeout
|
.map((condition: ServiceAgreementTemplateCondition) => condition.timeout)
|
||||||
})
|
|
||||||
|
|
||||||
return timeoutValues
|
return timeoutValues
|
||||||
}
|
}
|
||||||
|
|
||||||
private static getValuesFromService(service: ServiceAccess, serviceAgreementId: string): ValuePair[][] {
|
private static getValuesFromService(service: ServiceAccess, valuesMap: {[key: string]: string}): ValuePair[][] {
|
||||||
|
return (service.serviceAgreementTemplate.conditions || [])
|
||||||
const values: ValuePair[][] = []
|
.map(condition =>
|
||||||
|
(condition.parameters || [])
|
||||||
service.conditions.forEach((condition, i) => {
|
.map(({type, name}) => ({
|
||||||
const contionValues: ValuePair[] = []
|
type,
|
||||||
condition.parameters.forEach((parameter) => {
|
value: valuesMap[name.replace(/^_/, "")] || "",
|
||||||
|
}))
|
||||||
contionValues.push({
|
)
|
||||||
type: parameter.type,
|
|
||||||
value: parameter.name === "serviceId" ? serviceAgreementId : parameter.value,
|
|
||||||
} as ValuePair)
|
|
||||||
})
|
|
||||||
|
|
||||||
values[i] = contionValues
|
|
||||||
})
|
|
||||||
|
|
||||||
return values
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(serviceAgreementId: string) {
|
|
||||||
super(serviceAgreementId)
|
|
||||||
}
|
|
||||||
|
|
||||||
public async payAsset(assetId: string, price: number, consumer: Account): Promise<boolean> {
|
|
||||||
const {paymentConditions, token} = <any>await Keeper.getInstance()
|
|
||||||
|
|
||||||
await token.approve(paymentConditions.getAddress(), price, consumer.getId())
|
|
||||||
|
|
||||||
const lockPaymentReceipt = await paymentConditions.lockPayment(this.getId(), assetId, price, consumer.getId())
|
|
||||||
|
|
||||||
return lockPaymentReceipt.status
|
|
||||||
}
|
|
||||||
|
|
||||||
public async grantAccess(documentId: string, publisher: Account): Promise<boolean> {
|
|
||||||
const {accessConditions} = <any>await Keeper.getInstance()
|
|
||||||
|
|
||||||
const grantAccessReceipt =
|
|
||||||
await accessConditions.grantAccess(this.getId(), documentId, publisher.getId())
|
|
||||||
|
|
||||||
return !!grantAccessReceipt.events.AccessGranted
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,221 +0,0 @@
|
|||||||
import { Condition as DDOCondition, Dependency, Parameter } from "../../ddo/Condition"
|
|
||||||
import { MetaData } from "../../ddo/MetaData"
|
|
||||||
import ContractReflector from "../../keeper/ContractReflector"
|
|
||||||
import Keeper from "../../keeper/Keeper"
|
|
||||||
import Web3Provider from "../../keeper/Web3Provider"
|
|
||||||
import MethodReflection from "../../models/MethodReflection"
|
|
||||||
import ValuePair from "../../models/ValuePair"
|
|
||||||
import Logger from "../../utils/Logger"
|
|
||||||
import Account from "../Account"
|
|
||||||
import OceanBase from "../OceanBase"
|
|
||||||
import Condition from "./Condition"
|
|
||||||
import Method from "./Method"
|
|
||||||
import TemplateBase from "./Templates/TemplateBase"
|
|
||||||
|
|
||||||
export default class ServiceAgreementTemplate extends OceanBase {
|
|
||||||
|
|
||||||
private static generateConditionsKey(serviceAgreementTemplateId: string, methodReflection: MethodReflection): string {
|
|
||||||
const values = [
|
|
||||||
{type: "bytes32", value: serviceAgreementTemplateId} as ValuePair,
|
|
||||||
{type: "address", value: methodReflection.address} as ValuePair,
|
|
||||||
{type: "bytes4", value: methodReflection.signature} as ValuePair,
|
|
||||||
]
|
|
||||||
return (Web3Provider as any).getWeb3().utils.soliditySha3(...values).toString("hex")
|
|
||||||
}
|
|
||||||
|
|
||||||
public constructor(private template: TemplateBase) {
|
|
||||||
super(template.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
public async register(templateOwnerAddress: string): Promise<boolean> {
|
|
||||||
|
|
||||||
const dependencyMatrix: number[] =
|
|
||||||
await Promise.all(this.template.Methods.map(async (method: Method) => {
|
|
||||||
return this.compressDependencies(method.dependencies, method.dependencyTimeoutFlags)
|
|
||||||
}))
|
|
||||||
|
|
||||||
const fulfillmentIndices: number[] = this.template.Methods
|
|
||||||
.map((method: Method, i: number) => method.isTerminalCondition ? i : null)
|
|
||||||
.filter((index: number) => index !== null)
|
|
||||||
|
|
||||||
const {serviceAgreement} = <any>await Keeper.getInstance()
|
|
||||||
|
|
||||||
const owner = await this.getOwner()
|
|
||||||
|
|
||||||
if (owner.getId() === templateOwnerAddress) {
|
|
||||||
// tslint:disable-next-line
|
|
||||||
Logger.error(`Template with id "${this.template.id}" is already registered to your account "${templateOwnerAddress}".`)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!owner.getId().startsWith("0x00000")) {
|
|
||||||
Logger.error(`Template with id "${this.template.id}" already registered by someone else.`)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
let receipt
|
|
||||||
try {
|
|
||||||
receipt = await serviceAgreement
|
|
||||||
.setupTemplate(
|
|
||||||
this.template.id,
|
|
||||||
await this.getMethodReflections(),
|
|
||||||
dependencyMatrix,
|
|
||||||
fulfillmentIndices,
|
|
||||||
this.template.fulfillmentOperator,
|
|
||||||
templateOwnerAddress)
|
|
||||||
} catch (e) {
|
|
||||||
Logger.error(e)
|
|
||||||
throw new Error(`Is not possible to setup the agreement template`)
|
|
||||||
}
|
|
||||||
const {templateId, provider} = receipt.events.TemplateSetup.returnValues
|
|
||||||
|
|
||||||
if (templateId !== this.template.id) {
|
|
||||||
// tslint:disable-next-line
|
|
||||||
throw new Error(`TemplateId missmatch on ${this.template.templateName}! Should be "${this.template.id}" but is ${templateId}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (provider !== templateOwnerAddress) {
|
|
||||||
// tslint:disable-next-line
|
|
||||||
throw new Error(`Template owner missmatch on ${this.template.templateName}! Should be "${templateOwnerAddress}" but is ${provider}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!receipt.status) {
|
|
||||||
Logger.error(`Registering template failed, status was "false".`)
|
|
||||||
}
|
|
||||||
|
|
||||||
return receipt.status
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gets the status of a service agreement template
|
|
||||||
*/
|
|
||||||
public async getStatus(): Promise<boolean> {
|
|
||||||
const {serviceAgreement} = <any>await Keeper.getInstance()
|
|
||||||
return serviceAgreement.getTemplateStatus(this.getId())
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getOwner(): Promise<Account> {
|
|
||||||
const {serviceAgreement} = <any>await Keeper.getInstance()
|
|
||||||
|
|
||||||
return new Account(await serviceAgreement.getTemplateOwner(this.id))
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getConditions(metadata: MetaData, assetId: string): Promise<DDOCondition[]> {
|
|
||||||
const conditions = await this.blendConditions()
|
|
||||||
return conditions.map((condition: Condition, index: number): DDOCondition => {
|
|
||||||
|
|
||||||
const mapParameterValueToName = (name) => {
|
|
||||||
|
|
||||||
switch (name) {
|
|
||||||
case "price":
|
|
||||||
return metadata.base.price
|
|
||||||
case "assetId":
|
|
||||||
return assetId
|
|
||||||
case "documentKeyId":
|
|
||||||
return assetId
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const parameters: Parameter[] = condition.parameters.map((parameter: Parameter) => {
|
|
||||||
return {
|
|
||||||
name: parameter.name,
|
|
||||||
type: parameter.type,
|
|
||||||
value: mapParameterValueToName(parameter.name),
|
|
||||||
} as Parameter
|
|
||||||
})
|
|
||||||
|
|
||||||
// Logger.log(`${condition.methodReflection.contractName}.${condition.methodReflection.methodName}`,
|
|
||||||
// JSON.stringify(parameters, null, 2))
|
|
||||||
|
|
||||||
const dependencies: Dependency[] = condition.dependencies.map((dep, i) => {
|
|
||||||
return {
|
|
||||||
name: dep,
|
|
||||||
timeout: condition.dependencyTimeoutFlags[i],
|
|
||||||
} as Dependency
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
|
||||||
name: condition.methodReflection.methodName,
|
|
||||||
dependencies,
|
|
||||||
timeout: condition.timeout,
|
|
||||||
isTerminalCondition: condition.isTerminalCondition,
|
|
||||||
conditionKey: condition.condtionKey,
|
|
||||||
contractName: condition.methodReflection.contractName,
|
|
||||||
functionName: condition.methodReflection.methodName,
|
|
||||||
index,
|
|
||||||
parameters,
|
|
||||||
events: condition.events,
|
|
||||||
} as DDOCondition
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private async blendConditions(): Promise<Condition[]> {
|
|
||||||
const methodReflections = await this.getMethodReflections()
|
|
||||||
|
|
||||||
const conditions: Condition[] = methodReflections.map((methodReflection, i) => {
|
|
||||||
const method: Method = this.template.Methods[i]
|
|
||||||
return {
|
|
||||||
methodReflection,
|
|
||||||
timeout: method.timeout,
|
|
||||||
events: method.events,
|
|
||||||
parameters: method.parameters,
|
|
||||||
dependencies: method.dependencies,
|
|
||||||
dependencyTimeoutFlags: method.dependencyTimeoutFlags,
|
|
||||||
isTerminalCondition: method.isTerminalCondition,
|
|
||||||
condtionKey: ServiceAgreementTemplate
|
|
||||||
.generateConditionsKey(this.getId(), methodReflection),
|
|
||||||
} as Condition
|
|
||||||
})
|
|
||||||
|
|
||||||
Logger.debug("Conditions", JSON.stringify(conditions, null, 2))
|
|
||||||
|
|
||||||
return conditions
|
|
||||||
}
|
|
||||||
|
|
||||||
private compressDependencies(dependencies: string[], dependencyTimeoutFlags: number[]): number {
|
|
||||||
|
|
||||||
if (dependencies.length !== dependencyTimeoutFlags.length) {
|
|
||||||
throw new Error("Deps and timeouts need the same length")
|
|
||||||
}
|
|
||||||
|
|
||||||
const mappedDependencies: number[] = []
|
|
||||||
const mappedDependencyTimeoutFlags: number[] = []
|
|
||||||
|
|
||||||
this.template.Methods.forEach((m, i) => {
|
|
||||||
const di = dependencies.findIndex((d) => d === m.name)
|
|
||||||
mappedDependencies.push(di > -1 ? 1 : 0)
|
|
||||||
mappedDependencyTimeoutFlags.push((di > -1 && dependencyTimeoutFlags[di]) ? 1 : 0)
|
|
||||||
})
|
|
||||||
|
|
||||||
if (mappedDependencies.length !== mappedDependencyTimeoutFlags.length) {
|
|
||||||
throw new Error("Deps and timeouts need the same length")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Logger.log(dependencies, mappedDependencies, dependencyTimeoutFlags, mappedDependencyTimeoutFlags)
|
|
||||||
|
|
||||||
let compressedDependencyValue: number = 0
|
|
||||||
const numBits: number = 2 // 1st for dependency, 2nd for timeout flag
|
|
||||||
mappedDependencies.forEach((d: number, i: number) => {
|
|
||||||
const t: number = mappedDependencyTimeoutFlags[i]
|
|
||||||
const offset: number = i * numBits
|
|
||||||
// tslint:disable-next-line
|
|
||||||
compressedDependencyValue |= d * 2 ** (offset + 0) // the dependency bit
|
|
||||||
// tslint:disable-next-line
|
|
||||||
compressedDependencyValue |= t * 2 ** (offset + 1) // the timeout bit
|
|
||||||
})
|
|
||||||
|
|
||||||
return compressedDependencyValue
|
|
||||||
}
|
|
||||||
|
|
||||||
private async getMethodReflections(): Promise<MethodReflection[]> {
|
|
||||||
const methodReflections: MethodReflection[] = []
|
|
||||||
for (const method of this.template.Methods) {
|
|
||||||
methodReflections.push(
|
|
||||||
await ContractReflector.reflectContractMethod(method.contractName, method.methodName),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return methodReflections
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,141 +0,0 @@
|
|||||||
import Event from "../Event"
|
|
||||||
import EventHandler from "../EventHandler"
|
|
||||||
import Method from "../Method"
|
|
||||||
import Parameter from "../Parameter"
|
|
||||||
import TemplateBase from "./TemplateBase"
|
|
||||||
|
|
||||||
export default class Access extends TemplateBase {
|
|
||||||
|
|
||||||
public templateName: string = "Access"
|
|
||||||
public id: string = "0x044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d"
|
|
||||||
public Methods: Method[] = [
|
|
||||||
{
|
|
||||||
name: "lockPayment",
|
|
||||||
contractName: "PaymentConditions",
|
|
||||||
methodName: "lockPayment",
|
|
||||||
timeout: 0,
|
|
||||||
parameters: [
|
|
||||||
{
|
|
||||||
name: "assetId",
|
|
||||||
type: "bytes32",
|
|
||||||
} as Parameter, {
|
|
||||||
name: "price",
|
|
||||||
type: "uint256",
|
|
||||||
} as Parameter,
|
|
||||||
],
|
|
||||||
events: [
|
|
||||||
{
|
|
||||||
name: "PaymentLocked",
|
|
||||||
actorType: "publisher",
|
|
||||||
handler: {
|
|
||||||
moduleName: "accessControl",
|
|
||||||
functionName: "grantAccess",
|
|
||||||
version: "0.1",
|
|
||||||
} as EventHandler,
|
|
||||||
} as Event,
|
|
||||||
],
|
|
||||||
dependencies: [],
|
|
||||||
dependencyTimeoutFlags: [],
|
|
||||||
isTerminalCondition: false,
|
|
||||||
} as Method, {
|
|
||||||
name: "grantAccess",
|
|
||||||
contractName: "AccessConditions",
|
|
||||||
methodName: "grantAccess",
|
|
||||||
timeout: 0,
|
|
||||||
parameters: [
|
|
||||||
{
|
|
||||||
name: "documentKeyId",
|
|
||||||
type: "bytes32",
|
|
||||||
} as Parameter,
|
|
||||||
],
|
|
||||||
events: [
|
|
||||||
{
|
|
||||||
name: "AccessGranted",
|
|
||||||
actorType: "publisher",
|
|
||||||
handler: {
|
|
||||||
moduleName: "payment",
|
|
||||||
functionName: "releasePayment",
|
|
||||||
version: "0.1",
|
|
||||||
} as EventHandler,
|
|
||||||
} as Event,
|
|
||||||
{
|
|
||||||
name: "AccessGranted",
|
|
||||||
actorType: "consumer",
|
|
||||||
handler: {
|
|
||||||
moduleName: "accessControl",
|
|
||||||
functionName: "consumeAsset",
|
|
||||||
version: "0.1",
|
|
||||||
} as EventHandler,
|
|
||||||
} as Event,
|
|
||||||
{
|
|
||||||
name: "AccessTimeout",
|
|
||||||
actorType: "consumer",
|
|
||||||
handler: {
|
|
||||||
moduleName: "payment",
|
|
||||||
functionName: "refundPayment",
|
|
||||||
version: "0.1",
|
|
||||||
} as EventHandler,
|
|
||||||
} as Event,
|
|
||||||
],
|
|
||||||
dependencies: ["lockPayment"],
|
|
||||||
dependencyTimeoutFlags: [0],
|
|
||||||
isTerminalCondition: false,
|
|
||||||
} as Method, {
|
|
||||||
name: "releasePayment",
|
|
||||||
contractName: "PaymentConditions",
|
|
||||||
methodName: "releasePayment",
|
|
||||||
timeout: 0,
|
|
||||||
parameters: [
|
|
||||||
{
|
|
||||||
name: "assetId",
|
|
||||||
type: "bytes32",
|
|
||||||
} as Parameter, {
|
|
||||||
name: "price",
|
|
||||||
type: "uint256",
|
|
||||||
} as Parameter,
|
|
||||||
],
|
|
||||||
events: [
|
|
||||||
{
|
|
||||||
name: "PaymentReleased",
|
|
||||||
actorType: "consumer",
|
|
||||||
handler: {
|
|
||||||
moduleName: "serviceAgreement",
|
|
||||||
functionName: "fulfillAgreement",
|
|
||||||
version: "0.1",
|
|
||||||
} as EventHandler,
|
|
||||||
} as Event,
|
|
||||||
],
|
|
||||||
dependencies: ["grantAccess"],
|
|
||||||
dependencyTimeoutFlags: [0],
|
|
||||||
isTerminalCondition: true,
|
|
||||||
} as Method, {
|
|
||||||
name: "refundPayment",
|
|
||||||
contractName: "PaymentConditions",
|
|
||||||
methodName: "refundPayment",
|
|
||||||
timeout: 10 * 60,
|
|
||||||
parameters: [
|
|
||||||
{
|
|
||||||
name: "assetId",
|
|
||||||
type: "bytes32",
|
|
||||||
} as Parameter, {
|
|
||||||
name: "price",
|
|
||||||
type: "uint256",
|
|
||||||
} as Parameter,
|
|
||||||
],
|
|
||||||
events: [
|
|
||||||
{
|
|
||||||
name: "PaymentRefund",
|
|
||||||
actorType: "publisher",
|
|
||||||
handler: {
|
|
||||||
moduleName: "serviceAgreement",
|
|
||||||
functionName: "terminateAgreement",
|
|
||||||
version: "0.1",
|
|
||||||
} as EventHandler,
|
|
||||||
} as Event,
|
|
||||||
],
|
|
||||||
dependencies: ["lockPayment", "grantAccess"],
|
|
||||||
dependencyTimeoutFlags: [0, 1],
|
|
||||||
isTerminalCondition: true,
|
|
||||||
} as Method,
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
import Method from "../Method"
|
|
||||||
import TemplateBase from "./TemplateBase"
|
|
||||||
|
|
||||||
export default class FitchainCompute extends TemplateBase {
|
|
||||||
|
|
||||||
public templateName: string = "FitchainCompute"
|
|
||||||
public id: string = "0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6"
|
|
||||||
public Methods: Method[] = [
|
|
||||||
{
|
|
||||||
name: "lockPayment",
|
|
||||||
contractName: "PaymentConditions",
|
|
||||||
methodName: "lockPayment",
|
|
||||||
timeout: 0,
|
|
||||||
dependencies: [],
|
|
||||||
dependencyTimeoutFlags: [],
|
|
||||||
isTerminalCondition: false,
|
|
||||||
} as Method,
|
|
||||||
{
|
|
||||||
name: "grantAccess",
|
|
||||||
contractName: "AccessConditions",
|
|
||||||
methodName: "grantAccess",
|
|
||||||
timeout: 10,
|
|
||||||
dependencies: ["lockPayment"],
|
|
||||||
dependencyTimeoutFlags: [0],
|
|
||||||
isTerminalCondition: false,
|
|
||||||
} as Method,
|
|
||||||
{
|
|
||||||
name: "releasePayment",
|
|
||||||
contractName: "PaymentConditions",
|
|
||||||
methodName: "releasePayment",
|
|
||||||
timeout: 10,
|
|
||||||
dependencies: ["grantAccess"],
|
|
||||||
dependencyTimeoutFlags: [0],
|
|
||||||
isTerminalCondition: true,
|
|
||||||
} as Method,
|
|
||||||
{
|
|
||||||
name: "refundPayment",
|
|
||||||
contractName: "PaymentConditions",
|
|
||||||
methodName: "refundPayment",
|
|
||||||
timeout: 10,
|
|
||||||
dependencies: ["lockPayment", "grantAccess"],
|
|
||||||
dependencyTimeoutFlags: [0, 1],
|
|
||||||
isTerminalCondition: true,
|
|
||||||
} as Method,
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
import Method from "../Method"
|
|
||||||
|
|
||||||
export default abstract class TemplateBase {
|
|
||||||
public Methods: Method[]
|
|
||||||
public templateName: string
|
|
||||||
public fulfillmentOperator: number = 1
|
|
||||||
public id: string = "0x00000000000000000000000000000000000000000000000000000000000000"
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user