UNPKG

o1js

Version:

TypeScript framework for zk-SNARKs and zkApps

106 lines (94 loc) 3.46 kB
import { Types } from '../../bindings/mina-transaction/types.js'; import { TokenId } from './account-update.js'; import { Int64 } from '../provable/int.js'; export { invalidTransactionError }; const ErrorHandlers = { Invalid_fee_excess({ transaction: { accountUpdates }, isFeePayer, accountCreationFee, }: ErrorHandlerArgs) { // 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(Int64.fromObject(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.`; }, }; type ErrorHandlerArgs = { transaction: Types.ZkappCommand; accountUpdateIndex: number; isFeePayer: boolean; accountCreationFee: string | number; }; function invalidTransactionError( transaction: Types.ZkappCommand, errors: string[][][], additionalContext: { accountCreationFee: string | number } ): string { 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 as keyof typeof ErrorHandlers]?.({ 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 as keyof typeof ErrorHandlers]?.({ 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; }