@cofhe/mock-contracts 0.1.0

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.
@@ -0,0 +1,441 @@
1
+ // SPDX-License-Identifier: BSD-3-Clause-Clear
2
+ pragma solidity >=0.8.25 <0.9.0;
3
+
4
+ import { Strings } from '@openzeppelin/contracts/utils/Strings.sol';
5
+ import { FHE } from '@fhenixprotocol/cofhe-contracts/FHE.sol';
6
+ import { FunctionId, Utils } from '@fhenixprotocol/cofhe-contracts/ICofhe.sol';
7
+ import { console } from 'hardhat/console.sol';
8
+
9
+ address constant SIGNER_ADDRESS = 0x6E12D8C87503D4287c294f2Fdef96ACd9DFf6bd2;
10
+ uint256 constant SIGNER_PRIVATE_KEY = 49099792800763675079532137679706322989817545357788440619111868498148356080914;
11
+
12
+ /**
13
+ * @dev Mock implementation of the CoFHE coprocessor, used to test FHE ops in isolation.
14
+ * Is inherited by MockTaskManager.
15
+ *
16
+ * It is responsible for storing a map of ctHash -> value
17
+ * and for performing the operations on the values.
18
+ *
19
+ * It is intended as a 1:1 drop-in replacement for the real CoFHE coprocessor, with the following differences:
20
+ * - AsyncCallbacks are called synchronously (with a mock 1-10 second delay).
21
+ * - Unencrypted values are available onchain via the `mockStorage` map.
22
+ *
23
+ * NOTE: This is not used in production
24
+ */
25
+ abstract contract MockCoFHE {
26
+ // Pulled from TMCommon
27
+ uint256 constant uintTypeMask = (type(uint8).max >> 1); // 0x7f - 7 bits reserved for uint type in the one before last byte
28
+ uint256 constant triviallyEncryptedMask = type(uint8).max - uintTypeMask; //0x80 1 bit reserved for isTriviallyEncrypted
29
+ uint256 constant shiftedTypeMask = uintTypeMask << 8; // 0x7f007 bits reserved for uint type in the one before last byte
30
+
31
+ bool public logOps = true;
32
+
33
+ mapping(uint256 => uint256) public mockStorage;
34
+ mapping(uint256 => bool) public inMockStorage;
35
+
36
+ error InputNotInMockStorage(uint256 ctHash);
37
+
38
+ // Used internally to check if we missed any operations in the mocks
39
+ error InvalidUnaryOperation(string operation);
40
+ error InvalidTwoInputOperation(string operation);
41
+ error InvalidThreeInputOperation(string operation);
42
+
43
+ // OPTIONS
44
+
45
+ function setLogOps(bool _logOps) public {
46
+ logOps = _logOps;
47
+ }
48
+
49
+ // Utils
50
+
51
+ function getUintTypeFromHash(uint256 hash) internal pure returns (uint8) {
52
+ return uint8((hash & shiftedTypeMask) >> 8);
53
+ }
54
+
55
+ function getUtypeStringFromHash(uint256 hash) internal pure returns (string memory) {
56
+ uint8 inputType = getUintTypeFromHash(hash);
57
+ if (inputType == Utils.EBOOL_TFHE) return 'ebool';
58
+ if (inputType == Utils.EUINT8_TFHE) return 'euint8';
59
+ if (inputType == Utils.EUINT16_TFHE) return 'euint16';
60
+ if (inputType == Utils.EUINT32_TFHE) return 'euint32';
61
+ if (inputType == Utils.EUINT64_TFHE) return 'euint64';
62
+ if (inputType == Utils.EUINT128_TFHE) return 'euint128';
63
+ if (inputType == Utils.EUINT256_TFHE) return 'euint256';
64
+ if (inputType == Utils.EADDRESS_TFHE) return 'eaddress';
65
+ return 'unknown';
66
+ }
67
+
68
+ function getUtypeBits(uint256 hash) internal pure returns (uint256) {
69
+ uint8 inputType = getUintTypeFromHash(hash);
70
+ if (inputType == Utils.EBOOL_TFHE) return 8;
71
+ if (inputType == Utils.EUINT8_TFHE) return 8;
72
+ if (inputType == Utils.EUINT16_TFHE) return 16;
73
+ if (inputType == Utils.EUINT32_TFHE) return 32;
74
+ if (inputType == Utils.EUINT64_TFHE) return 64;
75
+ if (inputType == Utils.EUINT128_TFHE) return 128;
76
+ if (inputType == Utils.EUINT256_TFHE) return 256;
77
+ if (inputType == Utils.EADDRESS_TFHE) return 160;
78
+ return 0;
79
+ }
80
+
81
+ function getUtypeMask(uint256 hash) internal pure returns (uint256) {
82
+ uint256 bits = getUtypeBits(hash);
83
+ unchecked {
84
+ return (1 << bits) - 1;
85
+ }
86
+ }
87
+
88
+ function removeFirstLetter(string memory str) public pure returns (string memory) {
89
+ bytes memory strBytes = bytes(str);
90
+ if (strBytes.length == 0) return '';
91
+ bytes memory result = new bytes(strBytes.length - 1);
92
+ for (uint i = 1; i < strBytes.length; i++) {
93
+ result[i - 1] = strBytes[i];
94
+ }
95
+ return string(result);
96
+ }
97
+
98
+ function getIsBoolTypeFromHash(uint256 hash) internal pure returns (bool) {
99
+ uint8 inputType = getUintTypeFromHash(hash);
100
+ return (inputType ^ Utils.EBOOL_TFHE) == 0;
101
+ }
102
+
103
+ function strEq(string memory _a, string memory _b) internal pure returns (bool) {
104
+ return keccak256(abi.encodePacked(_a)) == keccak256(abi.encodePacked(_b));
105
+ }
106
+
107
+ function opIs(string memory op, FunctionId fid) internal pure returns (bool) {
108
+ return strEq(op, Utils.functionIdToString(fid));
109
+ }
110
+
111
+ function sliceString(string memory str, uint start, uint length) public pure returns (string memory) {
112
+ bytes memory strBytes = bytes(str);
113
+ require(start + length <= strBytes.length, 'Out of bounds');
114
+
115
+ bytes memory result = new bytes(length);
116
+ for (uint i = 0; i < length; i++) {
117
+ result[i] = strBytes[start + i];
118
+ }
119
+
120
+ return string(result);
121
+ }
122
+
123
+ function logCtHash(uint256 ctHash) internal view returns (string memory) {
124
+ string memory hashStr = Strings.toString(ctHash);
125
+ uint256 length = bytes(hashStr).length;
126
+ if (length <= 6) {
127
+ return hashStr;
128
+ }
129
+
130
+ bool stored = inMockStorage[ctHash];
131
+ uint256 value = mockStorage[ctHash];
132
+ bool isBool = getIsBoolTypeFromHash(ctHash);
133
+
134
+ string memory valueString = isBool ? (value == 1 ? 'true' : 'false') : Strings.toString(value);
135
+
136
+ string memory truncated = string.concat(
137
+ getUtypeStringFromHash(ctHash),
138
+ '(',
139
+ sliceString(hashStr, 0, 4),
140
+ '..',
141
+ sliceString(hashStr, length - 4, 4),
142
+ ')[',
143
+ stored ? valueString : 'EMPTY',
144
+ ']'
145
+ );
146
+
147
+ return truncated;
148
+ }
149
+
150
+ string constant LOG_PREFIX = unicode'├ ';
151
+ string constant LOG_DIVIDER = unicode' | ';
152
+
153
+ function padRight(string memory input, uint256 length, bytes1 padChar) internal pure returns (string memory) {
154
+ bytes memory inputBytes = bytes(input);
155
+ if (inputBytes.length >= length) return input;
156
+
157
+ bytes memory padded = new bytes(length);
158
+ uint256 i = 0;
159
+ for (; i < inputBytes.length; i++) {
160
+ padded[i] = inputBytes[i];
161
+ }
162
+ for (; i < length; i++) {
163
+ padded[i] = padChar;
164
+ }
165
+ return string(padded);
166
+ }
167
+
168
+ function logOperation(string memory operation, string memory inputs, string memory output) internal view {
169
+ if (logOps)
170
+ console.log(string.concat(LOG_PREFIX, padRight(operation, 16, ' '), LOG_DIVIDER, inputs, ' => ', output));
171
+ }
172
+
173
+ function logAllow(string memory operation, uint256 ctHash, address account) internal view {
174
+ if (logOps)
175
+ console.log(
176
+ string.concat(
177
+ LOG_PREFIX,
178
+ padRight(operation, 16, ' '),
179
+ LOG_DIVIDER,
180
+ logCtHash(ctHash),
181
+ ' -> ',
182
+ Strings.toHexString(account)
183
+ )
184
+ );
185
+ }
186
+
187
+ // Storage functions
188
+
189
+ function _set(uint256 ctHash, uint256 value, bool log) internal {
190
+ mockStorage[ctHash] = value;
191
+ inMockStorage[ctHash] = true;
192
+
193
+ if (log) logOperation('set', '', logCtHash(ctHash));
194
+ }
195
+
196
+ function _set(uint256 ctHash, uint256 value) internal {
197
+ uint256 mask = getUtypeMask(ctHash);
198
+ _set(ctHash, value & mask, false);
199
+ }
200
+
201
+ function _set(uint256 ctHash, bool value) internal {
202
+ _set(ctHash, value ? 1 : 0);
203
+ }
204
+
205
+ function _get(uint256 ctHash) internal view returns (uint256) {
206
+ if (!inMockStorage[ctHash]) revert InputNotInMockStorage(ctHash);
207
+
208
+ uint256 mask = getUtypeMask(ctHash);
209
+ return mockStorage[ctHash] & mask;
210
+ }
211
+
212
+ // Public functions
213
+
214
+ function MOCK_setInEuintKey(uint256 ctHash, uint256 value) public {
215
+ _set(ctHash, value);
216
+ }
217
+
218
+ // Mock Log
219
+
220
+ function MOCK_logAllow(string memory operation, uint256 ctHash, address account) public view {
221
+ logAllow(operation, ctHash, account);
222
+ }
223
+
224
+ // Mock functions
225
+
226
+ function MOCK_verifyKeyInStorage(uint256 ctHash) internal view {
227
+ if (!inMockStorage[ctHash]) revert InputNotInMockStorage(ctHash);
228
+ }
229
+
230
+ function MOCK_unaryOperation(uint256 ctHash, string memory operation, uint256 input) internal {
231
+ if (opIs(operation, FunctionId.random)) {
232
+ _set(ctHash, uint256(blockhash(block.number - 1)));
233
+ logOperation('FHE.random', '', logCtHash(ctHash));
234
+ return;
235
+ }
236
+ if (opIs(operation, FunctionId.cast)) {
237
+ _set(ctHash, _get(input));
238
+ logOperation('FHE.cast', logCtHash(input), logCtHash(ctHash));
239
+ return;
240
+ }
241
+ if (opIs(operation, FunctionId.not)) {
242
+ bool inputIsTruthy = _get(input) == 1;
243
+ _set(ctHash, !inputIsTruthy);
244
+ logOperation('FHE.not', logCtHash(input), logCtHash(ctHash));
245
+ return;
246
+ }
247
+ if (opIs(operation, FunctionId.square)) {
248
+ unchecked {
249
+ _set(ctHash, _get(input) * _get(input));
250
+ }
251
+ logOperation('FHE.square', string.concat(logCtHash(input), ' * ', logCtHash(input)), logCtHash(ctHash));
252
+ return;
253
+ }
254
+ revert InvalidUnaryOperation(operation);
255
+ }
256
+
257
+ function MOCK_twoInputOperation(uint256 ctHash, string memory operation, uint256 input1, uint256 input2) internal {
258
+ if (opIs(operation, FunctionId.sub)) {
259
+ unchecked {
260
+ _set(ctHash, _get(input1) - _get(input2));
261
+ }
262
+ logOperation('FHE.sub', string.concat(logCtHash(input1), ' - ', logCtHash(input2)), logCtHash(ctHash));
263
+ return;
264
+ }
265
+ if (opIs(operation, FunctionId.add)) {
266
+ unchecked {
267
+ _set(ctHash, _get(input1) + _get(input2));
268
+ }
269
+ logOperation('FHE.add', string.concat(logCtHash(input1), ' + ', logCtHash(input2)), logCtHash(ctHash));
270
+ return;
271
+ }
272
+ if (opIs(operation, FunctionId.xor)) {
273
+ unchecked {
274
+ _set(ctHash, _get(input1) ^ _get(input2));
275
+ }
276
+ logOperation('FHE.xor', string.concat(logCtHash(input1), ' ^ ', logCtHash(input2)), logCtHash(ctHash));
277
+ return;
278
+ }
279
+ if (opIs(operation, FunctionId.and)) {
280
+ unchecked {
281
+ _set(ctHash, _get(input1) & _get(input2));
282
+ }
283
+ logOperation('FHE.and', string.concat(logCtHash(input1), ' & ', logCtHash(input2)), logCtHash(ctHash));
284
+ return;
285
+ }
286
+ if (opIs(operation, FunctionId.or)) {
287
+ unchecked {
288
+ _set(ctHash, _get(input1) | _get(input2));
289
+ }
290
+ logOperation('FHE.or', string.concat(logCtHash(input1), ' | ', logCtHash(input2)), logCtHash(ctHash));
291
+ return;
292
+ }
293
+ if (opIs(operation, FunctionId.div)) {
294
+ uint256 cleartext2 = _get(input2);
295
+ if (cleartext2 == 0) {
296
+ _set(ctHash, type(uint256).max);
297
+ } else {
298
+ unchecked {
299
+ _set(ctHash, _get(input1) / cleartext2);
300
+ }
301
+ }
302
+ logOperation('FHE.div', string.concat(logCtHash(input1), ' / ', logCtHash(input2)), logCtHash(ctHash));
303
+ return;
304
+ }
305
+ if (opIs(operation, FunctionId.rem)) {
306
+ unchecked {
307
+ _set(ctHash, _get(input1) % _get(input2));
308
+ }
309
+ logOperation('FHE.rem', string.concat(logCtHash(input1), ' % ', logCtHash(input2)), logCtHash(ctHash));
310
+ return;
311
+ }
312
+ if (opIs(operation, FunctionId.mul)) {
313
+ unchecked {
314
+ _set(ctHash, _get(input1) * _get(input2));
315
+ }
316
+ logOperation('FHE.mul', string.concat(logCtHash(input1), ' * ', logCtHash(input2)), logCtHash(ctHash));
317
+ return;
318
+ }
319
+ if (opIs(operation, FunctionId.shl)) {
320
+ unchecked {
321
+ _set(ctHash, _get(input1) << _get(input2));
322
+ }
323
+ logOperation('FHE.shl', string.concat(logCtHash(input1), ' << ', logCtHash(input2)), logCtHash(ctHash));
324
+ return;
325
+ }
326
+ if (opIs(operation, FunctionId.shr)) {
327
+ unchecked {
328
+ _set(ctHash, _get(input1) >> _get(input2));
329
+ }
330
+ logOperation('FHE.shr', string.concat(logCtHash(input1), ' >> ', logCtHash(input2)), logCtHash(ctHash));
331
+ return;
332
+ }
333
+ if (opIs(operation, FunctionId.gte)) {
334
+ _set(ctHash, _get(input1) >= _get(input2));
335
+ logOperation('FHE.gte', string.concat(logCtHash(input1), ' >= ', logCtHash(input2)), logCtHash(ctHash));
336
+ return;
337
+ }
338
+ if (opIs(operation, FunctionId.lte)) {
339
+ _set(ctHash, _get(input1) <= _get(input2));
340
+ logOperation('FHE.lte', string.concat(logCtHash(input1), ' <= ', logCtHash(input2)), logCtHash(ctHash));
341
+ return;
342
+ }
343
+ if (opIs(operation, FunctionId.lt)) {
344
+ _set(ctHash, _get(input1) < _get(input2));
345
+ logOperation('FHE.lt', string.concat(logCtHash(input1), ' < ', logCtHash(input2)), logCtHash(ctHash));
346
+ return;
347
+ }
348
+ if (opIs(operation, FunctionId.gt)) {
349
+ _set(ctHash, _get(input1) > _get(input2));
350
+ logOperation('FHE.gt', string.concat(logCtHash(input1), ' > ', logCtHash(input2)), logCtHash(ctHash));
351
+ return;
352
+ }
353
+ if (opIs(operation, FunctionId.min)) {
354
+ uint256 min;
355
+ unchecked {
356
+ min = _get(input1) < _get(input2) ? _get(input1) : _get(input2);
357
+ }
358
+ _set(ctHash, min);
359
+
360
+ logOperation(
361
+ 'FHE.min',
362
+ string.concat('min(', logCtHash(input1), ', ', logCtHash(input2), ')'),
363
+ logCtHash(ctHash)
364
+ );
365
+ return;
366
+ }
367
+ if (opIs(operation, FunctionId.max)) {
368
+ uint256 max;
369
+ unchecked {
370
+ max = _get(input1) > _get(input2) ? _get(input1) : _get(input2);
371
+ }
372
+ _set(ctHash, max);
373
+
374
+ logOperation(
375
+ 'FHE.max',
376
+ string.concat('max(', logCtHash(input1), ', ', logCtHash(input2), ')'),
377
+ logCtHash(ctHash)
378
+ );
379
+ return;
380
+ }
381
+ if (opIs(operation, FunctionId.eq)) {
382
+ _set(ctHash, _get(input1) == _get(input2));
383
+
384
+ logOperation('FHE.eq', string.concat(logCtHash(input1), ' == ', logCtHash(input2)), logCtHash(ctHash));
385
+ return;
386
+ }
387
+ if (opIs(operation, FunctionId.ne)) {
388
+ _set(ctHash, _get(input1) != _get(input2));
389
+
390
+ logOperation('FHE.ne', string.concat(logCtHash(input1), ' != ', logCtHash(input2)), logCtHash(ctHash));
391
+ return;
392
+ }
393
+ if (opIs(operation, FunctionId.rol)) {
394
+ unchecked {
395
+ _set(ctHash, _get(input1) << _get(input2));
396
+ }
397
+
398
+ logOperation('FHE.rol', string.concat(logCtHash(input1), ' << ', logCtHash(input2)), logCtHash(ctHash));
399
+ return;
400
+ }
401
+ if (opIs(operation, FunctionId.ror)) {
402
+ unchecked {
403
+ _set(ctHash, _get(input1) >> _get(input2));
404
+ }
405
+
406
+ logOperation('FHE.ror', string.concat(logCtHash(input1), ' >> ', logCtHash(input2)), logCtHash(ctHash));
407
+ return;
408
+ }
409
+ revert InvalidTwoInputOperation(operation);
410
+ }
411
+
412
+ function MOCK_threeInputOperation(
413
+ uint256 ctHash,
414
+ string memory operation,
415
+ uint256 input1,
416
+ uint256 input2,
417
+ uint256 input3
418
+ ) internal {
419
+ if (opIs(operation, FunctionId.trivialEncrypt)) {
420
+ _set(ctHash, input1);
421
+
422
+ logOperation(
423
+ string.concat('FHE.asE', removeFirstLetter(getUtypeStringFromHash(ctHash))),
424
+ string.concat(removeFirstLetter(getUtypeStringFromHash(ctHash)), '(', Strings.toString(input1), ')'),
425
+ logCtHash(ctHash)
426
+ );
427
+ return;
428
+ }
429
+ if (opIs(operation, FunctionId.select)) {
430
+ _set(ctHash, _get(input1) == 1 ? _get(input2) : _get(input3));
431
+
432
+ logOperation(
433
+ 'FHE.select',
434
+ string.concat(logCtHash(input1), ' ? ', logCtHash(input2), ' : ', logCtHash(input3)),
435
+ logCtHash(ctHash)
436
+ );
437
+ return;
438
+ }
439
+ revert InvalidThreeInputOperation(operation);
440
+ }
441
+ }
@@ -0,0 +1,133 @@
1
+ // SPDX-License-Identifier: BSD-3-Clause-Clear
2
+ // solhint-disable one-contract-per-file
3
+
4
+ pragma solidity >=0.8.19 <0.9.0;
5
+
6
+ import { MockACL } from './MockACL.sol';
7
+ import { MockTaskManager } from './MockTaskManager.sol';
8
+ import { Permission, MockPermissioned } from './Permissioned.sol';
9
+
10
+ contract MockQueryDecrypter {
11
+ MockTaskManager public mockTaskManager;
12
+ MockACL public mockAcl;
13
+
14
+ error NotAllowed();
15
+ error SealingKeyMissing();
16
+ error SealingKeyInvalid();
17
+
18
+ function initialize(address _taskManager, address _acl) public {
19
+ mockTaskManager = MockTaskManager(_taskManager);
20
+ mockAcl = MockACL(_acl);
21
+ }
22
+
23
+ // EXISTENCE
24
+
25
+ function exists() public pure returns (bool) {
26
+ return true;
27
+ }
28
+
29
+ // BODY
30
+
31
+ function queryDecrypt(
32
+ uint256 ctHash,
33
+ uint256,
34
+ Permission memory permission
35
+ ) public view returns (bool allowed, string memory error, uint256) {
36
+ bool isAllowed;
37
+ try mockAcl.isAllowedWithPermission(permission, ctHash) returns (bool _isAllowed) {
38
+ isAllowed = _isAllowed;
39
+ } catch Error(string memory reason) {
40
+ // Handle string error messages
41
+ return (false, reason, 0);
42
+ } catch Panic(uint /*errorCode*/) {
43
+ // Handle panic errors
44
+ return (false, 'Panic', 0);
45
+ } catch (bytes memory lowLevelData) {
46
+ return (false, decodeLowLevelReversion(lowLevelData), 0);
47
+ }
48
+
49
+ if (!isAllowed) return (false, 'NotAllowed', 0);
50
+
51
+ return (true, '', mockTaskManager.mockStorage(ctHash));
52
+ }
53
+
54
+ function seal(uint256 input, bytes32 key) public pure returns (bytes32) {
55
+ return bytes32(input) ^ key;
56
+ }
57
+
58
+ function unseal(bytes32 hashed, bytes32 key) public pure returns (uint256) {
59
+ return uint256(hashed ^ key);
60
+ }
61
+
62
+ // changed function name from 'testQueryDecrypt'
63
+ // Foundry was trying to run fuzz tests on it
64
+ function mockQueryDecrypt(
65
+ uint256 ctHash,
66
+ uint256,
67
+ address issuer
68
+ ) public view returns (bool allowed, string memory error, uint256) {
69
+ bool isAllowed;
70
+ try mockAcl.isAllowed(ctHash, issuer) returns (bool _isAllowed) {
71
+ isAllowed = _isAllowed;
72
+ } catch Error(string memory reason) {
73
+ // Handle string error messages
74
+ return (false, reason, 0);
75
+ } catch Panic(uint /*errorCode*/) {
76
+ // Handle panic errors
77
+ return (false, 'Panic', 0);
78
+ } catch (bytes memory lowLevelData) {
79
+ return (false, decodeLowLevelReversion(lowLevelData), 0);
80
+ }
81
+
82
+ if (!isAllowed) return (false, 'NotAllowed', 0);
83
+
84
+ uint256 value = mockTaskManager.mockStorage(ctHash);
85
+ return (true, '', value);
86
+ }
87
+
88
+ function querySealOutput(
89
+ uint256 ctHash,
90
+ uint256,
91
+ Permission memory permission
92
+ ) public view returns (bool allowed, string memory error, bytes32) {
93
+ if (permission.sealingKey == bytes32(0)) revert SealingKeyMissing();
94
+
95
+ bool isAllowed;
96
+ try mockAcl.isAllowedWithPermission(permission, ctHash) returns (bool _isAllowed) {
97
+ isAllowed = _isAllowed;
98
+ } catch Error(string memory reason) {
99
+ // Handle string error messages
100
+ return (false, reason, bytes32(0));
101
+ } catch Panic(uint /*errorCode*/) {
102
+ // Handle panic errors
103
+ return (false, 'Panic', bytes32(0));
104
+ } catch (bytes memory lowLevelData) {
105
+ return (false, decodeLowLevelReversion(lowLevelData), bytes32(0));
106
+ }
107
+
108
+ if (!isAllowed) return (false, 'NotAllowed', bytes32(0));
109
+
110
+ uint256 value = mockTaskManager.mockStorage(ctHash);
111
+ return (true, '', seal(value, permission.sealingKey));
112
+ }
113
+
114
+ // UTIL
115
+
116
+ function decodeLowLevelReversion(bytes memory data) public pure returns (string memory error) {
117
+ bytes4 selector = bytes4(data);
118
+ if (selector == MockPermissioned.PermissionInvalid_Expired.selector) {
119
+ return 'PermissionInvalid_Expired';
120
+ }
121
+ if (selector == MockPermissioned.PermissionInvalid_IssuerSignature.selector) {
122
+ return 'PermissionInvalid_IssuerSignature';
123
+ }
124
+ if (selector == MockPermissioned.PermissionInvalid_RecipientSignature.selector) {
125
+ return 'PermissionInvalid_RecipientSignature';
126
+ }
127
+ if (selector == MockPermissioned.PermissionInvalid_Disabled.selector) {
128
+ return 'PermissionInvalid_Disabled';
129
+ }
130
+ // Handle other errors
131
+ return 'Low Level Error';
132
+ }
133
+ }