vechain-sdk-js
vechain-sdk-js copied to clipboard
💡 [REQUEST] - Improve Developer Experience with decoded Error Messages
Summary
Calling contract functions or simulating transactions currently throw an error with the raw encoded error message. As developer I need to learn how to decode the messages and manually decode these.
A great help would be the SDK automatically trying to decode error messages and provide a human readable version of it. If not possible, its likely a non-standard-error and can remain as now.
I suggest to:
- automatically decode error messages by using
Error(string)
andparseError()
- within a contracts instance, use
parseError()
based on the current interface definition, to support custom errors
Basic Example
The following example is a contract call that throws an error for insufficient balance
:
import { ThorClient } from '@vechain/sdk-network';
import { ErrorDecoder } from 'ethers-decode-error';
import energyAbi from './energy.json' assert { type: 'json' };
const thor = ThorClient.fromUrl('https://mainnet.vechain.org');
const vtho = thor.contracts.load(
'0x0000000000000000000000000000456e65726779',
energyAbi
);
// failing simulation of transfer
try {
vtho.setContractReadOptions({
caller: '0x0000000000000000000000000000000000000003',
});
const failingTransfer = await vtho.read.transfer(
'0x0000000000000000000000000000456e65726779',
'1'
);
console.log('Failed Transfer Test', failingTransfer);
} catch (err) {
const errorDecoder = ErrorDecoder.create();
const decodedError = await errorDecoder.decode(err);
console.log(`Revert reason: ${decodedError.reason}`);
}
-- or --
try {
const failingTransfer = await thor.contracts.executeContractCall(
'0x0000000000000000000000000000456e65726779',
'transfer(address _to, uint256 _amount) returns(bool success)',
['0x0000000000000000000000000000456e65726779', '1'],
{
caller: '0x0000000000000000000000000000000000000003',
}
);
console.log('Failed Transfer Test', failingTransfer);
} catch (err) {
const errorDecoder = ErrorDecoder.create();
const decodedError = await errorDecoder.decode(err);
console.log(`Revert reason: ${decodedError.reason}`);
}
Instead of using another library to decode the message, I suggest that the error object already contains the decoded revertReason
.
The next example is a simulation that throws an error for Already closed
:
import { ThorClient } from '@vechain/sdk-network';
import { coder } from '@vechain/sdk-core';
const thor = ThorClient.fromUrl('https://mainnet.vechain.org');
const txId =
'0x27b515344514d5feeeaf582a93edf3139604f58f5a66785350e400e21584c7bb';
// define your interface, especially with the errors
const contractInterface = coder.createInterface([]);
const transaction = await thor.transactions.getTransaction(txId);
const simulation = await thor.transactions.simulateTransaction(
transaction.clauses,
{
revision: transaction.meta.blockID,
gas: transaction.gas,
caller: transaction.origin,
gasPayer: transaction.delegator ?? transaction.origin,
expiration: transaction.expiration,
blockRef: transaction.blockRef,
}
);
simulation.forEach((clause, clauseIndex) => {
if (!clause.reverted) {
return console.log(`Clause #${clauseIndex} was successful`);
}
const revertReason = contractInterface.parseError(clause.data);
console.log(`Clause #${clauseIndex} reverted with`);
console.log(' VM Error:', clause.vmError);
console.log(' Revert Reason:', revertReason.args);
});
Instead of using importing a coder
, creating a contract interface and use parseError()
to decode the message, I suggest that the clause also already contains the decoded revertReason
.
If custom errors are defined within the interface, using respecting those as well.