elrond-sdk-erdjs
elrond-sdk-erdjs copied to clipboard
Adjust / improve ResultsParser to properly handle outcome of relayed transactions
Issue raised by @MWFIAE - parsing the outcome of a relayed transaction would result into errors such as:
ErrCannotParseContractResults [Error]: cannot parse contract results
The following contribution of @MWFIAE can serve as a starting point for adjusting the ResultsParser
of sdk-core
:
/**
* Custom ResultsParser that is needed until elrond correctly implements relayedTransactions.
*
* @export
* @class KocResultParser
* @extends {ResultsParser}
*/
export class KocResultParser extends ResultsParser {
/**
* Create a bundle with data from relayed transactions.
*
* @protected
* @param {ITransactionOnNetwork} transaction Transaction to parse
* @param {TransactionMetadata} transactionMetadata Metadata of the transaction
* @return {(UntypedOutcomeBundle | null)}
* @memberof KocResultParser
*/
protected createBundleWithCustomHeuristics(
transaction: ITransactionOnNetwork,
transactionMetadata: TransactionMetadata
): UntypedOutcomeBundle | null {
const address = transactionMetadata.sender;
const hexAddress = new Address(address).hex();
let eventWriteLogWhereTopicIsSender = transaction.logs.findSingleOrNoneEvent("writeLog", event => {
debugger;
return event.findFirstOrNoneTopic(topic => topic.hex() == hexAddress) != undefined;
});
if (!eventWriteLogWhereTopicIsSender) {
for (const result of transaction.contractResults.items) {
eventWriteLogWhereTopicIsSender = result.logs.findSingleOrNoneEvent(
"writeLog",
event => event.findFirstOrNoneTopic(topic => topic.hex() == hexAddress) != undefined
);
if (!!eventWriteLogWhereTopicIsSender) break;
}
}
if (!eventWriteLogWhereTopicIsSender) {
return null;
}
const { returnCode, returnDataParts } = this.sliceDataFieldInPartsCustom(eventWriteLogWhereTopicIsSender.data);
const returnMessage = returnCode.toString();
return {
returnCode: returnCode,
returnMessage: returnMessage,
values: returnDataParts,
};
}
/**
* Copy of the sliceDataFieldInParts method. Needed until elrond fixes the access modifier.
*
* @private
* @param {string} data The data to split
* @return {{ returnCode: ReturnCode; returnDataParts: Buffer[] }}
* @memberof KocResultParser
*/
private sliceDataFieldInPartsCustom(data: string): { returnCode: ReturnCode; returnDataParts: Buffer[] } {
// By default, skip the first part, which is usually empty (e.g. "[empty]@6f6b")
let startingIndex = 1;
// Before trying to parse the hex strings, cut the unwanted parts of the data field, in case of token transfers:
if (data.startsWith("ESDTTransfer")) {
// Skip "ESDTTransfer" (1), token identifier (2), amount (3)
startingIndex = 3;
} else {
// TODO: Upon gathering more transaction samples, fix for other kinds of transfers, as well (future PR, as needed).
}
const parts = new ArgSerializer().stringToBuffers(data);
const returnCodePart = parts[startingIndex] || Buffer.from([]);
const returnDataParts = parts.slice(startingIndex + 1);
if (returnCodePart.length == 0) {
throw new ErrCannotParseContractResults("no return code");
}
const returnCode = ReturnCode.fromBuffer(returnCodePart);
return { returnCode, returnDataParts };
}
}
~~Normally, the "completion detection" issues should be resolved once sdk-core's TransactionWatcher
is updated to be compatible with sdk-network-provider's transaction status adjustment: https://github.com/multiversx/mx-sdk-js-network-providers/pull/41.~~
We will apply that as a non-breaking change (v12).
~~Related to: https://github.com/multiversx/mx-chain-proxy-go/pull/386.~~
Later edit: removed unrelated notes (it was a confusion on my side).