@raac/rpc 1.1.0-beta.53 → 1.1.0-beta.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/RPCLibrary.js +9 -0
- package/dist/pools/lendingPool/depositToLendingPool.js +3 -1
- package/dist/scripts/generateErrorMap.js +180 -0
- package/dist/scripts/index.js +5 -1
- package/dist/types/RPCLibrary.d.ts +8 -0
- package/dist/types/scripts/generateErrorMap.d.ts +1 -0
- package/dist/types/utils/errorDecoder.d.ts +37 -0
- package/dist/utils/errorDecoder.js +137 -0
- package/package.json +4 -3
package/dist/RPCLibrary.js
CHANGED
|
@@ -120,6 +120,7 @@ const vaultOpened_1 = __importDefault(require("./pools/lendingPool/vaultOpened")
|
|
|
120
120
|
const getWithdrawRequestInfo_2 = require("./pools/stabilityPool/getWithdrawRequestInfo");
|
|
121
121
|
const requestWithdraw_2 = require("./pools/stabilityPool/requestWithdraw");
|
|
122
122
|
const artifacts_1 = require("./utils/artifacts");
|
|
123
|
+
const errorDecoder_1 = require("./utils/errorDecoder");
|
|
123
124
|
class RPCLibrary {
|
|
124
125
|
signer;
|
|
125
126
|
isConnected;
|
|
@@ -139,6 +140,7 @@ class RPCLibrary {
|
|
|
139
140
|
checkAllowance;
|
|
140
141
|
getChainsConfig;
|
|
141
142
|
setChainsConfig;
|
|
143
|
+
errors;
|
|
142
144
|
constructor(privateKey) {
|
|
143
145
|
this.signer = null;
|
|
144
146
|
this.isConnected = false;
|
|
@@ -282,6 +284,13 @@ class RPCLibrary {
|
|
|
282
284
|
createZeno: createZeno_1.default,
|
|
283
285
|
getZenos: getZenos_1.default,
|
|
284
286
|
};
|
|
287
|
+
this.errors = {
|
|
288
|
+
decodeErrorName: errorDecoder_1.decodeErrorName,
|
|
289
|
+
getErrorInfo: errorDecoder_1.getErrorInfo,
|
|
290
|
+
attachDecodedError: errorDecoder_1.attachDecodedError,
|
|
291
|
+
decodeErrorMessage: errorDecoder_1.decodeErrorMessage,
|
|
292
|
+
attachDecodedErrorMessage: errorDecoder_1.attachDecodedErrorMessage,
|
|
293
|
+
};
|
|
285
294
|
}
|
|
286
295
|
async getWallet(privateKey, provider) {
|
|
287
296
|
// @ts-ignore
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const ethers_1 = require("ethers");
|
|
4
4
|
const _helpers_1 = require("./_helpers");
|
|
5
|
+
const errorDecoder_1 = require("../../utils/errorDecoder");
|
|
5
6
|
// checked
|
|
6
7
|
async function depositToLendingPool(chainId, amount, signer) {
|
|
7
8
|
if (!signer) {
|
|
@@ -22,7 +23,8 @@ async function depositToLendingPool(chainId, amount, signer) {
|
|
|
22
23
|
}
|
|
23
24
|
catch (error) {
|
|
24
25
|
console.error(`Lending Pool Deposit error:`, error);
|
|
25
|
-
|
|
26
|
+
const message = (0, errorDecoder_1.attachDecodedError)("Lending Pool Deposit failed", error);
|
|
27
|
+
throw new Error(`${message}: ${error.message}`);
|
|
26
28
|
}
|
|
27
29
|
}
|
|
28
30
|
exports.default = depositToLendingPool;
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const fs_1 = __importDefault(require("fs"));
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const ethers_1 = require("ethers");
|
|
9
|
+
// Custom error messages based on error names
|
|
10
|
+
const ERROR_MESSAGES = {
|
|
11
|
+
// Access Control
|
|
12
|
+
'AccessControlBadConfirmation': 'Invalid access control confirmation',
|
|
13
|
+
'AccessControlUnauthorizedAccount': 'Account does not have required permissions',
|
|
14
|
+
'AccessDenied': 'Access denied - insufficient permissions',
|
|
15
|
+
// Adapter Errors
|
|
16
|
+
'AdapterAlreadySupported': 'This adapter is already supported',
|
|
17
|
+
'AdapterNotSupported': 'This adapter is not supported',
|
|
18
|
+
// Address Errors
|
|
19
|
+
'AddressCannotBeZero': 'Address cannot be zero',
|
|
20
|
+
'AddressEmptyCode': 'Target address has no code',
|
|
21
|
+
'AddressInsufficientBalance': 'Insufficient balance for operation',
|
|
22
|
+
// Amount Errors
|
|
23
|
+
'AmountDifferentThanRequested': 'Amount differs from requested amount',
|
|
24
|
+
'ApprovalFailed': 'Token approval failed',
|
|
25
|
+
// Compliance
|
|
26
|
+
'BlacklistedAddress': 'Address is blacklisted',
|
|
27
|
+
// Pool Errors
|
|
28
|
+
'BorrowCapReached': 'Borrow cap has been reached',
|
|
29
|
+
'BorrowThresholdTooHigh': 'Borrow threshold is too high',
|
|
30
|
+
'CannotBorrowUnderLiquidation': 'Cannot borrow while under liquidation',
|
|
31
|
+
'CannotDepositWhenUnderLiquidation': 'Cannot deposit while under liquidation',
|
|
32
|
+
'CannotRepayUnderLiquidationWithoutInsurance': 'Cannot repay under liquidation without insurance',
|
|
33
|
+
'CannotWithdrawInSameBlock': 'Cannot withdraw in the same block',
|
|
34
|
+
'CannotWithdrawUnderLiquidation': 'Cannot withdraw while under liquidation',
|
|
35
|
+
'CapExceedSupply': 'Cap exceeds available supply',
|
|
36
|
+
'CapZero': 'Cap cannot be zero',
|
|
37
|
+
'DebtNotZero': 'Debt must be zero for this operation',
|
|
38
|
+
'SupplyCapReached': 'Supply cap has been reached',
|
|
39
|
+
// Pause Errors
|
|
40
|
+
'EnforcedPause': 'Contract is paused',
|
|
41
|
+
'ExpectedPause': 'Contract should be paused',
|
|
42
|
+
// General Errors
|
|
43
|
+
'FailedInnerCall': 'Internal call failed',
|
|
44
|
+
'GracePeriodExpired': 'Grace period has expired',
|
|
45
|
+
'InsufficientAllowance': 'Insufficient allowance for operation',
|
|
46
|
+
'InsufficientBalance': 'Insufficient balance for operation',
|
|
47
|
+
'InvalidAmount': 'Invalid amount provided',
|
|
48
|
+
'InvalidCollateralRatio': 'Invalid collateral ratio',
|
|
49
|
+
'InvalidHealthFactor': 'Invalid health factor',
|
|
50
|
+
'InvalidLiquidationThreshold': 'Invalid liquidation threshold',
|
|
51
|
+
'InvalidParameter': 'Invalid parameter provided',
|
|
52
|
+
'InvalidPrice': 'Invalid price provided',
|
|
53
|
+
'InvalidToken': 'Invalid token address',
|
|
54
|
+
'LiquidationNotAllowed': 'Liquidation is not allowed',
|
|
55
|
+
'NoLiquidationAvailable': 'No liquidation available',
|
|
56
|
+
'NotEnoughLiquidity': 'Not enough liquidity available',
|
|
57
|
+
'OperationNotAllowed': 'Operation is not allowed',
|
|
58
|
+
'Overflow': 'Arithmetic overflow occurred',
|
|
59
|
+
'Paused': 'Contract is paused',
|
|
60
|
+
'ReentrancyGuardReentrantCall': 'Reentrant call detected',
|
|
61
|
+
'ReserveAlreadyInitialized': 'Reserve is already initialized',
|
|
62
|
+
'ReserveNotActive': 'Reserve is not active',
|
|
63
|
+
'ReserveNotInitialized': 'Reserve is not initialized',
|
|
64
|
+
'SafeERC20FailedOperation': 'SafeERC20 operation failed',
|
|
65
|
+
'TransferFailed': 'Token transfer failed',
|
|
66
|
+
'Unauthorized': 'Unauthorized operation',
|
|
67
|
+
'Underflow': 'Arithmetic underflow occurred',
|
|
68
|
+
'VaultNotOpen': 'Vault is not open',
|
|
69
|
+
'WithdrawalNotAllowed': 'Withdrawal is not allowed',
|
|
70
|
+
// Custom contract-specific errors
|
|
71
|
+
'InvalidOraclePrice': 'Invalid oracle price received',
|
|
72
|
+
'PriceStale': 'Oracle price is stale',
|
|
73
|
+
'InvalidRandomSeed': 'Invalid random seed provided',
|
|
74
|
+
'RandomSeedNotReady': 'Random seed is not ready',
|
|
75
|
+
'NFTNotAvailable': 'NFT is not available',
|
|
76
|
+
'InvalidNFTId': 'Invalid NFT ID provided',
|
|
77
|
+
'NFTAlreadyDeposited': 'NFT is already deposited',
|
|
78
|
+
'NFTNotDeposited': 'NFT is not deposited',
|
|
79
|
+
'InvalidVaultPosition': 'Invalid vault position',
|
|
80
|
+
'PositionNotOpen': 'Position is not open',
|
|
81
|
+
'InvalidCollateral': 'Invalid collateral provided',
|
|
82
|
+
'CollateralNotSupported': 'Collateral is not supported',
|
|
83
|
+
'InvalidDebtToken': 'Invalid debt token',
|
|
84
|
+
'DebtTokenNotSupported': 'Debt token is not supported',
|
|
85
|
+
'InvalidLiquidationProxy': 'Invalid liquidation proxy',
|
|
86
|
+
'InvalidVaultProxy': 'Invalid vault proxy',
|
|
87
|
+
'InvalidComplianceRegistry': 'Invalid compliance registry',
|
|
88
|
+
'InvalidPrimeRate': 'Invalid prime rate',
|
|
89
|
+
'InvalidAdmin': 'Invalid admin address',
|
|
90
|
+
'InvalidReserveAsset': 'Invalid reserve asset',
|
|
91
|
+
'InvalidRToken': 'Invalid R token',
|
|
92
|
+
'InvalidDebtTokenAddress': 'Invalid debt token address',
|
|
93
|
+
'InvalidLiquidationProxyAddress': 'Invalid liquidation proxy address',
|
|
94
|
+
'InvalidVaultProxyAddress': 'Invalid vault proxy address',
|
|
95
|
+
'InvalidComplianceRegistryAddress': 'Invalid compliance registry address',
|
|
96
|
+
'InvalidInitialPrimeRate': 'Invalid initial prime rate',
|
|
97
|
+
'InvalidAdminAddress': 'Invalid admin address',
|
|
98
|
+
};
|
|
99
|
+
function walkDir(dir) {
|
|
100
|
+
const files = [];
|
|
101
|
+
const items = fs_1.default.readdirSync(dir, { withFileTypes: true });
|
|
102
|
+
for (const item of items) {
|
|
103
|
+
const fullPath = path_1.default.join(dir, item.name);
|
|
104
|
+
if (item.isDirectory()) {
|
|
105
|
+
files.push(...walkDir(fullPath));
|
|
106
|
+
}
|
|
107
|
+
else if (item.name.endsWith('.json')) {
|
|
108
|
+
files.push(fullPath);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return files;
|
|
112
|
+
}
|
|
113
|
+
function generateErrorMap() {
|
|
114
|
+
const errorMap = {};
|
|
115
|
+
const artifactsDir = path_1.default.join(process.cwd(), 'artifacts');
|
|
116
|
+
if (!fs_1.default.existsSync(artifactsDir)) {
|
|
117
|
+
console.error('Artifacts directory not found');
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
const jsonFiles = walkDir(artifactsDir);
|
|
121
|
+
for (const filePath of jsonFiles) {
|
|
122
|
+
try {
|
|
123
|
+
const content = fs_1.default.readFileSync(filePath, 'utf8');
|
|
124
|
+
const json = JSON.parse(content);
|
|
125
|
+
if (!json.abi || !Array.isArray(json.abi))
|
|
126
|
+
continue;
|
|
127
|
+
const contractName = json.contractName || path_1.default.basename(filePath, '.json');
|
|
128
|
+
for (const item of json.abi) {
|
|
129
|
+
if (item.type !== 'error')
|
|
130
|
+
continue;
|
|
131
|
+
const inputs = item.inputs || [];
|
|
132
|
+
const signature = `${item.name}(${inputs.map((input) => input.type).join(',')})`;
|
|
133
|
+
const selector = (0, ethers_1.id)(signature).slice(0, 10).toLowerCase();
|
|
134
|
+
// Skip if already processed (first occurrence wins)
|
|
135
|
+
if (errorMap[selector])
|
|
136
|
+
continue;
|
|
137
|
+
const customMessage = ERROR_MESSAGES[item.name] ||
|
|
138
|
+
`${item.name.replace(/([A-Z])/g, ' $1').trim()} error occurred`;
|
|
139
|
+
errorMap[selector] = {
|
|
140
|
+
name: item.name,
|
|
141
|
+
signature,
|
|
142
|
+
message: customMessage,
|
|
143
|
+
contract: contractName,
|
|
144
|
+
inputs: inputs.map((input) => ({
|
|
145
|
+
name: input.name || '',
|
|
146
|
+
type: input.type,
|
|
147
|
+
internalType: input.internalType || input.type,
|
|
148
|
+
})),
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
console.warn(`Failed to process ${filePath}:`, error);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return errorMap;
|
|
157
|
+
}
|
|
158
|
+
function main() {
|
|
159
|
+
console.log('🔍 Scanning ABIs for error definitions...');
|
|
160
|
+
const errorMap = generateErrorMap();
|
|
161
|
+
const outputPath = path_1.default.join(process.cwd(), 'generated', 'errorMap.json');
|
|
162
|
+
// Ensure generated directory exists
|
|
163
|
+
const generatedDir = path_1.default.dirname(outputPath);
|
|
164
|
+
if (!fs_1.default.existsSync(generatedDir)) {
|
|
165
|
+
fs_1.default.mkdirSync(generatedDir, { recursive: true });
|
|
166
|
+
}
|
|
167
|
+
// Write the error map
|
|
168
|
+
fs_1.default.writeFileSync(outputPath, JSON.stringify(errorMap, null, 2));
|
|
169
|
+
console.log(`✅ Generated error map with ${Object.keys(errorMap).length} errors`);
|
|
170
|
+
console.log(`📁 Output: ${outputPath}`);
|
|
171
|
+
// Show some examples
|
|
172
|
+
const examples = Object.entries(errorMap).slice(0, 5);
|
|
173
|
+
console.log('\n📋 Examples:');
|
|
174
|
+
for (const [selector, info] of examples) {
|
|
175
|
+
console.log(` ${selector} → ${info.name}: ${info.message}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (require.main === module) {
|
|
179
|
+
main();
|
|
180
|
+
}
|
package/dist/scripts/index.js
CHANGED
|
@@ -33,9 +33,13 @@ async function createWallet(mnemonic, provider) {
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
async function setup() {
|
|
36
|
+
const rpc = new RPCLibrary_1.default();
|
|
37
|
+
const error = rpc.errors.getErrorInfo("0xa9b65aba");
|
|
38
|
+
console.log(error);
|
|
39
|
+
return;
|
|
36
40
|
const provider = await getProvider();
|
|
37
41
|
const signer = await createWallet(TEST_MNEMONIC, provider);
|
|
38
|
-
const rpc = new
|
|
42
|
+
// const rpc = new RPCLibrary();
|
|
39
43
|
rpc.address = signer.address;
|
|
40
44
|
rpc.provider = provider;
|
|
41
45
|
rpc.chainId = chainId;
|
|
@@ -95,6 +95,7 @@ import vaultOpened from "./pools/lendingPool/vaultOpened";
|
|
|
95
95
|
import { getWithdrawRequestInfo as getStabilityPoolWithdrawRequestInfo } from "./pools/stabilityPool/getWithdrawRequestInfo";
|
|
96
96
|
import { requestWithdraw as requestStabilityPoolWithdraw } from "./pools/stabilityPool/requestWithdraw";
|
|
97
97
|
import { getABI } from "./utils/artifacts";
|
|
98
|
+
import { decodeErrorName, getErrorInfo, attachDecodedError, decodeErrorMessage, attachDecodedErrorMessage } from "./utils/errorDecoder";
|
|
98
99
|
declare class RPCLibrary {
|
|
99
100
|
signer: Signer | null;
|
|
100
101
|
isConnected: boolean;
|
|
@@ -236,6 +237,13 @@ declare class RPCLibrary {
|
|
|
236
237
|
checkAllowance: typeof checkAllowance;
|
|
237
238
|
getChainsConfig: typeof getChainsConfig;
|
|
238
239
|
setChainsConfig: typeof setChainConfig;
|
|
240
|
+
errors: {
|
|
241
|
+
decodeErrorName: typeof decodeErrorName;
|
|
242
|
+
getErrorInfo: typeof getErrorInfo;
|
|
243
|
+
attachDecodedError: typeof attachDecodedError;
|
|
244
|
+
decodeErrorMessage: typeof decodeErrorMessage;
|
|
245
|
+
attachDecodedErrorMessage: typeof attachDecodedErrorMessage;
|
|
246
|
+
};
|
|
239
247
|
constructor(privateKey?: string);
|
|
240
248
|
getWallet(privateKey: string, provider: Provider): Promise<ethers.JsonRpcSigner | ethers.Wallet>;
|
|
241
249
|
getProvider(chainId: ChainId, providerRpc?: string): Promise<ethers.BrowserProvider | ethers.JsonRpcProvider>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
interface GeneratedErrorInfo {
|
|
2
|
+
name: string;
|
|
3
|
+
signature: string;
|
|
4
|
+
message: string;
|
|
5
|
+
contract?: string;
|
|
6
|
+
inputs?: Array<{
|
|
7
|
+
name: string;
|
|
8
|
+
type: string;
|
|
9
|
+
internalType: string;
|
|
10
|
+
}>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Returns detailed information about the error encoded in the given data blob.
|
|
14
|
+
* @param data The revert data returned by the EVM (e.g., error.data).
|
|
15
|
+
*/
|
|
16
|
+
export declare function getErrorInfo(data?: string): GeneratedErrorInfo | null;
|
|
17
|
+
/**
|
|
18
|
+
* Returns only the error name, or null if it cannot be decoded.
|
|
19
|
+
*/
|
|
20
|
+
export declare function decodeErrorName(data?: string): string | null;
|
|
21
|
+
/**
|
|
22
|
+
* Returns the custom error message, or null if it cannot be decoded.
|
|
23
|
+
*/
|
|
24
|
+
export declare function decodeErrorMessage(data?: string): string | null;
|
|
25
|
+
/**
|
|
26
|
+
* Builds a user-friendly error prefix with decoded error name (if available).
|
|
27
|
+
* Usage example:
|
|
28
|
+
* const msg = attachDecodedError("Deposit failed", caughtError);
|
|
29
|
+
*/
|
|
30
|
+
export declare function attachDecodedError(prefix: string, error: any): string;
|
|
31
|
+
/**
|
|
32
|
+
* Builds a user-friendly error message with custom error description (if available).
|
|
33
|
+
* Usage example:
|
|
34
|
+
* const msg = attachDecodedErrorMessage("Deposit failed", caughtError);
|
|
35
|
+
*/
|
|
36
|
+
export declare function attachDecodedErrorMessage(prefix: string, error: any): string;
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getErrorInfo = getErrorInfo;
|
|
4
|
+
exports.decodeErrorName = decodeErrorName;
|
|
5
|
+
exports.decodeErrorMessage = decodeErrorMessage;
|
|
6
|
+
exports.attachDecodedError = attachDecodedError;
|
|
7
|
+
exports.attachDecodedErrorMessage = attachDecodedErrorMessage;
|
|
8
|
+
const ethers_1 = require("ethers");
|
|
9
|
+
const artifacts_1 = require("./artifacts");
|
|
10
|
+
// Try to load the generated error map, fallback to runtime scanning
|
|
11
|
+
let ERROR_SIGNATURE_MAP = {};
|
|
12
|
+
try {
|
|
13
|
+
const generatedMap = require('../generated/errorMap.json');
|
|
14
|
+
ERROR_SIGNATURE_MAP = generatedMap;
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
console.warn('Generated error map not found, falling back to runtime scanning...');
|
|
18
|
+
// Fallback to runtime scanning (original implementation)
|
|
19
|
+
(function buildErrorSignatureMap() {
|
|
20
|
+
for (const abiKey in artifacts_1.ABIS) {
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
22
|
+
// @ts-ignore – ABIS may contain unknown items
|
|
23
|
+
const abi = artifacts_1.ABIS[abiKey];
|
|
24
|
+
if (!Array.isArray(abi))
|
|
25
|
+
continue;
|
|
26
|
+
for (const item of abi) {
|
|
27
|
+
if (item.type !== "error")
|
|
28
|
+
continue;
|
|
29
|
+
const inputs = (item.inputs || []);
|
|
30
|
+
const signature = `${item.name}(${inputs.map((input) => input.type).join(",")})`;
|
|
31
|
+
const selector = (0, ethers_1.id)(signature).slice(0, 10).toLowerCase();
|
|
32
|
+
if (!ERROR_SIGNATURE_MAP[selector]) {
|
|
33
|
+
ERROR_SIGNATURE_MAP[selector] = {
|
|
34
|
+
name: item.name,
|
|
35
|
+
signature,
|
|
36
|
+
message: `${item.name.replace(/([A-Z])/g, ' $1').trim()} error occurred`,
|
|
37
|
+
contract: abiKey,
|
|
38
|
+
inputs: inputs.map((input) => ({
|
|
39
|
+
name: input.name || '',
|
|
40
|
+
type: input.type,
|
|
41
|
+
internalType: input.internalType || input.type,
|
|
42
|
+
})),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
})();
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Returns detailed information about the error encoded in the given data blob.
|
|
51
|
+
* @param data The revert data returned by the EVM (e.g., error.data).
|
|
52
|
+
*/
|
|
53
|
+
function getErrorInfo(data) {
|
|
54
|
+
if (!data || typeof data !== "string")
|
|
55
|
+
return null;
|
|
56
|
+
let selector;
|
|
57
|
+
if (data.startsWith("0x")) {
|
|
58
|
+
selector = data.slice(0, 10).toLowerCase();
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
// look for first 4-byte hex inside the string (e.g., error message)
|
|
62
|
+
const match = data.match(/0x[0-9a-fA-F]{8}/);
|
|
63
|
+
if (match)
|
|
64
|
+
selector = match[0].toLowerCase();
|
|
65
|
+
}
|
|
66
|
+
if (!selector)
|
|
67
|
+
return null;
|
|
68
|
+
return ERROR_SIGNATURE_MAP[selector] ?? null;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Returns only the error name, or null if it cannot be decoded.
|
|
72
|
+
*/
|
|
73
|
+
function decodeErrorName(data) {
|
|
74
|
+
const info = getErrorInfo(data);
|
|
75
|
+
return info?.name ?? null;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Returns the custom error message, or null if it cannot be decoded.
|
|
79
|
+
*/
|
|
80
|
+
function decodeErrorMessage(data) {
|
|
81
|
+
const info = getErrorInfo(data);
|
|
82
|
+
return info?.message ?? null;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Builds a user-friendly error prefix with decoded error name (if available).
|
|
86
|
+
* Usage example:
|
|
87
|
+
* const msg = attachDecodedError("Deposit failed", caughtError);
|
|
88
|
+
*/
|
|
89
|
+
function attachDecodedError(prefix, error) {
|
|
90
|
+
// ethers@6 nests the original error under error.error
|
|
91
|
+
// viem/ethcall surface it directly on error.data
|
|
92
|
+
const data = (error && ((error.data ?? error.error?.data) ||
|
|
93
|
+
// viem error format: error.shortMessage
|
|
94
|
+
undefined));
|
|
95
|
+
// If data not found, attempt to extract selector from message like
|
|
96
|
+
// "Encoded error signature \"0xa9b65aba\" not found on ABI"
|
|
97
|
+
let selector;
|
|
98
|
+
if (data && data.startsWith("0x")) {
|
|
99
|
+
selector = data.slice(0, 10).toLowerCase();
|
|
100
|
+
}
|
|
101
|
+
else if (typeof error?.message === "string") {
|
|
102
|
+
const SIGNATURE_REGEX = /Encoded error signature \"(0x[0-9a-fA-F]{8})\"/;
|
|
103
|
+
const match = error.message.match(SIGNATURE_REGEX);
|
|
104
|
+
if (match)
|
|
105
|
+
selector = match[1].toLowerCase();
|
|
106
|
+
}
|
|
107
|
+
if (!selector)
|
|
108
|
+
return prefix; // unable to determine
|
|
109
|
+
const decodedName = ERROR_SIGNATURE_MAP[selector]?.name ?? null;
|
|
110
|
+
// console.debug("Decoded", selector, decodedName);
|
|
111
|
+
return decodedName ? `${prefix} (${decodedName})` : prefix;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Builds a user-friendly error message with custom error description (if available).
|
|
115
|
+
* Usage example:
|
|
116
|
+
* const msg = attachDecodedErrorMessage("Deposit failed", caughtError);
|
|
117
|
+
*/
|
|
118
|
+
function attachDecodedErrorMessage(prefix, error) {
|
|
119
|
+
const data = (error && ((error.data ?? error.error?.data) ||
|
|
120
|
+
undefined));
|
|
121
|
+
let selector;
|
|
122
|
+
if (data && data.startsWith("0x")) {
|
|
123
|
+
selector = data.slice(0, 10).toLowerCase();
|
|
124
|
+
}
|
|
125
|
+
else if (typeof error?.message === "string") {
|
|
126
|
+
const SIGNATURE_REGEX = /Encoded error signature \"(0x[0-9a-fA-F]{8})\"/;
|
|
127
|
+
const match = error.message.match(SIGNATURE_REGEX);
|
|
128
|
+
if (match)
|
|
129
|
+
selector = match[1].toLowerCase();
|
|
130
|
+
}
|
|
131
|
+
if (!selector)
|
|
132
|
+
return prefix;
|
|
133
|
+
const errorInfo = ERROR_SIGNATURE_MAP[selector];
|
|
134
|
+
if (!errorInfo)
|
|
135
|
+
return prefix;
|
|
136
|
+
return `${prefix}: ${errorInfo.message}`;
|
|
137
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@raac/rpc",
|
|
3
|
-
"version": "1.1.0-beta.
|
|
3
|
+
"version": "1.1.0-beta.55",
|
|
4
4
|
"description": "RPC Library for RAAC ",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/types/index.d.ts",
|
|
@@ -9,12 +9,13 @@
|
|
|
9
9
|
],
|
|
10
10
|
"scripts": {
|
|
11
11
|
"dev": "ts-node-dev --transpile-only --env-file=.env scripts/index.ts",
|
|
12
|
-
"build": "tsc && cp -r typechain-types dist/types",
|
|
12
|
+
"build": "npm run generate:errors && tsc && cp -r typechain-types dist/types",
|
|
13
13
|
"build:watch": "tsc --watch",
|
|
14
14
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
15
15
|
"sync": "bash setup.sh",
|
|
16
16
|
"clean": "rm -rf dist",
|
|
17
|
-
"prebuild": "npm run clean"
|
|
17
|
+
"prebuild": "npm run clean",
|
|
18
|
+
"generate:errors": "ts-node scripts/generateErrorMap.ts"
|
|
18
19
|
},
|
|
19
20
|
"keywords": [
|
|
20
21
|
"RAAC",
|