From b9170e929492f3305a420c75c7d12d06b288e0ab Mon Sep 17 00:00:00 2001 From: Elena Izaguirre Date: Wed, 22 Sep 2021 09:11:29 +0200 Subject: [PATCH] fix: openapi tests for besu, htlc-eth-besu and htlc-eth-besu-erc20 Changes endpoints getSingleStatus and getStatus in htlc-eth-besu and htlc-eth-besu-erc20 which now are of type post and defines for that new request schemas. Includes tests for all endpoints in besu, htlc-eth-besu and htlc-eth-besu-erc20, each of them with test cases: - Right request - Request including an invalid parameter - Request without a required parameter Closes #1291 Relationed with #847 Signed-off-by: Elena Izaguirre --- .../src/main/json/openapi.json | 142 ++- .../generated/openapi/typescript-axios/api.ts | 196 ++-- .../typescript/plugin-htlc-eth-besu-erc20.ts | 29 +- .../get-single-status-endpoint.ts | 19 +- .../web-services/get-status-endpoint.ts | 22 +- .../src/main/json/openapi.json | 151 ++- .../generated/openapi/typescript-axios/api.ts | 188 ++-- .../main/typescript/plugin-htlc-eth-besu.ts | 29 +- .../get-single-status-endpoint.ts | 19 +- .../web-services/get-status-endpoint.ts | 22 +- .../src/main/json/openapi.json | 18 +- .../openapi/openapi-validation.test.ts | 891 ++++++++++++++++++ ...get-single-status-endpoint-invalid.test.ts | 6 +- .../get-single-status-endpoint.test.ts | 6 +- .../get-status-endpoint.test.ts | 10 +- .../openapi/openapi-validation.test.ts | 803 ++++++++++++++++ .../refund-endpoint.test.ts | 4 +- .../withdraw-endpoint.test.ts | 4 +- ...get-single-status-endpoint-invalid.test.ts | 10 +- .../get-single-status-endpoint.test.ts | 6 +- .../get-status-endpoint-invalid.test.ts | 6 +- .../get-status-endpoint.test.ts | 4 +- .../openapi/openapi-validation.test.ts | 804 ++++++++++++++++ .../refund-endpoint.test.ts | 4 +- .../withdraw-endpoint.test.ts | 6 +- 25 files changed, 2907 insertions(+), 492 deletions(-) create mode 100644 packages/cactus-plugin-ledger-connector-besu/src/test/typescript/integration/plugin-ledger-connector-besu/openapi/openapi-validation.test.ts create mode 100644 packages/cactus-test-plugin-htlc-eth-besu-erc20/src/test/typescript/integration/plugin-htlc-eth-besu-erc20/openapi/openapi-validation.test.ts create mode 100644 packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/openapi/openapi-validation.test.ts diff --git a/packages/cactus-plugin-htlc-eth-besu-erc20/src/main/json/openapi.json b/packages/cactus-plugin-htlc-eth-besu-erc20/src/main/json/openapi.json index d99ebf7a6b..dfe759d728 100644 --- a/packages/cactus-plugin-htlc-eth-besu-erc20/src/main/json/openapi.json +++ b/packages/cactus-plugin-htlc-eth-besu-erc20/src/main/json/openapi.json @@ -191,6 +191,57 @@ } } }, + "GetStatusRequest": { + "description": "Defines the parameters for retrieving the status of the HTLC swap.", + "required": [ + "ids", + "web3SigningCredential", + "connectorId", + "keychainId" + ], + "additionalProperties": false, + "properties": { + "ids": { + "type": "array", + "items": { + "type": "string" + } + }, + "web3SigningCredential": { + "$ref": "https://raw.githubusercontent.com/hyperledger/cactus/v0.8.0/packages/cactus-plugin-ledger-connector-besu/src/main/json/openapi.json#/components/schemas/Web3SigningCredential" + }, + "connectorId": { + "type": "string" + }, + "keychainId": { + "type": "string" + } + } + }, + "GetSingleStatusRequest": { + "description": "Defines the parameters for retrieving the single status of the HTLC swap.", + "required": [ + "id", + "web3SigningCredential", + "connectorId", + "keychainId" + ], + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "web3SigningCredential": { + "$ref": "https://raw.githubusercontent.com/hyperledger/cactus/v0.8.0/packages/cactus-plugin-ledger-connector-besu/src/main/json/openapi.json#/components/schemas/Web3SigningCredential" + }, + "connectorId": { + "type": "string" + }, + "keychainId": { + "type": "string" + } + } + }, "InitializeRequest": { "type": "object", "required": [ @@ -325,53 +376,23 @@ } }, "/api/v1/plugins/@hyperledger/cactus-plugin-htlc-eth-besu-erc20/get-status": { - "get": { + "post": { "x-hyperledger-cactus": { "http": { - "verbLowerCase": "get", + "verbLowerCase": "post", "path": "/api/v1/plugins/@hyperledger/cactus-plugin-htlc-eth-besu-erc20/get-status" } }, "operationId": "getStatusV1", - "summary": "Get array of status of a hashtimelock contract, the status are ( 0 - Invalid, 1 - Active, 2 - Refunded, 3 - Withdrawn, 4 - Expired)", - "parameters": [ - { - "name": "ids", - "in": "query", - "required": true, - "schema": { - "type": "array", - "items": { - "type": "string", - "format": "bytes32" + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetStatusRequest" } } - }, - { - "name": "web3SigningCredential", - "in": "query", - "required": true, - "schema": { - "$ref": "https://raw.githubusercontent.com/hyperledger/cactus/v0.8.0/packages/cactus-plugin-ledger-connector-besu/src/main/json/openapi.json#/components/schemas/Web3SigningCredential" - } - }, - { - "name": "connectorId", - "in": "query", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "keychainId", - "in": "query", - "required": true, - "schema": { - "type": "string" - } } - ], + }, "responses": { "200": { "description": "OK", @@ -381,50 +402,23 @@ } }, "/api/v1/plugins/@hyperledger/cactus-plugin-htlc-eth-besu-erc20/get-single-status": { - "get": { + "post": { "x-hyperledger-cactus": { "http": { - "verbLowerCase": "get", + "verbLowerCase": "post", "path": "/api/v1/plugins/@hyperledger/cactus-plugin-htlc-eth-besu-erc20/get-single-status" } }, "operationId": "getSingleStatusV1", - "summary": "Get a status of a hashtimelock contract, the status are ( 0 - Invalid, 1 - Active, 2 - Refunded, 3 - Withdrawn, 4 - Expired)", - "parameters": [ - { - "name": "id", - "in": "query", - "required": true, - "schema": { - "type": "string", - "format": "bytes32" - } - }, - { - "name": "web3SigningCredential", - "in": "query", - "required": true, - "schema": { - "$ref": "https://raw.githubusercontent.com/hyperledger/cactus/v0.8.0/packages/cactus-plugin-ledger-connector-besu/src/main/json/openapi.json#/components/schemas/Web3SigningCredential" - } - }, - { - "name": "connectorId", - "in": "query", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "keychainId", - "in": "query", - "required": true, - "schema": { - "type": "string" + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetSingleStatusRequest" + } } } - ], + }, "responses": { "200": { "description": "OK", diff --git a/packages/cactus-plugin-htlc-eth-besu-erc20/src/main/typescript/generated/openapi/typescript-axios/api.ts b/packages/cactus-plugin-htlc-eth-besu-erc20/src/main/typescript/generated/openapi/typescript-axios/api.ts index bc3411a806..7d801f7f76 100644 --- a/packages/cactus-plugin-htlc-eth-besu-erc20/src/main/typescript/generated/openapi/typescript-axios/api.ts +++ b/packages/cactus-plugin-htlc-eth-besu-erc20/src/main/typescript/generated/openapi/typescript-axios/api.ts @@ -21,6 +21,68 @@ import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObj // @ts-ignore import { BASE_PATH, COLLECTION_FORMATS, RequestArgs, BaseAPI, RequiredError } from './base'; +/** + * Defines the parameters for retrieving the single status of the HTLC swap. + * @export + * @interface GetSingleStatusRequest + */ +export interface GetSingleStatusRequest { + /** + * + * @type {string} + * @memberof GetSingleStatusRequest + */ + id: string; + /** + * + * @type {Web3SigningCredential} + * @memberof GetSingleStatusRequest + */ + web3SigningCredential: Web3SigningCredential; + /** + * + * @type {string} + * @memberof GetSingleStatusRequest + */ + connectorId: string; + /** + * + * @type {string} + * @memberof GetSingleStatusRequest + */ + keychainId: string; +} +/** + * Defines the parameters for retrieving the status of the HTLC swap. + * @export + * @interface GetStatusRequest + */ +export interface GetStatusRequest { + /** + * + * @type {Array} + * @memberof GetStatusRequest + */ + ids: Array; + /** + * + * @type {Web3SigningCredential} + * @memberof GetStatusRequest + */ + web3SigningCredential: Web3SigningCredential; + /** + * + * @type {string} + * @memberof GetStatusRequest + */ + connectorId: string; + /** + * + * @type {string} + * @memberof GetStatusRequest + */ + keychainId: string; +} /** * * @export @@ -421,23 +483,11 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati return { /** * - * @summary Get a status of a hashtimelock contract, the status are ( 0 - Invalid, 1 - Active, 2 - Refunded, 3 - Withdrawn, 4 - Expired) - * @param {string} id - * @param {Web3SigningCredential} web3SigningCredential - * @param {string} connectorId - * @param {string} keychainId + * @param {GetSingleStatusRequest} [getSingleStatusRequest] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getSingleStatusV1: async (id: string, web3SigningCredential: Web3SigningCredential, connectorId: string, keychainId: string, options: any = {}): Promise => { - // verify required parameter 'id' is not null or undefined - assertParamExists('getSingleStatusV1', 'id', id) - // verify required parameter 'web3SigningCredential' is not null or undefined - assertParamExists('getSingleStatusV1', 'web3SigningCredential', web3SigningCredential) - // verify required parameter 'connectorId' is not null or undefined - assertParamExists('getSingleStatusV1', 'connectorId', connectorId) - // verify required parameter 'keychainId' is not null or undefined - assertParamExists('getSingleStatusV1', 'keychainId', keychainId) + getSingleStatusV1: async (getSingleStatusRequest?: GetSingleStatusRequest, options: any = {}): Promise => { const localVarPath = `/api/v1/plugins/@hyperledger/cactus-plugin-htlc-eth-besu-erc20/get-single-status`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -446,31 +496,18 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati baseOptions = configuration.baseOptions; } - const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; const localVarHeaderParameter = {} as any; const localVarQueryParameter = {} as any; - if (id !== undefined) { - localVarQueryParameter['id'] = id; - } - - if (web3SigningCredential !== undefined) { - localVarQueryParameter['web3SigningCredential'] = web3SigningCredential; - } - - if (connectorId !== undefined) { - localVarQueryParameter['connectorId'] = connectorId; - } - - if (keychainId !== undefined) { - localVarQueryParameter['keychainId'] = keychainId; - } - + localVarHeaderParameter['Content-Type'] = 'application/json'; + setSearchParams(localVarUrlObj, localVarQueryParameter, options.query); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(getSingleStatusRequest, localVarRequestOptions, configuration) return { url: toPathString(localVarUrlObj), @@ -479,23 +516,11 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati }, /** * - * @summary Get array of status of a hashtimelock contract, the status are ( 0 - Invalid, 1 - Active, 2 - Refunded, 3 - Withdrawn, 4 - Expired) - * @param {Array} ids - * @param {Web3SigningCredential} web3SigningCredential - * @param {string} connectorId - * @param {string} keychainId + * @param {GetStatusRequest} [getStatusRequest] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getStatusV1: async (ids: Array, web3SigningCredential: Web3SigningCredential, connectorId: string, keychainId: string, options: any = {}): Promise => { - // verify required parameter 'ids' is not null or undefined - assertParamExists('getStatusV1', 'ids', ids) - // verify required parameter 'web3SigningCredential' is not null or undefined - assertParamExists('getStatusV1', 'web3SigningCredential', web3SigningCredential) - // verify required parameter 'connectorId' is not null or undefined - assertParamExists('getStatusV1', 'connectorId', connectorId) - // verify required parameter 'keychainId' is not null or undefined - assertParamExists('getStatusV1', 'keychainId', keychainId) + getStatusV1: async (getStatusRequest?: GetStatusRequest, options: any = {}): Promise => { const localVarPath = `/api/v1/plugins/@hyperledger/cactus-plugin-htlc-eth-besu-erc20/get-status`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -504,31 +529,18 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati baseOptions = configuration.baseOptions; } - const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; const localVarHeaderParameter = {} as any; const localVarQueryParameter = {} as any; - if (ids) { - localVarQueryParameter['ids'] = ids; - } - - if (web3SigningCredential !== undefined) { - localVarQueryParameter['web3SigningCredential'] = web3SigningCredential; - } - - if (connectorId !== undefined) { - localVarQueryParameter['connectorId'] = connectorId; - } - - if (keychainId !== undefined) { - localVarQueryParameter['keychainId'] = keychainId; - } - + localVarHeaderParameter['Content-Type'] = 'application/json'; + setSearchParams(localVarUrlObj, localVarQueryParameter, options.query); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(getStatusRequest, localVarRequestOptions, configuration) return { url: toPathString(localVarUrlObj), @@ -683,30 +695,22 @@ export const DefaultApiFp = function(configuration?: Configuration) { return { /** * - * @summary Get a status of a hashtimelock contract, the status are ( 0 - Invalid, 1 - Active, 2 - Refunded, 3 - Withdrawn, 4 - Expired) - * @param {string} id - * @param {Web3SigningCredential} web3SigningCredential - * @param {string} connectorId - * @param {string} keychainId + * @param {GetSingleStatusRequest} [getSingleStatusRequest] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async getSingleStatusV1(id: string, web3SigningCredential: Web3SigningCredential, connectorId: string, keychainId: string, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.getSingleStatusV1(id, web3SigningCredential, connectorId, keychainId, options); + async getSingleStatusV1(getSingleStatusRequest?: GetSingleStatusRequest, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getSingleStatusV1(getSingleStatusRequest, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** * - * @summary Get array of status of a hashtimelock contract, the status are ( 0 - Invalid, 1 - Active, 2 - Refunded, 3 - Withdrawn, 4 - Expired) - * @param {Array} ids - * @param {Web3SigningCredential} web3SigningCredential - * @param {string} connectorId - * @param {string} keychainId + * @param {GetStatusRequest} [getStatusRequest] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async getStatusV1(ids: Array, web3SigningCredential: Web3SigningCredential, connectorId: string, keychainId: string, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>> { - const localVarAxiosArgs = await localVarAxiosParamCreator.getStatusV1(ids, web3SigningCredential, connectorId, keychainId, options); + async getStatusV1(getStatusRequest?: GetStatusRequest, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getStatusV1(getStatusRequest, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -765,29 +769,21 @@ export const DefaultApiFactory = function (configuration?: Configuration, basePa return { /** * - * @summary Get a status of a hashtimelock contract, the status are ( 0 - Invalid, 1 - Active, 2 - Refunded, 3 - Withdrawn, 4 - Expired) - * @param {string} id - * @param {Web3SigningCredential} web3SigningCredential - * @param {string} connectorId - * @param {string} keychainId + * @param {GetSingleStatusRequest} [getSingleStatusRequest] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getSingleStatusV1(id: string, web3SigningCredential: Web3SigningCredential, connectorId: string, keychainId: string, options?: any): AxiosPromise { - return localVarFp.getSingleStatusV1(id, web3SigningCredential, connectorId, keychainId, options).then((request) => request(axios, basePath)); + getSingleStatusV1(getSingleStatusRequest?: GetSingleStatusRequest, options?: any): AxiosPromise { + return localVarFp.getSingleStatusV1(getSingleStatusRequest, options).then((request) => request(axios, basePath)); }, /** * - * @summary Get array of status of a hashtimelock contract, the status are ( 0 - Invalid, 1 - Active, 2 - Refunded, 3 - Withdrawn, 4 - Expired) - * @param {Array} ids - * @param {Web3SigningCredential} web3SigningCredential - * @param {string} connectorId - * @param {string} keychainId + * @param {GetStatusRequest} [getStatusRequest] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getStatusV1(ids: Array, web3SigningCredential: Web3SigningCredential, connectorId: string, keychainId: string, options?: any): AxiosPromise> { - return localVarFp.getStatusV1(ids, web3SigningCredential, connectorId, keychainId, options).then((request) => request(axios, basePath)); + getStatusV1(getStatusRequest?: GetStatusRequest, options?: any): AxiosPromise> { + return localVarFp.getStatusV1(getStatusRequest, options).then((request) => request(axios, basePath)); }, /** * @@ -841,32 +837,24 @@ export const DefaultApiFactory = function (configuration?: Configuration, basePa export class DefaultApi extends BaseAPI { /** * - * @summary Get a status of a hashtimelock contract, the status are ( 0 - Invalid, 1 - Active, 2 - Refunded, 3 - Withdrawn, 4 - Expired) - * @param {string} id - * @param {Web3SigningCredential} web3SigningCredential - * @param {string} connectorId - * @param {string} keychainId + * @param {GetSingleStatusRequest} [getSingleStatusRequest] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof DefaultApi */ - public getSingleStatusV1(id: string, web3SigningCredential: Web3SigningCredential, connectorId: string, keychainId: string, options?: any) { - return DefaultApiFp(this.configuration).getSingleStatusV1(id, web3SigningCredential, connectorId, keychainId, options).then((request) => request(this.axios, this.basePath)); + public getSingleStatusV1(getSingleStatusRequest?: GetSingleStatusRequest, options?: any) { + return DefaultApiFp(this.configuration).getSingleStatusV1(getSingleStatusRequest, options).then((request) => request(this.axios, this.basePath)); } /** * - * @summary Get array of status of a hashtimelock contract, the status are ( 0 - Invalid, 1 - Active, 2 - Refunded, 3 - Withdrawn, 4 - Expired) - * @param {Array} ids - * @param {Web3SigningCredential} web3SigningCredential - * @param {string} connectorId - * @param {string} keychainId + * @param {GetStatusRequest} [getStatusRequest] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof DefaultApi */ - public getStatusV1(ids: Array, web3SigningCredential: Web3SigningCredential, connectorId: string, keychainId: string, options?: any) { - return DefaultApiFp(this.configuration).getStatusV1(ids, web3SigningCredential, connectorId, keychainId, options).then((request) => request(this.axios, this.basePath)); + public getStatusV1(getStatusRequest?: GetStatusRequest, options?: any) { + return DefaultApiFp(this.configuration).getStatusV1(getStatusRequest, options).then((request) => request(this.axios, this.basePath)); } /** diff --git a/packages/cactus-plugin-htlc-eth-besu-erc20/src/main/typescript/plugin-htlc-eth-besu-erc20.ts b/packages/cactus-plugin-htlc-eth-besu-erc20/src/main/typescript/plugin-htlc-eth-besu-erc20.ts index d380746d1d..92ae241ef7 100644 --- a/packages/cactus-plugin-htlc-eth-besu-erc20/src/main/typescript/plugin-htlc-eth-besu-erc20.ts +++ b/packages/cactus-plugin-htlc-eth-besu-erc20/src/main/typescript/plugin-htlc-eth-besu-erc20.ts @@ -14,7 +14,6 @@ import { InvokeContractV1Response, PluginLedgerConnectorBesu, RunTransactionResponse, - Web3SigningCredential, } from "@hyperledger/cactus-plugin-ledger-connector-besu"; import { GetSingleStatusEndpoint } from "./web-services/get-single-status-endpoint"; import { GetStatusEndpoint } from "./web-services/get-status-endpoint"; @@ -29,6 +28,8 @@ import { InitializeRequest, RefundRequest, WithdrawRequest, + GetStatusRequest, + GetSingleStatusRequest, } from "./generated/openapi/typescript-axios"; export interface IPluginHtlcEthBesuErc20Options extends ICactusPluginOptions { @@ -230,43 +231,37 @@ export class PluginHtlcEthBesuErc20 } public async getSingleStatus( - id: string, - connectorId: string, - keychainId: string, - web3SigningCredential: Web3SigningCredential, + req: GetSingleStatusRequest, ): Promise { const connector = this.pluginRegistry.plugins.find( - (plugin) => plugin.getInstanceId() == connectorId, + (plugin) => plugin.getInstanceId() == req.connectorId, ) as PluginLedgerConnectorBesu; const result = await connector.invokeContract({ contractName: HashTimeLockJSON.contractName, - signingCredential: web3SigningCredential, + signingCredential: req.web3SigningCredential, invocationType: EthContractInvocationType.Call, methodName: "getSingleStatus", - params: [id], - keychainId, + params: [req.id], + keychainId: req.keychainId, }); return result; } public async getStatus( - ids: string[], - connectorId: string, - keychainId: string, - web3SigningCredential: Web3SigningCredential, + req: GetStatusRequest, ): Promise { const connector = this.pluginRegistry.plugins.find( - (plugin) => plugin.getInstanceId() == connectorId, + (plugin) => plugin.getInstanceId() == req.connectorId, ) as PluginLedgerConnectorBesu; const result = await connector.invokeContract({ contractName: HashTimeLockJSON.contractName, - signingCredential: web3SigningCredential, + signingCredential: req.web3SigningCredential, invocationType: EthContractInvocationType.Call, methodName: "getStatus", - params: [ids], - keychainId, + params: [req.ids], + keychainId: req.keychainId, }); return result; } diff --git a/packages/cactus-plugin-htlc-eth-besu-erc20/src/main/typescript/web-services/get-single-status-endpoint.ts b/packages/cactus-plugin-htlc-eth-besu-erc20/src/main/typescript/web-services/get-single-status-endpoint.ts index b1a18c982e..1840d1cf8b 100644 --- a/packages/cactus-plugin-htlc-eth-besu-erc20/src/main/typescript/web-services/get-single-status-endpoint.ts +++ b/packages/cactus-plugin-htlc-eth-besu-erc20/src/main/typescript/web-services/get-single-status-endpoint.ts @@ -14,7 +14,6 @@ import { import { registerWebServiceEndpoint } from "@hyperledger/cactus-core"; import OAS from "../../json/openapi.json"; import { PluginHtlcEthBesuErc20 } from "../plugin-htlc-eth-besu-erc20"; -import { Web3SigningCredential } from "../generated/openapi/typescript-axios"; export interface IGetSingleStatusEndpointOptions { logLevel?: LogLevelDesc; @@ -43,15 +42,15 @@ export class GetSingleStatusEndpoint implements IWebServiceEndpoint { ]; } public getVerbLowerCase(): string { - return this.oasPath.get["x-hyperledger-cactus"].http.verbLowerCase; + return this.oasPath.post["x-hyperledger-cactus"].http.verbLowerCase; } public getPath(): string { - return this.oasPath.get["x-hyperledger-cactus"].http.path; + return this.oasPath.post["x-hyperledger-cactus"].http.path; } public getOperationId(): string { - return this.oasPath.get.operationId; + return this.oasPath.post.operationId; } getAuthorizationOptionsProvider(): IAsyncProvider { @@ -77,18 +76,10 @@ export class GetSingleStatusEndpoint implements IWebServiceEndpoint { public async handleRequest(req: Request, res: Response): Promise { const fnTag = "GetSingleStatusEndpoint#handleRequest()"; - this.log.debug(`GET ${this.getPath()}`); + this.log.debug(`POST ${this.getPath()}`); try { - const id = req.query["id"]; - const connectorId = req.query["connectorId"]; - const keychainId = req.query["keychainId"]; - const web3SigningCredential = req.query["web3SigningCredential"]; - const { callOutput } = await this.options.plugin.getSingleStatus( - id as string, - connectorId as string, - keychainId as string, - (web3SigningCredential as unknown) as Web3SigningCredential, + req.body, ); res.send(callOutput); diff --git a/packages/cactus-plugin-htlc-eth-besu-erc20/src/main/typescript/web-services/get-status-endpoint.ts b/packages/cactus-plugin-htlc-eth-besu-erc20/src/main/typescript/web-services/get-status-endpoint.ts index 27e388a6de..562cf298cc 100644 --- a/packages/cactus-plugin-htlc-eth-besu-erc20/src/main/typescript/web-services/get-status-endpoint.ts +++ b/packages/cactus-plugin-htlc-eth-besu-erc20/src/main/typescript/web-services/get-status-endpoint.ts @@ -13,7 +13,6 @@ import { IWebServiceEndpoint, } from "@hyperledger/cactus-core-api"; import { registerWebServiceEndpoint } from "@hyperledger/cactus-core"; -import { Web3SigningCredential } from "@hyperledger/cactus-plugin-ledger-connector-besu"; import OAS from "../../json/openapi.json"; import { PluginHtlcEthBesuErc20 } from "../plugin-htlc-eth-besu-erc20"; @@ -45,15 +44,15 @@ export class GetStatusEndpoint implements IWebServiceEndpoint { } public getVerbLowerCase(): string { - return this.oasPath.get["x-hyperledger-cactus"].http.verbLowerCase; + return this.oasPath.post["x-hyperledger-cactus"].http.verbLowerCase; } public getPath(): string { - return this.oasPath.get["x-hyperledger-cactus"].http.path; + return this.oasPath.post["x-hyperledger-cactus"].http.path; } public getOperationId(): string { - return this.oasPath.get.operationId; + return this.oasPath.post.operationId; } getAuthorizationOptionsProvider(): IAsyncProvider { @@ -79,20 +78,9 @@ export class GetStatusEndpoint implements IWebServiceEndpoint { public async handleRequest(req: Request, res: Response): Promise { const fnTag = "GetStatusEndpoint#handleRequest()"; - this.log.debug(`GET ${this.getPath()}`); + this.log.debug(`POST ${this.getPath()}`); try { - const query = req.query["ids"]?.toString(); - const ids = query?.split(","); - const connectorId = req.query["connectorId"]; - const keychainId = req.query["keychainId"]; - const web3SigningCredential = req.query["web3SigningCredential"]; - - const { callOutput } = await this.options.plugin.getStatus( - ids as string[], - connectorId as string, - keychainId as string, - (web3SigningCredential as unknown) as Web3SigningCredential, - ); + const { callOutput } = await this.options.plugin.getStatus(req.body); res.send(callOutput); } catch (ex) { diff --git a/packages/cactus-plugin-htlc-eth-besu/src/main/json/openapi.json b/packages/cactus-plugin-htlc-eth-besu/src/main/json/openapi.json index 7576d7a716..ea006c2dcb 100644 --- a/packages/cactus-plugin-htlc-eth-besu/src/main/json/openapi.json +++ b/packages/cactus-plugin-htlc-eth-besu/src/main/json/openapi.json @@ -40,8 +40,7 @@ "type": "number" }, "hashLock": { - "type": "string", - "format": "bytes32" + "type": "string" }, "receiver": { "type": "string" @@ -60,9 +59,7 @@ "nullable": false }, "web3SigningCredential": { - "description": "Web3SigningCredentialType", - "$ref": "https://raw.githubusercontent.com/hyperledger/cactus/v0.8.0/packages/cactus-plugin-ledger-connector-besu/src/main/json/openapi.json#/components/schemas/Web3SigningCredential", - "nullable": false + "$ref": "https://raw.githubusercontent.com/hyperledger/cactus/v0.8.0/packages/cactus-plugin-ledger-connector-besu/src/main/json/openapi.json#/components/schemas/Web3SigningCredential" }, "keychainId": { "description": "keychainId for the keychian plugin", @@ -97,9 +94,7 @@ "nullable": false }, "web3SigningCredential": { - "description": "Web3SigningCredentialType", - "$ref": "https://raw.githubusercontent.com/hyperledger/cactus/v0.8.0/packages/cactus-plugin-ledger-connector-besu/src/main/json/openapi.json#/components/schemas/Web3SigningCredential", - "nullable": false + "$ref": "https://raw.githubusercontent.com/hyperledger/cactus/v0.8.0/packages/cactus-plugin-ledger-connector-besu/src/main/json/openapi.json#/components/schemas/Web3SigningCredential" }, "connectorId": { "description": "connectorId for the connector besu plugin", @@ -205,6 +200,57 @@ "type": "number" } } + }, + "GetStatusRequest": { + "description": "Defines the parameters for retrieving the status of the HTLC swap.", + "required": [ + "ids", + "web3SigningCredential", + "connectorId", + "keychainId" + ], + "additionalProperties": false, + "properties": { + "ids": { + "type": "array", + "items": { + "type": "string" + } + }, + "web3SigningCredential": { + "$ref": "https://raw.githubusercontent.com/hyperledger/cactus/v0.8.0/packages/cactus-plugin-ledger-connector-besu/src/main/json/openapi.json#/components/schemas/Web3SigningCredential" + }, + "connectorId": { + "type": "string" + }, + "keychainId": { + "type": "string" + } + } + }, + "GetSingleStatusRequest": { + "description": "Defines the parameters for retrieving the single status of the HTLC swap.", + "required": [ + "id", + "web3SigningCredential", + "connectorId", + "keychainId" + ], + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "web3SigningCredential": { + "$ref": "https://raw.githubusercontent.com/hyperledger/cactus/v0.8.0/packages/cactus-plugin-ledger-connector-besu/src/main/json/openapi.json#/components/schemas/Web3SigningCredential" + }, + "connectorId": { + "type": "string" + }, + "keychainId": { + "type": "string" + } + } } }, "responses": { @@ -334,52 +380,23 @@ } }, "/api/v1/plugins/@hyperledger/cactus-plugin-htlc-eth-besu/get-status": { - "get": { + "post": { "x-hyperledger-cactus": { "http": { - "verbLowerCase": "get", + "verbLowerCase": "post", "path": "/api/v1/plugins/@hyperledger/cactus-plugin-htlc-eth-besu/get-status" } }, "operationId": "getStatusV1", - "parameters": [ - { - "name": "ids", - "in": "query", - "required": true, - "schema": { - "type": "array", - "items": { - "type": "string", - "format": "bytes32" + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetStatusRequest" } } - }, - { - "name": "web3SigningCredential", - "in": "query", - "required": true, - "schema": { - "$ref": "https://raw.githubusercontent.com/hyperledger/cactus/v0.8.0/packages/cactus-plugin-ledger-connector-besu/src/main/json/openapi.json#/components/schemas/Web3SigningCredential" - } - }, - { - "name": "connectorId", - "in": "query", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "keychainId", - "in": "query", - "required": true, - "schema": { - "type": "string" - } } - ], + }, "responses": { "200": { "description": "OK", @@ -389,49 +406,23 @@ } }, "/api/v1/plugins/@hyperledger/cactus-plugin-htlc-eth-besu/get-single-status": { - "get": { + "post": { "x-hyperledger-cactus": { "http": { - "verbLowerCase": "get", + "verbLowerCase": "post", "path": "/api/v1/plugins/@hyperledger/cactus-plugin-htlc-eth-besu/get-single-status" } }, "operationId": "getSingleStatusV1", - "parameters": [ - { - "name": "id", - "in": "query", - "required": true, - "schema": { - "type": "string", - "format": "bytes32" - } - }, - { - "name": "web3SigningCredential", - "in": "query", - "required": true, - "schema": { - "$ref": "https://raw.githubusercontent.com/hyperledger/cactus/v0.8.0/packages/cactus-plugin-ledger-connector-besu/src/main/json/openapi.json#/components/schemas/Web3SigningCredential" - } - }, - { - "name": "connectorId", - "in": "query", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "keychainId", - "in": "query", - "required": true, - "schema": { - "type": "string" + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetSingleStatusRequest" + } } } - ], + }, "responses": { "200": { "description": "OK", diff --git a/packages/cactus-plugin-htlc-eth-besu/src/main/typescript/generated/openapi/typescript-axios/api.ts b/packages/cactus-plugin-htlc-eth-besu/src/main/typescript/generated/openapi/typescript-axios/api.ts index 924a0a5859..613aaba70f 100644 --- a/packages/cactus-plugin-htlc-eth-besu/src/main/typescript/generated/openapi/typescript-axios/api.ts +++ b/packages/cactus-plugin-htlc-eth-besu/src/main/typescript/generated/openapi/typescript-axios/api.ts @@ -21,6 +21,68 @@ import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObj // @ts-ignore import { BASE_PATH, COLLECTION_FORMATS, RequestArgs, BaseAPI, RequiredError } from './base'; +/** + * Defines the parameters for retrieving the single status of the HTLC swap. + * @export + * @interface GetSingleStatusRequest + */ +export interface GetSingleStatusRequest { + /** + * + * @type {string} + * @memberof GetSingleStatusRequest + */ + id: string; + /** + * + * @type {Web3SigningCredential} + * @memberof GetSingleStatusRequest + */ + web3SigningCredential: Web3SigningCredential; + /** + * + * @type {string} + * @memberof GetSingleStatusRequest + */ + connectorId: string; + /** + * + * @type {string} + * @memberof GetSingleStatusRequest + */ + keychainId: string; +} +/** + * Defines the parameters for retrieving the status of the HTLC swap. + * @export + * @interface GetStatusRequest + */ +export interface GetStatusRequest { + /** + * + * @type {Array} + * @memberof GetStatusRequest + */ + ids: Array; + /** + * + * @type {Web3SigningCredential} + * @memberof GetStatusRequest + */ + web3SigningCredential: Web3SigningCredential; + /** + * + * @type {string} + * @memberof GetStatusRequest + */ + connectorId: string; + /** + * + * @type {string} + * @memberof GetStatusRequest + */ + keychainId: string; +} /** * * @export @@ -415,22 +477,11 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati return { /** * - * @param {string} id - * @param {Web3SigningCredential} web3SigningCredential - * @param {string} connectorId - * @param {string} keychainId + * @param {GetSingleStatusRequest} [getSingleStatusRequest] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getSingleStatusV1: async (id: string, web3SigningCredential: Web3SigningCredential, connectorId: string, keychainId: string, options: any = {}): Promise => { - // verify required parameter 'id' is not null or undefined - assertParamExists('getSingleStatusV1', 'id', id) - // verify required parameter 'web3SigningCredential' is not null or undefined - assertParamExists('getSingleStatusV1', 'web3SigningCredential', web3SigningCredential) - // verify required parameter 'connectorId' is not null or undefined - assertParamExists('getSingleStatusV1', 'connectorId', connectorId) - // verify required parameter 'keychainId' is not null or undefined - assertParamExists('getSingleStatusV1', 'keychainId', keychainId) + getSingleStatusV1: async (getSingleStatusRequest?: GetSingleStatusRequest, options: any = {}): Promise => { const localVarPath = `/api/v1/plugins/@hyperledger/cactus-plugin-htlc-eth-besu/get-single-status`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -439,31 +490,18 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati baseOptions = configuration.baseOptions; } - const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; const localVarHeaderParameter = {} as any; const localVarQueryParameter = {} as any; - if (id !== undefined) { - localVarQueryParameter['id'] = id; - } - - if (web3SigningCredential !== undefined) { - localVarQueryParameter['web3SigningCredential'] = web3SigningCredential; - } - - if (connectorId !== undefined) { - localVarQueryParameter['connectorId'] = connectorId; - } - - if (keychainId !== undefined) { - localVarQueryParameter['keychainId'] = keychainId; - } - + localVarHeaderParameter['Content-Type'] = 'application/json'; + setSearchParams(localVarUrlObj, localVarQueryParameter, options.query); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(getSingleStatusRequest, localVarRequestOptions, configuration) return { url: toPathString(localVarUrlObj), @@ -472,22 +510,11 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati }, /** * - * @param {Array} ids - * @param {Web3SigningCredential} web3SigningCredential - * @param {string} connectorId - * @param {string} keychainId + * @param {GetStatusRequest} [getStatusRequest] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getStatusV1: async (ids: Array, web3SigningCredential: Web3SigningCredential, connectorId: string, keychainId: string, options: any = {}): Promise => { - // verify required parameter 'ids' is not null or undefined - assertParamExists('getStatusV1', 'ids', ids) - // verify required parameter 'web3SigningCredential' is not null or undefined - assertParamExists('getStatusV1', 'web3SigningCredential', web3SigningCredential) - // verify required parameter 'connectorId' is not null or undefined - assertParamExists('getStatusV1', 'connectorId', connectorId) - // verify required parameter 'keychainId' is not null or undefined - assertParamExists('getStatusV1', 'keychainId', keychainId) + getStatusV1: async (getStatusRequest?: GetStatusRequest, options: any = {}): Promise => { const localVarPath = `/api/v1/plugins/@hyperledger/cactus-plugin-htlc-eth-besu/get-status`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -496,31 +523,18 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati baseOptions = configuration.baseOptions; } - const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; const localVarHeaderParameter = {} as any; const localVarQueryParameter = {} as any; - if (ids) { - localVarQueryParameter['ids'] = ids; - } - - if (web3SigningCredential !== undefined) { - localVarQueryParameter['web3SigningCredential'] = web3SigningCredential; - } - - if (connectorId !== undefined) { - localVarQueryParameter['connectorId'] = connectorId; - } - - if (keychainId !== undefined) { - localVarQueryParameter['keychainId'] = keychainId; - } - + localVarHeaderParameter['Content-Type'] = 'application/json'; + setSearchParams(localVarUrlObj, localVarQueryParameter, options.query); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(getStatusRequest, localVarRequestOptions, configuration) return { url: toPathString(localVarUrlObj), @@ -671,28 +685,22 @@ export const DefaultApiFp = function(configuration?: Configuration) { return { /** * - * @param {string} id - * @param {Web3SigningCredential} web3SigningCredential - * @param {string} connectorId - * @param {string} keychainId + * @param {GetSingleStatusRequest} [getSingleStatusRequest] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async getSingleStatusV1(id: string, web3SigningCredential: Web3SigningCredential, connectorId: string, keychainId: string, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.getSingleStatusV1(id, web3SigningCredential, connectorId, keychainId, options); + async getSingleStatusV1(getSingleStatusRequest?: GetSingleStatusRequest, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getSingleStatusV1(getSingleStatusRequest, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** * - * @param {Array} ids - * @param {Web3SigningCredential} web3SigningCredential - * @param {string} connectorId - * @param {string} keychainId + * @param {GetStatusRequest} [getStatusRequest] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async getStatusV1(ids: Array, web3SigningCredential: Web3SigningCredential, connectorId: string, keychainId: string, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>> { - const localVarAxiosArgs = await localVarAxiosParamCreator.getStatusV1(ids, web3SigningCredential, connectorId, keychainId, options); + async getStatusV1(getStatusRequest?: GetStatusRequest, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getStatusV1(getStatusRequest, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -747,27 +755,21 @@ export const DefaultApiFactory = function (configuration?: Configuration, basePa return { /** * - * @param {string} id - * @param {Web3SigningCredential} web3SigningCredential - * @param {string} connectorId - * @param {string} keychainId + * @param {GetSingleStatusRequest} [getSingleStatusRequest] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getSingleStatusV1(id: string, web3SigningCredential: Web3SigningCredential, connectorId: string, keychainId: string, options?: any): AxiosPromise { - return localVarFp.getSingleStatusV1(id, web3SigningCredential, connectorId, keychainId, options).then((request) => request(axios, basePath)); + getSingleStatusV1(getSingleStatusRequest?: GetSingleStatusRequest, options?: any): AxiosPromise { + return localVarFp.getSingleStatusV1(getSingleStatusRequest, options).then((request) => request(axios, basePath)); }, /** * - * @param {Array} ids - * @param {Web3SigningCredential} web3SigningCredential - * @param {string} connectorId - * @param {string} keychainId + * @param {GetStatusRequest} [getStatusRequest] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getStatusV1(ids: Array, web3SigningCredential: Web3SigningCredential, connectorId: string, keychainId: string, options?: any): AxiosPromise> { - return localVarFp.getStatusV1(ids, web3SigningCredential, connectorId, keychainId, options).then((request) => request(axios, basePath)); + getStatusV1(getStatusRequest?: GetStatusRequest, options?: any): AxiosPromise> { + return localVarFp.getStatusV1(getStatusRequest, options).then((request) => request(axios, basePath)); }, /** * @@ -817,30 +819,24 @@ export const DefaultApiFactory = function (configuration?: Configuration, basePa export class DefaultApi extends BaseAPI { /** * - * @param {string} id - * @param {Web3SigningCredential} web3SigningCredential - * @param {string} connectorId - * @param {string} keychainId + * @param {GetSingleStatusRequest} [getSingleStatusRequest] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof DefaultApi */ - public getSingleStatusV1(id: string, web3SigningCredential: Web3SigningCredential, connectorId: string, keychainId: string, options?: any) { - return DefaultApiFp(this.configuration).getSingleStatusV1(id, web3SigningCredential, connectorId, keychainId, options).then((request) => request(this.axios, this.basePath)); + public getSingleStatusV1(getSingleStatusRequest?: GetSingleStatusRequest, options?: any) { + return DefaultApiFp(this.configuration).getSingleStatusV1(getSingleStatusRequest, options).then((request) => request(this.axios, this.basePath)); } /** * - * @param {Array} ids - * @param {Web3SigningCredential} web3SigningCredential - * @param {string} connectorId - * @param {string} keychainId + * @param {GetStatusRequest} [getStatusRequest] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof DefaultApi */ - public getStatusV1(ids: Array, web3SigningCredential: Web3SigningCredential, connectorId: string, keychainId: string, options?: any) { - return DefaultApiFp(this.configuration).getStatusV1(ids, web3SigningCredential, connectorId, keychainId, options).then((request) => request(this.axios, this.basePath)); + public getStatusV1(getStatusRequest?: GetStatusRequest, options?: any) { + return DefaultApiFp(this.configuration).getStatusV1(getStatusRequest, options).then((request) => request(this.axios, this.basePath)); } /** diff --git a/packages/cactus-plugin-htlc-eth-besu/src/main/typescript/plugin-htlc-eth-besu.ts b/packages/cactus-plugin-htlc-eth-besu/src/main/typescript/plugin-htlc-eth-besu.ts index 990478c100..ed56be7418 100644 --- a/packages/cactus-plugin-htlc-eth-besu/src/main/typescript/plugin-htlc-eth-besu.ts +++ b/packages/cactus-plugin-htlc-eth-besu/src/main/typescript/plugin-htlc-eth-besu.ts @@ -21,7 +21,6 @@ import { InvokeContractV1Response, PluginLedgerConnectorBesu, RunTransactionResponse, - Web3SigningCredential, } from "@hyperledger/cactus-plugin-ledger-connector-besu"; import HashTimeLockJSON from "../solidity/contracts/HashTimeLock.json"; @@ -31,6 +30,8 @@ import { WithdrawReq, NewContractObj, InitializeRequest, + GetStatusRequest, + GetSingleStatusRequest, } from "./generated/openapi/typescript-axios"; export interface IPluginHtlcEthBesuOptions extends ICactusPluginOptions { logLevel?: LogLevelDesc; @@ -189,43 +190,37 @@ export class PluginHtlcEthBesu implements ICactusPlugin, IPluginWebService { } public async getSingleStatus( - id: string, - connectorId: string, - keychainId: string, - web3SigningCredential: Web3SigningCredential, + req: GetSingleStatusRequest, ): Promise { const connector = this.pluginRegistry.plugins.find( - (plugin) => plugin.getInstanceId() == connectorId, + (plugin) => plugin.getInstanceId() == req.connectorId, ) as PluginLedgerConnectorBesu; const result = await connector.invokeContract({ contractName: HashTimeLockJSON.contractName, - signingCredential: web3SigningCredential, + signingCredential: req.web3SigningCredential, invocationType: EthContractInvocationType.Call, methodName: "getSingleStatus", - params: [id], - keychainId, + params: [req.id], + keychainId: req.keychainId, }); return result; } public async getStatus( - ids: string[], - connectorId: string, - keychainId: string, - web3SigningCredential: Web3SigningCredential, + req: GetStatusRequest, ): Promise { const connector = this.pluginRegistry.plugins.find( - (plugin) => plugin.getInstanceId() == connectorId, + (plugin) => plugin.getInstanceId() == req.connectorId, ) as PluginLedgerConnectorBesu; const result = await connector.invokeContract({ contractName: HashTimeLockJSON.contractName, - signingCredential: web3SigningCredential, + signingCredential: req.web3SigningCredential, invocationType: EthContractInvocationType.Call, methodName: "getStatus", - params: [ids], - keychainId, + params: [req.ids], + keychainId: req.keychainId, }); return result; } diff --git a/packages/cactus-plugin-htlc-eth-besu/src/main/typescript/web-services/get-single-status-endpoint.ts b/packages/cactus-plugin-htlc-eth-besu/src/main/typescript/web-services/get-single-status-endpoint.ts index 38980472de..fe3153fe15 100644 --- a/packages/cactus-plugin-htlc-eth-besu/src/main/typescript/web-services/get-single-status-endpoint.ts +++ b/packages/cactus-plugin-htlc-eth-besu/src/main/typescript/web-services/get-single-status-endpoint.ts @@ -13,7 +13,6 @@ import { } from "@hyperledger/cactus-core-api"; import { registerWebServiceEndpoint } from "@hyperledger/cactus-core"; import { PluginHtlcEthBesu } from "../plugin-htlc-eth-besu"; -import { Web3SigningCredential } from "../generated/openapi/typescript-axios"; import OAS from "../../json/openapi.json"; export interface IGetSingleStatusEndpointOptions { @@ -43,15 +42,15 @@ export class GetSingleStatusEndpoint implements IWebServiceEndpoint { } public getVerbLowerCase(): string { - return this.oasPath.get["x-hyperledger-cactus"].http.verbLowerCase; + return this.oasPath.post["x-hyperledger-cactus"].http.verbLowerCase; } public getPath(): string { - return this.oasPath.get["x-hyperledger-cactus"].http.path; + return this.oasPath.post["x-hyperledger-cactus"].http.path; } public getOperationId(): string { - return this.oasPath.get.operationId; + return this.oasPath.post.operationId; } getAuthorizationOptionsProvider(): IAsyncProvider { @@ -77,18 +76,10 @@ export class GetSingleStatusEndpoint implements IWebServiceEndpoint { public async handleRequest(req: Request, res: Response): Promise { const fnTag = "GetSingleStatusEndpoint#handleRequest()"; - this.log.debug(`GET ${this.getPath()}`); + this.log.debug(`POST ${this.getPath()}`); try { - const id = req.query["id"]; - const connectorId = req.query["connectorId"]; - const keychainId = req.query["keychainId"]; - const web3SigningCredential = req.query["web3SigningCredential"]; - const { callOutput } = await this.options.plugin.getSingleStatus( - id as string, - connectorId as string, - keychainId as string, - (web3SigningCredential as unknown) as Web3SigningCredential, + req.body, ); if (callOutput === undefined) { diff --git a/packages/cactus-plugin-htlc-eth-besu/src/main/typescript/web-services/get-status-endpoint.ts b/packages/cactus-plugin-htlc-eth-besu/src/main/typescript/web-services/get-status-endpoint.ts index df91fcdf3e..cc8d3ac578 100644 --- a/packages/cactus-plugin-htlc-eth-besu/src/main/typescript/web-services/get-status-endpoint.ts +++ b/packages/cactus-plugin-htlc-eth-besu/src/main/typescript/web-services/get-status-endpoint.ts @@ -12,7 +12,6 @@ import { IWebServiceEndpoint, } from "@hyperledger/cactus-core-api"; import { registerWebServiceEndpoint } from "@hyperledger/cactus-core"; -import { Web3SigningCredential } from "@hyperledger/cactus-plugin-ledger-connector-besu"; import OAS from "../../json/openapi.json"; import { PluginHtlcEthBesu } from "../plugin-htlc-eth-besu"; export interface IGetStatusEndpointOptions { @@ -42,15 +41,15 @@ export class GetStatusEndpoint implements IWebServiceEndpoint { } public getVerbLowerCase(): string { - return this.oasPath.get["x-hyperledger-cactus"].http.verbLowerCase; + return this.oasPath.post["x-hyperledger-cactus"].http.verbLowerCase; } public getPath(): string { - return this.oasPath.get["x-hyperledger-cactus"].http.path; + return this.oasPath.post["x-hyperledger-cactus"].http.path; } public getOperationId(): string { - return this.oasPath.get.operationId; + return this.oasPath.post.operationId; } getAuthorizationOptionsProvider(): IAsyncProvider { @@ -76,20 +75,9 @@ export class GetStatusEndpoint implements IWebServiceEndpoint { public async handleRequest(req: Request, res: Response): Promise { const fnTag = "GetStatusEndpoint#handleRequest()"; - this.log.debug(`GET ${this.getPath()}`); + this.log.debug(`POST ${this.getPath()}`); try { - const query = req.query["ids"]?.toString(); - const ids = query?.split(","); - const connectorId = req.query["connectorId"]; - const keychainId = req.query["keychainId"]; - const web3SigningCredential = req.query["web3SigningCredential"]; - - const { callOutput } = await this.options.plugin.getStatus( - ids as string[], - connectorId as string, - keychainId as string, - (web3SigningCredential as unknown) as Web3SigningCredential, - ); + const { callOutput } = await this.options.plugin.getStatus(req.body); if (callOutput === undefined) { res.status(400).json({ diff --git a/packages/cactus-plugin-ledger-connector-besu/src/main/json/openapi.json b/packages/cactus-plugin-ledger-connector-besu/src/main/json/openapi.json index 3b1ec7d5a2..706be9574a 100644 --- a/packages/cactus-plugin-ledger-connector-besu/src/main/json/openapi.json +++ b/packages/cactus-plugin-ledger-connector-besu/src/main/json/openapi.json @@ -665,9 +665,9 @@ }, "transactionHash": { "type": "string", - "minLength": 64, - "maxLength": 64, - "pattern": "/^0x([A-Fa-f0-9]{64})$/" + "minLength": 66, + "maxLength": 66, + "pattern": "^0x([A-Fa-f0-9]{64})$" }, "transactionIndex": { "type": "number", @@ -675,9 +675,9 @@ }, "blockHash": { "type": "string", - "minLength": 64, - "maxLength": 64, - "pattern": "/^0x([A-Fa-f0-9]{64})$/" + "minLength": 66, + "maxLength": 66, + "pattern": "^0x([A-Fa-f0-9]{64})$" }, "blockNumber": { "type": "number", @@ -989,9 +989,9 @@ }, "transactionHash": { "type": "string", - "minLength": 64, - "maxLength": 64, - "pattern": "/^0x([A-Fa-f0-9]{64})$/" + "minLength": 66, + "maxLength": 66, + "pattern": "^0x([A-Fa-f0-9]{64})$" } } }, diff --git a/packages/cactus-plugin-ledger-connector-besu/src/test/typescript/integration/plugin-ledger-connector-besu/openapi/openapi-validation.test.ts b/packages/cactus-plugin-ledger-connector-besu/src/test/typescript/integration/plugin-ledger-connector-besu/openapi/openapi-validation.test.ts new file mode 100644 index 0000000000..d7386637bc --- /dev/null +++ b/packages/cactus-plugin-ledger-connector-besu/src/test/typescript/integration/plugin-ledger-connector-besu/openapi/openapi-validation.test.ts @@ -0,0 +1,891 @@ +import test, { Test } from "tape-promise/tape"; +import { v4 as uuidv4 } from "uuid"; +import { Server as SocketIoServer } from "socket.io"; +import { PluginRegistry } from "@hyperledger/cactus-core"; +import { + Web3SigningCredentialType, + PluginLedgerConnectorBesu, + BesuApiClient, + IPluginLedgerConnectorBesuOptions, + ReceiptType, + RunTransactionRequest, + InvokeContractV1Request, + EthContractInvocationType, + DeployContractSolidityBytecodeV1Request, + SignTransactionRequest, + GetBalanceV1Request, + GetPastLogsV1Request, + GetBlockV1Request, + GetBesuRecordV1Request, +} from "../../../../../main/typescript/public-api"; +import { PluginKeychainMemory } from "@hyperledger/cactus-plugin-keychain-memory"; +import { + BesuTestLedger, + pruneDockerAllIfGithubAction, +} from "@hyperledger/cactus-test-tooling"; +import KeyEncoder from "key-encoder"; +import { + IListenOptions, + KeyFormat, + LogLevelDesc, + Secp256k1Keys, + Servers, +} from "@hyperledger/cactus-common"; +import { Constants } from "@hyperledger/cactus-core-api"; +import express from "express"; +import bodyParser from "body-parser"; +import http from "http"; +import HelloWorldContractJson from "../../../../solidity/hello-world-contract/HelloWorld.json"; +import { AddressInfo } from "net"; +import { BesuApiClientOptions } from "../../../../../main/typescript/api-client/besu-api-client"; + +import { installOpenapiValidationMiddleware } from "@hyperledger/cactus-core"; +import OAS from "../../../../../main/json/openapi.json"; + +const logLevel: LogLevelDesc = "TRACE"; +const testCase = "Besu API"; + +test("BEFORE " + testCase, async (t: Test) => { + const pruning = pruneDockerAllIfGithubAction({ logLevel }); + await t.doesNotReject(pruning, "Pruning did not throw OK"); + t.end(); +}); + +test(testCase, async (t: Test) => { + const keyEncoder: KeyEncoder = new KeyEncoder("secp256k1"); + const keychainIdForSigned = uuidv4(); + const keychainIdForUnsigned = uuidv4(); + const keychainRefForSigned = uuidv4(); + const keychainRefForUnsigned = uuidv4(); + + const besuTestLedger = new BesuTestLedger(); + await besuTestLedger.start(); + test.onFinish(async () => { + await besuTestLedger.stop(); + await besuTestLedger.destroy(); + }); + + const rpcApiHttpHost = await besuTestLedger.getRpcApiHttpHost(); + const rpcApiWsHost = await besuTestLedger.getRpcApiWsHost(); + + const testEthAccount1 = await besuTestLedger.createEthTestAccount(); + const testEthAccount2 = await besuTestLedger.createEthTestAccount(); + const firstHighNetWorthAccount = besuTestLedger.getGenesisAccountPubKey(); + + // keychainPlugin for signed transactions + const { privateKey } = Secp256k1Keys.generateKeyPairsBuffer(); + const keyHex = privateKey.toString("hex"); + const pem = keyEncoder.encodePrivate(keyHex, KeyFormat.Raw, KeyFormat.PEM); + const signedKeychainPlugin = new PluginKeychainMemory({ + instanceId: uuidv4(), + keychainId: keychainIdForSigned, + backend: new Map([[keychainRefForSigned, pem]]), + logLevel, + }); + + // keychainPlugin for unsigned transactions + const keychainEntryValue = testEthAccount1.privateKey; + const unsignedKeychainPlugin = new PluginKeychainMemory({ + instanceId: uuidv4(), + keychainId: keychainIdForUnsigned, + backend: new Map([[keychainRefForUnsigned, keychainEntryValue]]), + logLevel, + }); + unsignedKeychainPlugin.set( + HelloWorldContractJson.contractName, + JSON.stringify(HelloWorldContractJson), + ); + + const pluginRegistry = new PluginRegistry({ + plugins: [signedKeychainPlugin, unsignedKeychainPlugin], + }); + + const options: IPluginLedgerConnectorBesuOptions = { + instanceId: uuidv4(), + rpcApiHttpHost, + rpcApiWsHost, + pluginRegistry, + logLevel, + }; + const connector = new PluginLedgerConnectorBesu(options); + pluginRegistry.add(connector); + + const expressApp = express(); + expressApp.use(bodyParser.json({ limit: "250mb" })); + const server = http.createServer(expressApp); + + const wsApi = new SocketIoServer(server, { + path: Constants.SocketIoConnectionPathV1, + }); + + const listenOptions: IListenOptions = { + hostname: "localhost", + port: 0, + server, + }; + const addressInfo = (await Servers.listen(listenOptions)) as AddressInfo; + test.onFinish(async () => await Servers.shutdown(server)); + const { address, port } = addressInfo; + const apiHost = `http://${address}:${port}`; + t.comment( + `Metrics URL: ${apiHost}/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-besu/get-prometheus-exporter-metrics`, + ); + + const wsBasePath = apiHost + Constants.SocketIoConnectionPathV1; + t.comment("WS base path: " + wsBasePath); + const besuApiClientOptions = new BesuApiClientOptions({ basePath: apiHost }); + const apiClient = new BesuApiClient(besuApiClientOptions); + + await installOpenapiValidationMiddleware({ + logLevel, + app: expressApp, + apiSpec: OAS, + }); + + await connector.getOrCreateWebServices(); + await connector.registerWebServices(expressApp, wsApi); + + const fDeploy = "deployContractSolBytecodeV1"; + const fInvoke = "invokeContractV1"; + const fRun = "runTransactionV1"; + const fSign = "signTransactionV1"; + const fBalance = "getBalanceV1"; + const fBlock = "getBlockV1"; + const fPastLogs = "getPastLogsV1"; + const fRecord = "getBesuRecordV1"; + const cOk = "without bad request error"; + const cWithoutParams = "not sending all required parameters"; + const cInvalidParams = "sending invalid parameters"; + + test(`${testCase} - ${fDeploy} - ${cOk}`, async (t2: Test) => { + const parameters = { + keychainId: keychainIdForUnsigned, + contractName: HelloWorldContractJson.contractName, + contractAbi: HelloWorldContractJson.abi, + constructorArgs: [], + web3SigningCredential: { + ethAccount: testEthAccount1.address, + secret: testEthAccount1.privateKey, + type: Web3SigningCredentialType.PrivateKeyHex, + }, + bytecode: HelloWorldContractJson.bytecode, + gas: 1000000, + }; + const res = await apiClient.deployContractSolBytecodeV1( + parameters as DeployContractSolidityBytecodeV1Request, + ); + t2.ok(res, "Contract deployed successfully"); + t2.ok(res.data); + t2.equal( + res.status, + 200, + `Endpoint ${fDeploy}: response.status === 200 OK`, + ); + + t2.end(); + }); + + test(`${testCase} - ${fDeploy} - ${cWithoutParams}`, async (t2: Test) => { + try { + const parameters = { + keychainId: keychainIdForUnsigned, + contractAbi: HelloWorldContractJson.abi, + constructorArgs: [], + web3SigningCredential: { + ethAccount: testEthAccount1.address, + secret: testEthAccount1.privateKey, + type: Web3SigningCredentialType.PrivateKeyHex, + }, + }; + await apiClient.deployContractSolBytecodeV1( + (parameters as any) as DeployContractSolidityBytecodeV1Request, + ); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fDeploy} without required contractName and bytecode: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("contractName"), + "Rejected because contractName is required", + ); + t2.ok( + fields.includes("bytecode"), + "Rejected because bytecode is required", + ); + t2.notOk(fields.includes("gas"), "gas is not required"); + } + + t2.end(); + }); + + test(`${testCase} - ${fDeploy} - ${cInvalidParams}`, async (t2: Test) => { + try { + const parameters = { + keychainId: keychainIdForUnsigned, + contractName: HelloWorldContractJson.contractName, + contractAbi: HelloWorldContractJson.abi, + constructorArgs: [], + web3SigningCredential: { + ethAccount: testEthAccount1.address, + secret: testEthAccount1.privateKey, + type: Web3SigningCredentialType.PrivateKeyHex, + }, + bytecode: HelloWorldContractJson.bytecode, + gas: 1000000, + fake: 4, + }; + await apiClient.deployContractSolBytecodeV1( + parameters as DeployContractSolidityBytecodeV1Request, + ); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fDeploy} with fake=4: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("fake"), + "Rejected because fake is not a valid parameter", + ); + } + + t2.end(); + }); + + test(`${testCase} - ${fInvoke} - ${cOk}`, async (t2: Test) => { + const parameters = { + contractName: "HelloWorld", + keychainId: keychainIdForUnsigned, + invocationType: EthContractInvocationType.Call, + methodName: "sayHello", + params: [], + signingCredential: { + ethAccount: testEthAccount1.address, + secret: testEthAccount1.privateKey, + type: Web3SigningCredentialType.PrivateKeyHex, + }, + }; + const res = await apiClient.invokeContractV1( + parameters as InvokeContractV1Request, + ); + t2.ok(res, "Contract deployed successfully"); + t2.ok(res.data); + t2.equal( + res.status, + 200, + `Endpoint ${fInvoke}: response.status === 200 OK`, + ); + + t2.end(); + }); + + test(`${testCase} - ${fInvoke} - ${cWithoutParams}`, async (t2: Test) => { + try { + const parameters = { + keychainId: keychainIdForUnsigned, + invocationType: EthContractInvocationType.Call, + methodName: "sayHello", + params: [], + signingCredential: { + ethAccount: testEthAccount1.address, + secret: testEthAccount1.privateKey, + type: Web3SigningCredentialType.PrivateKeyHex, + }, + }; + await apiClient.invokeContractV1( + (parameters as any) as InvokeContractV1Request, + ); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fInvoke} without required contractName: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("contractName"), + "Rejected because contractName is required", + ); + t2.notOk(fields.includes("gas"), "gas is not required"); + } + + t2.end(); + }); + + test(`${testCase} - ${fInvoke} - ${cInvalidParams}`, async (t2: Test) => { + try { + const parameters = { + contractName: "HelloWorld", + keychainId: keychainIdForUnsigned, + invocationType: EthContractInvocationType.Call, + methodName: "sayHello", + params: [], + signingCredential: { + ethAccount: testEthAccount1.address, + secret: testEthAccount1.privateKey, + type: Web3SigningCredentialType.PrivateKeyHex, + }, + fake: 4, + }; + await apiClient.invokeContractV1(parameters as InvokeContractV1Request); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fInvoke} with fake=4: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("fake"), + "Rejected because fake is not a valid parameter", + ); + } + + t2.end(); + }); + + test(`${testCase} - ${fRun} - ${cOk}`, async (t2: Test) => { + const parameters = { + web3SigningCredential: { + ethAccount: testEthAccount1.address, + secret: testEthAccount1.privateKey, + type: Web3SigningCredentialType.PrivateKeyHex, + }, + transactionConfig: { + from: testEthAccount1.address, + to: testEthAccount2.address, + value: 10e7, + gas: 1000000, + }, + consistencyStrategy: { + blockConfirmations: 0, + receiptType: ReceiptType.NodeTxPoolAck, + timeoutMs: 60000, + }, + }; + const res = await apiClient.runTransactionV1( + parameters as RunTransactionRequest, + ); + t2.ok(res, "Transaction runned successfully"); + t2.ok(res.data); + t2.equal(res.status, 200, `Endpoint ${fRun}: response.status === 200 OK`); + + t2.end(); + }); + + test(`${testCase} - ${fRun} - ${cWithoutParams}`, async (t2: Test) => { + try { + const parameters = { + web3SigningCredential: { + ethAccount: testEthAccount1.address, + secret: testEthAccount1.privateKey, + type: Web3SigningCredentialType.PrivateKeyHex, + }, + transactionConfig: { + from: testEthAccount1.address, + to: testEthAccount2.address, + value: 10e7, + gas: 1000000, + }, + }; + await apiClient.runTransactionV1(parameters as RunTransactionRequest); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fRun} without required consistencyStrategy: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("consistencyStrategy"), + "Rejected because consistencyStrategy is required", + ); + } + + t2.end(); + }); + + test(`${testCase} - ${fRun} - ${cInvalidParams}`, async (t2: Test) => { + try { + const parameters = { + web3SigningCredential: { + ethAccount: testEthAccount1.address, + secret: testEthAccount1.privateKey, + type: Web3SigningCredentialType.PrivateKeyHex, + }, + transactionConfig: { + from: testEthAccount1.address, + to: testEthAccount2.address, + value: 10e7, + gas: 1000000, + }, + consistencyStrategy: { + blockConfirmations: 0, + receiptType: ReceiptType.NodeTxPoolAck, + timeoutMs: 60000, + }, + fake: 4, + }; + await apiClient.runTransactionV1(parameters as RunTransactionRequest); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fRun} with fake=4: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("fake"), + "Rejected because fake is not a valid parameter", + ); + } + + t2.end(); + }); + + test(`${testCase} - ${fSign} - ${cOk}`, async (t2: Test) => { + const runTxRes = await apiClient.runTransactionV1({ + consistencyStrategy: { + blockConfirmations: 0, + receiptType: ReceiptType.LedgerBlockAck, + timeoutMs: 120000, + }, + transactionConfig: { + from: testEthAccount1.address, + to: testEthAccount2.address, + value: 1, + gas: 10000000, + }, + web3SigningCredential: { + ethAccount: testEthAccount1.address, + secret: testEthAccount1.privateKey, + type: Web3SigningCredentialType.PrivateKeyHex, + }, + }); + + t2.ok(runTxRes, "runTxRes truthy OK"); + t2.ok(runTxRes.status, "runTxRes.status truthy OK"); + t2.equal(runTxRes.status, 200, "runTxRes.status === 200 OK"); + t2.ok(runTxRes.data, "runTxRes.data truthy OK"); + t2.ok( + (runTxRes.data as any).data.transactionReceipt, + "runTxRes.data.transactionReceipt truthy OK", + ); + + const parameters = { + keychainId: keychainIdForSigned, + keychainRef: keychainRefForSigned, + transactionHash: (runTxRes.data as any).data.transactionReceipt + .transactionHash, + }; + + const res = await apiClient.signTransactionV1( + parameters as SignTransactionRequest, + ); + + t2.ok(res, "Transaction signed successfully"); + t2.ok(res.data); + t2.equal(res.status, 200, `Endpoint ${fSign}: response.status === 200 OK`); + + t2.end(); + }); + + test(`${testCase} - ${fSign} - ${cWithoutParams}`, async (t2: Test) => { + const runTxRes = await apiClient.runTransactionV1({ + consistencyStrategy: { + blockConfirmations: 0, + receiptType: ReceiptType.LedgerBlockAck, + timeoutMs: 120000, + }, + transactionConfig: { + from: testEthAccount1.address, + to: testEthAccount2.address, + value: 1, + gas: 10000000, + }, + web3SigningCredential: { + ethAccount: testEthAccount1.address, + secret: testEthAccount1.privateKey, + type: Web3SigningCredentialType.PrivateKeyHex, + }, + }); + t2.ok(runTxRes, "runTxRes truthy OK"); + t2.ok(runTxRes.status, "runTxRes.status truthy OK"); + t2.equal(runTxRes.status, 200, "runTxRes.status === 200 OK"); + t2.ok(runTxRes.data, "runTxRes.data truthy OK"); + t2.ok( + (runTxRes.data as any).data.transactionReceipt, + "runTxRes.data.transactionReceipt truthy OK", + ); + + try { + const parameters = { + keychainRef: keychainRefForSigned, + transactionHash: (runTxRes.data as any).data.transactionReceipt + .transactionHash, + }; + + await apiClient.signTransactionV1(parameters as SignTransactionRequest); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fSign} without required keychainId: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("keychainId"), + "Rejected because keychainId is required", + ); + } + + t2.end(); + }); + + test(`${testCase} - ${fSign} - ${cInvalidParams}`, async (t2: Test) => { + const runTxRes = await apiClient.runTransactionV1({ + consistencyStrategy: { + blockConfirmations: 0, + receiptType: ReceiptType.LedgerBlockAck, + timeoutMs: 120000, + }, + transactionConfig: { + from: testEthAccount1.address, + to: testEthAccount2.address, + value: 1, + gas: 10000000, + }, + web3SigningCredential: { + ethAccount: testEthAccount1.address, + secret: testEthAccount1.privateKey, + type: Web3SigningCredentialType.PrivateKeyHex, + }, + }); + t2.ok(runTxRes, "runTxRes truthy OK"); + t2.ok(runTxRes.status, "runTxRes.status truthy OK"); + t2.equal(runTxRes.status, 200, "runTxRes.status === 200 OK"); + t2.ok(runTxRes.data, "runTxRes.data truthy OK"); + t2.ok( + (runTxRes.data as any).data.transactionReceipt, + "runTxRes.data.transactionReceipt truthy OK", + ); + + try { + const parameters = { + keychainId: keychainIdForSigned, + keychainRef: keychainRefForSigned, + transactionHash: (runTxRes.data as any).data.transactionReceipt + .transactionHash, + fake: 4, + }; + + await apiClient.signTransactionV1(parameters as SignTransactionRequest); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fSign} with fake=4: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("fake"), + "Rejected because fake is not a valid parameter", + ); + } + + t2.end(); + }); + + test(`${testCase} - ${fBalance} - ${cOk}`, async (t2: Test) => { + const parameters = { address: firstHighNetWorthAccount }; + const res = await apiClient.getBalanceV1(parameters as GetBalanceV1Request); + t2.equal( + res.status, + 200, + `Endpoint ${fBalance}: response.status === 200 OK`, + ); + t2.ok(res.data.balance, " Balance response is OK"); + + t2.end(); + }); + + test(`${testCase} - ${fBalance} - ${cWithoutParams}`, async (t2: Test) => { + try { + const parameters = {}; + await apiClient.getBalanceV1(parameters as GetBalanceV1Request); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fBalance} without required address: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok(fields.includes("address"), "Rejected because address is required"); + } + + t2.end(); + }); + + test(`${testCase} - ${fBalance} - ${cInvalidParams}`, async (t2: Test) => { + try { + const parameters = { + address: firstHighNetWorthAccount, + fake: 4, + }; + await apiClient.getBalanceV1(parameters as GetBalanceV1Request); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fBalance} with fake=4: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("fake"), + "Rejected because fake is not a valid parameter", + ); + } + + t2.end(); + }); + + test(`${testCase} - ${fBlock} - ${cOk}`, async (t2: Test) => { + const parameters = { blockHashOrBlockNumber: 0 }; + const res = await apiClient.getBlockV1(parameters as GetBlockV1Request); + t2.equal(res.status, 200, `Endpoint ${fBlock}: response.status === 200 OK`); + t2.ok(res.data.block, " Block response is OK"); + + t2.end(); + }); + + test(`${testCase} - ${fBlock} - ${cWithoutParams}`, async (t2: Test) => { + try { + const parameters = {}; + await apiClient.getBlockV1(parameters as GetBlockV1Request); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fBlock} without required blockHashOrBlockNumber: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("blockHashOrBlockNumber"), + "Rejected because blockHashOrBlockNumber is required", + ); + } + + t2.end(); + }); + + test(`${testCase} - ${fBlock} - ${cInvalidParams}`, async (t2: Test) => { + try { + const parameters = { + blockHashOrBlockNumber: 0, + fake: 4, + }; + await apiClient.getBlockV1(parameters as GetBlockV1Request); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fBlock} with fake=4: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("fake"), + "Rejected because fake is not a valid parameter", + ); + } + + t2.end(); + }); + + test(`${testCase} - ${fPastLogs} - ${cOk}`, async (t2: Test) => { + const parameters = { address: firstHighNetWorthAccount }; + const res = await apiClient.getPastLogsV1( + parameters as GetPastLogsV1Request, + ); + t2.equal( + res.status, + 200, + `Endpoint ${fPastLogs}: response.status === 200 OK`, + ); + t2.ok(res.data.logs, "Logs response is OK"); + + t2.end(); + }); + + test(`${testCase} - ${fPastLogs} - ${cWithoutParams}`, async (t2: Test) => { + try { + const parameters = {}; + await apiClient.getPastLogsV1(parameters as GetPastLogsV1Request); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fPastLogs} without required address: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok(fields.includes("address"), "Rejected because address is required"); + } + + t2.end(); + }); + + test(`${testCase} - ${fPastLogs} - ${cInvalidParams}`, async (t2: Test) => { + try { + const parameters = { + address: firstHighNetWorthAccount, + fake: 4, + }; + await apiClient.getPastLogsV1(parameters as GetPastLogsV1Request); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fPastLogs} with fake=4: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("fake"), + "Rejected because fake is not a valid parameter", + ); + } + + t2.end(); + }); + + test(`${testCase} - ${fRecord} - ${cOk}`, async (t2: Test) => { + const runTxRes = await apiClient.runTransactionV1({ + consistencyStrategy: { + blockConfirmations: 0, + receiptType: ReceiptType.LedgerBlockAck, + timeoutMs: 120000, + }, + transactionConfig: { + from: testEthAccount1.address, + to: testEthAccount2.address, + value: 1, + gas: 10000000, + }, + web3SigningCredential: { + ethAccount: testEthAccount1.address, + secret: testEthAccount1.privateKey, + type: Web3SigningCredentialType.PrivateKeyHex, + }, + }); + + t2.ok(runTxRes, "runTxRes truthy OK"); + t2.ok(runTxRes.status, "runTxRes.status truthy OK"); + t2.equal(runTxRes.status, 200, "runTxRes.status === 200 OK"); + t2.ok(runTxRes.data, "runTxRes.data truthy OK"); + t2.ok( + (runTxRes.data as any).data.transactionReceipt, + "runTxRes.data.transactionReceipt truthy OK", + ); + + const parameters = { + transactionHash: (runTxRes.data as any).data.transactionReceipt + .transactionHash, + }; + const res = await apiClient.getBesuRecordV1( + parameters as GetBesuRecordV1Request, + ); + t2.equal( + res.status, + 200, + `Endpoint ${fRecord}: response.status === 200 OK`, + ); + t2.ok(res.data, "Record response is OK"); + + t2.end(); + }); + + test(`${testCase} - ${fRecord} - ${cWithoutParams}`, async (t2: Test) => { + try { + const parameters = {}; + await apiClient.getBesuRecordV1(parameters as GetBesuRecordV1Request); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fRecord} without required transactionHash: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("transactionHash"), + "Rejected because transactionHash is required", + ); + } + + t2.end(); + }); + + test(`${testCase} - ${fRecord} - ${cInvalidParams}`, async (t2: Test) => { + try { + const parameters = { + transactionHash: "", + fake: 5, + }; + await apiClient.getBesuRecordV1(parameters as GetBesuRecordV1Request); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fRecord} with fake=4: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("fake"), + "Rejected because fake is not a valid parameter", + ); + } + + t2.end(); + }); + + t.end(); +}); + +test("AFTER " + testCase, async (t: Test) => { + const pruning = pruneDockerAllIfGithubAction({ logLevel }); + await t.doesNotReject(pruning, "Pruning did not throw OK"); + t.end(); +}); diff --git a/packages/cactus-test-plugin-htlc-eth-besu-erc20/src/test/typescript/integration/plugin-htlc-eth-besu-erc20/get-single-status-endpoint-invalid.test.ts b/packages/cactus-test-plugin-htlc-eth-besu-erc20/src/test/typescript/integration/plugin-htlc-eth-besu-erc20/get-single-status-endpoint-invalid.test.ts index db0b3aa5ab..85d036bbe1 100644 --- a/packages/cactus-test-plugin-htlc-eth-besu-erc20/src/test/typescript/integration/plugin-htlc-eth-besu-erc20/get-single-status-endpoint-invalid.test.ts +++ b/packages/cactus-test-plugin-htlc-eth-besu-erc20/src/test/typescript/integration/plugin-htlc-eth-besu-erc20/get-single-status-endpoint-invalid.test.ts @@ -238,12 +238,12 @@ test(testCase, async (t: Test) => { t.comment("Get status with invalid id"); const fakeId = "0x66616b654964"; - const res = await api.getSingleStatusV1( - fakeId, + const res = await api.getSingleStatusV1({ + id: fakeId, web3SigningCredential, connectorId, keychainId, - ); + }); t.equal(res.status, 200, "response status is 200 OK"); t.equal(res.data, 0, "the contract status is 0 - INVALID"); t.end(); diff --git a/packages/cactus-test-plugin-htlc-eth-besu-erc20/src/test/typescript/integration/plugin-htlc-eth-besu-erc20/get-single-status-endpoint.test.ts b/packages/cactus-test-plugin-htlc-eth-besu-erc20/src/test/typescript/integration/plugin-htlc-eth-besu-erc20/get-single-status-endpoint.test.ts index e44b3b1a69..61c75a9895 100644 --- a/packages/cactus-test-plugin-htlc-eth-besu-erc20/src/test/typescript/integration/plugin-htlc-eth-besu-erc20/get-single-status-endpoint.test.ts +++ b/packages/cactus-test-plugin-htlc-eth-besu-erc20/src/test/typescript/integration/plugin-htlc-eth-besu-erc20/get-single-status-endpoint.test.ts @@ -272,12 +272,12 @@ test(testCase, async (t: Test) => { ], }); - const res = await api.getSingleStatusV1( - callOutput as string, + const res = await api.getSingleStatusV1({ + id: callOutput as string, web3SigningCredential, connectorId, keychainId, - ); + }); t.equal(res.status, 200, "response status is 200 OK"); t.equal(res.data, 1, "the contract status is 1 - Active"); t.end(); diff --git a/packages/cactus-test-plugin-htlc-eth-besu-erc20/src/test/typescript/integration/plugin-htlc-eth-besu-erc20/get-status-endpoint.test.ts b/packages/cactus-test-plugin-htlc-eth-besu-erc20/src/test/typescript/integration/plugin-htlc-eth-besu-erc20/get-status-endpoint.test.ts index aaa3b461a7..1c3fa00718 100644 --- a/packages/cactus-test-plugin-htlc-eth-besu-erc20/src/test/typescript/integration/plugin-htlc-eth-besu-erc20/get-status-endpoint.test.ts +++ b/packages/cactus-test-plugin-htlc-eth-besu-erc20/src/test/typescript/integration/plugin-htlc-eth-besu-erc20/get-status-endpoint.test.ts @@ -272,12 +272,12 @@ test(testCase, async (t: Test) => { ], }); const ids = [responseTxId.callOutput as string]; - const res = await api.getStatusV1( + const res = await api.getStatusV1({ ids, web3SigningCredential, connectorId, keychainId, - ); + }); t.equal(res.status, 200, "response status is 200 OK"); t.equal(res.data[0], "1", "the contract status is 1 - Active"); t.end(); @@ -458,12 +458,12 @@ test("Test get invalid id status", async (t: Test) => { t.comment("Get invalid status of HTLC"); const fakeId = "0x66616b654964"; - const res = await api.getStatusV1( - [fakeId], + const res = await api.getStatusV1({ + ids: [fakeId], web3SigningCredential, connectorId, keychainId, - ); + }); t.equal(res.status, 200, "response status is 200 OK"); t.equal(res.data[0], "0", "the contract status is 0 - INVALID"); t.end(); diff --git a/packages/cactus-test-plugin-htlc-eth-besu-erc20/src/test/typescript/integration/plugin-htlc-eth-besu-erc20/openapi/openapi-validation.test.ts b/packages/cactus-test-plugin-htlc-eth-besu-erc20/src/test/typescript/integration/plugin-htlc-eth-besu-erc20/openapi/openapi-validation.test.ts new file mode 100644 index 0000000000..3eb7943809 --- /dev/null +++ b/packages/cactus-test-plugin-htlc-eth-besu-erc20/src/test/typescript/integration/plugin-htlc-eth-besu-erc20/openapi/openapi-validation.test.ts @@ -0,0 +1,803 @@ +import http from "http"; +import type { AddressInfo } from "net"; +import test, { Test } from "tape-promise/tape"; +import { v4 as uuidv4 } from "uuid"; +import express from "express"; +import bodyParser from "body-parser"; +import { + Configuration, + DefaultApi as BesuApi, + IPluginHtlcEthBesuErc20Options, + PluginFactoryHtlcEthBesuErc20, + NewContractRequest, + InitializeRequest, + RefundRequest, + WithdrawRequest, + GetStatusRequest, + GetSingleStatusRequest, +} from "@hyperledger/cactus-plugin-htlc-eth-besu-erc20"; +import { + EthContractInvocationType, + PluginFactoryLedgerConnector, + PluginLedgerConnectorBesu, + Web3SigningCredential, + Web3SigningCredentialType, +} from "@hyperledger/cactus-plugin-ledger-connector-besu"; +import { PluginKeychainMemory } from "@hyperledger/cactus-plugin-keychain-memory"; +import { + LogLevelDesc, + IListenOptions, + Servers, +} from "@hyperledger/cactus-common"; +import { PluginRegistry } from "@hyperledger/cactus-core"; +import { PluginImportType } from "@hyperledger/cactus-core-api"; +import { + BesuTestLedger, + pruneDockerAllIfGithubAction, +} from "@hyperledger/cactus-test-tooling"; +import TestTokenJSON from "../../../../solidity/token-erc20-contract/Test_Token.json"; +import DemoHelperJSON from "../../../../solidity/token-erc20-contract/DemoHelpers.json"; +import HashTimeLockJSON from "../../../../../../../cactus-plugin-htlc-eth-besu-erc20/src/main/solidity/contracts/HashedTimeLockContract.json"; + +import { installOpenapiValidationMiddleware } from "@hyperledger/cactus-core"; +import { PluginHtlcEthBesuErc20 } from "@hyperledger/cactus-plugin-htlc-eth-besu-erc20"; + +const connectorId = uuidv4(); +const logLevel: LogLevelDesc = "INFO"; +const expiration = 2147483648; +const secret = + "0x3853485acd2bfc3c632026ee365279743af107a30492e3ceaa7aefc30c2a048a"; +const estimatedGas = 6721975; +const receiver = "0x627306090abaB3A6e1400e9345bC60c78a8BEf57"; +const hashLock = + "0x3c335ba7f06a8b01d0596589f73c19069e21c81e5013b91f408165d1bf623d32"; +const firstHighNetWorthAccount = "0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1"; +const privateKey = + "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d"; +const web3SigningCredential: Web3SigningCredential = { + ethAccount: firstHighNetWorthAccount, + secret: privateKey, + type: Web3SigningCredentialType.PrivateKeyHex, +} as Web3SigningCredential; + +const testCase = "Test cactus-plugin-htlc-eth-besu-erc20 openapi validation"; + +test("BEFORE " + testCase, async (t: Test) => { + const pruning = pruneDockerAllIfGithubAction({ logLevel }); + await t.doesNotReject(pruning, "Pruning did not throw OK"); + t.end(); +}); + +test(testCase, async (t: Test) => { + const timeout = (ms: number) => { + return new Promise((resolve) => setTimeout(resolve, ms)); + }; + + t.comment("Starting Besu Test Ledger"); + const besuTestLedger = new BesuTestLedger({ logLevel }); + + test.onFailure(async () => { + await besuTestLedger.stop(); + await besuTestLedger.destroy(); + }); + + test.onFinish(async () => { + await besuTestLedger.stop(); + await besuTestLedger.destroy(); + }); + + await besuTestLedger.start(); + + const rpcApiHttpHost = await besuTestLedger.getRpcApiHttpHost(); + const rpcApiWsHost = await besuTestLedger.getRpcApiWsHost(); + const keychainId = uuidv4(); + const keychainPlugin = new PluginKeychainMemory({ + instanceId: uuidv4(), + keychainId, + // pre-provision keychain with mock backend holding the private key of the + // test account that we'll reference while sending requests with the + // signing credential pointing to this keychain entry. + backend: new Map([ + [TestTokenJSON.contractName, JSON.stringify(TestTokenJSON)], + ]), + logLevel, + }); + keychainPlugin.set( + DemoHelperJSON.contractName, + JSON.stringify(DemoHelperJSON), + ); + keychainPlugin.set( + HashTimeLockJSON.contractName, + JSON.stringify(HashTimeLockJSON), + ); + + const factory = new PluginFactoryLedgerConnector({ + pluginImportType: PluginImportType.Local, + }); + + const pluginRegistry = new PluginRegistry({}); + const connector: PluginLedgerConnectorBesu = await factory.create({ + rpcApiHttpHost, + rpcApiWsHost, + logLevel, + instanceId: connectorId, + pluginRegistry: new PluginRegistry({ plugins: [keychainPlugin] }), + }); + + pluginRegistry.add(connector); + const pluginOptions: IPluginHtlcEthBesuErc20Options = { + logLevel, + instanceId: uuidv4(), + pluginRegistry, + }; + + const factoryHTLC = new PluginFactoryHtlcEthBesuErc20({ + pluginImportType: PluginImportType.Local, + }); + + const pluginHtlc = await factoryHTLC.create(pluginOptions); + pluginRegistry.add(pluginHtlc); + + const expressApp = express(); + expressApp.use(bodyParser.json({ limit: "250mb" })); + const server = http.createServer(expressApp); + const listenOptions: IListenOptions = { + hostname: "0.0.0.0", + port: 0, + server, + }; + const addressInfo = (await Servers.listen(listenOptions)) as AddressInfo; + test.onFinish(async () => await Servers.shutdown(server)); + const { address, port } = addressInfo; + const apiHost = `http://${address}:${port}`; + + const configuration = new Configuration({ basePath: apiHost }); + const api = new BesuApi(configuration); + + const OAS = (pluginHtlc as PluginHtlcEthBesuErc20).getOpenApiSpec(); + + await installOpenapiValidationMiddleware({ + logLevel, + app: expressApp, + apiSpec: OAS, + }); + + await pluginHtlc.getOrCreateWebServices(); + await pluginHtlc.registerWebServices(expressApp); + + const fInitialize = "initializeV1"; + const fNew = "newContractV1"; + const fRefund = "refundV1"; + const fWithdraw = "withdrawV1"; + const fStatus = "getStatusV1"; + const fSingleStatus = "getSingleStatusV1"; + + const cOk = "without bad request error"; + const cWithoutParams = "not sending all required parameters"; + const cInvalidParams = "sending invalid parameters"; + + let hashTimeLockAddress: string; + let timestamp: number; + let tokenAddress: string; + let txId: string; + + test(`${testCase} - ${fInitialize} - ${cOk}`, async (t2: Test) => { + const parameters = { + connectorId, + keychainId, + constructorArgs: [], + web3SigningCredential, + gas: estimatedGas, + }; + + const res = await api.initializeV1(parameters); + t2.ok(res, "initialize called successfully"); + t2.equal( + res.status, + 200, + `Endpoint ${fInitialize}: response.status === 200 OK`, + ); + + hashTimeLockAddress = res.data.transactionReceipt.contractAddress as string; + + t2.end(); + }); + + test(`${testCase} - ${fInitialize} - ${cWithoutParams}`, async (t2: Test) => { + const parameters = { + // connectorId, + keychainId, + constructorArgs: [], + web3SigningCredential, + gas: estimatedGas, + }; + + try { + await api.initializeV1((parameters as any) as InitializeRequest); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fInitialize} without required connectorId: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("connectorId"), + "Rejected because connectorId is required", + ); + } + + t2.end(); + }); + + test(`${testCase} - ${fInitialize} - ${cInvalidParams}`, async (t2: Test) => { + const parameters = { + connectorId, + keychainId, + constructorArgs: [], + web3SigningCredential, + gas: estimatedGas, + fake: 4, + }; + + try { + await api.initializeV1((parameters as any) as InitializeRequest); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fInitialize} with fake=4: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("fake"), + "Rejected because fake is not a valid parameter", + ); + } + + t2.end(); + }); + + test(`${testCase} - ${fNew} - ${cOk}`, async (t2: Test) => { + const deployOutToken = await connector.deployContract({ + contractName: TestTokenJSON.contractName, + contractAbi: TestTokenJSON.abi, + bytecode: TestTokenJSON.bytecode, + web3SigningCredential, + keychainId, + constructorArgs: ["100", "token", "2", "TKN"], + gas: estimatedGas, + }); + t2.ok(deployOutToken, "deployOutToken is truthy OK"); + t2.ok( + deployOutToken.transactionReceipt, + "deployOutToken.transactionReceipt is truthy OK", + ); + t2.ok( + deployOutToken.transactionReceipt.contractAddress, + "deployOutToken.transactionReceipt.contractAddress is truthy OK", + ); + tokenAddress = deployOutToken.transactionReceipt.contractAddress as string; + + const deployOutDemo = await connector.deployContract({ + contractName: DemoHelperJSON.contractName, + contractAbi: DemoHelperJSON.abi, + bytecode: DemoHelperJSON.bytecode, + web3SigningCredential, + keychainId, + constructorArgs: [], + gas: estimatedGas, + }); + t2.ok(deployOutDemo, "deployOutToken is truthy OK"); + + const { success } = await connector.invokeContract({ + contractName: TestTokenJSON.contractName, + keychainId, + signingCredential: web3SigningCredential, + invocationType: EthContractInvocationType.Send, + methodName: "approve", + params: [hashTimeLockAddress, "10"], + gas: estimatedGas, + }); + t2.equal(success, true, "approve() transactionReceipt.status is true OK"); + + const { callOutput } = await connector.invokeContract({ + contractName: DemoHelperJSON.contractName, + keychainId, + signingCredential: web3SigningCredential, + invocationType: EthContractInvocationType.Call, + methodName: "getTimestamp", + params: [], + }); + t2.ok(callOutput, "callOutput() output.callOutput is truthy OK"); + timestamp = callOutput as number; + timestamp = +timestamp + +10; + + t2.comment("Call to newContract endpoint"); + const parameters = { + contractAddress: hashTimeLockAddress, + inputAmount: 10, + outputAmount: 1, + expiration: timestamp, + hashLock, + tokenAddress, + receiver, + outputNetwork: "BTC", + outputAddress: "1AcVYm7M3kkJQH28FXAvyBFQzFRL6xPKu8", + connectorId, + keychainId, + web3SigningCredential, + gas: estimatedGas, + }; + const res = await api.newContractV1(parameters); + t2.ok(res, "newContract called successfully"); + t2.equal(res.status, 200, `Endpoint ${fNew}: response.status === 200 OK`); + + t2.end(); + }); + + test(`${testCase} - ${fNew} - ${cWithoutParams}`, async (t2: Test) => { + const parameters = { + // contractAddress: hashTimeLockAddress, + inputAmount: 10, + outputAmount: 1, + expiration: timestamp, + hashLock, + tokenAddress, + receiver, + outputNetwork: "BTC", + outputAddress: "1AcVYm7M3kkJQH28FXAvyBFQzFRL6xPKu8", + connectorId, + keychainId, + web3SigningCredential, + gas: estimatedGas, + }; + try { + await api.newContractV1((parameters as any) as NewContractRequest); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fNew} without required contractAddress: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("contractAddress"), + "Rejected because contractAddress is required", + ); + } + + t2.end(); + }); + + test(`${testCase} - ${fNew} - ${cInvalidParams}`, async (t2: Test) => { + const parameters = { + contractAddress: hashTimeLockAddress, + inputAmount: 10, + outputAmount: 1, + expiration: timestamp, + hashLock, + tokenAddress, + receiver, + outputNetwork: "BTC", + outputAddress: "1AcVYm7M3kkJQH28FXAvyBFQzFRL6xPKu8", + connectorId, + keychainId, + web3SigningCredential, + gas: estimatedGas, + fake: 4, + }; + try { + await api.newContractV1((parameters as any) as NewContractRequest); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fNew} with fake=4: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("fake"), + "Rejected because fake is not a valid parameter", + ); + } + + t2.end(); + }); + + test(`${testCase} - ${fRefund} - ${cOk}`, async (t2: Test) => { + const responseTxId = await connector.invokeContract({ + contractName: DemoHelperJSON.contractName, + keychainId, + signingCredential: web3SigningCredential, + invocationType: EthContractInvocationType.Call, + methodName: "getTxId", + params: [ + firstHighNetWorthAccount, + receiver, + 10, + hashLock, + timestamp, + tokenAddress, + ], + }); + t2.ok(responseTxId.callOutput, "result is truthy OK"); + txId = responseTxId.callOutput as string; + + await timeout(6000); + + const parameters = { + id: txId, + web3SigningCredential, + connectorId, + keychainId, + }; + const res = await api.refundV1(parameters); + t2.equal( + res.status, + 200, + `Endpoint ${fRefund}: response.status === 200 OK`, + ); + + t2.end(); + }); + + test(`${testCase} - ${fRefund} - ${cWithoutParams}`, async (t2: Test) => { + const parameters = { + // id, + web3SigningCredential, + connectorId, + keychainId, + }; + try { + await api.refundV1((parameters as any) as RefundRequest); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fRefund} without required id: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok(fields.includes("id"), "Rejected because id is required"); + } + + t2.end(); + }); + + test(`${testCase} - ${fRefund} - ${cInvalidParams}`, async (t2: Test) => { + const parameters = { + id: "", + web3SigningCredential, + connectorId, + keychainId, + fake: 4, + }; + try { + await api.refundV1((parameters as any) as RefundRequest); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fRefund} with fake=4: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("fake"), + "Rejected because fake is not a valid parameter", + ); + } + + t2.end(); + }); + + test(`${testCase} - ${fWithdraw} - ${cOk}`, async (t2: Test) => { + const deployOutToken = await connector.deployContract({ + contractName: TestTokenJSON.contractName, + contractAbi: TestTokenJSON.abi, + bytecode: TestTokenJSON.bytecode, + web3SigningCredential, + keychainId, + constructorArgs: ["100", "token", "2", "TKN"], + gas: estimatedGas, + }); + t2.ok( + deployOutToken.transactionReceipt.contractAddress, + "deployContract() output.transactionReceipt.contractAddress is truthy OK", + ); + const tokenAddress = deployOutToken.transactionReceipt + .contractAddress as string; + + await connector.deployContract({ + contractName: DemoHelperJSON.contractName, + contractAbi: DemoHelperJSON.abi, + bytecode: DemoHelperJSON.bytecode, + web3SigningCredential, + keychainId, + constructorArgs: [], + gas: estimatedGas, + }); + + await connector.invokeContract({ + contractName: TestTokenJSON.contractName, + keychainId, + signingCredential: web3SigningCredential, + invocationType: EthContractInvocationType.Send, + methodName: "approve", + params: [hashTimeLockAddress, "10"], + gas: estimatedGas, + }); + + await api.newContractV1({ + contractAddress: hashTimeLockAddress, + inputAmount: 10, + outputAmount: 1, + expiration, + hashLock, + tokenAddress, + receiver, + outputNetwork: "BTC", + outputAddress: "1AcVYm7M3kkJQH28FXAvyBFQzFRL6xPKu8", + connectorId, + keychainId, + web3SigningCredential, + gas: estimatedGas, + }); + + const responseTxId = await connector.invokeContract({ + contractName: DemoHelperJSON.contractName, + keychainId, + signingCredential: web3SigningCredential, + invocationType: EthContractInvocationType.Call, + methodName: "getTxId", + params: [ + firstHighNetWorthAccount, + receiver, + 10, + hashLock, + expiration, + tokenAddress, + ], + }); + t2.ok(responseTxId.callOutput, "result is truthy OK"); + const id = responseTxId.callOutput as string; + + const withdrawRequest: WithdrawRequest = { + id, + secret, + web3SigningCredential, + connectorId, + keychainId, + }; + const resWithdraw = await api.withdrawV1(withdrawRequest); + t2.equal( + resWithdraw.status, + 200, + `Endpoint ${fWithdraw}: response.status === 200 OK`, + ); + + t2.end(); + }); + + test(`${testCase} - ${fWithdraw} - ${cWithoutParams}`, async (t2: Test) => { + const parameters = { + // id, + secret, + web3SigningCredential, + connectorId, + keychainId, + }; + + try { + await api.withdrawV1((parameters as any) as WithdrawRequest); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fWithdraw} without required id: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok(fields.includes("id"), "Rejected because id is required"); + } + + t2.end(); + }); + + test(`${testCase} - ${fWithdraw} - ${cInvalidParams}`, async (t2: Test) => { + const parameters = { + id: "", + secret, + web3SigningCredential, + connectorId, + keychainId, + fake: 4, + }; + + try { + await api.withdrawV1((parameters as any) as WithdrawRequest); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fWithdraw} with fake=4: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("fake"), + "Rejected because fake is not a valid parameter", + ); + } + + t2.end(); + }); + + test(`${testCase} - ${fStatus} - ${cOk}`, async (t2: Test) => { + const ids = [txId as string]; + + const parameters = { + ids, + web3SigningCredential, + connectorId, + keychainId, + }; + const res = await api.getStatusV1(parameters); + t2.equal( + res.status, + 200, + `Endpoint ${fStatus}: response.status === 200 OK`, + ); + + t2.end(); + }); + + test(`${testCase} - ${fStatus} - ${cWithoutParams}`, async (t2: Test) => { + const parameters = { + // ids, + web3SigningCredential, + connectorId, + keychainId, + }; + + try { + await api.getStatusV1((parameters as any) as GetStatusRequest); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fStatus} without required id: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok(fields.includes("ids"), "Rejected because ids is required"); + } + + t2.end(); + }); + + test(`${testCase} - ${fStatus} - ${cInvalidParams}`, async (t2: Test) => { + const parameters = { + ids: [""], + web3SigningCredential, + connectorId, + keychainId, + fake: 4, + }; + + try { + await api.getStatusV1((parameters as any) as GetStatusRequest); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fStatus} with fake=4: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("fake"), + "Rejected because fake is not a valid parameter", + ); + } + + t2.end(); + }); + + test(`${testCase} - ${fSingleStatus} - ${cOk}`, async (t2: Test) => { + const parameters = { + id: txId, + web3SigningCredential, + connectorId, + keychainId, + }; + const res = await api.getSingleStatusV1(parameters); + t2.equal( + res.status, + 200, + `Endpoint ${fSingleStatus}: response.status === 200 OK`, + ); + + t2.end(); + }); + + test(`${testCase} - ${fSingleStatus} - ${cWithoutParams}`, async (t2: Test) => { + const parameters = { + // id: callOutput, + web3SigningCredential, + connectorId, + keychainId, + }; + + try { + await api.getSingleStatusV1( + (parameters as any) as GetSingleStatusRequest, + ); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fSingleStatus} without required id: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok(fields.includes("id"), "Rejected because id is required"); + } + + t2.end(); + }); + + test(`${testCase} - ${fSingleStatus} - ${cInvalidParams}`, async (t2: Test) => { + const parameters = { + id: "", + web3SigningCredential, + connectorId, + keychainId, + fake: 4, + }; + + try { + // eslint-disable-next-line prettier/prettier + await api.getSingleStatusV1((parameters as any) as GetSingleStatusRequest); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fSingleStatus} with fake=4: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("fake"), + "Rejected because fake is not a valid parameter", + ); + } + + t2.end(); + }); + + t.end(); +}); + +test("AFTER " + testCase, async (t: Test) => { + const pruning = pruneDockerAllIfGithubAction({ logLevel }); + await t.doesNotReject(pruning, "Pruning did not throw OK"); + t.end(); +}); diff --git a/packages/cactus-test-plugin-htlc-eth-besu-erc20/src/test/typescript/integration/plugin-htlc-eth-besu-erc20/refund-endpoint.test.ts b/packages/cactus-test-plugin-htlc-eth-besu-erc20/src/test/typescript/integration/plugin-htlc-eth-besu-erc20/refund-endpoint.test.ts index 2fc29594c0..9be571c2a8 100644 --- a/packages/cactus-test-plugin-htlc-eth-besu-erc20/src/test/typescript/integration/plugin-htlc-eth-besu-erc20/refund-endpoint.test.ts +++ b/packages/cactus-test-plugin-htlc-eth-besu-erc20/src/test/typescript/integration/plugin-htlc-eth-besu-erc20/refund-endpoint.test.ts @@ -333,12 +333,12 @@ test(testCase, async (t: Test) => { "balance of account is 100 OK", ); t.comment("Get status of HTLC"); - const resStatus = await api.getSingleStatusV1( + const resStatus = await api.getSingleStatusV1({ id, web3SigningCredential, connectorId, keychainId, - ); + }); t.equal(resStatus.status, 200, "response status is 200 OK"); t.equal(resStatus.data, 2, "the contract status is 2 - Refunded"); t.end(); diff --git a/packages/cactus-test-plugin-htlc-eth-besu-erc20/src/test/typescript/integration/plugin-htlc-eth-besu-erc20/withdraw-endpoint.test.ts b/packages/cactus-test-plugin-htlc-eth-besu-erc20/src/test/typescript/integration/plugin-htlc-eth-besu-erc20/withdraw-endpoint.test.ts index e50cec948a..55be3aff34 100644 --- a/packages/cactus-test-plugin-htlc-eth-besu-erc20/src/test/typescript/integration/plugin-htlc-eth-besu-erc20/withdraw-endpoint.test.ts +++ b/packages/cactus-test-plugin-htlc-eth-besu-erc20/src/test/typescript/integration/plugin-htlc-eth-besu-erc20/withdraw-endpoint.test.ts @@ -293,12 +293,12 @@ test(testCase, async (t: Test) => { t.equal(resWithdraw.status, 200, "response status is 200 OK"); t.comment("Get status of HTLC"); - const resStatus = await api.getSingleStatusV1( + const resStatus = await api.getSingleStatusV1({ id, web3SigningCredential, connectorId, keychainId, - ); + }); t.equal(resStatus.status, 200, "response status is 200 OK"); t.equal(resStatus.data, 3, "the contract status is 3 - Withdrawn"); diff --git a/packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/get-single-status-endpoint-invalid.test.ts b/packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/get-single-status-endpoint-invalid.test.ts index b68dda96f5..91d45510b4 100644 --- a/packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/get-single-status-endpoint-invalid.test.ts +++ b/packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/get-single-status-endpoint-invalid.test.ts @@ -210,12 +210,12 @@ test(testCase, async (t: Test) => { ); try { const fakeId = "0x66616b654964"; - const res = await api.getSingleStatusV1( - fakeId, - fakeWeb3SigningCredential, + const res = await api.getSingleStatusV1({ + id: fakeId, + web3SigningCredential: fakeWeb3SigningCredential, connectorId, - "", - ); + keychainId: "", + }); t.equal(res.status, 500, "response status is 500"); } catch (e) { t.equal(e.response.status, 500); diff --git a/packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/get-single-status-endpoint.test.ts b/packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/get-single-status-endpoint.test.ts index f55cf8617b..00fd1de9b2 100644 --- a/packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/get-single-status-endpoint.test.ts +++ b/packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/get-single-status-endpoint.test.ts @@ -220,12 +220,12 @@ test(testCase, async (t: Test) => { "Balance of account is OK", ); - const res = await api.getSingleStatusV1( - callOutput as string, + const res = await api.getSingleStatusV1({ + id: callOutput as string, web3SigningCredential, connectorId, keychainId, - ); + }); t.equal(res.status, 200); t.equal(res.data, 1, "the contract status is 1 - Active"); t.end(); diff --git a/packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/get-status-endpoint-invalid.test.ts b/packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/get-status-endpoint-invalid.test.ts index c34a227dc6..be16e15df4 100644 --- a/packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/get-status-endpoint-invalid.test.ts +++ b/packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/get-status-endpoint-invalid.test.ts @@ -221,12 +221,12 @@ test(testCase, async (t: Test) => { try { const ids = [responseTxId.callOutput as string]; - const res = await api.getStatusV1( + const res = await api.getStatusV1({ ids, web3SigningCredential, connectorId, - "", - ); + keychainId: "", + }); t.equal(res.status, 500, "response status is 500"); } catch (e) { t.equal(e.response.status, 500); diff --git a/packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/get-status-endpoint.test.ts b/packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/get-status-endpoint.test.ts index fc0b68f71e..4266df02a8 100644 --- a/packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/get-status-endpoint.test.ts +++ b/packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/get-status-endpoint.test.ts @@ -221,12 +221,12 @@ test(testCase, async (t: Test) => { ); const ids = [responseTxId.callOutput as string]; - const res = await api.getStatusV1( + const res = await api.getStatusV1({ ids, web3SigningCredential, connectorId, keychainId, - ); + }); t.equal(res.status, 200, "response status is 200 OK"); t.equal(res.data[0], "1", "the contract status is 1 - Active"); t.end(); diff --git a/packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/openapi/openapi-validation.test.ts b/packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/openapi/openapi-validation.test.ts new file mode 100644 index 0000000000..f202d385b2 --- /dev/null +++ b/packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/openapi/openapi-validation.test.ts @@ -0,0 +1,804 @@ +import http from "http"; +import type { AddressInfo } from "net"; +import test, { Test } from "tape-promise/tape"; +import { v4 as uuidv4 } from "uuid"; +import express from "express"; +import bodyParser from "body-parser"; +import { + Configuration, + DefaultApi as BesuApi, + IPluginHtlcEthBesuOptions, + PluginFactoryHtlcEthBesu, + NewContractObj, + InitializeRequest, + RefundReq, + WithdrawReq, + GetStatusRequest, + GetSingleStatusRequest, +} from "@hyperledger/cactus-plugin-htlc-eth-besu"; +import { + EthContractInvocationType, + PluginFactoryLedgerConnector, + PluginLedgerConnectorBesu, + Web3SigningCredential, + Web3SigningCredentialType, +} from "@hyperledger/cactus-plugin-ledger-connector-besu"; +import { PluginKeychainMemory } from "@hyperledger/cactus-plugin-keychain-memory"; +import { + LogLevelDesc, + IListenOptions, + Servers, +} from "@hyperledger/cactus-common"; +import { PluginRegistry } from "@hyperledger/cactus-core"; +import { PluginImportType } from "@hyperledger/cactus-core-api"; +import { + BesuTestLedger, + pruneDockerAllIfGithubAction, +} from "@hyperledger/cactus-test-tooling"; +import { DataTest } from "../../data-test"; +import DemoHelperJSON from "../../../../solidity/contracts/DemoHelpers.json"; +import HashTimeLockJSON from "../../../../../../../cactus-plugin-htlc-eth-besu/src/main/solidity/contracts/HashTimeLock.json"; + +import { installOpenapiValidationMiddleware } from "@hyperledger/cactus-core"; +import { PluginHtlcEthBesu } from "@hyperledger/cactus-plugin-htlc-eth-besu"; + +const connectorId = uuidv4(); +const logLevel: LogLevelDesc = "INFO"; + +const testCase = "Test cactus-plugin-htlc-eth-besu openapi validation"; + +test("BEFORE " + testCase, async (t: Test) => { + const pruning = pruneDockerAllIfGithubAction({ logLevel }); + await t.doesNotReject(pruning, "Pruning did not throw OK"); + t.end(); +}); + +test(testCase, async (t: Test) => { + const timeout = (ms: number) => { + return new Promise((resolve) => setTimeout(resolve, ms)); + }; + + t.comment("Starting Besu Test Ledger"); + const besuTestLedger = new BesuTestLedger({ logLevel }); + + const firstHighNetWorthAccount = besuTestLedger.getGenesisAccountPubKey(); + const privateKey = besuTestLedger.getGenesisAccountPrivKey(); + + const web3SigningCredential: Web3SigningCredential = { + ethAccount: firstHighNetWorthAccount, + secret: privateKey, + type: Web3SigningCredentialType.PrivateKeyHex, + } as Web3SigningCredential; + + test.onFailure(async () => { + await besuTestLedger.stop(); + await besuTestLedger.destroy(); + }); + + test.onFinish(async () => { + await besuTestLedger.stop(); + await besuTestLedger.destroy(); + }); + + await besuTestLedger.start(); + + const rpcApiHttpHost = await besuTestLedger.getRpcApiHttpHost(); + const rpcApiWsHost = await besuTestLedger.getRpcApiWsHost(); + const keychainId = uuidv4(); + const keychainPlugin = new PluginKeychainMemory({ + instanceId: uuidv4(), + keychainId, + // pre-provision keychain with mock backend holding the private key of the + // test account that we'll reference while sending requests with the + // signing credential pointing to this keychain entry. + backend: new Map([ + [DemoHelperJSON.contractName, JSON.stringify(DemoHelperJSON)], + ]), + logLevel, + }); + keychainPlugin.set( + HashTimeLockJSON.contractName, + JSON.stringify(HashTimeLockJSON), + ); + + const factory = new PluginFactoryLedgerConnector({ + pluginImportType: PluginImportType.Local, + }); + + const pluginRegistry = new PluginRegistry({}); + const connector: PluginLedgerConnectorBesu = await factory.create({ + rpcApiHttpHost, + rpcApiWsHost, + logLevel, + instanceId: connectorId, + pluginRegistry: new PluginRegistry({ plugins: [keychainPlugin] }), + }); + + pluginRegistry.add(connector); + const pluginOptions: IPluginHtlcEthBesuOptions = { + logLevel, + instanceId: uuidv4(), + pluginRegistry, + }; + + const factoryHTLC = new PluginFactoryHtlcEthBesu({ + pluginImportType: PluginImportType.Local, + }); + + const pluginHtlc = await factoryHTLC.create(pluginOptions); + pluginRegistry.add(pluginHtlc); + + const expressApp = express(); + expressApp.use(bodyParser.json({ limit: "250mb" })); + const server = http.createServer(expressApp); + const listenOptions: IListenOptions = { + hostname: "0.0.0.0", + port: 0, + server, + }; + const addressInfo = (await Servers.listen(listenOptions)) as AddressInfo; + test.onFinish(async () => await Servers.shutdown(server)); + const { address, port } = addressInfo; + const apiHost = `http://${address}:${port}`; + + const configuration = new Configuration({ basePath: apiHost }); + const api = new BesuApi(configuration); + + const OAS = (pluginHtlc as PluginHtlcEthBesu).getOpenApiSpec(); + + await installOpenapiValidationMiddleware({ + logLevel, + app: expressApp, + apiSpec: OAS, + }); + + await pluginHtlc.getOrCreateWebServices(); + await pluginHtlc.registerWebServices(expressApp); + + const fInitialize = "initialize"; + const fNew = "newContract"; + const fRefund = "refund"; + const fWithdraw = "withdraw"; + const fStatus = "getStatus"; + const fSingleStatus = "getSingleStatus"; + + const cOk = "without bad request error"; + const cWithoutParams = "not sending all required parameters"; + const cInvalidParams = "sending invalid parameters"; + + let hashTimeLockAddress: string; + let timestamp = 0; + + test(`${testCase} - ${fInitialize} - ${cOk}`, async (t2: Test) => { + const parameters = { + connectorId, + keychainId, + constructorArgs: [], + web3SigningCredential, + gas: DataTest.estimated_gas, + }; + + const res = await api.initializeV1(parameters); + t2.ok(res, "initialize called successfully"); + t2.equal( + res.status, + 200, + `Endpoint ${fInitialize}: response.status === 200 OK`, + ); + + hashTimeLockAddress = res.data.transactionReceipt.contractAddress as string; + + t2.end(); + }); + + test(`${testCase} - ${fInitialize} - ${cWithoutParams}`, async (t2: Test) => { + const parameters = { + // connectorId, + keychainId, + constructorArgs: [], + web3SigningCredential, + gas: DataTest.estimated_gas, + }; + + try { + await api.initializeV1((parameters as any) as InitializeRequest); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fInitialize} without required connectorId: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("connectorId"), + "Rejected because connectorId is required", + ); + } + + t2.end(); + }); + + test(`${testCase} - ${fInitialize} - ${cInvalidParams}`, async (t2: Test) => { + const parameters = { + connectorId, + keychainId, + constructorArgs: [], + web3SigningCredential, + gas: DataTest.estimated_gas, + fake: 4, + }; + + try { + await api.initializeV1((parameters as any) as InitializeRequest); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fInitialize} with fake=4: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("fake"), + "Rejected because fake is not a valid parameter", + ); + } + + t2.end(); + }); + + test(`${testCase} - ${fNew} - ${cOk}`, async (t2: Test) => { + await connector.deployContract({ + contractName: DemoHelperJSON.contractName, + contractAbi: DemoHelperJSON.abi, + bytecode: DemoHelperJSON.bytecode, + web3SigningCredential, + keychainId, + constructorArgs: [], + gas: DataTest.estimated_gas, + }); + + const { callOutput } = await connector.invokeContract({ + contractName: DemoHelperJSON.contractName, + keychainId, + signingCredential: web3SigningCredential, + invocationType: EthContractInvocationType.Call, + methodName: "getTimestamp", + params: [], + }); + t2.ok(callOutput, "callOutput() output.callOutput is truthy OK"); + timestamp = callOutput as number; + timestamp = +timestamp + +10; + + const parameters = { + contractAddress: hashTimeLockAddress, + inputAmount: 10, + outputAmount: 0x04, + expiration: timestamp, + hashLock: DataTest.hashLock, + receiver: DataTest.receiver, + outputNetwork: "BTC", + outputAddress: "1AcVYm7M3kkJQH28FXAvyBFQzFRL6xPKu8", + connectorId: connectorId, + web3SigningCredential, + keychainId, + gas: DataTest.estimated_gas, + }; + const res = await api.newContractV1(parameters); + t2.ok(res, "newContract called successfully"); + t2.equal(res.status, 200, `Endpoint ${fNew}: response.status === 200 OK`); + + t2.end(); + }); + + test(`${testCase} - ${fNew} - ${cWithoutParams}`, async (t2: Test) => { + const parameters = { + // contractAddress: hashTimeLockAddress, + inputAmount: 10, + outputAmount: 0x04, + expiration: timestamp, + hashLock: DataTest.hashLock, + receiver: DataTest.receiver, + outputNetwork: "BTC", + outputAddress: "1AcVYm7M3kkJQH28FXAvyBFQzFRL6xPKu8", + connectorId: connectorId, + web3SigningCredential, + keychainId, + gas: DataTest.estimated_gas, + }; + try { + await api.newContractV1((parameters as any) as NewContractObj); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fNew} without required contractAddress: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("contractAddress"), + "Rejected because contractAddress is required", + ); + } + + t2.end(); + }); + + test(`${testCase} - ${fNew} - ${cInvalidParams}`, async (t2: Test) => { + const parameters = { + contractAddress: hashTimeLockAddress, + inputAmount: 10, + outputAmount: 0x04, + expiration: timestamp, + hashLock: DataTest.hashLock, + receiver: DataTest.receiver, + outputNetwork: "BTC", + outputAddress: "1AcVYm7M3kkJQH28FXAvyBFQzFRL6xPKu8", + connectorId: connectorId, + web3SigningCredential, + keychainId, + gas: DataTest.estimated_gas, + fake: 4, + }; + try { + await api.newContractV1((parameters as any) as NewContractObj); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fNew} with fake=4: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("fake"), + "Rejected because fake is not a valid parameter", + ); + } + + t2.end(); + }); + + test(`${testCase} - ${fRefund} - ${cOk}`, async (t2: Test) => { + const responseTxId = await connector.invokeContract({ + contractName: DemoHelperJSON.contractName, + keychainId, + signingCredential: web3SigningCredential, + invocationType: EthContractInvocationType.Call, + methodName: "getTxId", + params: [ + firstHighNetWorthAccount, + DataTest.receiver, + 10, + DataTest.hashLock, + timestamp, + ], + }); + t2.ok(responseTxId.callOutput, "result is truthy OK"); + const id = responseTxId.callOutput as string; + + await timeout(6000); + + const parameters = { + id, + web3SigningCredential, + connectorId, + keychainId, + }; + const res = await api.refundV1(parameters); + t2.equal( + res.status, + 200, + `Endpoint ${fRefund}: response.status === 200 OK`, + ); + + t2.end(); + }); + + test(`${testCase} - ${fRefund} - ${cWithoutParams}`, async (t2: Test) => { + const parameters = { + // id, + web3SigningCredential, + connectorId, + keychainId, + }; + try { + await api.refundV1((parameters as any) as RefundReq); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fRefund} without required id: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok(fields.includes("id"), "Rejected because id is required"); + } + + t2.end(); + }); + + test(`${testCase} - ${fRefund} - ${cInvalidParams}`, async (t2: Test) => { + const parameters = { + id: "", + web3SigningCredential, + connectorId, + keychainId, + fake: 4, + }; + try { + await api.refundV1((parameters as any) as RefundReq); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fRefund} with fake=4: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("fake"), + "Rejected because fake is not a valid parameter", + ); + } + + t2.end(); + }); + + test(`${testCase} - ${fWithdraw} - ${cOk}`, async (t2: Test) => { + const bodyObj: NewContractObj = { + contractAddress: hashTimeLockAddress, + inputAmount: 10, + outputAmount: 0x04, + expiration: DataTest.expiration, + hashLock: DataTest.hashLock, + receiver: DataTest.receiver, + outputNetwork: "BTC", + outputAddress: "1AcVYm7M3kkJQH28FXAvyBFQzFRL6xPKu8", + connectorId: connectorId, + web3SigningCredential, + keychainId, + gas: DataTest.estimated_gas, + }; + await api.newContractV1(bodyObj); + + const { callOutput } = await connector.invokeContract({ + contractName: DemoHelperJSON.contractName, + keychainId, + signingCredential: web3SigningCredential, + invocationType: EthContractInvocationType.Call, + methodName: "getTxId", + params: [ + firstHighNetWorthAccount, + DataTest.receiver, + 10, + DataTest.hashLock, + DataTest.expiration, + ], + }); + + const parameters = { + id: callOutput, + secret: + "0x3853485acd2bfc3c632026ee365279743af107a30492e3ceaa7aefc30c2a048a", + web3SigningCredential, + connectorId, + keychainId, + }; + + const res = await api.withdrawV1(parameters); + t2.equal( + res.status, + 200, + `Endpoint ${fWithdraw}: response.status === 200 OK`, + ); + + t2.end(); + }); + + test(`${testCase} - ${fWithdraw} - ${cWithoutParams}`, async (t2: Test) => { + const parameters = { + // id: callOutput, + secret: + "0x3853485acd2bfc3c632026ee365279743af107a30492e3ceaa7aefc30c2a048a", + web3SigningCredential, + connectorId, + keychainId, + }; + + try { + await api.withdrawV1((parameters as any) as WithdrawReq); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fWithdraw} without required id: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok(fields.includes("id"), "Rejected because id is required"); + } + + t2.end(); + }); + + test(`${testCase} - ${fWithdraw} - ${cInvalidParams}`, async (t2: Test) => { + const parameters = { + id: "", + secret: + "0x3853485acd2bfc3c632026ee365279743af107a30492e3ceaa7aefc30c2a048a", + web3SigningCredential, + connectorId, + keychainId, + fake: 4, + }; + + try { + await api.withdrawV1((parameters as any) as WithdrawReq); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fWithdraw} with fake=4: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("fake"), + "Rejected because fake is not a valid parameter", + ); + } + + t2.end(); + }); + + test(`${testCase} - ${fStatus} - ${cOk}`, async (t2: Test) => { + const initRequest: InitializeRequest = { + connectorId, + keychainId, + constructorArgs: [], + web3SigningCredential, + gas: DataTest.estimated_gas, + }; + const deployOut = await pluginHtlc.initialize(initRequest); + const hashTimeLockAddress2 = deployOut.transactionReceipt + .contractAddress as string; + + const bodyObj: NewContractObj = { + contractAddress: hashTimeLockAddress2, + inputAmount: 10, + outputAmount: 0x04, + expiration: DataTest.expiration, + hashLock: DataTest.hashLock, + receiver: DataTest.receiver, + outputNetwork: "BTC", + outputAddress: "1AcVYm7M3kkJQH28FXAvyBFQzFRL6xPKu8", + connectorId: connectorId, + web3SigningCredential, + keychainId, + gas: DataTest.estimated_gas, + }; + await api.newContractV1(bodyObj); + + const { callOutput } = await connector.invokeContract({ + contractName: DemoHelperJSON.contractName, + keychainId, + signingCredential: web3SigningCredential, + invocationType: EthContractInvocationType.Call, + methodName: "getTxId", + params: [ + firstHighNetWorthAccount, + DataTest.receiver, + 10, + DataTest.hashLock, + DataTest.expiration, + ], + }); + + const ids = [callOutput as string]; + + const parameters = { + ids, + web3SigningCredential, + connectorId, + keychainId, + }; + const res = await api.getStatusV1(parameters); + t2.equal( + res.status, + 200, + `Endpoint ${fStatus}: response.status === 200 OK`, + ); + + t2.end(); + }); + + test(`${testCase} - ${fStatus} - ${cWithoutParams}`, async (t2: Test) => { + const parameters = { + // ids, + web3SigningCredential, + connectorId, + keychainId, + }; + + try { + await api.getStatusV1((parameters as any) as GetStatusRequest); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fStatus} without required ids: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok(fields.includes("ids"), "Rejected because ids is required"); + } + + t2.end(); + }); + + test(`${testCase} - ${fStatus} - ${cInvalidParams}`, async (t2: Test) => { + const parameters = { + ids: [""], + web3SigningCredential, + connectorId, + keychainId, + fake: 4, + }; + + try { + await api.getStatusV1((parameters as any) as GetStatusRequest); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fStatus} with fake=4: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("fake"), + "Rejected because fake is not a valid parameter", + ); + } + + t2.end(); + }); + + test(`${testCase} - ${fSingleStatus} - ${cOk}`, async (t2: Test) => { + const initRequest: InitializeRequest = { + connectorId, + keychainId, + constructorArgs: [], + web3SigningCredential, + gas: DataTest.estimated_gas, + }; + const deployOut = await pluginHtlc.initialize(initRequest); + const hashTimeLockAddress2 = deployOut.transactionReceipt + .contractAddress as string; + + const bodyObj: NewContractObj = { + contractAddress: hashTimeLockAddress2, + inputAmount: 10, + outputAmount: 0x04, + expiration: DataTest.expiration, + hashLock: DataTest.hashLock, + receiver: DataTest.receiver, + outputNetwork: "BTC", + outputAddress: "1AcVYm7M3kkJQH28FXAvyBFQzFRL6xPKu8", + connectorId: connectorId, + web3SigningCredential, + keychainId, + gas: DataTest.estimated_gas, + }; + await api.newContractV1(bodyObj); + + const { callOutput } = await connector.invokeContract({ + contractName: DemoHelperJSON.contractName, + keychainId, + signingCredential: web3SigningCredential, + invocationType: EthContractInvocationType.Call, + methodName: "getTxId", + params: [ + firstHighNetWorthAccount, + DataTest.receiver, + 10, + DataTest.hashLock, + DataTest.expiration, + ], + }); + + const parameters = { + id: callOutput, + web3SigningCredential, + connectorId, + keychainId, + }; + const res = await api.getSingleStatusV1(parameters); + t2.equal( + res.status, + 200, + `Endpoint ${fSingleStatus}: response.status === 200 OK`, + ); + + t2.end(); + }); + + test(`${testCase} - ${fSingleStatus} - ${cWithoutParams}`, async (t2: Test) => { + const parameters = { + // id: callOutput, + web3SigningCredential, + connectorId, + keychainId, + }; + + try { + await api.getSingleStatusV1( + (parameters as any) as GetSingleStatusRequest, + ); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fSingleStatus} without required id: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok(fields.includes("id"), "Rejected because id is required"); + } + + t2.end(); + }); + + test(`${testCase} - ${fSingleStatus} - ${cInvalidParams}`, async (t2: Test) => { + const parameters = { + id: "", + web3SigningCredential, + connectorId, + keychainId, + fake: 4, + }; + + try { + await api.getSingleStatusV1( + (parameters as any) as GetSingleStatusRequest, + ); + } catch (e) { + t2.equal( + e.response.status, + 400, + `Endpoint ${fSingleStatus} with fake=4: response.status === 400 OK`, + ); + const fields = e.response.data.map((param: any) => + param.path.replace(".body.", ""), + ); + t2.ok( + fields.includes("fake"), + "Rejected because fake is not a valid parameter", + ); + } + + t2.end(); + }); + + t.end(); +}); + +test("AFTER " + testCase, async (t: Test) => { + const pruning = pruneDockerAllIfGithubAction({ logLevel }); + await t.doesNotReject(pruning, "Pruning did not throw OK"); + t.end(); +}); diff --git a/packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/refund-endpoint.test.ts b/packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/refund-endpoint.test.ts index 76d7c1faea..0b46aca277 100644 --- a/packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/refund-endpoint.test.ts +++ b/packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/refund-endpoint.test.ts @@ -251,12 +251,12 @@ test(testCase, async (t: Test) => { ); const balance2 = await web3.eth.getBalance(firstHighNetWorthAccount); t.equal(balance1, balance2, "Retrieved balance of test account OK"); - const res = await api.getSingleStatusV1( + const res = await api.getSingleStatusV1({ id, web3SigningCredential, connectorId, keychainId, - ); + }); t.equal(res.status, 200); t.equal(res.data, 2, "the contract status is Refunded"); t.end(); diff --git a/packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/withdraw-endpoint.test.ts b/packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/withdraw-endpoint.test.ts index 325fc90708..aefeb98201 100644 --- a/packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/withdraw-endpoint.test.ts +++ b/packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/withdraw-endpoint.test.ts @@ -237,12 +237,12 @@ test(testCase, async (t: Test) => { "Retrieved balance of test account OK", ); t.comment("Get single status of HTLC"); - const resStatus = await api.getSingleStatusV1( - callOutput as string, + const resStatus = await api.getSingleStatusV1({ + id: callOutput as string, web3SigningCredential, connectorId, keychainId, - ); + }); t.equal(resStatus.status, 200, "response status is 200 OK"); t.equal(resStatus.data, 3, "the contract status is Withdrawn"); t.end();