Skip to content

Commit 22f0fe6

Browse files
Merge pull request #497 from multiversx/outcome-08
In outcome parsers, handle both "TransactionOnNetwork" and "TransactionOutcome"
2 parents 52f0efb + 8983762 commit 22f0fe6

File tree

8 files changed

+241
-78
lines changed

8 files changed

+241
-78
lines changed

.github/workflows/build.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,5 @@ jobs:
2727
- run: npm run lint
2828
- run: npm run compile
2929
- run: npm install esmify && npm run compile-browser
30-
- run: npm test
30+
- run: npm run tests-unit
31+
- run: npm run tests-devnet

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@
2222
],
2323
"scripts": {
2424
"test": "npm run tests-unit",
25-
"tests-unit": "mocha $(find . -name '*.spec.ts' ! -name '*.local.net.spec.*' ! -name '*.devnet.spec.*' ! -name '*.testnet.spec.*')",
25+
"tests-unit": "mocha $(find . -name '*.spec.ts' ! -name '*.local.net.spec.*' ! -name '*.test.net.spec.*' ! -name '*.dev.net.spec.*' ! -name '*.main.net.spec.*')",
2626
"tests-localnet": "mocha $(find . -name '*.local.net.spec.ts')",
27-
"tests-devnet": "mocha $(find . -name '*.devnet.spec.ts')",
28-
"tests-testnet": "mocha $(find . -name '*.testnet.spec.ts')",
27+
"tests-testnet": "mocha $(find . -name '*.test.net.spec.ts')",
28+
"tests-devnet": "mocha $(find . -name '*.dev.net.spec.ts')",
29+
"tests-mainnet": "mocha $(find . -name '*.main.net.spec.ts')",
2930
"compile-browser": "tsc -p tsconfig.json && browserify out/index.js -o out-browser/sdk-core.js --standalone multiversxSdkCore -p esmify",
3031
"compile": "tsc -p tsconfig.json",
3132
"compile-proto": "npx pbjs -t static-module -w default -o src/proto/compiled.js src/proto/transaction.proto",

src/converters/transactionsConverter.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,14 @@ export class TransactionsConverter {
7979
return Buffer.from(value || "", "hex");
8080
}
8181

82+
/**
83+
* @deprecated Where {@link TransactionOutcome} was needed (throughout the SDK), pass the {@link ITransactionOnNetwork} object instead.
84+
*
85+
* Summarizes the outcome of a transaction on the network, and maps it to the "standard" resources (according to the sdk-specs).
86+
*
87+
* In the future, this converter function will become obsolete,
88+
* as the impedance mismatch between the network components and the "core" components will be reduced.
89+
*/
8290
public transactionOnNetworkToOutcome(transactionOnNetwork: ITransactionOnNetwork): TransactionOutcome {
8391
// In the future, this will not be needed because the transaction, as returned from the API,
8492
// will hold the data corresponding to the direct smart contract call outcome (in case of smart contract calls).

src/testutils/networkProviders.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { ApiNetworkProvider, ProxyNetworkProvider } from "../networkProviders";
21
import { IAddress } from "../interface";
32
import {
43
IAccountOnNetwork,
@@ -7,6 +6,7 @@ import {
76
ITransactionOnNetwork,
87
ITransactionStatus,
98
} from "../interfaceOfNetwork";
9+
import { ApiNetworkProvider, ProxyNetworkProvider } from "../networkProviders";
1010
import { Query } from "../smartcontracts/query";
1111
import { Transaction } from "../transaction";
1212

@@ -15,7 +15,24 @@ export function createLocalnetProvider(): INetworkProvider {
1515
}
1616

1717
export function createTestnetProvider(): INetworkProvider {
18-
return new ApiNetworkProvider("https://testnet-api.multiversx.com", { timeout: 5000 });
18+
return new ApiNetworkProvider("https://testnet-api.multiversx.com", {
19+
timeout: 5000,
20+
clientName: "mx-sdk-js-core/tests",
21+
});
22+
}
23+
24+
export function createDevnetProvider(): INetworkProvider {
25+
return new ProxyNetworkProvider("https://devnet-gateway.multiversx.com", {
26+
timeout: 5000,
27+
clientName: "mx-sdk-js-core/tests",
28+
});
29+
}
30+
31+
export function createMainnetProvider(): INetworkProvider {
32+
return new ProxyNetworkProvider("https://gateway.multiversx.com", {
33+
timeout: 10000,
34+
clientName: "mx-sdk-js-core/tests",
35+
});
1936
}
2037

2138
export interface INetworkProvider {

src/transactionsOutcomeParsers/delegationTransactionsOutcomeParser.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,35 @@
11
import { Address } from "../address";
2+
import { TransactionsConverter } from "../converters/transactionsConverter";
23
import { ErrParseTransactionOutcome } from "../errors";
4+
import { ITransactionOnNetwork } from "../interfaceOfNetwork";
35
import { TransactionEvent, TransactionOutcome, findEventsByIdentifier } from "./resources";
46

57
export class DelegationTransactionsOutcomeParser {
68
constructor() {}
79

8-
parseCreateNewDelegationContract(transactionOutcome: TransactionOutcome): { contractAddress: string }[] {
9-
this.ensureNoError(transactionOutcome.logs.events);
10+
parseCreateNewDelegationContract(
11+
transaction: TransactionOutcome | ITransactionOnNetwork,
12+
): { contractAddress: string }[] {
13+
transaction = this.ensureTransactionOutcome(transaction);
1014

11-
const events = findEventsByIdentifier(transactionOutcome, "SCDeploy");
15+
this.ensureNoError(transaction.logs.events);
16+
17+
const events = findEventsByIdentifier(transaction, "SCDeploy");
1218

1319
return events.map((event) => ({ contractAddress: this.extractContractAddress(event) }));
1420
}
1521

22+
/**
23+
* Temporary workaround, until "TransactionOnNetwork" completely replaces "TransactionOutcome".
24+
*/
25+
private ensureTransactionOutcome(transaction: TransactionOutcome | ITransactionOnNetwork): TransactionOutcome {
26+
if ("hash" in transaction) {
27+
return new TransactionsConverter().transactionOnNetworkToOutcome(transaction);
28+
}
29+
30+
return transaction;
31+
}
32+
1633
private ensureNoError(transactionEvents: TransactionEvent[]) {
1734
for (const event of transactionEvents) {
1835
if (event.identifier == "signalError") {

src/transactionsOutcomeParsers/smartContractTransactionsOutcomeParser.ts

Lines changed: 81 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
import { Address } from "../address";
22
import { Err } from "../errors";
3+
import { ITransactionOnNetwork } from "../interfaceOfNetwork";
34
import { EndpointDefinition, ResultsParser, ReturnCode, Type, UntypedOutcomeBundle } from "../smartcontracts";
4-
import { TransactionEvent, TransactionOutcome, findEventsByIdentifier } from "./resources";
5+
import { TransactionOutcome, findEventsByIdentifier } from "./resources";
6+
7+
enum Events {
8+
SCDeploy = "SCDeploy",
9+
SignalError = "signalError",
10+
WriteLog = "writeLog",
11+
}
512

613
interface IAbi {
714
getEndpoint(name: string): EndpointDefinition;
@@ -28,15 +35,31 @@ export class SmartContractTransactionsOutcomeParser {
2835

2936
constructor(options?: { abi?: IAbi; legacyResultsParser?: ILegacyResultsParser }) {
3037
this.abi = options?.abi;
31-
32-
// Prior v13, we've advertised that people can override the "ResultsParser" to alter it's behavior in case of exotic flows.
33-
// Now, since the new "SmartContractTransactionsOutcomeParser" (still) depends on the legacy "ResultsParser",
34-
// at least until "return data parts of direct outcome of contract call" are included on API & Proxy responses (on GET transaction),
35-
// we have to allow the same level of customization (for exotic flows).
3638
this.legacyResultsParser = options?.legacyResultsParser || new ResultsParser();
3739
}
3840

39-
parseDeploy(options: { transactionOutcome: TransactionOutcome }): {
41+
parseDeploy(
42+
options: { transactionOutcome: TransactionOutcome } | { transactionOnNetwork: ITransactionOnNetwork },
43+
): {
44+
returnCode: string;
45+
returnMessage: string;
46+
contracts: {
47+
address: string;
48+
ownerAddress: string;
49+
codeHash: Uint8Array;
50+
}[];
51+
} {
52+
if ("transactionOutcome" in options) {
53+
return this.parseDeployGivenTransactionOutcome(options.transactionOutcome);
54+
}
55+
56+
return this.parseDeployGivenTransactionOnNetwork(options.transactionOnNetwork);
57+
}
58+
59+
/**
60+
* Legacy approach.
61+
*/
62+
protected parseDeployGivenTransactionOutcome(transactionOutcome: TransactionOutcome): {
4063
returnCode: string;
4164
returnMessage: string;
4265
contracts: {
@@ -45,8 +68,8 @@ export class SmartContractTransactionsOutcomeParser {
4568
codeHash: Uint8Array;
4669
}[];
4770
} {
48-
const directCallOutcome = options.transactionOutcome.directSmartContractCallOutcome;
49-
const events = findEventsByIdentifier(options.transactionOutcome, "SCDeploy");
71+
const directCallOutcome = transactionOutcome.directSmartContractCallOutcome;
72+
const events = findEventsByIdentifier(transactionOutcome, Events.SCDeploy);
5073
const contracts = events.map((event) => this.parseScDeployEvent(event));
5174

5275
return {
@@ -56,7 +79,19 @@ export class SmartContractTransactionsOutcomeParser {
5679
};
5780
}
5881

59-
private parseScDeployEvent(event: TransactionEvent): {
82+
protected parseDeployGivenTransactionOnNetwork(_transactionOnNetwork: ITransactionOnNetwork): {
83+
returnCode: string;
84+
returnMessage: string;
85+
contracts: {
86+
address: string;
87+
ownerAddress: string;
88+
codeHash: Uint8Array;
89+
}[];
90+
} {
91+
throw new Error("Not implemented.");
92+
}
93+
94+
private parseScDeployEvent(event: { topics: Uint8Array[] }): {
6095
address: string;
6196
ownerAddress: string;
6297
codeHash: Uint8Array;
@@ -76,12 +111,34 @@ export class SmartContractTransactionsOutcomeParser {
76111
};
77112
}
78113

79-
parseExecute(options: { transactionOutcome: TransactionOutcome; function?: string }): {
114+
parseExecute(
115+
options:
116+
| { transactionOutcome: TransactionOutcome; function?: string }
117+
| { transactionOnNetwork: ITransactionOnNetwork; function?: string },
118+
): {
80119
values: any[];
81120
returnCode: string;
82121
returnMessage: string;
83122
} {
84-
const directCallOutcome = options.transactionOutcome.directSmartContractCallOutcome;
123+
if ("transactionOutcome" in options) {
124+
return this.parseExecuteGivenTransactionOutcome(options.transactionOutcome, options.function);
125+
}
126+
127+
return this.parseExecuteGivenTransactionOnNetwork(options.transactionOnNetwork, options.function);
128+
}
129+
130+
/**
131+
* Legacy approach.
132+
*/
133+
protected parseExecuteGivenTransactionOutcome(
134+
transactionOutcome: TransactionOutcome,
135+
functionName?: string,
136+
): {
137+
values: any[];
138+
returnCode: string;
139+
returnMessage: string;
140+
} {
141+
const directCallOutcome = transactionOutcome.directSmartContractCallOutcome;
85142

86143
if (!this.abi) {
87144
return {
@@ -91,7 +148,7 @@ export class SmartContractTransactionsOutcomeParser {
91148
};
92149
}
93150

94-
const functionName = options.function || directCallOutcome.function;
151+
functionName = functionName || directCallOutcome.function;
95152

96153
if (!functionName) {
97154
throw new Err(
@@ -115,4 +172,15 @@ export class SmartContractTransactionsOutcomeParser {
115172
returnMessage: legacyTypedBundle.returnMessage,
116173
};
117174
}
175+
176+
protected parseExecuteGivenTransactionOnNetwork(
177+
_transactionOnNetwork: ITransactionOnNetwork,
178+
_functionName?: string,
179+
): {
180+
values: any[];
181+
returnCode: string;
182+
returnMessage: string;
183+
} {
184+
throw new Error("Not implemented.");
185+
}
118186
}

0 commit comments

Comments
 (0)