o1js
Version:
TypeScript framework for zk-SNARKs and zkApps
92 lines (89 loc) • 3.89 kB
JavaScript
import { TokenId } from './account-update.js';
export { humanizeErrors, invalidTransactionError };
const ErrorHandlers = {
Invalid_fee_excess({ transaction: { accountUpdates }, isFeePayer, accountCreationFee, }) {
// TODO: handle fee payer for Invalid_fee_excess?
if (isFeePayer)
return;
let balances = accountUpdates.map(({ body }) => {
if (body.tokenId.equals(TokenId.default).toBoolean()) {
return Number(body.balanceChange.toString()) * 1e-9;
}
});
let sum = balances.reduce((a = 0, b = 0) => a + b) ?? 0;
return `Invalid fee excess.
This means that balance changes in your transaction do not sum up to the amount of fees needed.
Here's the list of balance changes:
${balances
.map((balance, i) => {
return `Account update #${i + 1}) ${balance === undefined ? 'not a MINA account' : `${balance.toFixed(2)} MINA`}`;
})
.join(`\n`)}
Total change: ${sum.toFixed(2)} MINA
If there are no new accounts created in your transaction, then this sum should be equal to 0.00 MINA.
If you are creating new accounts -- by updating accounts that didn't exist yet --
then keep in mind the ${(Number(accountCreationFee) * 1e-9).toFixed(2)} MINA account creation fee, and make sure that the sum equals
${(-Number(accountCreationFee) * 1e-9).toFixed(2)} times the number of newly created accounts.`;
},
};
const defaultErrorReplacementRules = [
{
pattern: /\(invalid \(Invalid_proof \\"In progress\\"\)\)/g,
replacement: 'Stale verification key detected. Please make sure that deployed verification key reflects latest zkApp changes.',
},
];
function invalidTransactionError(transaction, errors, additionalContext) {
let errorMessages = [];
let rawErrors = JSON.stringify(errors);
let n = transaction.accountUpdates.length;
// Check if the number of errors match the number of account updates. If there are more, then the fee payer has an error.
// We do this check because the fee payer error is not included in network transaction errors and is always present (even if empty) in the local transaction errors.
if (errors.length > n) {
let errorsForFeePayer = errors.shift() ?? [];
for (let [error] of errorsForFeePayer) {
let message = ErrorHandlers[error]?.({
transaction,
accountUpdateIndex: NaN,
isFeePayer: true,
...additionalContext,
});
if (message)
errorMessages.push(message);
}
}
for (let i = 0; i < errors.length; i++) {
let errorsForUpdate = errors[i];
for (let [error] of errorsForUpdate) {
let message = ErrorHandlers[error]?.({
transaction,
accountUpdateIndex: i,
isFeePayer: false,
...additionalContext,
});
if (message)
errorMessages.push(message);
}
}
if (errorMessages.length > 1) {
return [
'There were multiple errors when applying your transaction:',
...errorMessages.map((msg, i) => `${i + 1}.) ${msg}`),
`Raw list of errors: ${rawErrors}`,
].join('\n\n');
}
if (errorMessages.length === 1) {
return `${errorMessages[0]}\n\nRaw list of errors: ${rawErrors}`;
}
// fallback if we don't have a good error message yet
return rawErrors;
}
function humanizeErrors(errors, replacements = defaultErrorReplacementRules) {
return errors.map((error) => {
let modifiedError = error;
replacements.forEach(({ pattern, replacement }) => {
modifiedError = modifiedError.replace(pattern, replacement);
});
return modifiedError;
});
}
//# sourceMappingURL=errors.js.map