diff --git a/src/index.ts b/src/index.ts index 769a450..39a2150 100644 --- a/src/index.ts +++ b/src/index.ts @@ -236,6 +236,9 @@ const renderCurrentMultisigInfo = (): void => { const formatOrder = (lastOrder: LastOrder): string => { if (lastOrder.errorMessage) { if (lastOrder.errorMessage.startsWith('Contract not active')) return ``; + if (lastOrder.errorMessage.startsWith('Failed')) { + return `
Failed Order #${lastOrder.order.id} — Execution error
`; + } return `
Invalid Order #${lastOrder.order.id} — ${lastOrder.errorMessage}
`; } else { const isExpired = lastOrder.orderInfo ? (new Date()).getTime() > lastOrder.orderInfo.expiresAt.getTime() : false; diff --git a/src/multisig/MultisigChecker.ts b/src/multisig/MultisigChecker.ts index c0e14c8..53b10ab 100644 --- a/src/multisig/MultisigChecker.ts +++ b/src/multisig/MultisigChecker.ts @@ -8,7 +8,7 @@ import { } from "../utils/utils"; import {Address, Cell, Dictionary} from "@ton/core"; import {endParse, Multisig, parseMultisigData} from "./Multisig"; -import {MyNetworkProvider, sendToIndex} from "../utils/MyNetworkProvider"; +import {MyNetworkProvider, sendToIndex, sendToTonApi} from "../utils/MyNetworkProvider"; import {Op} from "./Constants"; import {Order} from "./Order"; import {checkMultisigOrder, MultisigOrderInfo} from "./MultisigOrderChecker"; @@ -78,6 +78,7 @@ const parseNewOrderOutMsg = (outMsg: any) => { export interface LastOrder { utime: number, + transactionHash: string; type: 'new' | 'execute' | 'pending' | 'executed'; errorMessage?: string; order?: { @@ -224,6 +225,7 @@ export const checkMultisig = async ( lastOrders.push({ utime: tx.now, + transactionHash: tx.hash, type: 'execute', order: { address: { @@ -238,6 +240,7 @@ export const checkMultisig = async ( } catch (e: any) { lastOrders.push({ utime: tx.now, + transactionHash: tx.hash, type: 'execute', errorMessage: e.message }) @@ -280,6 +283,7 @@ export const checkMultisig = async ( lastOrders.push({ utime: tx.now, + transactionHash: tx.hash, type: 'new', order: { address: { @@ -295,6 +299,7 @@ export const checkMultisig = async ( console.log(e); lastOrders.push({ utime: tx.now, + transactionHash: tx.hash, type: 'new', errorMessage: 'Invalid new order: ' + e.message }) @@ -312,6 +317,7 @@ export const checkMultisig = async ( if (!lastOrdersMap[orderId]) { lastOrdersMap[orderId] = { utime: lastOrder.utime, + transactionHash: lastOrder.transactionHash, type: lastOrder.type === 'new' ? 'pending' : 'executed', order: lastOrder.order } @@ -325,6 +331,33 @@ export const checkMultisig = async ( lastOrders = Object.values(lastOrdersMap); + + const findFailTx = (tonApiResult: any): boolean => { + if (tonApiResult.transaction) { + if (tonApiResult.transaction.success === false) { + if (tonApiResult.transaction.in_msg.decoded_op_name !== "excess") { + return true; + } + } + } + if (tonApiResult.children) { + for (let child of tonApiResult.children) { + if (findFailTx(child)) return true; + } + } + return false; + } + + for (const lastOrder of lastOrders) { + if (lastOrder.type === 'executed') { + const transactionHashHex = Buffer.from(lastOrder.transactionHash, 'base64').toString('hex'); + const result = await sendToTonApi('traces/' + transactionHashHex, {}, isTestnet); + if (findFailTx(result)) { + lastOrder.errorMessage = 'Failed'; + } + } + } + for (const lastOrder of lastOrders) { if (lastOrder.type === 'pending') { try { diff --git a/src/utils/MyNetworkProvider.ts b/src/utils/MyNetworkProvider.ts index 7f61a3b..1e4b708 100644 --- a/src/utils/MyNetworkProvider.ts +++ b/src/utils/MyNetworkProvider.ts @@ -36,6 +36,27 @@ export const sendToIndex = async (method: string, params: any, isTestnet: boolea return json; } +export const sendToTonApi = async (method: string, params: any, isTestnet: boolean) => { + const mainnetRpc = 'https://dev.tonapi.io/v2/'; + const testnetRpc = 'https://testnet.tonapi.io/v2/'; + const rpc = isTestnet ? testnetRpc : mainnetRpc; + + const headers = { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer AHIQH4F4Y4XR6UIAAAAOGYUHWOWLUS6ZIPEXSCLAPOMMD6FSNMPUKHCIJHIP52YTU4VKURA' + }; + + const response = await fetch(rpc + method + '?' + new URLSearchParams(params), { + method: 'GET', + headers: headers, + }); + const json = await response.json(); + if (json.error) { + throw new Error(json.error); + } + return json; +} + export class MyNetworkProvider implements ContractProvider { private contractAddress: Address; private isTestnet: boolean;