diff --git a/CHANGELOG.md b/CHANGELOG.md index 4abdf1ae0..20bd3ea5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how - [Breaking change: unifying provider interfaces, preparing network providers for extraction - step 2](https://github.com/ElrondNetwork/elrond-sdk-erdjs/pull/181) - [Breaking change: unifying provider interfaces, preparing network providers for extraction - step 3](https://github.com/ElrondNetwork/elrond-sdk-erdjs/pull/182) - [Breaking change: SmartContract does not depend on IProvider anymore](https://github.com/ElrondNetwork/elrond-sdk-erdjs/pull/183). + - [Breaking change: unifying provider interfaces, preparing network providers for extraction - step 4](https://github.com/ElrondNetwork/elrond-sdk-erdjs/pull/184) **Breaking changes** - Removed utility functions: `transaction.awaitExecuted()`, `transaction.awaitPending()`. `TransactionWatcher` should be used directly, instead. diff --git a/src/interface.ts b/src/interface.ts index 42520e4e4..9efd49471 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -1,10 +1,9 @@ import { Transaction } from "./transaction"; import { Signature } from "./signature"; import { Query } from "./smartcontracts"; -import { QueryResponse } from "./smartcontracts"; import { Token } from "./token"; import BigNumber from "bignumber.js"; -import { IAccountOnNetwork, IFungibleTokenOfAccountOnNetwork, INetworkConfig, INetworkStake, INetworkStats, INetworkStatus, ITransactionOnNetwork, ITransactionStatus } from "./interfaceOfNetwork"; +import { IAccountOnNetwork, IContractQueryResponse, IFungibleTokenOfAccountOnNetwork, INetworkConfig, INetworkStake, INetworkStats, INetworkStatus, ITransactionOnNetwork, ITransactionStatus } from "./interfaceOfNetwork"; export interface ITransactionFetcher { /** @@ -55,7 +54,7 @@ export interface IProvider extends ITransactionFetcher { /** * Queries a Smart Contract - runs a pure function defined by the contract and returns its results. */ - queryContract(query: Query): Promise; + queryContract(query: Query): Promise; /** * Broadcasts an already-signed {@link Transaction}. diff --git a/src/interfaceOfNetwork.ts b/src/interfaceOfNetwork.ts index c237ff7c9..f087799c9 100644 --- a/src/interfaceOfNetwork.ts +++ b/src/interfaceOfNetwork.ts @@ -79,6 +79,18 @@ export interface IContractResultItem { logs: ITransactionLogs; } +export interface IContractQueryResponse { + returnCode: IContractReturnCode; + returnMessage: string; + gasUsed: IGasLimit; + getReturnDataParts(): Buffer[]; + isSuccess(): boolean; +} + +export interface IContractReturnCode { + toString(): string; +} + export interface ITransactionLogs { events: ITransactionEvent[]; diff --git a/src/networkProvider/apiNetworkProvider.ts b/src/networkProvider/apiNetworkProvider.ts index e25a2679d..dc9df71bb 100644 --- a/src/networkProvider/apiNetworkProvider.ts +++ b/src/networkProvider/apiNetworkProvider.ts @@ -1,11 +1,9 @@ import axios, { AxiosRequestConfig } from "axios"; import { AccountOnNetwork } from "./accounts"; -import { IAddress, IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, IHash, INetworkProvider, INonce, INonFungibleTokenOfAccountOnNetwork, ITransaction, Pagination } from "./interface"; +import { IAddress, IContractQuery, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, IHash, INetworkProvider, INonce, INonFungibleTokenOfAccountOnNetwork, ITransaction, Pagination } from "./interface"; import { NetworkConfig } from "./networkConfig"; import { NetworkStake } from "./networkStake"; -import { Query } from "../smartcontracts"; import { Stats } from "./stats"; -import { ContractQueryResponse } from "./contractResults"; import { ProxyNetworkProvider } from "./proxyNetworkProvider"; import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; @@ -15,6 +13,7 @@ import { Hash } from "./primitives"; import { ErrNetworkProvider } from "./errors"; import { defaultAxiosConfig } from "./config"; import { NetworkStatus } from "./networkStatus"; +import { ContractQueryResponse } from "./contractQueryResponse"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". export class ApiNetworkProvider implements INetworkProvider { @@ -112,7 +111,7 @@ export class ApiNetworkProvider implements INetworkProvider { return await this.backingProxyNetworkProvider.simulateTransaction(tx); } - async queryContract(query: Query): Promise { + async queryContract(query: IContractQuery): Promise { let data = query.toHttpRequest(); let response = await this.doPostGeneric("query", data); let queryResponse = ContractQueryResponse.fromHttpResponse(response); diff --git a/src/networkProvider/constants.ts b/src/networkProvider/constants.ts new file mode 100644 index 000000000..f4ab70a0a --- /dev/null +++ b/src/networkProvider/constants.ts @@ -0,0 +1,3 @@ +import BigNumber from "bignumber.js"; + +export const MaxUint64AsBigNumber = new BigNumber("18446744073709551615"); diff --git a/src/smartcontracts/queryResponse.ts b/src/networkProvider/contractQueryResponse.ts similarity index 56% rename from src/smartcontracts/queryResponse.ts rename to src/networkProvider/contractQueryResponse.ts index eb1dcb45a..404d96006 100644 --- a/src/smartcontracts/queryResponse.ts +++ b/src/networkProvider/contractQueryResponse.ts @@ -1,61 +1,43 @@ -import { GasLimit } from "../networkParams"; -import { MaxUint64 } from "./query"; -import { ReturnCode } from "./returnCode"; import BigNumber from "bignumber.js"; -import { ErrContract } from "../errors"; -import { ArgSerializer } from "./argSerializer"; +import { MaxUint64AsBigNumber } from "./constants"; +import { IContractReturnCode, IGasLimit } from "./interface"; +import { ContractReturnCode } from "./primitives"; -export class QueryResponse { +export class ContractQueryResponse { returnData: string[]; - returnCode: ReturnCode; + returnCode: IContractReturnCode; returnMessage: string; - gasUsed: GasLimit; + gasUsed: IGasLimit; - constructor(init?: Partial) { + constructor(init?: Partial) { this.returnData = init?.returnData || []; - this.returnCode = init?.returnCode || ReturnCode.Unknown; + this.returnCode = init?.returnCode || new ContractReturnCode(""); this.returnMessage = init?.returnMessage || ""; - this.gasUsed = init?.gasUsed || new GasLimit(0); + this.gasUsed = init?.gasUsed || 0; } /** * Constructs a QueryResponse object from a HTTP response (as returned by the provider). */ - static fromHttpResponse(payload: any): QueryResponse { + static fromHttpResponse(payload: any): ContractQueryResponse { let returnData = payload["returnData"] || payload["ReturnData"]; let returnCode = payload["returnCode"] || payload["ReturnCode"]; let returnMessage = payload["returnMessage"] || payload["ReturnMessage"]; let gasRemaining = new BigNumber(payload["gasRemaining"] || payload["GasRemaining"] || 0); - let gasUsed = new GasLimit(MaxUint64.minus(gasRemaining).toNumber()); + let gasUsed = new Number(MaxUint64AsBigNumber.minus(gasRemaining).toNumber()); - return new QueryResponse({ + return new ContractQueryResponse({ returnData: returnData, - returnCode: new ReturnCode(returnCode), + returnCode: new ContractReturnCode(returnCode), returnMessage: returnMessage, gasUsed: gasUsed, }); } - getReturnCode(): ReturnCode { - return this.returnCode; - } - - getReturnMessage(): string { - return this.returnMessage; - } - getReturnDataParts(): Buffer[] { return this.returnData.map((item) => Buffer.from(item || "", "base64")); } - assertSuccess() { - if (this.isSuccess()) { - return; - } - - throw new ErrContract(`${this.getReturnCode()}: ${this.getReturnMessage()}`); - } - isSuccess(): boolean { return this.returnCode.isSuccess(); } diff --git a/src/networkProvider/contractResults.ts b/src/networkProvider/contractResults.ts index 3d9b4299e..8ecfeacf9 100644 --- a/src/networkProvider/contractResults.ts +++ b/src/networkProvider/contractResults.ts @@ -1,8 +1,6 @@ -import { BigNumber } from "bignumber.js"; -import { IAddress, IContractQueryResponse, IContractReturnCode, IGasLimit, IGasPrice, IHash, INonce } from "./interface"; +import { IAddress, IGasLimit, IGasPrice, IHash, INonce } from "./interface"; import { TransactionLogs } from "./transactionLogs"; -import { MaxUint64 } from "../smartcontracts/query"; -import { Address, ContractReturnCode, Hash, Nonce, TransactionValue } from "./primitives"; +import { Address, Hash, Nonce, TransactionValue } from "./primitives"; export class ContractResults { readonly items: ContractResultItem[]; @@ -84,26 +82,3 @@ export class ContractResultItem { return item; } } - -export class ContractQueryResponse implements IContractQueryResponse { - returnData: string[] = []; - returnCode: IContractReturnCode = new ContractReturnCode(""); - returnMessage: string = ""; - gasUsed: IGasLimit = 0; - - static fromHttpResponse(payload: any): ContractQueryResponse { - let response = new ContractQueryResponse(); - let gasRemaining = new BigNumber(payload["gasRemaining"] || payload["GasRemaining"] || 0); - - response.returnData = payload["returnData"] || []; - response.returnCode = new ContractReturnCode(payload["returnCode"] || ""); - response.returnMessage = payload["returnMessage"] || ""; - response.gasUsed = MaxUint64.minus(gasRemaining).toNumber(); - - return response; - } - - getReturnDataParts(): Buffer[] { - return this.returnData.map((item) => Buffer.from(item || "")); - } -} diff --git a/src/networkProvider/interface.ts b/src/networkProvider/interface.ts index bfbc8a263..2bcae8e68 100644 --- a/src/networkProvider/interface.ts +++ b/src/networkProvider/interface.ts @@ -2,11 +2,11 @@ import { BigNumber } from "bignumber.js"; import { AccountOnNetwork } from "./accounts"; import { NetworkConfig } from "./networkConfig"; import { NetworkStake } from "./networkStake"; -import { Query } from "../smartcontracts"; import { Stats } from "./stats"; import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; import { NetworkStatus } from "./networkStatus"; +import { ContractQueryResponse } from "./contractQueryResponse"; /** * An interface that defines the endpoints of an HTTP API Provider. @@ -81,7 +81,7 @@ export interface INetworkProvider { /** * Queries a Smart Contract - runs a pure function defined by the contract and returns its results. */ - queryContract(query: Query): Promise; + queryContract(query: IContractQuery): Promise; /** * Fetches the definition of a fungible token. @@ -159,17 +159,13 @@ export interface IDefinitionOfTokenCollectionOnNetwork { // TODO: add "assets", "roles" } -export interface IContractQueryResponse { - returnData: string[]; - returnCode: IContractReturnCode; - returnMessage: string; - gasUsed: IGasLimit; - - getReturnDataParts(): Buffer[]; +export interface IContractQuery { + toHttpRequest(): any; } export interface IContractReturnCode { toString(): string; + isSuccess(): boolean; } export interface IContractSimulation { diff --git a/src/networkProvider/primitives.ts b/src/networkProvider/primitives.ts index 0adef98a7..1a32caa38 100644 --- a/src/networkProvider/primitives.ts +++ b/src/networkProvider/primitives.ts @@ -69,6 +69,8 @@ export class TransactionPayload implements ITransactionPayload { } export class ContractReturnCode { + private static OK: string = "ok"; + private readonly value: string; constructor(value: string) { @@ -78,6 +80,10 @@ export class ContractReturnCode { toString() { return this.value; } + + isSuccess(): boolean { + return this.value == ContractReturnCode.OK; + } } export class AccountBalance { diff --git a/src/networkProvider/proxyNetworkProvider.ts b/src/networkProvider/proxyNetworkProvider.ts index 07318e170..822e8be0b 100644 --- a/src/networkProvider/proxyNetworkProvider.ts +++ b/src/networkProvider/proxyNetworkProvider.ts @@ -1,11 +1,9 @@ import axios, { AxiosRequestConfig } from "axios"; import { AccountOnNetwork } from "./accounts"; -import { IAddress, IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, IHash, INetworkProvider, INonce, INonFungibleTokenOfAccountOnNetwork, ITransaction, Pagination } from "./interface"; +import { IAddress, IContractQuery, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, IHash, INetworkProvider, INonce, INonFungibleTokenOfAccountOnNetwork, ITransaction, Pagination } from "./interface"; import { NetworkConfig } from "./networkConfig"; import { NetworkStake } from "./networkStake"; -import { Query } from "../smartcontracts"; import { Stats } from "./stats"; -import { ContractQueryResponse } from "./contractResults"; import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; @@ -13,6 +11,7 @@ import { Hash } from "./primitives"; import { ErrNetworkProvider } from "./errors"; import { defaultAxiosConfig } from "./config"; import { NetworkStatus } from "./networkStatus"; +import { ContractQueryResponse } from "./contractQueryResponse"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". export class ProxyNetworkProvider implements INetworkProvider { @@ -116,7 +115,7 @@ export class ProxyNetworkProvider implements INetworkProvider { return response; } - async queryContract(query: Query): Promise { + async queryContract(query: IContractQuery): Promise { let data = query.toHttpRequest(); let response = await this.doPostGeneric("vm-values/query", data); let queryResponse = ContractQueryResponse.fromHttpResponse(response.data); diff --git a/src/proxyProvider.ts b/src/proxyProvider.ts index 711185efa..a47d128d2 100644 --- a/src/proxyProvider.ts +++ b/src/proxyProvider.ts @@ -1,16 +1,15 @@ import axios, { AxiosRequestConfig } from "axios"; import BigNumber from "bignumber.js"; -import { IProvider } from "./interface"; +import { IHash, IProvider } from "./interface"; import { Transaction, TransactionHash } from "./transaction"; import { Address } from "./address"; import * as errors from "./errors"; import { Query } from "./smartcontracts/query"; -import { QueryResponse } from "./smartcontracts/queryResponse"; import { Logger } from "./logger"; import { defaultConfig } from "./constants"; import { ProxyNetworkProvider } from "./networkProvider/proxyNetworkProvider"; -import { IAccountOnNetwork, IFungibleTokenOfAccountOnNetwork, INetworkConfig, INetworkStatus, ITransactionOnNetwork, ITransactionStatus } from "./interfaceOfNetwork"; +import { IAccountOnNetwork, IContractQueryResponse, IFungibleTokenOfAccountOnNetwork, INetworkConfig, INetworkStatus, ITransactionOnNetwork, ITransactionStatus } from "./interfaceOfNetwork"; export class ProxyProvider implements IProvider { private url: string; @@ -57,33 +56,22 @@ export class ProxyProvider implements IProvider { /** * Queries a Smart Contract - runs a pure function defined by the contract and returns its results. */ - async queryContract(query: Query): Promise { - try { - let data = query.toHttpRequest(); - return this.doPostGeneric("vm-values/query", data, (response) => - QueryResponse.fromHttpResponse(response.data || response.vmOutput) - ); - } catch (err: any) { - throw errors.ErrContractQuery.increaseSpecificity(err); - } + async queryContract(query: Query): Promise { + return await this.backingProvider.queryContract(query); } /** * Broadcasts an already-signed {@link Transaction}. */ - async sendTransaction(tx: Transaction): Promise { - return this.doPostGeneric( - "transaction/send", - tx.toSendable(), - (response) => new TransactionHash(response.txHash) - ); + async sendTransaction(tx: Transaction): Promise { + return await this.backingProvider.sendTransaction(tx); } /** * Simulates the processing of an already-signed {@link Transaction}. */ async simulateTransaction(tx: Transaction): Promise { - return this.doPostGeneric("transaction/simulate", tx.toSendable(), (response) => response); + return await this.backingProvider.simulateTransaction(tx); } /** diff --git a/src/smartcontracts/index.ts b/src/smartcontracts/index.ts index f167a04be..ed248c95e 100644 --- a/src/smartcontracts/index.ts +++ b/src/smartcontracts/index.ts @@ -15,7 +15,6 @@ export * from "./interactionChecker"; export * from "./interface"; export * from "./nativeSerializer"; export * from "./query"; -export * from "./queryResponse"; export * from "./resultsParser"; export * from "./returnCode"; export * from "./smartContract"; diff --git a/src/smartcontracts/interaction.spec.ts b/src/smartcontracts/interaction.spec.ts index 87afd26f2..a57aef738 100644 --- a/src/smartcontracts/interaction.spec.ts +++ b/src/smartcontracts/interaction.spec.ts @@ -14,7 +14,7 @@ import { assert } from "chai"; import { Interaction } from "./interaction"; import { ChainID, GasLimit } from "../networkParams"; import { ContractFunction } from "./function"; -import { QueryResponse } from "./queryResponse"; +import { ContractQueryResponse } from "../networkProvider/contractQueryResponse"; import { Nonce } from "../nonce"; import { ReturnCode } from "./returnCode"; import { Balance } from "../balance"; @@ -126,7 +126,7 @@ describe("test smart contract interactor", function() { provider.mockQueryContractOnFunction( "getUltimateAnswer", - new QueryResponse({ returnData: ["Kg=="], returnCode: ReturnCode.Ok }) + new ContractQueryResponse({ returnData: ["Kg=="], returnCode: ReturnCode.Ok }) ); // Query @@ -183,7 +183,7 @@ describe("test smart contract interactor", function() { // For "get()", return fake 7 provider.mockQueryContractOnFunction( "get", - new QueryResponse({ returnData: ["Bw=="], returnCode: ReturnCode.Ok }) + new ContractQueryResponse({ returnData: ["Bw=="], returnCode: ReturnCode.Ok }) ); // Query "get()" diff --git a/src/smartcontracts/interface.ts b/src/smartcontracts/interface.ts index 5ebfb01cc..af024e0c8 100644 --- a/src/smartcontracts/interface.ts +++ b/src/smartcontracts/interface.ts @@ -1,13 +1,12 @@ import { Address } from "../address"; import { Balance } from "../balance"; import { IChainID, IGasLimit, IGasPrice } from "../interface"; -import { ITransactionOnNetwork } from "../interfaceOfNetwork"; +import { IContractQueryResponse, ITransactionOnNetwork } from "../interfaceOfNetwork"; import { Transaction } from "../transaction"; import { Code } from "./code"; import { CodeMetadata } from "./codeMetadata"; import { ContractFunction } from "./function"; import { Interaction } from "./interaction"; -import { QueryResponse } from "./queryResponse"; import { ReturnCode } from "./returnCode"; import { EndpointDefinition, TypedValue } from "./typesystem"; @@ -99,8 +98,8 @@ export interface IInteractionChecker { } export interface IResultsParser { - parseQueryResponse(queryResponse: QueryResponse, endpoint: EndpointDefinition): TypedOutcomeBundle; - parseUntypedQueryResponse(queryResponse: QueryResponse): UntypedOutcomeBundle; + parseQueryResponse(queryResponse: IContractQueryResponse, endpoint: EndpointDefinition): TypedOutcomeBundle; + parseUntypedQueryResponse(queryResponse: IContractQueryResponse): UntypedOutcomeBundle; parseOutcome(transaction: ITransactionOnNetwork, endpoint: EndpointDefinition): TypedOutcomeBundle; parseUntypedOutcome(transaction: ITransactionOnNetwork): UntypedOutcomeBundle; diff --git a/src/smartcontracts/query.main.net.spec.ts b/src/smartcontracts/query.main.net.spec.ts index c7ab81796..6b7f49857 100644 --- a/src/smartcontracts/query.main.net.spec.ts +++ b/src/smartcontracts/query.main.net.spec.ts @@ -17,7 +17,7 @@ describe("test queries on mainnet", function () { let response = await provider.queryContract(query); assert.isTrue(response.isSuccess()); - assert.lengthOf(response.returnData, 5); + assert.lengthOf(response.getReturnDataParts(), 5); }); it("delegation: should getNumUsers", async () => { @@ -28,7 +28,7 @@ describe("test queries on mainnet", function () { let response = await provider.queryContract(query); assert.isTrue(response.isSuccess()); - assert.lengthOf(response.returnData, 1); + assert.lengthOf(response.getReturnDataParts(), 1); assert.isAtLeast(response.gasUsed.valueOf(), 1000000); assert.isAtMost(response.gasUsed.valueOf(), 50000000); }); @@ -43,7 +43,7 @@ describe("test queries on mainnet", function () { let response = await provider.queryContract(query); assert.isTrue(response.isSuccess()); - assert.isAtLeast(response.returnData.length, 42); + assert.isAtLeast(response.getReturnDataParts().length, 42); }); it("delegation: should getClaimableRewards", async function () { @@ -68,6 +68,6 @@ describe("test queries on mainnet", function () { response = await provider.queryContract(query); assert.isTrue(response.isSuccess()); - assert.isAtLeast(response.returnData.length, 1); + assert.isAtLeast(response.getReturnDataParts().length, 1); }); }); diff --git a/src/smartcontracts/query.ts b/src/smartcontracts/query.ts index bb3d95fdf..67f1fea23 100644 --- a/src/smartcontracts/query.ts +++ b/src/smartcontracts/query.ts @@ -4,11 +4,8 @@ import { Address } from "../address"; import { guardValueIsSet } from "../utils"; import { TypedValue } from "./typesystem"; import { ArgSerializer } from "./argSerializer"; -import BigNumber from "bignumber.js"; import { IBech32Address, ITransactionValue } from "../interface"; -export const MaxUint64 = new BigNumber("18446744073709551615"); - export class Query { caller: Address; address: IBech32Address; diff --git a/src/smartcontracts/resultsParser.spec.ts b/src/smartcontracts/resultsParser.spec.ts index 2274ab92f..e3c8e8c2f 100644 --- a/src/smartcontracts/resultsParser.spec.ts +++ b/src/smartcontracts/resultsParser.spec.ts @@ -3,7 +3,7 @@ import path from "path"; import { assert } from "chai"; import { BigUIntType, BigUIntValue, EndpointDefinition, EndpointModifiers, EndpointParameterDefinition } from "./typesystem"; import { BytesType, BytesValue } from "./typesystem/bytes"; -import { QueryResponse } from "./queryResponse"; +import { ContractQueryResponse } from "../networkProvider/contractQueryResponse"; import { ReturnCode } from "./returnCode"; import { ResultsParser } from "./resultsParser"; import { Nonce } from "../nonce"; @@ -45,7 +45,7 @@ describe("test smart contract results parser", () => { ]; let endpoint = new EndpointDefinition("foo", [], outputParameters, endpointModifiers); - let queryResponse = new QueryResponse({ + let queryResponse = new ContractQueryResponse({ returnData: [ Buffer.from([42]).toString("base64"), Buffer.from("abba", "hex").toString("base64") diff --git a/src/smartcontracts/resultsParser.ts b/src/smartcontracts/resultsParser.ts index 03caec9a1..d9c27e23a 100644 --- a/src/smartcontracts/resultsParser.ts +++ b/src/smartcontracts/resultsParser.ts @@ -2,10 +2,9 @@ import { TransactionDecoder, TransactionMetadata } from "@elrondnetwork/transact import { Address } from "../address"; import { ErrCannotParseContractResults } from "../errors"; import { Logger } from "../logger"; -import { IContractResults, ITransactionLogs, ITransactionOnNetwork } from "../interfaceOfNetwork"; +import { IContractQueryResponse, IContractResults, ITransactionLogs, ITransactionOnNetwork } from "../interfaceOfNetwork"; import { ArgSerializer } from "./argSerializer"; import { TypedOutcomeBundle, IResultsParser, UntypedOutcomeBundle } from "./interface"; -import { QueryResponse } from "./queryResponse"; import { ReturnCode } from "./returnCode"; import { EndpointDefinition } from "./typesystem"; import { adaptToAddress } from "../boundaryAdapters"; @@ -26,12 +25,13 @@ enum WellKnownTopics { * The parsing involves some heuristics, in order to handle slight inconsistencies (e.g. some SCRs are present on API, but missing on Gateway). */ export class ResultsParser implements IResultsParser { - parseQueryResponse(queryResponse: QueryResponse, endpoint: EndpointDefinition): TypedOutcomeBundle { + parseQueryResponse(queryResponse: IContractQueryResponse, endpoint: EndpointDefinition): TypedOutcomeBundle { let parts = queryResponse.getReturnDataParts(); let values = new ArgSerializer().buffersToValues(parts, endpoint.output); + let returnCode = new ReturnCode(queryResponse.returnCode.toString()); return { - returnCode: queryResponse.returnCode, + returnCode: returnCode, returnMessage: queryResponse.returnMessage, values: values, firstValue: values[0], @@ -40,9 +40,11 @@ export class ResultsParser implements IResultsParser { }; } - parseUntypedQueryResponse(queryResponse: QueryResponse): UntypedOutcomeBundle { + parseUntypedQueryResponse(queryResponse: IContractQueryResponse): UntypedOutcomeBundle { + let returnCode = new ReturnCode(queryResponse.returnCode.toString()) + return { - returnCode: queryResponse.returnCode, + returnCode: returnCode, returnMessage: queryResponse.returnMessage, values: queryResponse.getReturnDataParts() }; diff --git a/src/smartcontracts/wrapper/contractLogger.ts b/src/smartcontracts/wrapper/contractLogger.ts index 066b9d734..394e0a46a 100644 --- a/src/smartcontracts/wrapper/contractLogger.ts +++ b/src/smartcontracts/wrapper/contractLogger.ts @@ -1,8 +1,7 @@ import { Address } from "../../address"; -import { IContractResults, INetworkConfig } from "../../interfaceOfNetwork"; +import { IContractQueryResponse, IContractResults, INetworkConfig } from "../../interfaceOfNetwork"; import { Transaction } from "../../transaction"; import { Query } from "../query"; -import { QueryResponse } from "../queryResponse"; import { findImmediateResult, findResultingCalls, TypedResult } from "./deprecatedContractResults"; /** @@ -36,7 +35,7 @@ export class ContractLogger { console.log(`Query created. Sending...`); } - queryComplete(_result: any, _response: QueryResponse) { + queryComplete(_result: any, _response: IContractQueryResponse) { console.log(`done.`); } } diff --git a/src/smartcontracts/wrapper/contractWrapper.spec.ts b/src/smartcontracts/wrapper/contractWrapper.spec.ts index a0f3c815c..3bd690a07 100644 --- a/src/smartcontracts/wrapper/contractWrapper.spec.ts +++ b/src/smartcontracts/wrapper/contractWrapper.spec.ts @@ -5,7 +5,7 @@ import { } from "../../testutils"; import { Address } from "../../address"; import { assert } from "chai"; -import { QueryResponse } from "../queryResponse"; +import { ContractQueryResponse } from "../../networkProvider/contractQueryResponse"; import { ReturnCode } from "../returnCode"; import BigNumber from "bignumber.js"; import { SystemWrapper } from "./systemWrapper"; @@ -101,7 +101,7 @@ describe("test smart contract wrapper", async function() { function mockQuery(provider: MockProvider, functionName: string, mockedResult: string) { provider.mockQueryContractOnFunction( functionName, - new QueryResponse({ returnData: [mockedResult], returnCode: ReturnCode.Ok }) + new ContractQueryResponse({ returnData: [mockedResult], returnCode: ReturnCode.Ok }) ); } diff --git a/src/smartcontracts/wrapper/deprecatedContractResults.ts b/src/smartcontracts/wrapper/deprecatedContractResults.ts index 5c480ffcd..0685c1d9d 100644 --- a/src/smartcontracts/wrapper/deprecatedContractResults.ts +++ b/src/smartcontracts/wrapper/deprecatedContractResults.ts @@ -8,9 +8,8 @@ */ import { ContractResultItem } from "../../networkProvider/contractResults"; -import { IContractResultItem, IContractResults, ITransactionOnNetwork } from "../../interfaceOfNetwork"; +import { IContractQueryResponse, IContractResultItem, IContractResults, ITransactionOnNetwork } from "../../interfaceOfNetwork"; import { ArgSerializer } from "../argSerializer"; -import { QueryResponse } from "../queryResponse"; import { ReturnCode } from "../returnCode"; import { EndpointDefinition, TypedValue } from "../typesystem"; import { Result } from "./result"; @@ -55,7 +54,7 @@ export interface ExecutionResultsBundle { } export interface QueryResponseBundle { - queryResponse: QueryResponse; + queryResponse: IContractQueryResponse; firstValue: TypedValue; values: TypedValue[]; returnCode: ReturnCode; diff --git a/src/smartcontracts/wrapper/result.ts b/src/smartcontracts/wrapper/result.ts index 391cc66a1..3ed5fd0c8 100644 --- a/src/smartcontracts/wrapper/result.ts +++ b/src/smartcontracts/wrapper/result.ts @@ -1,6 +1,6 @@ import { ErrContract } from "../../errors"; +import { IContractQueryResponse } from "../../interfaceOfNetwork"; import { ArgSerializer } from "../argSerializer"; -import { QueryResponse } from "../queryResponse"; import { ReturnCode } from "../returnCode"; import { EndpointDefinition } from "../typesystem"; import { TypedResult } from "./deprecatedContractResults"; @@ -26,8 +26,11 @@ export namespace Result { throw new ErrContract(`${result.getReturnCode()}: ${result.getReturnMessage()}`); } - export function unpackQueryOutput(endpoint: EndpointDefinition, queryResponse: QueryResponse) { - queryResponse.assertSuccess(); + export function unpackQueryOutput(endpoint: EndpointDefinition, queryResponse: IContractQueryResponse) { + if (!queryResponse.isSuccess()) { + throw new ErrContract(`${queryResponse.returnCode}: ${queryResponse.returnMessage}`); + } + let buffers = queryResponse.getReturnDataParts(); let typedValues = new ArgSerializer().buffersToValues(buffers, endpoint.output); let values = typedValues.map((value) => value?.valueOf()); diff --git a/src/testutils/mockProvider.ts b/src/testutils/mockProvider.ts index f9169dc4e..bb2476d53 100644 --- a/src/testutils/mockProvider.ts +++ b/src/testutils/mockProvider.ts @@ -7,7 +7,7 @@ import { AsyncTimer } from "../asyncTimer"; import { Balance } from "../balance"; import * as errors from "../errors"; import { Query } from "../smartcontracts/query"; -import { QueryResponse } from "../smartcontracts/queryResponse"; +import { ContractQueryResponse } from "../networkProvider/contractQueryResponse"; import { TypedEvent } from "../events"; import { BalanceBuilder } from "../balanceBuilder"; import BigNumber from "bignumber.js"; @@ -84,7 +84,7 @@ export class MockProvider implements IProvider { this.transactions.set(hash.toString(), item); } - mockQueryContractOnFunction(functionName: string, response: QueryResponse) { + mockQueryContractOnFunction(functionName: string, response: ContractQueryResponse) { let predicate = (query: Query) => query.func.name == functionName; this.queryContractResponders.push(new QueryContractResponder(predicate, response)); } @@ -216,14 +216,14 @@ export class MockProvider implements IProvider { return new NetworkStatus(); } - async queryContract(query: Query): Promise { + async queryContract(query: Query): Promise { for (const responder of this.queryContractResponders) { if (responder.matches(query)) { return responder.response; } } - return new QueryResponse(); + return new ContractQueryResponse(); } } @@ -239,9 +239,9 @@ export class InHyperblock { } class QueryContractResponder { readonly matches: (query: Query) => boolean; - readonly response: QueryResponse; + readonly response: ContractQueryResponse; - constructor(matches: (query: Query) => boolean, response: QueryResponse) { + constructor(matches: (query: Query) => boolean, response: ContractQueryResponse) { this.matches = matches; this.response = response; }