|
1 | 1 | import { RpcError } from '@protobuf-ts/runtime-rpc' |
2 | 2 | import { |
3 | 3 | UnspecifiedErrorCode, |
| 4 | + TransactionException, |
4 | 5 | grpcErrorCodeToErrorCode, |
5 | 6 | GrpcUnaryRequestException, |
6 | 7 | } from '@injectivelabs/exceptions' |
@@ -81,19 +82,81 @@ export default class BaseGrpcConsumer { |
81 | 82 | } |
82 | 83 |
|
83 | 84 | /** |
84 | | - * Centralized error handler for gRPC calls |
85 | | - * Converts RpcError to GrpcUnaryRequestException with proper error codes |
| 85 | + * Extracts the ABCI error code from a gRPC error message. |
| 86 | + * Chain errors contain patterns like: {key:"ABCICode" value:"100"} |
| 87 | + */ |
| 88 | + private getABCICodeFromMessage(message: string): number | undefined { |
| 89 | + const ABCICodePattern = /{key:"ABCICode"[ \t]+value:"(.*?)"}/g |
| 90 | + const ABCICode = ABCICodePattern.exec(message) |
| 91 | + |
| 92 | + if (!ABCICode || ABCICode.length < 2) { |
| 93 | + return undefined |
| 94 | + } |
| 95 | + |
| 96 | + return Number(ABCICode[1]) |
| 97 | + } |
| 98 | + |
| 99 | + /** |
| 100 | + * Extracts the codespace/module from a gRPC error message. |
| 101 | + * Chain errors contain patterns like: {key:"Codespace" value:"exchange"} |
| 102 | + */ |
| 103 | + private getCodespaceFromMessage(message: string): string | undefined { |
| 104 | + const codespacePattern = /{key:"Codespace"[ \t]+value:"(.*?)"}/g |
| 105 | + const codespace = codespacePattern.exec(message) |
| 106 | + |
| 107 | + if (!codespace || codespace.length < 2) { |
| 108 | + return undefined |
| 109 | + } |
| 110 | + |
| 111 | + return codespace[1] |
| 112 | + } |
| 113 | + |
| 114 | + /** |
| 115 | + * Centralized error handler for gRPC calls. |
| 116 | + * When the error contains chain error details (ABCI code and codespace), |
| 117 | + * throws a TransactionException which will map the error to a user-friendly message. |
| 118 | + * Otherwise throws a GrpcUnaryRequestException for generic gRPC errors. |
86 | 119 | */ |
87 | 120 | protected handleGrpcError(e: unknown, context: string): never { |
88 | 121 | if (e instanceof RpcError) { |
89 | | - throw new GrpcUnaryRequestException(new Error(e.message), { |
| 122 | + const message = e.message |
| 123 | + const abciCode = this.getABCICodeFromMessage(message) |
| 124 | + const codespace = this.getCodespaceFromMessage(message) |
| 125 | + |
| 126 | + // If we have chain error details, throw TransactionException |
| 127 | + // which will map the error to a user-friendly message |
| 128 | + if (abciCode && codespace) { |
| 129 | + throw new TransactionException(new Error(message), { |
| 130 | + code: grpcErrorCodeToErrorCode(Number(e.code)), |
| 131 | + context, |
| 132 | + contextModule: codespace, |
| 133 | + contextCode: abciCode, |
| 134 | + }) |
| 135 | + } |
| 136 | + |
| 137 | + throw new GrpcUnaryRequestException(new Error(message), { |
90 | 138 | code: grpcErrorCodeToErrorCode(Number(e.code)), |
91 | 139 | context, |
92 | 140 | contextModule: this.module, |
93 | 141 | }) |
94 | 142 | } |
95 | 143 |
|
96 | | - throw new GrpcUnaryRequestException(e as Error, { |
| 144 | + const error = e as Error |
| 145 | + const message = error?.message || '' |
| 146 | + const abciCode = this.getABCICodeFromMessage(message) |
| 147 | + const codespace = this.getCodespaceFromMessage(message) |
| 148 | + |
| 149 | + // If we have chain error details, throw TransactionException |
| 150 | + if (abciCode && codespace) { |
| 151 | + throw new TransactionException(error, { |
| 152 | + code: UnspecifiedErrorCode, |
| 153 | + context, |
| 154 | + contextModule: codespace, |
| 155 | + contextCode: abciCode, |
| 156 | + }) |
| 157 | + } |
| 158 | + |
| 159 | + throw new GrpcUnaryRequestException(error, { |
97 | 160 | code: UnspecifiedErrorCode, |
98 | 161 | context, |
99 | 162 | contextModule: this.module, |
|
0 commit comments