resolc 1.2.0

Solidity frontend for the revive compiler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
{
  "language": "Solidity",
  "sources": {
    "lib/forge-std/src/interfaces/IERC165.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.2;\n\ninterface IERC165 {\n    /// @notice Query if a contract implements an interface\n    /// @param interfaceID The interface identifier, as specified in ERC-165\n    /// @dev Interface identification is specified in ERC-165. This function\n    /// uses less than 30,000 gas.\n    /// @return `true` if the contract implements `interfaceID` and\n    /// `interfaceID` is not 0xffffffff, `false` otherwise\n    function supportsInterface(bytes4 interfaceID) external view returns (bool);\n}\n"
    },
    "src/common/GasService.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IGasService} from \"src/common/interfaces/IGasService.sol\";\n\n/// @title  GasService\n/// @notice This is a utility contract used to determine the execution gas limit\n///         for a payload being sent across all supported adapters.\ncontract GasService is IGasService {\n    uint128 internal immutable _maxBatchSize;\n    uint128 internal immutable _messageGasLimit;\n\n    constructor(uint128 maxBatchSize_, uint128 messageGasLimit) {\n        _maxBatchSize = maxBatchSize_;\n        _messageGasLimit = messageGasLimit;\n    }\n\n    /// @inheritdoc IGasService\n    function maxBatchSize(uint16) public view returns (uint128) {\n        return _maxBatchSize;\n    }\n\n    /// @inheritdoc IGasService\n    function gasLimit(uint16, bytes calldata) public view returns (uint128) {\n        return _messageGasLimit;\n    }\n}\n"
    },
    "src/common/Gateway.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {ArrayLib} from \"src/misc/libraries/ArrayLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {Recoverable, IRecoverable, ETH_ADDRESS} from \"src/misc/Recoverable.sol\";\nimport {TransientArrayLib} from \"src/misc/libraries/TransientArrayLib.sol\";\nimport {TransientBytesLib} from \"src/misc/libraries/TransientBytesLib.sol\";\nimport {TransientStorageLib} from \"src/misc/libraries/TransientStorageLib.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {IGasService} from \"src/common/interfaces/IGasService.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {IMessageProcessor} from \"src/common/interfaces/IMessageProcessor.sol\";\nimport {IMessageSender} from \"src/common/interfaces/IMessageSender.sol\";\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {IGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {MessageProofLib} from \"src/common/libraries/MessageProofLib.sol\";\n\n/// @title  Gateway\n/// @notice Routing contract that forwards outgoing messages to multiple adapters (1 full message, n-1 proofs)\n///         and validates that multiple adapters have confirmed a message.\n///\n///         Supports batching multiple messages, as well as paying for methods manually or through pool-level subsidies.\n///\n///         Supports processing multiple duplicate messages in parallel by storing counts of messages\n///         and proofs that have been received. Also implements a retry method for failed messages.\ncontract Gateway is Auth, Recoverable, IGateway {\n    using BytesLib for bytes;\n    using MathLib for uint256;\n    using MessageProofLib for *;\n    using ArrayLib for uint16[8];\n    using TransientStorageLib for bytes32;\n\n    uint8 public constant MAX_ADAPTER_COUNT = 8;\n    uint8 public constant PRIMARY_ADAPTER_ID = 1;\n    PoolId public constant GLOBAL_POT = PoolId.wrap(0);\n    uint256 public constant RECOVERY_CHALLENGE_PERIOD = 7 days;\n    bytes32 public constant BATCH_LOCATORS_SLOT = bytes32(uint256(keccak256(\"Centrifuge/batch-locators\")) - 1);\n\n    uint16 public immutable localCentrifugeId;\n\n    // Dependencies\n    IRoot public immutable root;\n    IGasService public gasService;\n    IMessageProcessor public processor;\n\n    // Outbound & payments\n    bool public transient isBatching;\n    uint256 public transient fuel;\n    address public transient transactionRefund;\n    mapping(PoolId => Funds) public subsidy;\n    mapping(uint16 centrifugeId => mapping(bytes32 batchHash => Underpaid)) public underpaid;\n\n    // Adapters\n    mapping(uint16 centrifugeId => IAdapter[]) public adapters;\n    mapping(uint16 centrifugeId => mapping(IAdapter adapter => Adapter)) internal _activeAdapters;\n\n    // Inbound & recoveries\n    mapping(uint16 centrifugeId => mapping(bytes32 messageHash => uint256)) public failedMessages;\n    mapping(uint16 centrifugeId => mapping(bytes32 batchHash => InboundBatch)) public inboundBatch;\n    mapping(uint16 centrifugeId => mapping(IAdapter adapter => mapping(bytes32 payloadHash => uint256 timestamp)))\n        public recoveries;\n\n    constructor(uint16 localCentrifugeId_, IRoot root_, IGasService gasService_, address deployer) Auth(deployer) {\n        localCentrifugeId = localCentrifugeId_;\n        root = root_;\n        gasService = gasService_;\n\n        setRefundAddress(GLOBAL_POT, IRecoverable(address(this)));\n    }\n\n    modifier pauseable() {\n        require(!root.paused(), Paused());\n        _;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Administration\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IGateway\n    function file(bytes32 what, uint16 centrifugeId, IAdapter[] calldata addresses) external auth {\n        if (what == \"adapters\") {\n            uint8 quorum_ = addresses.length.toUint8();\n            require(quorum_ != 0, EmptyAdapterSet());\n            require(quorum_ <= MAX_ADAPTER_COUNT, ExceedsMax());\n\n            // Increment session id to reset pending votes\n            uint256 numAdapters = adapters[centrifugeId].length;\n            uint64 sessionId =\n                numAdapters > 0 ? _activeAdapters[centrifugeId][adapters[centrifugeId][0]].activeSessionId + 1 : 0;\n\n            // Disable old adapters\n            for (uint8 i; i < numAdapters; i++) {\n                delete _activeAdapters[centrifugeId][adapters[centrifugeId][i]];\n            }\n\n            // Enable new adapters, setting quorum to number of adapters\n            for (uint8 j; j < quorum_; j++) {\n                require(_activeAdapters[centrifugeId][addresses[j]].id == 0, NoDuplicatesAllowed());\n\n                // Ids are assigned sequentially starting at 1\n                _activeAdapters[centrifugeId][addresses[j]] = Adapter(j + 1, quorum_, sessionId);\n            }\n\n            adapters[centrifugeId] = addresses;\n        } else {\n            revert FileUnrecognizedParam();\n        }\n\n        emit File(what, centrifugeId, addresses);\n    }\n\n    /// @inheritdoc IGateway\n    function file(bytes32 what, address instance) external auth {\n        if (what == \"gasService\") gasService = IGasService(instance);\n        else if (what == \"processor\") processor = IMessageProcessor(instance);\n        else revert FileUnrecognizedParam();\n\n        emit File(what, instance);\n    }\n\n    receive() external payable {\n        _subsidizePool(GLOBAL_POT, msg.sender, msg.value);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Incoming\n    //----------------------------------------------------------------------------------------------\n\n    /// @dev Handle an inbound payload\n    function handle(uint16 centrifugeId, bytes calldata payload) external pauseable {\n        _handle(centrifugeId, payload, IAdapter(msg.sender), false);\n    }\n\n    function _handle(uint16 centrifugeId, bytes calldata payload, IAdapter adapter_, bool isRecovery) internal {\n        Adapter memory adapter = _activeAdapters[centrifugeId][adapter_];\n        require(adapter.id != 0, InvalidAdapter());\n\n        IMessageProcessor processor_ = processor;\n        if (processor_.isMessageRecovery(payload)) {\n            require(!isRecovery, RecoveryPayloadRecovered());\n            return processor_.handle(centrifugeId, payload);\n        }\n\n        bool isMessageProof = payload.toUint8(0) == MessageProofLib.MESSAGE_PROOF_ID;\n\n        // Verify adapter and parse message hash\n        bytes32 batchHash;\n        if (isMessageProof) {\n            require(adapter.id != PRIMARY_ADAPTER_ID, NonProofAdapter());\n\n            batchHash = payload.deserializeMessageProof();\n            bytes32 payloadId = keccak256(abi.encodePacked(centrifugeId, localCentrifugeId, batchHash));\n            emit HandleProof(centrifugeId, payloadId, batchHash, adapter_);\n        } else {\n            require(adapter.id == PRIMARY_ADAPTER_ID, NonBatchAdapter());\n\n            batchHash = keccak256(payload);\n            bytes32 payloadId = keccak256(abi.encodePacked(centrifugeId, localCentrifugeId, batchHash));\n            emit HandleBatch(centrifugeId, payloadId, payload, adapter_);\n        }\n\n        // Special case for gas efficiency\n        if (adapter.quorum == 1 && !isMessageProof) {\n            _handleBatch(centrifugeId, payload);\n            return;\n        }\n\n        InboundBatch storage state = inboundBatch[centrifugeId][batchHash];\n\n        if (adapter.activeSessionId != state.sessionId) {\n            // Clear votes from previous session\n            delete state.votes;\n            state.sessionId = adapter.activeSessionId;\n        }\n\n        // Increase vote\n        state.votes[adapter.id - 1]++;\n\n        if (state.votes.countNonZeroValues() >= adapter.quorum) {\n            // Reduce votes by quorum\n            state.votes.decreaseFirstNValues(adapter.quorum);\n\n            if (isMessageProof) {\n                _handleBatch(centrifugeId, state.pendingBatch);\n            } else {\n                _handleBatch(centrifugeId, payload);\n            }\n\n            // Only if there are no more pending messages, remove the pending message\n            if (state.votes.isEmpty()) {\n                delete state.pendingBatch;\n            }\n        } else if (!isMessageProof) {\n            state.pendingBatch = payload;\n        }\n    }\n\n    function _handleBatch(uint16 centrifugeId, bytes memory batch_) internal {\n        IMessageProcessor processor_ = processor;\n        bytes memory remaining = batch_;\n\n        while (remaining.length > 0) {\n            uint256 length = processor_.messageLength(remaining);\n            bytes memory message = remaining.slice(0, length);\n            remaining = remaining.slice(length, remaining.length - length);\n\n            try processor_.handle(centrifugeId, message) {\n                emit ExecuteMessage(centrifugeId, message);\n            } catch (bytes memory err) {\n                bytes32 messageHash = keccak256(message);\n                failedMessages[centrifugeId][messageHash]++;\n                emit FailMessage(centrifugeId, message, err);\n            }\n        }\n    }\n\n    /// @inheritdoc IGateway\n    function retry(uint16 centrifugeId, bytes memory message) external pauseable {\n        bytes32 messageHash = keccak256(message);\n        require(failedMessages[centrifugeId][messageHash] > 0, NotFailedMessage());\n\n        processor.handle(centrifugeId, message);\n        failedMessages[centrifugeId][messageHash]--;\n\n        emit ExecuteMessage(centrifugeId, message);\n    }\n\n    /// @inheritdoc IGatewayHandler\n    function initiateRecovery(uint16 centrifugeId, IAdapter adapter, bytes32 payloadHash) external auth {\n        require(_activeAdapters[centrifugeId][adapter].id != 0, InvalidAdapter());\n        recoveries[centrifugeId][adapter][payloadHash] = block.timestamp + RECOVERY_CHALLENGE_PERIOD;\n        emit InitiateRecovery(centrifugeId, payloadHash, adapter);\n    }\n\n    /// @inheritdoc IGatewayHandler\n    function disputeRecovery(uint16 centrifugeId, IAdapter adapter, bytes32 payloadHash) external auth {\n        delete recoveries[centrifugeId][adapter][payloadHash];\n        emit DisputeRecovery(centrifugeId, payloadHash, adapter);\n    }\n\n    /// @inheritdoc IGateway\n    function executeRecovery(uint16 centrifugeId, IAdapter adapter, bytes calldata payload) external {\n        bytes32 payloadHash = keccak256(payload);\n        uint256 recovery = recoveries[centrifugeId][adapter][payloadHash];\n\n        require(recovery != 0, RecoveryNotInitiated());\n        require(recovery <= block.timestamp, RecoveryChallengePeriodNotEnded());\n\n        delete recoveries[centrifugeId][adapter][payloadHash];\n        _handle(centrifugeId, payload, adapter, true);\n        emit ExecuteRecovery(centrifugeId, payload, adapter);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Outgoing\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IMessageSender\n    function send(uint16 centrifugeId, bytes calldata message) external pauseable auth {\n        require(message.length > 0, EmptyMessage());\n\n        PoolId poolId = processor.messagePoolId(message);\n\n        emit PrepareMessage(centrifugeId, poolId, message);\n\n        if (isBatching) {\n            bytes32 batchSlot = _outboundBatchSlot(centrifugeId, poolId);\n            bytes memory previousMessage = TransientBytesLib.get(batchSlot);\n\n            bytes32 gasLimitSlot = _gasLimitSlot(centrifugeId, poolId);\n            uint128 newGasLimit = gasLimitSlot.tloadUint128() + gasService.gasLimit(centrifugeId, message);\n            require(newGasLimit <= gasService.maxBatchSize(centrifugeId), ExceedsMaxBatchSize());\n            gasLimitSlot.tstore(uint256(newGasLimit));\n\n            if (previousMessage.length == 0) {\n                TransientArrayLib.push(BATCH_LOCATORS_SLOT, _encodeLocator(centrifugeId, poolId));\n            }\n\n            TransientBytesLib.append(batchSlot, message);\n        } else {\n            _send(centrifugeId, poolId, message, gasService.gasLimit(centrifugeId, message));\n            _refundTransaction();\n        }\n    }\n\n    function _send(uint16 centrifugeId, PoolId poolId, bytes memory batch, uint128 batchGasLimit)\n        internal\n        returns (bool succeeded)\n    {\n        IAdapter[] memory adapters_ = adapters[centrifugeId];\n        require(adapters[centrifugeId].length != 0, EmptyAdapterSet());\n\n        SendData memory data = SendData({\n            batchHash: keccak256(batch),\n            payloadId: bytes32(\"\"),\n            gasCost: new uint256[](MAX_ADAPTER_COUNT)\n        });\n        data.payloadId = keccak256(abi.encodePacked(localCentrifugeId, centrifugeId, data.batchHash));\n\n        {\n            // Estimate gas usage\n            uint256 total;\n            for (uint256 i; i < adapters_.length; i++) {\n                data.gasCost[i] = adapters_[i].estimate(\n                    centrifugeId,\n                    i == PRIMARY_ADAPTER_ID - 1 ? batch : data.batchHash.serializeMessageProof(),\n                    batchGasLimit\n                );\n\n                total += data.gasCost[i];\n            }\n\n            // Ensure sufficient funds are available\n            if (transactionRefund != address(0)) {\n                require(total <= fuel, NotEnoughTransactionGas());\n                fuel -= total;\n            } else {\n                if (total > subsidy[poolId].value) {\n                    _requestPoolFunding(poolId);\n                }\n\n                if (total <= subsidy[poolId].value) {\n                    subsidy[poolId].value -= uint96(total);\n                } else {\n                    underpaid[centrifugeId][data.batchHash].counter++;\n                    underpaid[centrifugeId][data.batchHash].gasLimit = batchGasLimit;\n                    emit UnderpaidBatch(centrifugeId, batch);\n                    return false;\n                }\n            }\n        }\n\n        // Send batch and proofs\n        for (uint256 j; j < adapters_.length; j++) {\n            bytes32 adapterData = adapters_[j].send{value: data.gasCost[j]}(\n                centrifugeId,\n                j == PRIMARY_ADAPTER_ID - 1 ? batch : data.batchHash.serializeMessageProof(),\n                batchGasLimit,\n                transactionRefund != address(0) ? transactionRefund : address(subsidy[poolId].refund)\n            );\n\n            if (j == PRIMARY_ADAPTER_ID - 1) {\n                emit SendBatch(\n                    centrifugeId,\n                    data.payloadId,\n                    batch,\n                    adapters_[j],\n                    adapterData,\n                    transactionRefund != address(0) ? transactionRefund : address(subsidy[poolId].refund)\n                );\n            } else {\n                emit SendProof(\n                    centrifugeId,\n                    data.payloadId,\n                    data.batchHash,\n                    adapters_[j],\n                    adapterData\n                );\n            }\n        }\n\n        return true;\n    }\n\n    /// @inheritdoc IGateway\n    function repay(uint16 centrifugeId, bytes memory batch) external payable pauseable {\n        bytes32 batchHash = keccak256(batch);\n        Underpaid storage underpaid_ = underpaid[centrifugeId][batchHash];\n        require(underpaid_.counter > 0, NotUnderpaidBatch());\n\n        PoolId poolId = processor.messagePoolId(batch);\n        if (msg.value > 0) subsidizePool(poolId);\n\n        require(_send(centrifugeId, poolId, batch, underpaid_.gasLimit), InsufficientFundsForRepayment());\n        underpaid[centrifugeId][batchHash].counter--;\n\n        emit RepayBatch(centrifugeId, batch);\n    }\n\n    function _refundTransaction() internal {\n        if (transactionRefund == address(0)) return;\n\n        // Reset before external call\n        uint256 fuel_ = fuel;\n        address transactionRefund_ = transactionRefund;\n        fuel = 0;\n        transactionRefund = address(0);\n\n        if (fuel_ > 0) {\n            (bool success,) = payable(transactionRefund_).call{value: fuel_}(new bytes(0));\n\n            if (!success) {\n                // If refund fails, move remaining fuel to global pot\n                _subsidizePool(GLOBAL_POT, transactionRefund_, fuel_);\n            }\n        }\n    }\n\n    function _requestPoolFunding(PoolId poolId) internal {\n        IRecoverable refund = subsidy[poolId].refund;\n        if (!poolId.isNull() && address(refund) != address(0)) {\n            uint256 refundBalance = address(refund).balance;\n            if (refundBalance == 0) return;\n\n            // Send to the gateway GLOBAL_POT\n            refund.recoverTokens(ETH_ADDRESS, address(this), refundBalance);\n\n            // Extract from the GLOBAL_POT\n            subsidy[GLOBAL_POT].value -= uint96(refundBalance);\n            _subsidizePool(poolId, address(refund), refundBalance);\n        }\n    }\n\n    /// @inheritdoc IGateway\n    function setRefundAddress(PoolId poolId, IRecoverable refund) public auth {\n        subsidy[poolId].refund = refund;\n        emit SetRefundAddress(poolId, refund);\n    }\n\n    /// @inheritdoc IGateway\n    function subsidizePool(PoolId poolId) public payable {\n        require(address(subsidy[poolId].refund) != address(0), RefundAddressNotSet());\n        _subsidizePool(poolId, msg.sender, msg.value);\n    }\n\n    function _subsidizePool(PoolId poolId, address who, uint256 value) internal {\n        subsidy[poolId].value += uint96(value);\n        emit SubsidizePool(poolId, who, value);\n    }\n\n    /// @inheritdoc IGateway\n    function payTransaction(address payer) external payable auth {\n        transactionRefund = payer;\n        fuel += msg.value;\n    }\n\n    /// @inheritdoc IGateway\n    function startBatching() external auth {\n        isBatching = true;\n    }\n\n    /// @inheritdoc IGateway\n    function endBatching() external auth {\n        require(isBatching, NoBatched());\n\n        bytes32[] memory locators = TransientArrayLib.getBytes32(BATCH_LOCATORS_SLOT);\n        for (uint256 i; i < locators.length; i++) {\n            (uint16 centrifugeId, PoolId poolId) = _parseLocator(locators[i]);\n            bytes32 outboundBatchSlot = _outboundBatchSlot(centrifugeId, poolId);\n            uint128 gasLimit = _gasLimitSlot(centrifugeId, poolId).tloadUint128();\n\n            _send(centrifugeId, poolId, TransientBytesLib.get(outboundBatchSlot), gasLimit);\n\n            TransientBytesLib.clear(outboundBatchSlot);\n            _gasLimitSlot(centrifugeId, poolId).tstore(uint256(0));\n        }\n\n        TransientArrayLib.clear(BATCH_LOCATORS_SLOT);\n        isBatching = false;\n\n        _refundTransaction();\n    }\n\n    function _encodeLocator(uint16 centrifugeId, PoolId poolId) internal pure returns (bytes32) {\n        return bytes32(abi.encodePacked(bytes2(centrifugeId), bytes8(poolId.raw())));\n    }\n\n    function _parseLocator(bytes32 locator) internal pure returns (uint16 centrifugeId, PoolId poolId) {\n        centrifugeId = uint16(bytes2(locator));\n        poolId = PoolId.wrap(uint64(bytes8(locator << 16)));\n    }\n\n    function _gasLimitSlot(uint16 centrifugeId, PoolId poolId) internal pure returns (bytes32) {\n        return keccak256(abi.encode(\"batchGasLimit\", centrifugeId, poolId));\n    }\n\n    function _outboundBatchSlot(uint16 centrifugeId, PoolId poolId) internal pure returns (bytes32) {\n        return keccak256(abi.encode(\"outboundBatch\", centrifugeId, poolId));\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // View methods\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IGateway\n    function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256 total) {\n        bytes memory proof = keccak256(payload).serializeMessageProof();\n\n        uint256 gasLimit = 0;\n        for (uint256 pos; pos < payload.length;) {\n            bytes calldata inner = payload[pos:payload.length];\n            gasLimit += gasService.gasLimit(centrifugeId, inner);\n            pos += processor.messageLength(inner);\n        }\n\n        uint256 adaptersCount = adapters[centrifugeId].length;\n        for (uint256 i; i < adaptersCount; i++) {\n            bytes memory message = i == PRIMARY_ADAPTER_ID - 1 ? payload : proof;\n            total += IAdapter(adapters[centrifugeId][i]).estimate(centrifugeId, message, gasLimit);\n        }\n    }\n\n    /// @inheritdoc IGateway\n    function quorum(uint16 centrifugeId) external view returns (uint8) {\n        Adapter memory adapter = _activeAdapters[centrifugeId][adapters[centrifugeId][0]];\n        return adapter.quorum;\n    }\n\n    /// @inheritdoc IGateway\n    function activeSessionId(uint16 centrifugeId) external view returns (uint64) {\n        Adapter memory adapter = _activeAdapters[centrifugeId][adapters[centrifugeId][0]];\n        return adapter.activeSessionId;\n    }\n\n    /// @inheritdoc IGateway\n    function votes(uint16 centrifugeId, bytes32 batchHash) external view returns (uint16[MAX_ADAPTER_COUNT] memory) {\n        return inboundBatch[centrifugeId][batchHash].votes;\n    }\n}\n\n"
    },
    "src/common/Guardian.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {IGuardian, ISafe} from \"src/common/interfaces/IGuardian.sol\";\nimport {IRootMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\nimport {IHubGuardianActions} from \"src/common/interfaces/IGuardianActions.sol\";\n\ncontract Guardian is IGuardian {\n    using CastLib for address;\n\n    IRoot public immutable root;\n\n    IHubGuardianActions public hub;\n    ISafe public safe;\n    IRootMessageSender public sender;\n\n    constructor(ISafe safe_, IRoot root_, IRootMessageSender messageDispatcher_) {\n        root = root_;\n        safe = safe_;\n        sender = messageDispatcher_;\n    }\n\n    modifier onlySafe() {\n        require(msg.sender == address(safe), NotTheAuthorizedSafe());\n        _;\n    }\n\n    modifier onlySafeOrOwner() {\n        require(msg.sender == address(safe) || _isSafeOwner(msg.sender), NotTheAuthorizedSafeOrItsOwner());\n        _;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Administration\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IGuardian\n    function file(bytes32 what, address data) external onlySafe {\n        if (what == \"safe\") safe = ISafe(data);\n        else if (what == \"sender\") sender = IRootMessageSender(data);\n        else if (what == \"hub\") hub = IHubGuardianActions(data);\n        else revert FileUnrecognizedParam();\n\n        emit File(what, data);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Admin actions\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IGuardian\n    function createPool(PoolId poolId, address admin, AssetId currency) external onlySafe {\n        return hub.createPool(poolId, admin, currency);\n    }\n\n    /// @inheritdoc IGuardian\n    function pause() external onlySafeOrOwner {\n        root.pause();\n    }\n\n    /// @inheritdoc IGuardian\n    function unpause() external onlySafe {\n        root.unpause();\n    }\n\n    /// @inheritdoc IGuardian\n    function scheduleRely(address target) external onlySafe {\n        root.scheduleRely(target);\n    }\n\n    /// @inheritdoc IGuardian\n    function cancelRely(address target) external onlySafe {\n        root.cancelRely(target);\n    }\n\n    /// @inheritdoc IGuardian\n    function scheduleUpgrade(uint16 centrifugeId, address target) external onlySafe {\n        sender.sendScheduleUpgrade(centrifugeId, target.toBytes32());\n    }\n\n    /// @inheritdoc IGuardian\n    function cancelUpgrade(uint16 centrifugeId, address target) external onlySafe {\n        sender.sendCancelUpgrade(centrifugeId, target.toBytes32());\n    }\n\n    /// @inheritdoc IGuardian\n    function recoverTokens(\n        uint16 centrifugeId,\n        address target,\n        address token,\n        uint256 tokenId,\n        address to,\n        uint256 amount\n    ) external onlySafe {\n        sender.sendRecoverTokens(centrifugeId, target.toBytes32(), token.toBytes32(), tokenId, to.toBytes32(), amount);\n    }\n\n    /// @inheritdoc IGuardian\n    function initiateRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, IAdapter adapter, bytes32 hash)\n        external\n        onlySafe\n    {\n        sender.sendInitiateRecovery(centrifugeId, adapterCentrifugeId, address(adapter).toBytes32(), hash);\n    }\n\n    /// @inheritdoc IGuardian\n    function disputeRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, IAdapter adapter, bytes32 hash)\n        external\n        onlySafe\n    {\n        sender.sendDisputeRecovery(centrifugeId, adapterCentrifugeId, address(adapter).toBytes32(), hash);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Helpers\n    //----------------------------------------------------------------------------------------------\n\n    function _isSafeOwner(address addr) internal view returns (bool) {\n        try safe.isOwner(addr) returns (bool isOwner) {\n            return isOwner;\n        } catch {\n            return false;\n        }\n    }\n}\n"
    },
    "src/common/MessageDispatcher.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\nimport {MessageLib} from \"src/common/libraries/MessageLib.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {\n    IRequestManagerGatewayHandler,\n    IPoolManagerGatewayHandler,\n    IBalanceSheetGatewayHandler,\n    IHubGatewayHandler\n} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {IVaultMessageSender, IPoolMessageSender, IRootMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {IMessageDispatcher} from \"src/common/interfaces/IMessageDispatcher.sol\";\nimport {ITokenRecoverer} from \"src/common/interfaces/ITokenRecoverer.sol\";\n\ncontract MessageDispatcher is Auth, IMessageDispatcher {\n    using CastLib for *;\n    using MessageLib for *;\n    using BytesLib for bytes;\n    using MathLib for uint256;\n\n    IRoot public immutable root;\n    IGateway public immutable gateway;\n    ITokenRecoverer public immutable tokenRecoverer;\n\n    uint16 public immutable localCentrifugeId;\n\n    IHubGatewayHandler public hub;\n    IPoolManagerGatewayHandler public poolManager;\n    IRequestManagerGatewayHandler public investmentManager;\n    IBalanceSheetGatewayHandler public balanceSheet;\n\n    constructor(\n        uint16 localCentrifugeId_,\n        IRoot root_,\n        IGateway gateway_,\n        ITokenRecoverer tokenRecoverer_,\n        address deployer\n    ) Auth(deployer) {\n        localCentrifugeId = localCentrifugeId_;\n        root = root_;\n        gateway = gateway_;\n        tokenRecoverer = tokenRecoverer_;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Administration\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IMessageDispatcher\n    function file(bytes32 what, address data) external auth {\n        if (what == \"hub\") hub = IHubGatewayHandler(data);\n        else if (what == \"poolManager\") poolManager = IPoolManagerGatewayHandler(data);\n        else if (what == \"investmentManager\") investmentManager = IRequestManagerGatewayHandler(data);\n        else if (what == \"balanceSheet\") balanceSheet = IBalanceSheetGatewayHandler(data);\n        else revert FileUnrecognizedParam();\n\n        emit File(what, data);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Helpers\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IMessageDispatcher\n    function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256 amount) {\n        if (centrifugeId == localCentrifugeId) return 0;\n        return gateway.estimate(centrifugeId, payload);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Outgoing\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IPoolMessageSender\n    function sendNotifyPool(uint16 centrifugeId, PoolId poolId) external auth {\n        if (centrifugeId == localCentrifugeId) {\n            poolManager.addPool(poolId);\n        } else {\n            gateway.send(centrifugeId, MessageLib.NotifyPool({poolId: poolId.raw()}).serialize());\n        }\n    }\n\n    /// @inheritdoc IPoolMessageSender\n    function sendNotifyShareClass(\n        uint16 centrifugeId,\n        PoolId poolId,\n        ShareClassId scId,\n        string memory name,\n        string memory symbol,\n        uint8 decimals,\n        bytes32 salt,\n        bytes32 hook\n    ) external auth {\n        if (centrifugeId == localCentrifugeId) {\n            poolManager.addShareClass(poolId, scId, name, symbol, decimals, salt, hook.toAddress());\n        } else {\n            gateway.send(\n                centrifugeId,\n                MessageLib.NotifyShareClass({\n                    poolId: poolId.raw(),\n                    scId: scId.raw(),\n                    name: name,\n                    symbol: symbol.toBytes32(),\n                    decimals: decimals,\n                    salt: salt,\n                    hook: hook\n                }).serialize()\n            );\n        }\n    }\n\n    /// @inheritdoc IPoolMessageSender\n    function sendNotifyShareMetadata(\n        uint16 centrifugeId,\n        PoolId poolId,\n        ShareClassId scId,\n        string memory name,\n        string memory symbol\n    ) external auth {\n        if (centrifugeId == localCentrifugeId) {\n            poolManager.updateShareMetadata(poolId, scId, name, symbol);\n        } else {\n            gateway.send(\n                centrifugeId,\n                MessageLib.NotifyShareMetadata({\n                    poolId: poolId.raw(),\n                    scId: scId.raw(),\n                    name: name,\n                    symbol: symbol.toBytes32()\n                }).serialize()\n            );\n        }\n    }\n\n    /// @inheritdoc IPoolMessageSender\n    function sendUpdateShareHook(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 hook) external auth {\n        if (centrifugeId == localCentrifugeId) {\n            poolManager.updateShareHook(poolId, scId, hook.toAddress());\n        } else {\n            gateway.send(\n                centrifugeId,\n                MessageLib.UpdateShareHook({poolId: poolId.raw(), scId: scId.raw(), hook: hook}).serialize()\n            );\n        }\n    }\n\n    /// @inheritdoc IPoolMessageSender\n    function sendNotifyPricePoolPerShare(uint16 chainId, PoolId poolId, ShareClassId scId, D18 sharePrice)\n        external\n        auth\n    {\n        uint64 timestamp = block.timestamp.toUint64();\n        if (chainId == localCentrifugeId) {\n            poolManager.updatePricePoolPerShare(poolId, scId, sharePrice.raw(), timestamp);\n        } else {\n            gateway.send(\n                chainId,\n                MessageLib.NotifyPricePoolPerShare({\n                    poolId: poolId.raw(),\n                    scId: scId.raw(),\n                    price: sharePrice.raw(),\n                    timestamp: timestamp\n                }).serialize()\n            );\n        }\n    }\n\n    function sendNotifyPricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, D18 price) external auth {\n        uint64 timestamp = block.timestamp.toUint64();\n        if (assetId.centrifugeId() == localCentrifugeId) {\n            poolManager.updatePricePoolPerAsset(poolId, scId, assetId, price.raw(), timestamp);\n        } else {\n            gateway.send(\n                assetId.centrifugeId(),\n                MessageLib.NotifyPricePoolPerAsset({\n                    poolId: poolId.raw(),\n                    scId: scId.raw(),\n                    assetId: assetId.raw(),\n                    price: price.raw(),\n                    timestamp: timestamp\n                }).serialize()\n            );\n        }\n    }\n\n    /// @inheritdoc IPoolMessageSender\n    function sendFulfilledDepositRequest(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        bytes32 investor,\n        uint128 assetAmount,\n        uint128 shareAmount\n    ) external auth {\n        if (assetId.centrifugeId() == localCentrifugeId) {\n            investmentManager.fulfillDepositRequest(\n                poolId, scId, investor.toAddress(), assetId, assetAmount, shareAmount\n            );\n        } else {\n            gateway.send(\n                assetId.centrifugeId(),\n                MessageLib.FulfilledDepositRequest({\n                    poolId: poolId.raw(),\n                    scId: scId.raw(),\n                    investor: investor,\n                    assetId: assetId.raw(),\n                    assetAmount: assetAmount,\n                    shareAmount: shareAmount\n                }).serialize()\n            );\n        }\n    }\n\n    /// @inheritdoc IPoolMessageSender\n    function sendFulfilledRedeemRequest(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        bytes32 investor,\n        uint128 assetAmount,\n        uint128 shareAmount\n    ) external auth {\n        if (assetId.centrifugeId() == localCentrifugeId) {\n            investmentManager.fulfillRedeemRequest(\n                poolId, scId, investor.toAddress(), assetId, assetAmount, shareAmount\n            );\n        } else {\n            gateway.send(\n                assetId.centrifugeId(),\n                MessageLib.FulfilledRedeemRequest({\n                    poolId: poolId.raw(),\n                    scId: scId.raw(),\n                    investor: investor,\n                    assetId: assetId.raw(),\n                    assetAmount: assetAmount,\n                    shareAmount: shareAmount\n                }).serialize()\n            );\n        }\n    }\n\n    /// @inheritdoc IPoolMessageSender\n    function sendFulfilledCancelDepositRequest(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        bytes32 investor,\n        uint128 cancelledAmount\n    ) external auth {\n        if (assetId.centrifugeId() == localCentrifugeId) {\n            investmentManager.fulfillCancelDepositRequest(\n                poolId, scId, investor.toAddress(), assetId, cancelledAmount, cancelledAmount\n            );\n        } else {\n            gateway.send(\n                assetId.centrifugeId(),\n                MessageLib.FulfilledCancelDepositRequest({\n                    poolId: poolId.raw(),\n                    scId: scId.raw(),\n                    investor: investor,\n                    assetId: assetId.raw(),\n                    cancelledAmount: cancelledAmount\n                }).serialize()\n            );\n        }\n    }\n\n    /// @inheritdoc IPoolMessageSender\n    function sendFulfilledCancelRedeemRequest(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        bytes32 investor,\n        uint128 cancelledShares\n    ) external auth {\n        if (assetId.centrifugeId() == localCentrifugeId) {\n            investmentManager.fulfillCancelRedeemRequest(poolId, scId, investor.toAddress(), assetId, cancelledShares);\n        } else {\n            gateway.send(\n                assetId.centrifugeId(),\n                MessageLib.FulfilledCancelRedeemRequest({\n                    poolId: poolId.raw(),\n                    scId: scId.raw(),\n                    investor: investor,\n                    assetId: assetId.raw(),\n                    cancelledShares: cancelledShares\n                }).serialize()\n            );\n        }\n    }\n\n    /// @inheritdoc IPoolMessageSender\n    function sendUpdateRestriction(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes calldata payload)\n        external\n        auth\n    {\n        if (centrifugeId == localCentrifugeId) {\n            poolManager.updateRestriction(poolId, scId, payload);\n        } else {\n            gateway.send(\n                centrifugeId,\n                MessageLib.UpdateRestriction({poolId: poolId.raw(), scId: scId.raw(), payload: payload}).serialize()\n            );\n        }\n    }\n\n    /// @inheritdoc IPoolMessageSender\n    function sendUpdateContract(\n        uint16 centrifugeId,\n        PoolId poolId,\n        ShareClassId scId,\n        bytes32 target,\n        bytes calldata payload\n    ) external auth {\n        if (centrifugeId == localCentrifugeId) {\n            poolManager.updateContract(poolId, scId, target.toAddress(), payload);\n        } else {\n            gateway.send(\n                centrifugeId,\n                MessageLib.UpdateContract({poolId: poolId.raw(), scId: scId.raw(), target: target, payload: payload})\n                    .serialize()\n            );\n        }\n    }\n\n    /// @inheritdoc IPoolMessageSender\n    function sendApprovedDeposits(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        uint128 assetAmount,\n        D18 pricePoolPerAsset\n    ) external auth {\n        if (assetId.centrifugeId() == localCentrifugeId) {\n            investmentManager.approvedDeposits(poolId, scId, assetId, assetAmount, pricePoolPerAsset);\n        } else {\n            gateway.send(\n                assetId.centrifugeId(),\n                MessageLib.ApprovedDeposits({\n                    poolId: poolId.raw(),\n                    scId: scId.raw(),\n                    assetId: assetId.raw(),\n                    assetAmount: assetAmount,\n                    pricePoolPerAsset: pricePoolPerAsset.raw()\n                }).serialize()\n            );\n        }\n    }\n\n    /// @inheritdoc IPoolMessageSender\n    function sendIssuedShares(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        uint128 shareAmount,\n        D18 pricePoolPerShare\n    ) external auth {\n        if (assetId.centrifugeId() == localCentrifugeId) {\n            investmentManager.issuedShares(poolId, scId, shareAmount, pricePoolPerShare);\n        } else {\n            gateway.send(\n                assetId.centrifugeId(),\n                MessageLib.IssuedShares({\n                    poolId: poolId.raw(),\n                    scId: scId.raw(),\n                    shareAmount: shareAmount,\n                    pricePoolPerShare: pricePoolPerShare.raw()\n                }).serialize()\n            );\n        }\n    }\n\n    /// @inheritdoc IPoolMessageSender\n    function sendRevokedShares(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        uint128 assetAmount,\n        uint128 shareAmount,\n        D18 pricePoolPerShare\n    ) external auth {\n        if (assetId.centrifugeId() == localCentrifugeId) {\n            investmentManager.revokedShares(poolId, scId, assetId, assetAmount, shareAmount, pricePoolPerShare);\n        } else {\n            gateway.send(\n                assetId.centrifugeId(),\n                MessageLib.RevokedShares({\n                    poolId: poolId.raw(),\n                    scId: scId.raw(),\n                    assetId: assetId.raw(),\n                    assetAmount: assetAmount,\n                    shareAmount: shareAmount,\n                    pricePoolPerShare: pricePoolPerShare.raw()\n                }).serialize()\n            );\n        }\n    }\n\n    /// @inheritdoc IPoolMessageSender\n    function sendTriggerIssueShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, address who, uint128 shares)\n        external\n        auth\n    {\n        if (centrifugeId == localCentrifugeId) {\n            balanceSheet.triggerIssueShares(poolId, scId, who, shares);\n        } else {\n            gateway.send(\n                centrifugeId,\n                MessageLib.TriggerIssueShares({\n                    poolId: poolId.raw(),\n                    scId: scId.raw(),\n                    who: who.toBytes32(),\n                    shares: shares\n                }).serialize()\n            );\n        }\n    }\n\n    /// @inheritdoc IPoolMessageSender\n    function sendTriggerSubmitQueuedShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId) external auth {\n        if (centrifugeId == localCentrifugeId) {\n            balanceSheet.submitQueuedShares(poolId, scId);\n        } else {\n            gateway.send(\n                centrifugeId, MessageLib.TriggerSubmitQueuedShares({poolId: poolId.raw(), scId: scId.raw()}).serialize()\n            );\n        }\n    }\n\n    /// @inheritdoc IPoolMessageSender\n    function sendTriggerSubmitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) external auth {\n        if (assetId.centrifugeId() == localCentrifugeId) {\n            balanceSheet.submitQueuedAssets(poolId, scId, assetId);\n        } else {\n            gateway.send(\n                assetId.centrifugeId(),\n                MessageLib.TriggerSubmitQueuedAssets({poolId: poolId.raw(), scId: scId.raw(), assetId: assetId.raw()})\n                    .serialize()\n            );\n        }\n    }\n\n    /// @inheritdoc IPoolMessageSender\n    function sendSetQueue(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bool enabled) external auth {\n        if (centrifugeId == localCentrifugeId) {\n            balanceSheet.setQueue(poolId, scId, enabled);\n        } else {\n            gateway.send(\n                centrifugeId,\n                MessageLib.SetQueue({poolId: poolId.raw(), scId: scId.raw(), enabled: enabled}).serialize()\n            );\n        }\n    }\n\n    /// @inheritdoc IRootMessageSender\n    function sendScheduleUpgrade(uint16 centrifugeId, bytes32 target) external auth {\n        if (centrifugeId == localCentrifugeId) {\n            root.scheduleRely(target.toAddress());\n        } else {\n            gateway.send(centrifugeId, MessageLib.ScheduleUpgrade({target: target}).serialize());\n        }\n    }\n\n    /// @inheritdoc IRootMessageSender\n    function sendCancelUpgrade(uint16 centrifugeId, bytes32 target) external auth {\n        if (centrifugeId == localCentrifugeId) {\n            root.cancelRely(target.toAddress());\n        } else {\n            gateway.send(centrifugeId, MessageLib.CancelUpgrade({target: target}).serialize());\n        }\n    }\n\n    /// @inheritdoc IRootMessageSender\n    function sendRecoverTokens(\n        uint16 centrifugeId,\n        bytes32 target,\n        bytes32 token,\n        uint256 tokenId,\n        bytes32 to,\n        uint256 amount\n    ) external auth {\n        if (centrifugeId == localCentrifugeId) {\n            tokenRecoverer.recoverTokens(\n                IRecoverable(target.toAddress()), token.toAddress(), tokenId, to.toAddress(), amount\n            );\n        } else {\n            gateway.send(\n                centrifugeId,\n                MessageLib.RecoverTokens({target: target, token: token, tokenId: tokenId, to: to, amount: amount})\n                    .serialize()\n            );\n        }\n    }\n\n    /// @inheritdoc IRootMessageSender\n    function sendInitiateRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, bytes32 adapter, bytes32 hash)\n        external\n        auth\n    {\n        if (centrifugeId == localCentrifugeId) {\n            gateway.initiateRecovery(adapterCentrifugeId, IAdapter(adapter.toAddress()), hash);\n        } else {\n            gateway.send(\n                centrifugeId,\n                MessageLib.InitiateRecovery({hash: hash, adapter: adapter, centrifugeId: adapterCentrifugeId}).serialize(\n                )\n            );\n        }\n    }\n\n    /// @inheritdoc IRootMessageSender\n    function sendDisputeRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, bytes32 adapter, bytes32 hash)\n        external\n        auth\n    {\n        if (centrifugeId == localCentrifugeId) {\n            gateway.disputeRecovery(adapterCentrifugeId, IAdapter(adapter.toAddress()), hash);\n        } else {\n            gateway.send(\n                centrifugeId,\n                MessageLib.DisputeRecovery({hash: hash, adapter: adapter, centrifugeId: adapterCentrifugeId}).serialize(\n                )\n            );\n        }\n    }\n\n    /// @inheritdoc IVaultMessageSender\n    function sendTransferShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 receiver, uint128 amount)\n        external\n        auth\n    {\n        if (centrifugeId == localCentrifugeId) {\n            poolManager.handleTransferShares(poolId, scId, receiver.toAddress(), amount);\n        } else {\n            gateway.send(\n                centrifugeId,\n                MessageLib.TransferShares({poolId: poolId.raw(), scId: scId.raw(), receiver: receiver, amount: amount})\n                    .serialize()\n            );\n        }\n    }\n\n    /// @inheritdoc IVaultMessageSender\n    function sendDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId, uint128 amount)\n        external\n        auth\n    {\n        if (poolId.centrifugeId() == localCentrifugeId) {\n            hub.depositRequest(poolId, scId, investor, assetId, amount);\n        } else {\n            gateway.send(\n                poolId.centrifugeId(),\n                MessageLib.DepositRequest({\n                    poolId: poolId.raw(),\n                    scId: scId.raw(),\n                    investor: investor,\n                    assetId: assetId.raw(),\n                    amount: amount\n                }).serialize()\n            );\n        }\n    }\n\n    /// @inheritdoc IVaultMessageSender\n    function sendRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId, uint128 amount)\n        external\n        auth\n    {\n        if (poolId.centrifugeId() == localCentrifugeId) {\n            hub.redeemRequest(poolId, scId, investor, assetId, amount);\n        } else {\n            gateway.send(\n                poolId.centrifugeId(),\n                MessageLib.RedeemRequest({\n                    poolId: poolId.raw(),\n                    scId: scId.raw(),\n                    investor: investor,\n                    assetId: assetId.raw(),\n                    amount: amount\n                }).serialize()\n            );\n        }\n    }\n\n    /// @inheritdoc IVaultMessageSender\n    function sendCancelDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId)\n        external\n        auth\n    {\n        if (poolId.centrifugeId() == localCentrifugeId) {\n            hub.cancelDepositRequest(poolId, scId, investor, assetId);\n        } else {\n            gateway.send(\n                poolId.centrifugeId(),\n                MessageLib.CancelDepositRequest({\n                    poolId: poolId.raw(),\n                    scId: scId.raw(),\n                    investor: investor,\n                    assetId: assetId.raw()\n                }).serialize()\n            );\n        }\n    }\n\n    /// @inheritdoc IVaultMessageSender\n    function sendCancelRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId)\n        external\n        auth\n    {\n        if (poolId.centrifugeId() == localCentrifugeId) {\n            hub.cancelRedeemRequest(poolId, scId, investor, assetId);\n        } else {\n            gateway.send(\n                poolId.centrifugeId(),\n                MessageLib.CancelRedeemRequest({\n                    poolId: poolId.raw(),\n                    scId: scId.raw(),\n                    investor: investor,\n                    assetId: assetId.raw()\n                }).serialize()\n            );\n        }\n    }\n\n    /// @inheritdoc IVaultMessageSender\n    function sendUpdateHoldingAmount(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        address provider,\n        uint128 amount,\n        D18 pricePoolPerAsset,\n        bool isIncrease\n    ) external auth {\n        if (poolId.centrifugeId() == localCentrifugeId) {\n            hub.updateHoldingAmount(poolId, scId, assetId, amount, pricePoolPerAsset, isIncrease);\n        } else {\n            gateway.send(\n                poolId.centrifugeId(),\n                MessageLib.UpdateHoldingAmount({\n                    poolId: poolId.raw(),\n                    scId: scId.raw(),\n                    assetId: assetId.raw(),\n                    who: provider.toBytes32(),\n                    amount: amount,\n                    pricePerUnit: pricePoolPerAsset.raw(),\n                    timestamp: uint64(block.timestamp),\n                    isIncrease: isIncrease\n                }).serialize()\n            );\n        }\n    }\n\n    /// @inheritdoc IVaultMessageSender\n    function sendUpdateShares(PoolId poolId, ShareClassId scId, uint128 shares, bool isIssuance) external auth {\n        if (poolId.centrifugeId() == localCentrifugeId) {\n            if (isIssuance) {\n                hub.increaseShareIssuance(poolId, scId, shares);\n            } else {\n                hub.decreaseShareIssuance(poolId, scId, shares);\n            }\n        } else {\n            gateway.send(\n                poolId.centrifugeId(),\n                MessageLib.UpdateShares({\n                    poolId: poolId.raw(),\n                    scId: scId.raw(),\n                    shares: shares,\n                    timestamp: uint64(block.timestamp),\n                    isIssuance: isIssuance\n                }).serialize()\n            );\n        }\n    }\n\n    /// @inheritdoc IVaultMessageSender\n    function sendRegisterAsset(uint16 centrifugeId, AssetId assetId, uint8 decimals) external auth {\n        if (centrifugeId == localCentrifugeId) {\n            hub.registerAsset(assetId, decimals);\n        } else {\n            gateway.send(\n                centrifugeId, MessageLib.RegisterAsset({assetId: assetId.raw(), decimals: decimals}).serialize()\n            );\n        }\n    }\n}\n"
    },
    "src/common/MessageProcessor.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\nimport {MessageType, MessageLib} from \"src/common/libraries/MessageLib.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\nimport {IMessageProcessor} from \"src/common/interfaces/IMessageProcessor.sol\";\nimport {IMessageProperties} from \"src/common/interfaces/IMessageProperties.sol\";\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {\n    IGatewayHandler,\n    IPoolManagerGatewayHandler,\n    IBalanceSheetGatewayHandler,\n    IHubGatewayHandler,\n    IRequestManagerGatewayHandler\n} from \"src/common/interfaces/IGatewayHandlers.sol\";\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ITokenRecoverer} from \"src/common/interfaces/ITokenRecoverer.sol\";\n\ncontract MessageProcessor is Auth, IMessageProcessor {\n    using CastLib for *;\n    using MessageLib for *;\n    using BytesLib for bytes;\n\n    IRoot public immutable root;\n    ITokenRecoverer public immutable tokenRecoverer;\n\n    IGatewayHandler public gateway;\n    IHubGatewayHandler public hub;\n    IPoolManagerGatewayHandler public poolManager;\n    IRequestManagerGatewayHandler public investmentManager;\n    IBalanceSheetGatewayHandler public balanceSheet;\n\n    constructor(IRoot root_, ITokenRecoverer tokenRecoverer_, address deployer) Auth(deployer) {\n        root = root_;\n        tokenRecoverer = tokenRecoverer_;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Administration\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IMessageProcessor\n    function file(bytes32 what, address data) external auth {\n        if (what == \"gateway\") gateway = IGatewayHandler(data);\n        else if (what == \"hub\") hub = IHubGatewayHandler(data);\n        else if (what == \"poolManager\") poolManager = IPoolManagerGatewayHandler(data);\n        else if (what == \"investmentManager\") investmentManager = IRequestManagerGatewayHandler(data);\n        else if (what == \"balanceSheet\") balanceSheet = IBalanceSheetGatewayHandler(data);\n        else revert FileUnrecognizedParam();\n\n        emit File(what, data);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Handlers\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IMessageHandler\n    function handle(uint16, bytes calldata message) external auth {\n        MessageType kind = message.messageType();\n\n        if (kind == MessageType.InitiateRecovery) {\n            MessageLib.InitiateRecovery memory m = message.deserializeInitiateRecovery();\n            gateway.initiateRecovery(m.centrifugeId, IAdapter(m.adapter.toAddress()), m.hash);\n        } else if (kind == MessageType.DisputeRecovery) {\n            MessageLib.DisputeRecovery memory m = message.deserializeDisputeRecovery();\n            gateway.disputeRecovery(m.centrifugeId, IAdapter(m.adapter.toAddress()), m.hash);\n        } else if (kind == MessageType.ScheduleUpgrade) {\n            MessageLib.ScheduleUpgrade memory m = message.deserializeScheduleUpgrade();\n            root.scheduleRely(m.target.toAddress());\n        } else if (kind == MessageType.CancelUpgrade) {\n            MessageLib.CancelUpgrade memory m = message.deserializeCancelUpgrade();\n            root.cancelRely(m.target.toAddress());\n        } else if (kind == MessageType.RecoverTokens) {\n            MessageLib.RecoverTokens memory m = message.deserializeRecoverTokens();\n            tokenRecoverer.recoverTokens(\n                IRecoverable(m.target.toAddress()), m.token.toAddress(), m.tokenId, m.to.toAddress(), m.amount\n            );\n        } else if (kind == MessageType.RegisterAsset) {\n            MessageLib.RegisterAsset memory m = message.deserializeRegisterAsset();\n            hub.registerAsset(AssetId.wrap(m.assetId), m.decimals);\n        } else if (kind == MessageType.NotifyPool) {\n            poolManager.addPool(PoolId.wrap(MessageLib.deserializeNotifyPool(message).poolId));\n        } else if (kind == MessageType.NotifyShareClass) {\n            MessageLib.NotifyShareClass memory m = MessageLib.deserializeNotifyShareClass(message);\n            poolManager.addShareClass(\n                PoolId.wrap(m.poolId),\n                ShareClassId.wrap(m.scId),\n                m.name,\n                m.symbol.toString(),\n                m.decimals,\n                m.salt,\n                m.hook.toAddress()\n            );\n        } else if (kind == MessageType.NotifyPricePoolPerShare) {\n            MessageLib.NotifyPricePoolPerShare memory m = MessageLib.deserializeNotifyPricePoolPerShare(message);\n            poolManager.updatePricePoolPerShare(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.price, m.timestamp);\n        } else if (kind == MessageType.NotifyPricePoolPerAsset) {\n            MessageLib.NotifyPricePoolPerAsset memory m = MessageLib.deserializeNotifyPricePoolPerAsset(message);\n            poolManager.updatePricePoolPerAsset(\n                PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), AssetId.wrap(m.assetId), m.price, m.timestamp\n            );\n        } else if (kind == MessageType.NotifyShareMetadata) {\n            MessageLib.NotifyShareMetadata memory m = MessageLib.deserializeNotifyShareMetadata(message);\n            poolManager.updateShareMetadata(\n                PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.name, m.symbol.toString()\n            );\n        } else if (kind == MessageType.UpdateShareHook) {\n            MessageLib.UpdateShareHook memory m = MessageLib.deserializeUpdateShareHook(message);\n            poolManager.updateShareHook(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.hook.toAddress());\n        } else if (kind == MessageType.TransferShares) {\n            MessageLib.TransferShares memory m = MessageLib.deserializeTransferShares(message);\n            poolManager.handleTransferShares(\n                PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.receiver.toAddress(), m.amount\n            );\n        } else if (kind == MessageType.UpdateRestriction) {\n            MessageLib.UpdateRestriction memory m = MessageLib.deserializeUpdateRestriction(message);\n            poolManager.updateRestriction(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.payload);\n        } else if (kind == MessageType.UpdateContract) {\n            MessageLib.UpdateContract memory m = MessageLib.deserializeUpdateContract(message);\n            poolManager.updateContract(\n                PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.target.toAddress(), m.payload\n            );\n        } else if (kind == MessageType.DepositRequest) {\n            MessageLib.DepositRequest memory m = message.deserializeDepositRequest();\n            hub.depositRequest(\n                PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.investor, AssetId.wrap(m.assetId), m.amount\n            );\n        } else if (kind == MessageType.RedeemRequest) {\n            MessageLib.RedeemRequest memory m = message.deserializeRedeemRequest();\n            hub.redeemRequest(\n                PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.investor, AssetId.wrap(m.assetId), m.amount\n            );\n        } else if (kind == MessageType.CancelDepositRequest) {\n            MessageLib.CancelDepositRequest memory m = message.deserializeCancelDepositRequest();\n            hub.cancelDepositRequest(\n                PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.investor, AssetId.wrap(m.assetId)\n            );\n        } else if (kind == MessageType.CancelRedeemRequest) {\n            MessageLib.CancelRedeemRequest memory m = message.deserializeCancelRedeemRequest();\n            hub.cancelRedeemRequest(\n                PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.investor, AssetId.wrap(m.assetId)\n            );\n        } else if (kind == MessageType.FulfilledDepositRequest) {\n            MessageLib.FulfilledDepositRequest memory m = message.deserializeFulfilledDepositRequest();\n            investmentManager.fulfillDepositRequest(\n                PoolId.wrap(m.poolId),\n                ShareClassId.wrap(m.scId),\n                m.investor.toAddress(),\n                AssetId.wrap(m.assetId),\n                m.assetAmount,\n                m.shareAmount\n            );\n        } else if (kind == MessageType.FulfilledRedeemRequest) {\n            MessageLib.FulfilledRedeemRequest memory m = message.deserializeFulfilledRedeemRequest();\n            investmentManager.fulfillRedeemRequest(\n                PoolId.wrap(m.poolId),\n                ShareClassId.wrap(m.scId),\n                m.investor.toAddress(),\n                AssetId.wrap(m.assetId),\n                m.assetAmount,\n                m.shareAmount\n            );\n        } else if (kind == MessageType.FulfilledCancelDepositRequest) {\n            MessageLib.FulfilledCancelDepositRequest memory m = message.deserializeFulfilledCancelDepositRequest();\n            investmentManager.fulfillCancelDepositRequest(\n                PoolId.wrap(m.poolId),\n                ShareClassId.wrap(m.scId),\n                m.investor.toAddress(),\n                AssetId.wrap(m.assetId),\n                m.cancelledAmount,\n                m.cancelledAmount\n            );\n        } else if (kind == MessageType.FulfilledCancelRedeemRequest) {\n            MessageLib.FulfilledCancelRedeemRequest memory m = message.deserializeFulfilledCancelRedeemRequest();\n            investmentManager.fulfillCancelRedeemRequest(\n                PoolId.wrap(m.poolId),\n                ShareClassId.wrap(m.scId),\n                m.investor.toAddress(),\n                AssetId.wrap(m.assetId),\n                m.cancelledShares\n            );\n        } else if (kind == MessageType.TriggerIssueShares) {\n            MessageLib.TriggerIssueShares memory m = message.deserializeTriggerIssueShares();\n            balanceSheet.triggerIssueShares(\n                PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.who.toAddress(), m.shares\n            );\n        } else if (kind == MessageType.UpdateHoldingAmount) {\n            MessageLib.UpdateHoldingAmount memory m = message.deserializeUpdateHoldingAmount();\n            hub.updateHoldingAmount(\n                PoolId.wrap(m.poolId),\n                ShareClassId.wrap(m.scId),\n                AssetId.wrap(m.assetId),\n                m.amount,\n                D18.wrap(m.pricePerUnit),\n                m.isIncrease\n            );\n        } else if (kind == MessageType.UpdateShares) {\n            MessageLib.UpdateShares memory m = message.deserializeUpdateShares();\n            if (m.isIssuance) {\n                hub.increaseShareIssuance(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.shares);\n            } else {\n                hub.decreaseShareIssuance(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.shares);\n            }\n        } else if (kind == MessageType.ApprovedDeposits) {\n            MessageLib.ApprovedDeposits memory m = message.deserializeApprovedDeposits();\n            investmentManager.approvedDeposits(\n                PoolId.wrap(m.poolId),\n                ShareClassId.wrap(m.scId),\n                AssetId.wrap(m.assetId),\n                m.assetAmount,\n                D18.wrap(m.pricePoolPerAsset)\n            );\n        } else if (kind == MessageType.IssuedShares) {\n            MessageLib.IssuedShares memory m = message.deserializeIssuedShares();\n            investmentManager.issuedShares(\n                PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.shareAmount, D18.wrap(m.pricePoolPerShare)\n            );\n        } else if (kind == MessageType.RevokedShares) {\n            MessageLib.RevokedShares memory m = message.deserializeRevokedShares();\n            investmentManager.revokedShares(\n                PoolId.wrap(m.poolId),\n                ShareClassId.wrap(m.scId),\n                AssetId.wrap(m.assetId),\n                m.assetAmount,\n                m.shareAmount,\n                D18.wrap(m.pricePoolPerShare)\n            );\n        } else if (kind == MessageType.TriggerSubmitQueuedShares) {\n            MessageLib.TriggerSubmitQueuedShares memory m = message.deserializeTriggerSubmitQueuedShares();\n            balanceSheet.submitQueuedShares(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId));\n        } else if (kind == MessageType.TriggerSubmitQueuedAssets) {\n            MessageLib.TriggerSubmitQueuedAssets memory m = message.deserializeTriggerSubmitQueuedAssets();\n            balanceSheet.submitQueuedAssets(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), AssetId.wrap(m.assetId));\n        } else if (kind == MessageType.SetQueue) {\n            MessageLib.SetQueue memory m = message.deserializeSetQueue();\n            balanceSheet.setQueue(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.enabled);\n        } else {\n            revert InvalidMessage(uint8(kind));\n        }\n    }\n\n    /// @inheritdoc IMessageProperties\n    function isMessageRecovery(bytes calldata message) external pure returns (bool) {\n        uint8 code = message.messageCode();\n        return code == uint8(MessageType.InitiateRecovery) || code == uint8(MessageType.DisputeRecovery);\n    }\n\n    /// @inheritdoc IMessageProperties\n    function messageLength(bytes calldata message) external pure returns (uint16) {\n        return message.messageLength();\n    }\n\n    /// @inheritdoc IMessageProperties\n    function messagePoolId(bytes calldata message) external pure returns (PoolId) {\n        return message.messagePoolId();\n    }\n}\n"
    },
    "src/common/Root.sol": {
      "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\n\n/// @title  Root\n/// @notice Core contract that is a ward on all other deployed contracts.\n/// @dev    Pausing can happen instantaneously, but relying on other contracts\n///         is restricted to the timelock set by the delay.\ncontract Root is Auth, IRoot {\n    /// @dev To prevent filing a delay that would block any updates indefinitely\n    uint256 internal constant MAX_DELAY = 4 weeks;\n\n    bool public paused;\n    uint256 public delay;\n    mapping(address => uint256) public endorsements;\n    mapping(address relyTarget => uint256 timestamp) public schedule;\n\n    constructor(uint256 _delay, address deployer) Auth(deployer) {\n        require(_delay <= MAX_DELAY, DelayTooLong());\n        delay = _delay;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Administration\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IRoot\n    function file(bytes32 what, uint256 data) external auth {\n        if (what == \"delay\") {\n            require(data <= MAX_DELAY, DelayTooLong());\n            delay = data;\n        } else {\n            revert FileUnrecognizedParam();\n        }\n        emit File(what, data);\n    }\n\n    /// @inheritdoc IRoot\n    function endorse(address user) external auth {\n        endorsements[user] = 1;\n        emit Endorse(user);\n    }\n\n    /// @inheritdoc IRoot\n    function veto(address user) external auth {\n        endorsements[user] = 0;\n        emit Veto(user);\n    }\n\n    /// @inheritdoc IRoot\n    function endorsed(address user) external view returns (bool) {\n        return endorsements[user] == 1;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Pause management\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IRoot\n    function pause() external auth {\n        paused = true;\n        emit Pause();\n    }\n\n    /// @inheritdoc IRoot\n    function unpause() external auth {\n        paused = false;\n        emit Unpause();\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Timelocked ward management\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IRoot\n    function scheduleRely(address target) external auth {\n        schedule[target] = block.timestamp + delay;\n        emit ScheduleRely(target, schedule[target]);\n    }\n\n    /// @inheritdoc IRoot\n    function cancelRely(address target) external auth {\n        require(schedule[target] != 0, TargetNotScheduled());\n        schedule[target] = 0;\n        emit CancelRely(target);\n    }\n\n    /// @inheritdoc IRoot\n    function executeScheduledRely(address target) external {\n        require(schedule[target] != 0, TargetNotScheduled());\n        require(schedule[target] <= block.timestamp, TargetNotReady());\n\n        wards[target] = 1;\n        emit Rely(target);\n\n        schedule[target] = 0;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // External contract ward management\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IRoot\n    function relyContract(address target, address user) external auth {\n        IAuth(target).rely(user);\n        emit RelyContract(target, user);\n    }\n\n    /// @inheritdoc IRoot\n    function denyContract(address target, address user) external auth {\n        IAuth(target).deny(user);\n        emit DenyContract(target, user);\n    }\n}\n"
    },
    "src/common/TokenRecoverer.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {ITokenRecoverer} from \"src/common/interfaces/ITokenRecoverer.sol\";\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\ncontract TokenRecoverer is Auth, ITokenRecoverer {\n    IRoot public immutable root;\n\n    constructor(IRoot root_, address deployer) Auth(deployer) {\n        root = root_;\n    }\n\n    /// @notice inheritdoc ITokenRecoverer\n    function recoverTokens(IRecoverable target, address token, uint256 tokenId, address to, uint256 amount)\n        external\n        auth\n    {\n        root.relyContract(address(target), address(this));\n\n        if (tokenId == 0) {\n            target.recoverTokens(token, to, amount);\n        } else {\n            target.recoverTokens(token, tokenId, to, amount);\n        }\n\n        root.denyContract(address(target), address(this));\n\n        emit RecoverTokens(target, token, tokenId, to, amount);\n    }\n}\n"
    },
    "src/common/adapters/AxelarAdapter.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {\n    IAxelarAdapter,\n    IAdapter,\n    IAxelarGateway,\n    IAxelarGasService,\n    AxelarSource,\n    AxelarDestination,\n    IAxelarExecutable\n} from \"src/common/interfaces/IAxelarAdapter.sol\";\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\n\n/// @title  Axelar Adapter\n/// @notice Routing contract that integrates with an Axelar Gateway\ncontract AxelarAdapter is Auth, IAxelarAdapter {\n    using CastLib for *;\n\n    IMessageHandler public immutable gateway;\n    IAxelarGateway public immutable axelarGateway;\n    IAxelarGasService public immutable axelarGasService;\n\n    mapping(string axelarId => AxelarSource) public sources;\n    mapping(uint16 centrifugeId => AxelarDestination) public destinations;\n\n    constructor(IMessageHandler gateway_, address axelarGateway_, address axelarGasService_, address deployer)\n        Auth(deployer)\n    {\n        gateway = gateway_;\n        axelarGateway = IAxelarGateway(axelarGateway_);\n        axelarGasService = IAxelarGasService(axelarGasService_);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Administration\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IAxelarAdapter\n    function file(bytes32 what, string calldata axelarId, uint16 centrifugeId, string calldata source) external auth {\n        if (what == \"sources\") sources[axelarId] = AxelarSource(centrifugeId, keccak256(bytes(source)));\n        else revert FileUnrecognizedParam();\n        emit File(what, axelarId, centrifugeId, source);\n    }\n\n    /// @inheritdoc IAxelarAdapter\n    function file(bytes32 what, uint16 centrifugeId, string calldata axelarId, string calldata destination)\n        external\n        auth\n    {\n        if (what == \"destinations\") destinations[centrifugeId] = AxelarDestination(axelarId, destination);\n        else revert FileUnrecognizedParam();\n        emit File(what, centrifugeId, axelarId, destination);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Incoming\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IAxelarExecutable\n    function execute(\n        bytes32 commandId,\n        string calldata sourceAxelarId,\n        string calldata sourceAddress,\n        bytes calldata payload\n    ) public {\n        AxelarSource memory source = sources[sourceAxelarId];\n        require(\n            source.addressHash != bytes32(\"\") && source.addressHash == keccak256(bytes(sourceAddress)), InvalidAddress()\n        );\n\n        require(\n            axelarGateway.validateContractCall(commandId, sourceAxelarId, sourceAddress, keccak256(payload)),\n            NotApprovedByGateway()\n        );\n\n        gateway.handle(source.centrifugeId, payload);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Outgoing\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IAdapter\n    function send(uint16 centrifugeId, bytes calldata payload, uint256, /* gasLimit */ address refund)\n        external\n        payable\n        returns (bytes32 adapterData)\n    {\n        require(msg.sender == address(gateway), NotGateway());\n        AxelarDestination memory destination = destinations[centrifugeId];\n        require(bytes(destination.axelarId).length != 0, UnknownChainId());\n\n        axelarGasService.payNativeGasForContractCall{value: msg.value}(\n            address(this), destination.axelarId, destination.addr, payload, refund\n        );\n\n        axelarGateway.callContract(destination.axelarId, destination.addr, payload);\n\n        adapterData = bytes32(\"\");\n    }\n\n    /// @inheritdoc IAdapter\n    function estimate(uint16 centrifugeId, bytes calldata payload, uint256 gasLimit) public view returns (uint256) {\n        AxelarDestination memory destination = destinations[centrifugeId];\n        return axelarGasService.estimateGasFee(destination.axelarId, destination.addr, payload, gasLimit, bytes(\"\"));\n    }\n}\n"
    },
    "src/common/adapters/WormholeAdapter.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\nimport {\n    IWormholeAdapter,\n    IAdapter,\n    IWormholeRelayer,\n    IWormholeDeliveryProvider,\n    IWormholeReceiver,\n    WormholeSource,\n    WormholeDestination\n} from \"src/common/interfaces/IWormholeAdapter.sol\";\n\n/// @title  Wormhole Adapter\n/// @notice Routing contract that integrates with the Wormhole Relayer service\ncontract WormholeAdapter is Auth, IWormholeAdapter {\n    using CastLib for bytes32;\n\n    uint16 public immutable localWormholeId;\n    IMessageHandler public immutable gateway;\n    IWormholeRelayer public immutable relayer;\n\n    mapping(uint16 wormholeId => WormholeSource) public sources;\n    mapping(uint16 centrifugeId => WormholeDestination) public destinations;\n\n    constructor(IMessageHandler gateway_, address relayer_, address deployer) Auth(deployer) {\n        gateway = gateway_;\n        relayer = IWormholeRelayer(relayer_);\n\n        IWormholeDeliveryProvider deliveryProvider = IWormholeDeliveryProvider(relayer.getDefaultDeliveryProvider());\n        localWormholeId = deliveryProvider.chainId();\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Administration\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IWormholeAdapter\n    function file(bytes32 what, uint16 centrifugeId, uint16 wormholeId, address addr) external auth {\n        if (what == \"sources\") sources[wormholeId] = WormholeSource(centrifugeId, addr);\n        else if (what == \"destinations\") destinations[centrifugeId] = WormholeDestination(wormholeId, addr);\n        else revert FileUnrecognizedParam();\n        emit File(what, centrifugeId, wormholeId, addr);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Incoming\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IWormholeReceiver\n    function receiveWormholeMessages(\n        bytes memory payload,\n        bytes[] memory, /* additionalVaas */\n        bytes32 sourceAddress,\n        uint16 sourceWormholeId,\n        bytes32 /* deliveryHash */\n    ) external payable {\n        WormholeSource memory source = sources[sourceWormholeId];\n        require(source.addr != address(0) && source.addr == sourceAddress.toAddressLeftPadded(), InvalidSource());\n        require(msg.sender == address(relayer), NotWormholeRelayer());\n\n        gateway.handle(source.centrifugeId, payload);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Outgoing\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IAdapter\n    function send(uint16 centrifugeId, bytes calldata payload, uint256 gasLimit, address refund)\n        external\n        payable\n        returns (bytes32 adapterData)\n    {\n        require(msg.sender == address(gateway), NotGateway());\n        WormholeDestination memory destination = destinations[centrifugeId];\n        require(destination.wormholeId != 0, UnknownChainId());\n\n        uint64 sequence = relayer.sendPayloadToEvm{value: msg.value}(\n            destination.wormholeId, destination.addr, payload, 0, gasLimit, localWormholeId, refund\n        );\n\n        adapterData = bytes32(bytes8(sequence));\n    }\n\n    /// @inheritdoc IAdapter\n    function estimate(uint16 centrifugeId, bytes calldata, uint256 gasLimit)\n        public\n        view\n        returns (uint256 nativePriceQuote)\n    {\n        (nativePriceQuote,) = relayer.quoteEVMDeliveryPrice(destinations[centrifugeId].wormholeId, 0, gasLimit);\n    }\n}\n"
    },
    "src/common/interfaces/IAdapter.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\n\ninterface IAdapter is IAuth {\n    error NotGateway();\n    error UnknownChainId();\n\n    /// @notice Send a payload to the destination chain\n    function send(uint16 centrifugeId, bytes calldata payload, uint256 gasLimit, address refund)\n        external\n        payable\n        returns (bytes32 adapterData);\n\n    /// @notice Estimate the total cost in native gas tokens\n    function estimate(uint16 centrifugeId, bytes calldata payload, uint256 gasLimit) external view returns (uint256);\n}\n"
    },
    "src/common/interfaces/IAxelarAdapter.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\n\n// From https://github.com/axelarnetwork/axelar-cgp-solidity/blob/main/contracts/interfaces/IAxelarGateway.sol\ninterface IAxelarGateway {\n    function callContract(string calldata destinationChain, string calldata contractAddress, bytes calldata payload)\n        external;\n\n    function validateContractCall(\n        bytes32 commandId,\n        string calldata sourceChain,\n        string calldata sourceAddress,\n        bytes32 payloadHash\n    ) external returns (bool);\n}\n\ninterface IAxelarGasService {\n    // From\n    // https://github.com/axelarnetwork/axelar-gmp-sdk-solidity/blob/00682b6c3db0cc922ec0c4ea3791852c93d7ae31/contracts/gas-estimation/InterchainGasEstimation.sol#L48\n    function estimateGasFee(\n        string calldata destinationChain,\n        string calldata destinationAddress,\n        bytes calldata payload,\n        uint256 executionGasLimit,\n        bytes calldata params\n    ) external view returns (uint256 gasEstimate);\n\n    // From https://github.com/axelarnetwork/axelar-cgp-solidity/blob/main/contracts/interfaces/IAxelarGasService.sol\n    function payNativeGasForContractCall(\n        address sender,\n        string calldata destinationChain,\n        string calldata destinationAddress,\n        bytes calldata payload,\n        address refundAddress\n    ) external payable;\n}\n\n// From\n// https://github.com/axelarnetwork/axelar-gmp-sdk-solidity/blob/00682b6c3db0cc922ec0c4ea3791852c93d7ae31/contracts/interfaces/IAxelarExecutable.sol#L14\ninterface IAxelarExecutable {\n    /**\n     * @dev Thrown when a function is called with an invalid address.\n     */\n    error InvalidAddress();\n\n    /**\n     * @dev Thrown when the call is not approved by the Axelar Gateway.\n     */\n    error NotApprovedByGateway();\n\n    /**\n     * @notice Executes the specified command sent from another chain.\n     * @dev This function is called by the Axelar Gateway to carry out cross-chain commands.\n     * Reverts if the call is not approved by the gateway or other checks fail.\n     * @param commandId The identifier of the command to execute.\n     * @param sourceChain The name of the source chain from where the command originated.\n     * @param sourceAddress The address on the source chain that sent the command.\n     * @param payload The payload of the command to be executed. This typically includes the function selector and\n     * encoded arguments.\n     */\n    function execute(\n        bytes32 commandId,\n        string calldata sourceChain,\n        string calldata sourceAddress,\n        bytes calldata payload\n    ) external;\n}\n\nstruct AxelarSource {\n    uint16 centrifugeId;\n    bytes32 addressHash;\n}\n\nstruct AxelarDestination {\n    string axelarId;\n    string addr;\n}\n\ninterface IAxelarAdapter is IAdapter, IAxelarExecutable {\n    event File(bytes32 indexed what, string axelarId, uint16 centrifugeId, string source);\n    event File(bytes32 indexed what, uint16 centrifugeId, string axelarId, string destination);\n\n    error FileUnrecognizedParam();\n\n    function file(bytes32 what, string calldata axelarId, uint16 centrifugeId, string calldata source) external;\n    function file(bytes32 what, uint16 centrifugeId, string calldata axelarId, string calldata destination) external;\n}\n"
    },
    "src/common/interfaces/IGasService.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\ninterface IGasService {\n    /// @notice Gas limit for the execution cost of an individual message in a remote chain.\n    /// @dev    NOTE: In the future we could want to dispatch:\n    ///         - by destination chain (for non-EVM chains)\n    ///         - by message type\n    ///         - by inspecting the payload checking different subsmessages that alter the endpoint processing\n    /// @param centrifugeId Where to the cost is defined\n    /// @param message Individual message\n    /// @return Estimated cost in WEI units\n    function gasLimit(uint16 centrifugeId, bytes calldata message) external view returns (uint128);\n\n    /// @notice Gas limit for the execution cost of a batch in a remote chain.\n    /// @param centrifugeId Where to the cost is defined\n    /// @return Max cost in WEI units\n    function maxBatchSize(uint16 centrifugeId) external view returns (uint128);\n}\n"
    },
    "src/common/interfaces/IGateway.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\nimport {IGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\nimport {IMessageSender} from \"src/common/interfaces/IMessageSender.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nuint8 constant MAX_ADAPTER_COUNT = 8;\n\n/// @notice Interface for dispatch-only gateway\ninterface IGateway is IMessageHandler, IMessageSender, IGatewayHandler {\n    /// @dev Each adapter struct is packed with the quorum to reduce SLOADs on handle\n    struct Adapter {\n        /// @notice Starts at 1 and maps to id - 1 as the index on the adapters array\n        uint8 id;\n        /// @notice Number of votes required for a message to be executed\n        uint8 quorum;\n        /// @notice Each time the quorum is decreased, a new session starts which invalidates old votes\n        uint64 activeSessionId;\n    }\n\n    struct InboundBatch {\n        /// @dev Counts are stored as integers (instead of boolean values) to accommodate duplicate\n        ///      messages (e.g. two investments from the same user with the same amount) being\n        ///      processed in parallel. The entire struct is packed in a single bytes32 slot.\n        ///      Max uint16 = 65,535 so at most 65,535 duplicate messages can be processed in parallel.\n        uint16[MAX_ADAPTER_COUNT] votes;\n        /// @notice Each time adapters are updated, a new session starts which invalidates old votes\n        uint64 sessionId;\n        bytes pendingBatch;\n    }\n\n    struct Funds {\n        /// @notice Funds associated to pay for sending messages\n        /// @dev    Overflows with type(uint64).max / 10**18 = 7.923 × 10^10 ETH\n        uint96 value;\n        /// @notice Address where to refund the remaining gas\n        IRecoverable refund;\n    }\n\n    // Used to bypass stack too deep issue\n    struct SendData {\n        bytes32 batchHash;\n        bytes32 payloadId;\n        uint256[] gasCost;\n    }\n\n    struct Underpaid {\n        uint128 counter;\n        uint128 gasLimit;\n    }\n\n    // --- Events ---\n    event PrepareMessage(uint16 indexed centrifugeId, PoolId poolId, bytes message);\n    event UnderpaidBatch(uint16 indexed centrifugeId, bytes batch);\n    event RepayBatch(uint16 indexed centrifugeId, bytes batch);\n    event SendBatch(\n        uint16 indexed centrifugeId,\n        bytes32 indexed payloadId,\n        bytes batch,\n        IAdapter adapter,\n        bytes32 adapterData,\n        address refund\n    );\n    event SendProof(\n        uint16 indexed centrifugeId, bytes32 indexed payloadId, bytes32 batchHash, IAdapter adapter, bytes32 adapterData\n    );\n    event HandleBatch(uint16 indexed centrifugeId, bytes32 indexed payloadId, bytes batch, IAdapter adapter);\n    event HandleProof(uint16 indexed centrifugeId, bytes32 indexed payloadId, bytes32 batchHash, IAdapter adapter);\n    event ExecuteMessage(uint16 indexed centrifugeId, bytes message);\n    event FailMessage(uint16 indexed centrifugeId, bytes message, bytes error);\n\n    event RecoverMessage(IAdapter adapter, bytes message);\n    event RecoverProof(IAdapter adapter, bytes32 batchHash);\n    event InitiateRecovery(uint16 centrifugeId, bytes32 batchHash, IAdapter adapter);\n    event DisputeRecovery(uint16 centrifugeId, bytes32 batchHash, IAdapter adapter);\n    event ExecuteRecovery(uint16 centrifugeId, bytes message, IAdapter adapter);\n\n    event File(bytes32 indexed what, uint16 centrifugeId, IAdapter[] adapters);\n    event File(bytes32 indexed what, address addr);\n\n    event SetRefundAddress(PoolId poolId, IRecoverable refund);\n    event SubsidizePool(PoolId indexed poolId, address indexed sender, uint256 amount);\n\n    /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n    error FileUnrecognizedParam();\n\n    /// @notice Dispatched when the batch is ended without starting it.\n    error NoBatched();\n\n    /// @notice Dispatched when the gateway is paused.\n    error Paused();\n\n    /// @notice Dispatched when the gateway is configured with a number of adapter exceeding the maximum.\n    error ExceedsMax();\n\n    /// @notice Dispatched when the gateway is configured with an empty adapter set.\n    error EmptyAdapterSet();\n\n    /// @notice Dispatched when the gateway is configured with duplicate adapters.\n    error NoDuplicatesAllowed();\n\n    /// @notice Dispatched when the gateway tries to handle a message from an adaptet not contained in the adapter set.\n    error InvalidAdapter();\n\n    /// @notice Dispatched when the gateway tries to recover a recovery message, which is not allowed.\n    error RecoveryPayloadRecovered();\n\n    /// @notice Dispatched when the gateway tries to handle a proof from a non proof adapter.\n    error NonProofAdapter();\n\n    /// @notice Dispatched when the gateway tries to handle a batch from a non message adapter.\n    error NonBatchAdapter();\n\n    /// @notice Dispatched when a recovery message is executed without being initiated.\n    error RecoveryNotInitiated();\n\n    /// @notice Dispatched when a recovery message is executed without waiting the challenge period.\n    error RecoveryChallengePeriodNotEnded();\n\n    /// @notice Dispatched when a the gateway tries to send an empty message.\n    error EmptyMessage();\n\n    /// @notice Dispatched when a the gateway has not enough fuel to send a message.\n    /// Only dispatched in PayTransaction method\n    error NotEnoughTransactionGas();\n\n    /// @notice Dispatched when a message that has not failed is retried.\n    error NotFailedMessage();\n\n    /// @notice Dispatched when a batch that has not been underpaid is repaid.\n    error NotUnderpaidBatch();\n\n    /// @notice Dispatched when a batch is repaid with insufficient funds.\n    error InsufficientFundsForRepayment();\n\n    /// @notice Dispatched when a message is added to a batch that causes it to exceed the max batch size.\n    error ExceedsMaxBatchSize();\n\n    /// @notice Dispatched when a refund address is not set.\n    error RefundAddressNotSet();\n\n    // --- Administration ---\n    /// @notice Used to update an array of addresses ( state variable ) on very rare occasions.\n    /// @dev    Currently it is used to update the supported adapters.\n    /// @param  what The name of the variable to be updated.\n    /// @param  centrifugeId Chain where the adapters are associated to.\n    /// @param  value New addresses.\n    function file(bytes32 what, uint16 centrifugeId, IAdapter[] calldata value) external;\n\n    /// @notice Used to update an address ( state variable ) on very rare occasions.\n    /// @dev    Currently used to update addresses of contract instances.\n    /// @param  what The name of the variable to be updated.\n    /// @param  data New address.\n    function file(bytes32 what, address data) external;\n\n    /// @notice Repay an underpaid batch. Send unused funds to subsidy pot of the pool.\n    function repay(uint16 centrifugeId, bytes memory batch) external payable;\n\n    /// @notice Retry a failed message.\n    function retry(uint16 centrifugeId, bytes memory message) external;\n\n    /// @notice Set the refund address for message associated to a poolId\n    function setRefundAddress(PoolId poolId, IRecoverable refund) external;\n\n    /// @notice Pay upfront to later be able to subsidize messages associated to a pool\n    function subsidizePool(PoolId poolId) external payable;\n\n    /// @notice Prepays for the TX cost for sending the messages through the adapters\n    ///         Currently being called from Vault Router only.\n    ///         In order to prepay, the method MUST be called with `msg.value`.\n    ///         Called is assumed to have called IGateway.estimate before calling this.\n    function payTransaction(address payer) external payable;\n\n    /// @notice Initialize batching message\n    function startBatching() external;\n\n    /// @notice Finalize batching messages and send the resulting batch message\n    function endBatching() external;\n\n    /// @notice Execute message recovery. After the challenge period, the recovery can be executed.\n    ///         If a malign adapter initiates message recovery,\n    ///         governance can dispute and immediately cancel the recovery, using any other valid adapter.\n    ///\n    ///         Only 1 recovery can be outstanding per message hash. If multiple adapters fail at the same time,\n    ///         these will need to be recovered serially (increasing the challenge period for each failed adapter).\n    /// @param  centrifugeId Chain where the adapter is configured for\n    /// @param  adapter Adapter's address that the recovery is targeting\n    /// @param  message Hash of the message to be recovered\n    function executeRecovery(uint16 centrifugeId, IAdapter adapter, bytes calldata message) external;\n\n    // --- Helpers ---\n    /// @notice A view method of the current quorum.abi\n    /// @dev    Quorum shows the amount of votes needed in order for a message to be dispatched further.\n    ///         The quorum is taken from the first adapter which is always the length of active adapters.\n    /// @param  centrifugeId Chain where the adapter is configured for\n    /// return  Needed amount\n    function quorum(uint16 centrifugeId) external view returns (uint8);\n\n    /// @notice Gets the current active routers session id.\n    /// @dev    When the adapters are updated with new ones,\n    ///         each new set of adapters has their own sessionId.\n    ///         Currently it uses sessionId of the previous set and\n    ///         increments it by 1. The idea of an activeSessionId is\n    ///         to invalidate any incoming messages from previously used adapters.\n    /// @param  centrifugeId Chain where the adapter is configured for\n    function activeSessionId(uint16 centrifugeId) external view returns (uint64);\n\n    /// @notice Counts how many times each incoming messages has been received per adapter.\n    /// @dev    It supports parallel messages ( duplicates ). That means that the incoming messages could be\n    ///         the result of two or more independ request from the user of the same type.\n    ///         i.e. Same user would like to deposit same underlying asset with the same amount more then once.\n    /// @param  centrifugeId Chain where the adapter is configured for\n    /// @param  batchHash The hash value of the incoming batch message.\n    function votes(uint16 centrifugeId, bytes32 batchHash) external view returns (uint16[MAX_ADAPTER_COUNT] memory);\n\n    /// @notice Used to calculate overall cost for bridging a payload on the first adapter and settling\n    ///         on the destination chain and bridging its payload proofs on n-1 adapter\n    ///         and settling on the destination chain.\n    /// @param  payload Used in gas cost calculations.\n    /// @dev    Currenly the payload is not taken into consideration.\n    /// @return total Total cost for sending one message and corresponding proofs on through all adapters\n    function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256 total);\n\n    /// @notice Returns the address of the adapter at the given id.\n    /// @param  centrifugeId Chain where the adapter is configured for\n    function adapters(uint16 centrifugeId, uint256 id) external view returns (IAdapter);\n\n    /// @notice Returns the timestamp when the given recovery can be executed.\n    /// @param  centrifugeId Chain where the adapter is configured for\n    function recoveries(uint16 centrifugeId, IAdapter adapter, bytes32 batchHash)\n        external\n        view\n        returns (uint256 timestamp);\n\n    /// @notice Returns the current gateway batching level.\n    function isBatching() external view returns (bool);\n}\n"
    },
    "src/common/interfaces/IGatewayHandlers.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18} from \"src/misc/types/D18.sol\";\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\n/// -----------------------------------------------------\n///  Common Handlers\n/// -----------------------------------------------------\n/// @notice Interface for Gateway methods called by messages\ninterface IGatewayHandler {\n    /// @notice Initialize the recovery of a payload.\n    /// @param  centrifugeId Chain where the adapter is configured for\n    /// @param  adapter Adapter that the recovery was targeting\n    /// @param  payloadHash Hash of the payload being disputed\n    function initiateRecovery(uint16 centrifugeId, IAdapter adapter, bytes32 payloadHash) external;\n\n    /// @notice Cancel the recovery of a payload.\n    /// @param  centrifugeId Chain where the adapter is configured for\n    /// @param  adapter Adapter that the recovery was targeting\n    /// @param  payloadHash Hash of the payload being disputed\n    function disputeRecovery(uint16 centrifugeId, IAdapter adapter, bytes32 payloadHash) external;\n}\n\n/// -----------------------------------------------------\n///  CP Handlers\n/// -----------------------------------------------------\n\n/// @notice Interface for CP methods called by messages\ninterface IHubGatewayHandler {\n    /// @notice Tells that an asset was already registered in CV, in order to perform the corresponding register.\n    function registerAsset(AssetId assetId, uint8 decimals) external;\n\n    /// @notice Perform a deposit that was requested from CV.\n    function depositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId, uint128 amount)\n        external;\n\n    /// @notice Perform a redeem that was requested from CV.\n    function redeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId, uint128 amount)\n        external;\n\n    /// @notice Perform a deposit cancellation that was requested from CV.\n    function cancelDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId)\n        external;\n\n    /// @notice Perform a redeem cancellation that was requested from CV.\n    function cancelRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId) external;\n\n    /// @notice Update a holding by request from CAL.\n    function updateHoldingAmount(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        uint128 amount,\n        D18 pricePoolPerAsset,\n        bool isIncrease\n    ) external;\n\n    /// @notice Increases the total issuance of shares by request from CAL.\n    function increaseShareIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external;\n\n    /// @notice Decreases the total issuance of shares by request from CAL.\n    function decreaseShareIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external;\n}\n\n/// -----------------------------------------------------\n///  CV Handlers\n/// -----------------------------------------------------\n\n/// @notice Interface for CV methods related to pools called by messages\ninterface IPoolManagerGatewayHandler {\n    /// @notice    New pool details from an existing Centrifuge pool are added.\n    /// @dev       The function can only be executed by the gateway contract.\n    function addPool(PoolId poolId) external;\n\n    /// @notice     New share class details from an existing Centrifuge pool are added.\n    /// @dev        The function can only be executed by the gateway contract.\n    function addShareClass(\n        PoolId poolId,\n        ShareClassId scId,\n        string memory tokenName,\n        string memory tokenSymbol,\n        uint8 decimals,\n        bytes32 salt,\n        address hook\n    ) external;\n\n    /// @notice   Updates the tokenName and tokenSymbol of a share class token\n    /// @dev      The function can only be executed by the gateway contract.\n    function updateShareMetadata(PoolId poolId, ShareClassId scId, string memory tokenName, string memory tokenSymbol)\n        external;\n\n    /// @notice  Updates the price of a share class token, i.e. the factor of pool currency amount per share class token\n    /// @dev     The function can only be executed by the gateway contract.\n    /// @param  poolId The pool id\n    /// @param  scId The share class id\n    /// @param  price The price of pool currency per share class token as factor.\n    /// @param  computedAt The timestamp when the price was computed\n    function updatePricePoolPerShare(PoolId poolId, ShareClassId scId, uint128 price, uint64 computedAt) external;\n\n    /// @notice  Updates the price of an asset, i.e. the factor of pool currency amount per asset unit\n    /// @dev     The function can only be executed by the gateway contract.\n    /// @param  poolId The pool id\n    /// @param  scId The share class id\n    /// @param  assetId The asset id\n    /// @param  poolPerAsset The price of pool currency per asset unit as factor.\n    /// @param  computedAt The timestamp when the price was computed\n    function updatePricePoolPerAsset(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        uint128 poolPerAsset,\n        uint64 computedAt\n    ) external;\n\n    /// @notice Updates the hook of a share class token\n    /// @param  poolId The centrifuge pool id\n    /// @param  scId The share class id\n    /// @param  hook The new hook addres\n    function updateShareHook(PoolId poolId, ShareClassId scId, address hook) external;\n\n    /// @notice Updates the restrictions on a share class token for a specific user\n    /// @param  poolId The centrifuge pool id\n    /// @param  scId The share class id\n    /// @param  update The restriction update in the form of a bytes array indicating\n    ///                the restriction to be updated, the user to be updated, and a validUntil timestamp.\n    function updateRestriction(PoolId poolId, ShareClassId scId, bytes memory update) external;\n\n    /// @notice Mints share class tokens to a recipient\n    /// @dev    The function can only be executed internally or by the gateway contract.\n    function handleTransferShares(PoolId poolId, ShareClassId scId, address destinationAddress, uint128 amount)\n        external;\n\n    /// @notice Updates the target address. Generic update function from CP to CV\n    /// @param  poolId The centrifuge pool id\n    /// @param  scId The share class id\n    /// @param  target The target address to be called\n    /// @param  update The payload to be processed by the target address\n    function updateContract(PoolId poolId, ShareClassId scId, address target, bytes memory update) external;\n}\n\n/// @notice Interface for CV methods related to async investments called by messages\ninterface IRequestManagerGatewayHandler {\n    /// @notice Signal from the Hub that an asynchronous investment order has been approved\n    ///\n    /// @dev This message needs to trigger making the asset amounts available to the pool-share-class.\n    function approvedDeposits(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        uint128 assetAmount,\n        D18 pricePoolPerAsset\n    ) external;\n\n    /// @notice Signal from the Hub that an asynchronous investment order has been finalized. Shares have been issued.\n    ///\n    /// @dev This message needs to trigger minting the new amount of shares.\n    function issuedShares(PoolId poolId, ShareClassId scId, uint128 shareAmount, D18 pricePoolPerShare) external;\n\n    /// @notice Signal from the Hub that an asynchronous redeem order has been finalized.\n    ///\n    /// @dev This messages needs to trigger reserving the asset amount for claims of redemptions by users.\n    function revokedShares(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        uint128 assetAmount,\n        uint128 shareAmount,\n        D18 pricePoolPerShare\n    ) external;\n\n    // --- Deposits ---\n    /// @notice Fulfills pending deposit requests after successful epoch execution on CP.\n    ///         The amount of shares that can be claimed by the user is minted and moved to the escrow contract.\n    ///         The MaxMint bookkeeping value is updated.\n    ///         The request fulfillment can be partial.\n    /// @dev    The shares in the escrow are reserved for the user and are transferred to the user on deposit\n    ///         and mint calls.\n    function fulfillDepositRequest(\n        PoolId poolId,\n        ShareClassId scId,\n        address user,\n        AssetId assetId,\n        uint128 assets,\n        uint128 shares\n    ) external;\n\n    /// @notice Fulfills deposit request cancellation after successful epoch execution on CP.\n    ///         The amount of assets that can be claimed by the user is locked in the escrow contract.\n    ///         Updates claimableCancelDepositRequest bookkeeping value. The cancellation order execution can be\n    ///         partial.\n    /// @dev    The assets in the escrow are reserved for the user and are transferred to the user during\n    ///         claimCancelDepositRequest calls.\n    ///         `fulfillment` represents the decrease in `pendingDepositRequest`.\n    ///         This is a separate parameter from `assets` since there can be some precision loss when calculating this,\n    ///         which would lead to having dust in the pendingDepositRequest value and\n    ///         never closing out the request even after it is technically fulfilled.\n    ///\n    ///         Example:\n    ///         User deposits 100 units of the vaults underlying asset.\n    ///         - At some point they make cancellation request. The order in which is not guaranteed\n    ///         Both requests arrive at CentrifugeChain. If the cancellation is first then all of the\n    ///         deposited amount will be cancelled.\n    ///\n    ///         - There is the case where the deposit event is first and it gets completely fulfilled then\n    ///         No amount of the deposited asset will be cancelled.\n    ///\n    ///         - There is the case where partially the deposit request is fulfilled. Let's say 40 units.\n    ///         Then the cancel request arrives.\n    ///         The remaining amount of deposited funds which is 60 units will cancelled.\n    ///         There is a scenario where the deposit funds might different from the pool currency so some\n    ///         swapping might happen. Either during this swapping or some fee collection or rounding there will be\n    ///         difference between the actual amount that will be returned to the user.\n    ///         `fulfillment` in this case will be 60 units but assets will be some lower amount because of the\n    ///         aforementioned reasons\n    ///         Let's assume the `asset` is 59. The user will be able to take back these 59 but\n    ///         in order to not let any dust, we use `fulfillment` in our calculations.\n    ///\n    ///         `pendingDepositRequest` not necessary gets zeroed during this cancellation event.\n    ///         When CentrifugeChain process the cancel event on its side, part of the deposit might be fulfilled.\n    ///         In such case the chain will send two messages, one `fulfillDepositRequest` and one\n    ///         `fulfillCancelDepositRequest`. In the example above, given the 100 units\n    ///         deposited, 40 units are fulfilled and 60 can be cancelled.\n    ///         The two messages sent from CentrifugeChain are not guaranteed to arrive in order.\n    ///\n    ///         Assuming first is the `fulfillCancelDepositRequest` the `pendingDepositRequest` here will be reduced to\n    ///         60 units only. Then the `fulfillCancelDepositRequest` arrives with `fulfillment` 60. This amount is\n    ///         removed from `pendingDepositRequests`. Since there are not more pendingDepositRequest` the\n    ///         `pendingCancelDepositRequest` gets deleted.\n    ///\n    ///         Assuming first the `fulfillCancelDepositRequest` arrives then the `pendingDepositRequest` will be 100.\n    ///         `fulfillment` is 60 so we are left with `pendingDepositRequest` equals to 40 ( 100 - 60 ).\n    ///         Then the second message arrives which is `fulfillDepositRequest`. ( Check `fulfillDepositRequest`\n    ///         implementation for details.)\n    ///         When it arrives the `pendingDepositRequest` is 40 and the assets is 40\n    ///         so there are no more `pendingDepositRequest` and right there the `pendingCancelDepositRequest will be\n    ///         deleted.\n    function fulfillCancelDepositRequest(\n        PoolId poolId,\n        ShareClassId scId,\n        address user,\n        AssetId assetId,\n        uint128 assets,\n        uint128 fulfillment\n    ) external;\n\n    // --- Redeems ---\n    /// @notice Fulfills pending redeem requests after successful epoch execution on CP.\n    ///         The amount of redeemed shares is burned. The amount of assets that can be claimed by the user in\n    ///         return is locked in the escrow contract. The MaxWithdraw bookkeeping value is updated.\n    ///         The request fulfillment can be partial.\n    /// @dev    The assets in the escrow are reserved for the user and are transferred to the user on redeem\n    ///         and withdraw calls.\n    function fulfillRedeemRequest(\n        PoolId poolId,\n        ShareClassId scId,\n        address user,\n        AssetId assetId,\n        uint128 assets,\n        uint128 shares\n    ) external;\n\n    /// @notice Fulfills redeem request cancellation after successful epoch execution on CP.\n    ///         The amount of shares that can be claimed by the user is locked in the escrow contract.\n    ///         Updates claimableCancelRedeemRequest bookkeeping value. The cancellation order execution can also be\n    ///         partial.\n    /// @dev    The shares in the escrow are reserved for the user and are transferred to the user during\n    ///         claimCancelRedeemRequest calls.\n    function fulfillCancelRedeemRequest(PoolId poolId, ShareClassId scId, address user, AssetId assetId, uint128 shares)\n        external;\n}\n\n/// @notice Interface for CV methods related to epoch called by messages\ninterface IBalanceSheetGatewayHandler {\n    function triggerDeposit(PoolId poolId, ShareClassId scId, AssetId assetId, address provider, uint128 amount)\n        external;\n\n    function triggerWithdraw(PoolId poolId, ShareClassId scId, AssetId assetId, address receiver, uint128 amount)\n        external;\n\n    function triggerIssueShares(PoolId poolId, ShareClassId scId, address to, uint128 shares) external;\n\n    function submitQueuedShares(PoolId poolId, ShareClassId scId) external;\n\n    function submitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) external;\n\n    function setQueue(PoolId poolId, ShareClassId scId, bool enabled) external;\n}\n"
    },
    "src/common/interfaces/IGatewaySenders.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18} from \"src/misc/types/D18.sol\";\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\ninterface ILocalCentrifugeId {\n    function localCentrifugeId() external view returns (uint16);\n}\n\n/// @notice Interface for dispatch-only gateway\ninterface IRootMessageSender {\n    /// @notice Creates and send the message\n    function sendScheduleUpgrade(uint16 centrifugeId, bytes32 target) external;\n\n    /// @notice Creates and send the message\n    function sendCancelUpgrade(uint16 centrifugeId, bytes32 target) external;\n\n    /// @notice Creates and send the message\n    function sendRecoverTokens(\n        uint16 centrifugeId,\n        bytes32 target,\n        bytes32 token,\n        uint256 tokenId,\n        bytes32 to,\n        uint256 amount\n    ) external;\n\n    /// @notice Creates and send the message\n    function sendInitiateRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, bytes32 adapter, bytes32 hash)\n        external;\n\n    /// @notice Creates and send the message\n    function sendDisputeRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, bytes32 adapter, bytes32 hash)\n        external;\n}\n\n/// @notice Interface for dispatch-only gateway\ninterface IPoolMessageSender is ILocalCentrifugeId {\n    /// @notice Creates and send the message\n    function sendNotifyPool(uint16 centrifugeId, PoolId poolId) external;\n\n    /// @notice Creates and send the message\n    function sendNotifyShareClass(\n        uint16 centrifugeId,\n        PoolId poolId,\n        ShareClassId scId,\n        string memory name,\n        string memory symbol,\n        uint8 decimals,\n        bytes32 salt,\n        bytes32 hook\n    ) external;\n\n    /// @notice Creates and send the message\n    function sendNotifyShareMetadata(\n        uint16 centrifugeId,\n        PoolId poolId,\n        ShareClassId scId,\n        string memory name,\n        string memory symbol\n    ) external;\n\n    /// @notice Creates and send the message\n    function sendUpdateShareHook(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 hook) external;\n\n    /// @notice Creates and send the message\n    function sendNotifyPricePoolPerShare(uint16 chainId, PoolId poolId, ShareClassId scId, D18 pricePerShare)\n        external;\n\n    /// @notice Creates and send the message\n    function sendNotifyPricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, D18 pricePerShare)\n        external;\n\n    /// @notice Creates and send the message\n    function sendFulfilledDepositRequest(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        bytes32 investor,\n        uint128 assetAmount,\n        uint128 shareAmount\n    ) external;\n\n    /// @notice Creates and send the message\n    function sendFulfilledRedeemRequest(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        bytes32 investor,\n        uint128 assetAmount,\n        uint128 shareAmount\n    ) external;\n\n    /// @notice Creates and send the message\n    function sendFulfilledCancelDepositRequest(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        bytes32 investor,\n        uint128 cancelledAmount\n    ) external;\n\n    /// @notice Creates and send the message\n    function sendFulfilledCancelRedeemRequest(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        bytes32 investor,\n        uint128 cancelledShares\n    ) external;\n\n    /// @notice Creates and send the message\n    function sendUpdateRestriction(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes calldata payload)\n        external;\n\n    /// @notice Creates and send the message\n    function sendUpdateContract(\n        uint16 centrifugeId,\n        PoolId poolId,\n        ShareClassId scId,\n        bytes32 target,\n        bytes calldata payload\n    ) external;\n\n    /// @notice Creates and send the message\n    function sendApprovedDeposits(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        uint128 assetAmount,\n        D18 pricePoolPerAsset\n    ) external;\n\n    // @notice Creates and send the message\n    function sendIssuedShares(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        uint128 shareAmount,\n        D18 pricePoolPerShare\n    ) external;\n\n    /// @notice Creates and send the message\n    function sendRevokedShares(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        uint128 assetAmount,\n        uint128 shareAmount,\n        D18 pricePoolPerShare\n    ) external;\n\n    /// @notice Creates and send the message\n    function sendTriggerIssueShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, address who, uint128 shares)\n        external;\n\n    /// @notice Creates and send the message\n    function sendTriggerSubmitQueuedShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId) external;\n\n    /// @notice Creates and send the message\n    function sendTriggerSubmitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) external;\n\n    /// @notice Creates and send the message\n    function sendSetQueue(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bool enabled) external;\n}\n\n/// @notice Interface for dispatch-only gateway\ninterface IVaultMessageSender is ILocalCentrifugeId {\n    /// @notice Creates and send the message\n    function sendTransferShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 receiver, uint128 amount)\n        external;\n\n    /// @notice Creates and send the message\n    function sendDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId, uint128 amount)\n        external;\n\n    /// @notice Creates and send the message\n    function sendRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId, uint128 amount)\n        external;\n\n    /// @notice Creates and send the message\n    function sendCancelDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId) external;\n\n    /// @notice Creates and send the message\n    function sendCancelRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId) external;\n\n    /// @notice Creates and send the message\n    function sendRegisterAsset(uint16 centrifugeId, AssetId assetId, uint8 decimals) external;\n\n    /// @notice Creates and send the message\n    function sendUpdateHoldingAmount(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        address provider,\n        uint128 amount,\n        D18 pricePoolPerAsset,\n        bool isIncrease\n    ) external;\n\n    /// @notice Creates and send the message\n    function sendUpdateShares(PoolId poolId, ShareClassId scId, uint128 shares, bool isIssuance) external;\n}\n"
    },
    "src/common/interfaces/IGuardian.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\n\ninterface ISafe {\n    function isOwner(address signer) external view returns (bool);\n}\n\ninterface IGuardian {\n    error NotTheAuthorizedSafe();\n    error NotTheAuthorizedSafeOrItsOwner();\n\n    /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n    error FileUnrecognizedParam();\n\n    /// @notice Emitted when a call to `file()` was performed.\n    event File(bytes32 indexed what, address addr);\n\n    /// @notice Return the linked Safe\n    function safe() external view returns (ISafe);\n\n    /// @notice Updates a contract parameter.\n    /// @param what Name of the parameter to update.\n    /// Accepts a `bytes32` representation of 'sender' string value.\n    /// @param data New value given to the `what` parameter\n    function file(bytes32 what, address data) external;\n\n    /// @notice Registers a new pool\n    function createPool(PoolId poolId, address admin, AssetId currency) external;\n\n    /// @notice Pause the protocol\n    /// @dev callable by both safe and owners\n    function pause() external;\n\n    /// @notice Unpause the protocol\n    /// @dev callable by safe only\n    function unpause() external;\n\n    /// @notice Schedule relying a target address on Root\n    /// @dev callable by safe only\n    function scheduleRely(address target) external;\n\n    /// @notice Cancel a scheduled rely\n    /// @dev callable by safe only\n    function cancelRely(address target) external;\n\n    /// @notice Schedule an upgrade (scheduled rely) on a specific chain\n    /// @dev    Only supports EVM targets today\n    function scheduleUpgrade(uint16 centrifugeId, address target) external;\n\n    /// @notice Cancel an upgrade (scheduled rely) on a specific chain\n    /// @dev    Only supports EVM targets today\n    function cancelUpgrade(uint16 centrifugeId, address target) external;\n\n    /// @notice Recover tokens on a specific chain\n    /// @dev    Only supports EVM targets today\n    function recoverTokens(\n        uint16 centrifugeId,\n        address target,\n        address token,\n        uint256 tokenId,\n        address to,\n        uint256 amount\n    ) external;\n\n    /// @notice Initiate a gateway payload recovery on a specific chain\n    /// @dev    Only supports EVM targets today\n    function initiateRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, IAdapter adapter, bytes32 hash)\n        external;\n\n    /// @notice Dispute a gateway paylaod recovery on a specific chain\n    /// @dev    Only supports EVM targets today\n    function disputeRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, IAdapter adapter, bytes32 hash)\n        external;\n}\n"
    },
    "src/common/interfaces/IGuardianActions.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\ninterface IHubGuardianActions {\n    /// @notice Creates a new pool. `msg.sender` will be the admin of the created pool.\n    /// @param currency The pool currency. Usually an AssetId identifying by a ISO4217 code.\n    function createPool(PoolId poolId, address admin, AssetId currency) external payable;\n}\n"
    },
    "src/common/interfaces/IHook.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nstruct HookData {\n    bytes16 from;\n    bytes16 to;\n}\n\nuint8 constant SUCCESS_CODE_ID = 0;\nstring constant SUCCESS_MESSAGE = \"transfer-allowed\";\n\nuint8 constant ERROR_CODE_ID = 1;\nstring constant ERROR_MESSAGE = \"transfer-blocked\";\n\n/// @dev Magic address denoting a transfer to the escrow\n/// @dev Solely used for gas saving since escrow is per pool\naddress constant ESCROW_HOOK_ID = address(uint160(uint8(0xce)));\n\n/// @notice Hook interface to customize share token behaviour\n/// @dev    To detect specific system actions:\n///           Deposit request:      address(0)      -> address(user)\n///           Deposit claim:        ESCROW_HOOK_ID  -> address(user)\n///           Redeem request:       address(user)   -> ESCROW_HOOK_ID\n///           Redeem claim:         address(user)   -> address(0)\n///           Cross-chain transfer: address(user)   -> address(uint160(chainId))\ninterface IHook is IERC165 {\n    // --- Errors ---\n    error TransferBlocked();\n    error InvalidUpdate();\n\n    /// @notice Callback on standard ERC20 transfer.\n    /// @dev    MUST return bytes4(keccak256(\"onERC20Transfer(address,address,uint256,(bytes16,bytes16))\"))\n    ///         if successful\n    function onERC20Transfer(address from, address to, uint256 value, HookData calldata hookdata)\n        external\n        returns (bytes4);\n\n    /// @notice Callback on authorized ERC20 transfer.\n    /// @dev    Cannot be blocked, can only be used to update state.\n    ///         Return value is ignored, only kept for compatibility with V2 share tokens.\n    function onERC20AuthTransfer(address sender, address from, address to, uint256 value, HookData calldata hookdata)\n        external\n        returns (bytes4);\n\n    /// @notice Check if given transfer can be performed\n    function checkERC20Transfer(address from, address to, uint256 value, HookData calldata hookData)\n        external\n        view\n        returns (bool);\n\n    /// @notice Update a set of restriction for a token\n    /// @dev    MAY be user specific, which would be included in the encoded `update` value\n    function updateRestriction(address token, bytes memory update) external;\n}\n"
    },
    "src/common/interfaces/IMessageDispatcher.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IVaultMessageSender, IPoolMessageSender, IRootMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\n\ninterface IMessageDispatcher is IRootMessageSender, IVaultMessageSender, IPoolMessageSender {\n    /// @notice Emitted when a call to `file()` was performed.\n    event File(bytes32 indexed what, address addr);\n\n    /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n    error FileUnrecognizedParam();\n\n    /// @notice Updates a contract parameter.\n    /// @param what Name of the parameter to update.\n    /// Accepts a `bytes32` representation of 'hubRegistry' string value.\n    /// @param data New value given to the `what` parameter\n    function file(bytes32 what, address data) external;\n\n    /// @notice Estimate sending a message through the gateway.\n    /// If the message is to the same centrifugeId, then the estimation is 0.\n    function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256 amount);\n}\n"
    },
    "src/common/interfaces/IMessageHandler.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/// @notice Generic interface for entities that handle incoming messages\ninterface IMessageHandler {\n    /// @notice Dispatched when an invalid message is trying to handle\n    error InvalidMessage(uint8 code);\n\n    /// @notice Handling incoming messages.\n    /// @param centrifugeId Source chain\n    /// @param message Incoming message\n    function handle(uint16 centrifugeId, bytes calldata message) external;\n}\n"
    },
    "src/common/interfaces/IMessageProcessor.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\nimport {IMessageProperties} from \"src/common/interfaces/IMessageProperties.sol\";\n\ninterface IMessageProcessor is IMessageHandler, IMessageProperties {\n    /// @notice Emitted when a call to `file()` was performed.\n    event File(bytes32 indexed what, address addr);\n\n    /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n    error FileUnrecognizedParam();\n\n    /// @notice Updates a contract parameter.\n    /// @param what Name of the parameter to update.\n    /// Accepts a `bytes32` representation of 'hubRegistry' string value.\n    /// @param data New value given to the `what` parameter\n    function file(bytes32 what, address data) external;\n}\n"
    },
    "src/common/interfaces/IMessageProperties.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\n/// @notice Defines methods to get properties from raw messages\ninterface IMessageProperties {\n    /// @notice Inspect the message to tell if the message is recovery message\n    function isMessageRecovery(bytes calldata message) external pure returns (bool);\n\n    /// @notice Inspect the message to return the length\n    function messageLength(bytes calldata message) external pure returns (uint16);\n\n    /// @notice Inspect the message to return the associated PoolId if any\n    function messagePoolId(bytes calldata message) external pure returns (PoolId);\n}\n"
    },
    "src/common/interfaces/IMessageSender.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/// @notice Generic interface for entities that handles outgoing messages\ninterface IMessageSender {\n    /// @notice Handling outgoing messages.\n    /// @param centrifugeId Destination chain\n    function send(uint16 centrifugeId, bytes calldata message) external;\n}\n"
    },
    "src/common/interfaces/IRoot.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\n\ninterface IRoot {\n    // --- Events ---\n    event File(bytes32 indexed what, uint256 data);\n    event Pause();\n    event Unpause();\n    event ScheduleRely(address indexed target, uint256 indexed scheduledTime);\n    event CancelRely(address indexed target);\n    event RelyContract(address indexed target, address indexed user);\n    event DenyContract(address indexed target, address indexed user);\n    event Endorse(address indexed user);\n    event Veto(address indexed user);\n\n    error DelayTooLong();\n    error FileUnrecognizedParam();\n    error TargetNotScheduled();\n    error TargetNotReady();\n\n    /// @notice Returns whether the root is paused\n    function paused() external view returns (bool);\n\n    /// @notice Returns the current timelock for adding new wards\n    function delay() external view returns (uint256);\n\n    /// @notice Trusted contracts within the system\n    function endorsements(address target) external view returns (uint256);\n\n    /// @notice Returns when `relyTarget` has passed the timelock\n    function schedule(address relyTarget) external view returns (uint256 timestamp);\n\n    // --- Administration ---\n    /// @notice Updates a contract parameter\n    /// @param what Accepts a bytes32 representation of 'delay'\n    function file(bytes32 what, uint256 data) external;\n\n    /// --- Endorsements ---\n    /// @notice Endorses the `user`\n    /// @dev    Endorsed users are trusted contracts in the system. They are allowed to bypass\n    ///         token restrictions (e.g. the Escrow can automatically receive share class tokens by being endorsed), and\n    ///         can automatically set operators in ERC-7540 vaults (e.g. the VaultRouter) is always an operator.\n    function endorse(address user) external;\n\n    /// @notice Removes the endorsed user\n    function veto(address user) external;\n\n    /// @notice Returns whether the user is endorsed\n    function endorsed(address user) external view returns (bool);\n\n    // --- Pause management ---\n    /// @notice Pause any contracts that depend on `Root.paused()`\n    function pause() external;\n\n    /// @notice Unpause any contracts that depend on `Root.paused()`\n    function unpause() external;\n\n    /// --- Timelocked ward management ---\n    /// @notice Schedule relying a new ward after the delay has passed\n    function scheduleRely(address target) external;\n\n    /// @notice Cancel a pending scheduled rely\n    function cancelRely(address target) external;\n\n    /// @notice Execute a scheduled rely\n    /// @dev    Can be triggered by anyone since the scheduling is protected\n    function executeScheduledRely(address target) external;\n\n    /// --- External contract ward management ---\n    /// @notice Make an address a ward on any contract that Root is a ward on\n    function relyContract(address target, address user) external;\n\n    /// @notice Removes an address as a ward on any contract that Root is a ward on\n    function denyContract(address target, address user) external;\n}\n"
    },
    "src/common/interfaces/ITokenRecoverer.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\ninterface ITokenRecoverer {\n    event RecoverTokens(\n        IRecoverable indexed target, address indexed token, uint256 tokenId, address indexed to, uint256 amount\n    );\n\n    function recoverTokens(IRecoverable target, address token, uint256 tokenId, address to, uint256 amount) external;\n}\n"
    },
    "src/common/interfaces/IWormholeAdapter.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\n\n// From https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/IWormholeRelayer.sol#L75\ninterface IWormholeRelayer {\n    /**\n     * @notice Publishes an instruction for the default delivery provider\n     * to relay a payload to the address `targetAddress` on chain `targetChain`\n     * with gas limit `gasLimit` and `msg.value` equal to `receiverValue`\n     *\n     * Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain`\n     * `targetAddress` must implement the IWormholeReceiver interface\n     *\n     * This function must be called with `msg.value` equal to `quoteEVMDeliveryPrice(targetChain, receiverValue,\n     * gasLimit)`\n     *\n     * @param targetChain in Wormhole Chain ID format\n     * @param targetAddress address to call on targetChain (that implements IWormholeReceiver)\n     * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`\n     * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain\n     * currency units)\n     * @param gasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according\n     * to the\n     *        `targetChainRefundPerGasUnused` rate quoted by the delivery provider\n     * @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format\n     * @param refundAddress The address on `refundChain` to deliver any refund to\n     * @return sequence sequence number of published VAA containing delivery instructions\n     */\n    function sendPayloadToEvm(\n        uint16 targetChain,\n        address targetAddress,\n        bytes memory payload,\n        uint256 receiverValue,\n        uint256 gasLimit,\n        uint16 refundChain,\n        address refundAddress\n    ) external payable returns (uint64 sequence);\n\n    /**\n     * @notice Returns the price to request a relay to chain `targetChain`, using the default delivery provider\n     *\n     * @param targetChain in Wormhole Chain ID format\n     * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain\n     * currency units)\n     * @param gasLimit gas limit with which to call `targetAddress`.\n     * @return nativePriceQuote Price, in units of current chain currency, that the delivery provider charges to perform\n     * the relay\n     * @return targetChainRefundPerGasUnused amount of target chain currency that will be refunded per unit of gas\n     * unused,\n     *         if a refundAddress is specified.\n     *         Note: This value can be overridden by the delivery provider on the target chain. The returned value here\n     * should be considered to be a\n     *         promise by the delivery provider of the amount of refund per gas unused that will be returned to the\n     * refundAddress at the target chain.\n     *         If a delivery provider decides to override, this will be visible as part of the emitted Delivery event on\n     * the target chain.\n     */\n    function quoteEVMDeliveryPrice(uint16 targetChain, uint256 receiverValue, uint256 gasLimit)\n        external\n        view\n        returns (uint256 nativePriceQuote, uint256 targetChainRefundPerGasUnused);\n\n    /**\n     * @notice Returns the address of the current default delivery provider\n     * @return deliveryProvider The address of (the default delivery provider)'s contract on this source\n     *   chain. This must be a contract that implements IDeliveryProvider.\n     */\n    function getDefaultDeliveryProvider() external view returns (address deliveryProvider);\n}\n\ninterface IWormholeDeliveryProvider {\n    /// @notice Returns the chain ID.\n    function chainId() external view returns (uint16);\n}\n\n// From\n// https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol\ninterface IWormholeReceiver {\n    /**\n     * @notice When a `send` is performed with this contract as the target, this function will be\n     *     invoked by the WormholeRelayer contract\n     *\n     * NOTE: This function should be restricted such that only the Wormhole Relayer contract can call it.\n     *\n     * We also recommend that this function checks that `sourceChain` and `sourceAddress` are indeed who\n     *       you expect to have requested the calling of `send` on the source chain\n     *\n     * The invocation of this function corresponding to the `send` request will have msg.value equal\n     *   to the receiverValue specified in the send request.\n     *\n     * If the invocation of this function reverts or exceeds the gas limit\n     *   specified by the send requester, this delivery will result in a `ReceiverFailure`.\n     *\n     * @param payload - an arbitrary message which was included in the delivery by the\n     *     requester. This message's signature will already have been verified (as long as msg.sender is the Wormhole\n     * Relayer contract)\n     * @param additionalMessages - Additional messages which were requested to be included in this delivery.\n     *      Note: There are no contract-level guarantees that the messages in this array are what was requested\n     *      so **you should verify any sensitive information given here!**\n     *\n     *      For example, if a 'VaaKey' was specified on the source chain, then MAKE SURE the corresponding message here\n     *      has valid signatures (by calling `parseAndVerifyVM(message)` on the Wormhole core contract)\n     *\n     *      This field can be used to perform and relay TokenBridge or CCTP transfers, and there are example\n     *      usages of this at\n     *         https://github.com/wormhole-foundation/hello-token\n     *         https://github.com/wormhole-foundation/hello-cctp\n     *\n     * @param sourceAddress - the (wormhole format) address on the sending chain which requested\n     *     this delivery.\n     * @param sourceChain - the wormhole chain ID where this delivery was requested.\n     * @param deliveryHash - the VAA hash of the deliveryVAA.\n     *\n     */\n    function receiveWormholeMessages(\n        bytes memory payload,\n        bytes[] memory additionalMessages,\n        bytes32 sourceAddress,\n        uint16 sourceChain,\n        bytes32 deliveryHash\n    ) external payable;\n}\n\nstruct WormholeSource {\n    uint16 centrifugeId;\n    address addr;\n}\n\nstruct WormholeDestination {\n    uint16 wormholeId;\n    address addr;\n}\n\ninterface IWormholeAdapter is IAdapter, IWormholeReceiver {\n    /// @dev see file() method\n    event File(bytes32 indexed what, uint16 fromChainId, uint16 toChainId, address addr);\n\n    error FileUnrecognizedParam();\n    error NotWormholeRelayer();\n    error InvalidSource();\n\n    /// @dev Configures the adapter\n    /// @param what Can be \"sources\" or \"destinations\".\n    /// @param addr if what == \"sources\", it represents the source\n    /// @param addr if what == \"destinations\", it represents the destination\n    function file(bytes32 what, uint16 centrifugeId, uint16 wormholeId, address addr) external;\n}\n"
    },
    "src/common/libraries/MessageLib.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nenum MessageType {\n    /// @dev Placeholder for null message type\n    _Invalid,\n    /// @dev Placeholder for proof message type\n    _MessageProof,\n    // -- Gateway messages\n    InitiateRecovery,\n    DisputeRecovery,\n    // -- Root messages\n    ScheduleUpgrade,\n    CancelUpgrade,\n    RecoverTokens,\n    // -- Pool manager messages\n    RegisterAsset,\n    NotifyPool,\n    NotifyShareClass,\n    NotifyPricePoolPerShare,\n    NotifyPricePoolPerAsset,\n    NotifyShareMetadata,\n    UpdateShareHook,\n    TransferShares,\n    UpdateRestriction,\n    UpdateContract,\n    ApprovedDeposits,\n    IssuedShares,\n    RevokedShares,\n    // -- Investment manager messages\n    DepositRequest,\n    RedeemRequest,\n    FulfilledDepositRequest,\n    FulfilledRedeemRequest,\n    CancelDepositRequest,\n    CancelRedeemRequest,\n    FulfilledCancelDepositRequest,\n    FulfilledCancelRedeemRequest,\n    // -- BalanceSheet messages\n    UpdateHoldingAmount,\n    UpdateShares,\n    TriggerIssueShares,\n    TriggerSubmitQueuedShares,\n    TriggerSubmitQueuedAssets,\n    SetQueue\n}\n\nenum UpdateRestrictionType {\n    /// @dev Placeholder for null update restriction type\n    Invalid,\n    Member,\n    Freeze,\n    Unfreeze\n}\n\nenum UpdateContractType {\n    /// @dev Placeholder for null update restriction type\n    Invalid,\n    VaultUpdate,\n    UpdateManager,\n    MaxAssetPriceAge,\n    MaxSharePriceAge,\n    Valuation,\n    SyncDepositMaxReserve\n}\n\n/// @dev Used internally in the VaultUpdateMessage (not represent a submessage)\nenum VaultUpdateKind {\n    DeployAndLink,\n    Link,\n    Unlink\n}\n\nlibrary MessageLib {\n    using MessageLib for bytes;\n    using BytesLib for bytes;\n    using CastLib for *;\n\n    error UnknownMessageType();\n\n    /// @dev Encode all message lengths in this constant to avoid a large list of if/elseif checks\n    /// and reduce generated bytecode.\n    /// If the message has some dynamic part, will be added later in `messageLength()`.\n    // forgefmt: disable-next-item\n    uint256 constant MESSAGE_LENGTHS_1 =\n        (67  << uint8(MessageType.InitiateRecovery) * 8) +\n        (67  << uint8(MessageType.DisputeRecovery) * 8) +\n        (33  << uint8(MessageType.ScheduleUpgrade) * 8) +\n        (33  << uint8(MessageType.CancelUpgrade) * 8) +\n        (161 << uint8(MessageType.RecoverTokens) * 8) +\n        (18  << uint8(MessageType.RegisterAsset) * 8) +\n        (9   << uint8(MessageType.NotifyPool) * 8) +\n        (250 << uint8(MessageType.NotifyShareClass) * 8) +\n        (49  << uint8(MessageType.NotifyPricePoolPerShare) * 8) +\n        (65  << uint8(MessageType.NotifyPricePoolPerAsset) * 8) +\n        (185 << uint8(MessageType.NotifyShareMetadata) * 8) +\n        (57  << uint8(MessageType.UpdateShareHook) * 8) +\n        (73  << uint8(MessageType.TransferShares) * 8) +\n        (25  << uint8(MessageType.UpdateRestriction) * 8) +\n        (57  << uint8(MessageType.UpdateContract) * 8) +\n        (73  << uint8(MessageType.ApprovedDeposits) * 8) +\n        (57  << uint8(MessageType.IssuedShares) * 8) +\n        (89  << uint8(MessageType.RevokedShares) * 8) +\n        (89  << uint8(MessageType.DepositRequest) * 8) +\n        (89  << uint8(MessageType.RedeemRequest) * 8) +\n        (105 << uint8(MessageType.FulfilledDepositRequest) * 8) +\n        (105 << uint8(MessageType.FulfilledRedeemRequest) * 8) +\n        (73  << uint8(MessageType.CancelDepositRequest) * 8) +\n        (73  << uint8(MessageType.CancelRedeemRequest) * 8) +\n        (89  << uint8(MessageType.FulfilledCancelDepositRequest) * 8) +\n        (89  << uint8(MessageType.FulfilledCancelRedeemRequest) * 8) +\n        (114 << uint8(MessageType.UpdateHoldingAmount) * 8) +\n        (50  << uint8(MessageType.UpdateShares) * 8) +\n        (73  << uint8(MessageType.TriggerIssueShares) * 8) +\n        (25  << uint8(MessageType.TriggerSubmitQueuedShares) * 8);\n\n    // forgefmt: disable-next-item\n    uint256 constant MESSAGE_LENGTHS_2 =\n        (41 << (uint8(MessageType.TriggerSubmitQueuedAssets) - 32) * 8) +\n        (26 << (uint8(MessageType.SetQueue) - 32) * 8);\n\n    function messageType(bytes memory message) internal pure returns (MessageType) {\n        return MessageType(message.toUint8(0));\n    }\n\n    function messageCode(bytes memory message) internal pure returns (uint8) {\n        return message.toUint8(0);\n    }\n\n    function messageLength(bytes memory message) internal pure returns (uint16 length) {\n        uint8 kind = message.toUint8(0);\n        require(kind <= uint8(type(MessageType).max), UnknownMessageType());\n\n        length = (kind <= 31)\n            ? uint16(uint8(bytes32(MESSAGE_LENGTHS_1)[31 - kind]))\n            : uint16(uint8(bytes32(MESSAGE_LENGTHS_2)[63 - kind]));\n\n        // Spetial treatment for messages with dynamic size:\n        if (kind == uint8(MessageType.UpdateRestriction)) {\n            length += 2 + message.toUint16(length); //payloadLength\n        } else if (kind == uint8(MessageType.UpdateContract)) {\n            length += 2 + message.toUint16(length); //payloadLength\n        }\n    }\n\n    function messagePoolId(bytes memory message) internal pure returns (PoolId poolId) {\n        uint8 kind = message.toUint8(0);\n\n        // All messages from NotifyPool to SetQueue contains a PoolId in position 1.\n        if (kind >= uint8(MessageType.NotifyPool) && kind <= uint8(MessageType.SetQueue)) {\n            return PoolId.wrap(message.toUint64(1));\n        } else {\n            return PoolId.wrap(0);\n        }\n    }\n\n    function updateRestrictionType(bytes memory message) internal pure returns (UpdateRestrictionType) {\n        return UpdateRestrictionType(message.toUint8(0));\n    }\n\n    function updateContractType(bytes memory message) internal pure returns (UpdateContractType) {\n        return UpdateContractType(message.toUint8(0));\n    }\n\n    //---------------------------------------\n    //    InitiateRecovery\n    //---------------------------------------\n\n    struct InitiateRecovery {\n        bytes32 hash;\n        bytes32 adapter;\n        uint16 centrifugeId;\n    }\n\n    function deserializeInitiateRecovery(bytes memory data) internal pure returns (InitiateRecovery memory) {\n        require(messageType(data) == MessageType.InitiateRecovery, UnknownMessageType());\n        return InitiateRecovery({hash: data.toBytes32(1), adapter: data.toBytes32(33), centrifugeId: data.toUint16(65)});\n    }\n\n    function serialize(InitiateRecovery memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(MessageType.InitiateRecovery, t.hash, t.adapter, t.centrifugeId);\n    }\n\n    //---------------------------------------\n    //    DisputeRecovery\n    //---------------------------------------\n\n    struct DisputeRecovery {\n        bytes32 hash;\n        bytes32 adapter;\n        uint16 centrifugeId;\n    }\n\n    function deserializeDisputeRecovery(bytes memory data) internal pure returns (DisputeRecovery memory) {\n        require(messageType(data) == MessageType.DisputeRecovery, UnknownMessageType());\n        return DisputeRecovery({hash: data.toBytes32(1), adapter: data.toBytes32(33), centrifugeId: data.toUint16(65)});\n    }\n\n    function serialize(DisputeRecovery memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(MessageType.DisputeRecovery, t.hash, t.adapter, t.centrifugeId);\n    }\n\n    //---------------------------------------\n    //    ScheduleUpgrade\n    //---------------------------------------\n\n    struct ScheduleUpgrade {\n        bytes32 target;\n    }\n\n    function deserializeScheduleUpgrade(bytes memory data) internal pure returns (ScheduleUpgrade memory) {\n        require(messageType(data) == MessageType.ScheduleUpgrade, UnknownMessageType());\n        return ScheduleUpgrade({target: data.toBytes32(1)});\n    }\n\n    function serialize(ScheduleUpgrade memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(MessageType.ScheduleUpgrade, t.target);\n    }\n\n    //---------------------------------------\n    //    CancelUpgrade\n    //---------------------------------------\n\n    struct CancelUpgrade {\n        bytes32 target;\n    }\n\n    function deserializeCancelUpgrade(bytes memory data) internal pure returns (CancelUpgrade memory) {\n        require(messageType(data) == MessageType.CancelUpgrade, UnknownMessageType());\n        return CancelUpgrade({target: data.toBytes32(1)});\n    }\n\n    function serialize(CancelUpgrade memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(MessageType.CancelUpgrade, t.target);\n    }\n\n    //---------------------------------------\n    //    RecoverTokens\n    //---------------------------------------\n\n    struct RecoverTokens {\n        bytes32 target;\n        bytes32 token;\n        uint256 tokenId;\n        bytes32 to;\n        uint256 amount;\n    }\n\n    function deserializeRecoverTokens(bytes memory data) internal pure returns (RecoverTokens memory) {\n        require(messageType(data) == MessageType.RecoverTokens, UnknownMessageType());\n        return RecoverTokens({\n            target: data.toBytes32(1),\n            token: data.toBytes32(33),\n            tokenId: data.toUint256(65),\n            to: data.toBytes32(97),\n            amount: data.toUint256(129)\n        });\n    }\n\n    function serialize(RecoverTokens memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(MessageType.RecoverTokens, t.target, t.token, t.tokenId, t.to, t.amount);\n    }\n\n    //---------------------------------------\n    //    RegisterAsset\n    //---------------------------------------\n\n    struct RegisterAsset {\n        uint128 assetId;\n        uint8 decimals;\n    }\n\n    function deserializeRegisterAsset(bytes memory data) internal pure returns (RegisterAsset memory) {\n        require(messageType(data) == MessageType.RegisterAsset, UnknownMessageType());\n        return RegisterAsset({assetId: data.toUint128(1), decimals: data.toUint8(17)});\n    }\n\n    function serialize(RegisterAsset memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(MessageType.RegisterAsset, t.assetId, t.decimals);\n    }\n\n    //---------------------------------------\n    //    NotifyPool\n    //---------------------------------------\n\n    struct NotifyPool {\n        uint64 poolId;\n    }\n\n    function deserializeNotifyPool(bytes memory data) internal pure returns (NotifyPool memory) {\n        require(messageType(data) == MessageType.NotifyPool, UnknownMessageType());\n        return NotifyPool({poolId: data.toUint64(1)});\n    }\n\n    function serialize(NotifyPool memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(MessageType.NotifyPool, t.poolId);\n    }\n\n    //---------------------------------------\n    //    NotifyShareClass\n    //---------------------------------------\n\n    struct NotifyShareClass {\n        uint64 poolId;\n        bytes16 scId;\n        string name; // Fixed to 128 bytes\n        bytes32 symbol; // utf8\n        uint8 decimals;\n        bytes32 salt;\n        bytes32 hook;\n    }\n\n    function deserializeNotifyShareClass(bytes memory data) internal pure returns (NotifyShareClass memory) {\n        require(messageType(data) == MessageType.NotifyShareClass, UnknownMessageType());\n        return NotifyShareClass({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            name: data.slice(25, 128).bytes128ToString(),\n            symbol: data.toBytes32(153),\n            decimals: data.toUint8(185),\n            salt: data.toBytes32(186),\n            hook: data.toBytes32(218)\n        });\n    }\n\n    function serialize(NotifyShareClass memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(\n            MessageType.NotifyShareClass,\n            t.poolId,\n            t.scId,\n            bytes(t.name).sliceZeroPadded(0, 128),\n            t.symbol,\n            t.decimals,\n            t.salt,\n            t.hook\n        );\n    }\n\n    //---------------------------------------\n    //    NotifyPricePoolPerShare\n    //---------------------------------------\n\n    struct NotifyPricePoolPerShare {\n        uint64 poolId;\n        bytes16 scId;\n        uint128 price;\n        uint64 timestamp;\n    }\n\n    function deserializeNotifyPricePoolPerShare(bytes memory data)\n        internal\n        pure\n        returns (NotifyPricePoolPerShare memory)\n    {\n        require(messageType(data) == MessageType.NotifyPricePoolPerShare, UnknownMessageType());\n        return NotifyPricePoolPerShare({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            price: data.toUint128(25),\n            timestamp: data.toUint64(41)\n        });\n    }\n\n    function serialize(NotifyPricePoolPerShare memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(MessageType.NotifyPricePoolPerShare, t.poolId, t.scId, t.price, t.timestamp);\n    }\n\n    //---------------------------------------\n    //    NotifyPricePoolPerAsset\n    //---------------------------------------\n\n    struct NotifyPricePoolPerAsset {\n        uint64 poolId;\n        bytes16 scId;\n        uint128 assetId;\n        uint128 price;\n        uint64 timestamp;\n    }\n\n    function deserializeNotifyPricePoolPerAsset(bytes memory data)\n        internal\n        pure\n        returns (NotifyPricePoolPerAsset memory)\n    {\n        require(messageType(data) == MessageType.NotifyPricePoolPerAsset, UnknownMessageType());\n        return NotifyPricePoolPerAsset({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            assetId: data.toUint128(25),\n            price: data.toUint128(41),\n            timestamp: data.toUint64(57)\n        });\n    }\n\n    function serialize(NotifyPricePoolPerAsset memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(MessageType.NotifyPricePoolPerAsset, t.poolId, t.scId, t.assetId, t.price, t.timestamp);\n    }\n\n    //---------------------------------------\n    //    NotifyShareMetadata\n    //---------------------------------------\n\n    struct NotifyShareMetadata {\n        uint64 poolId;\n        bytes16 scId;\n        string name; // Fixed to 128 bytes\n        bytes32 symbol; // utf8\n    }\n\n    function deserializeNotifyShareMetadata(bytes memory data) internal pure returns (NotifyShareMetadata memory) {\n        require(messageType(data) == MessageType.NotifyShareMetadata, UnknownMessageType());\n        return NotifyShareMetadata({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            name: data.slice(25, 128).bytes128ToString(),\n            symbol: data.toBytes32(153)\n        });\n    }\n\n    function serialize(NotifyShareMetadata memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(\n            MessageType.NotifyShareMetadata, t.poolId, t.scId, bytes(t.name).sliceZeroPadded(0, 128), t.symbol\n        );\n    }\n\n    //---------------------------------------\n    //    UpdateShareHook\n    //---------------------------------------\n\n    struct UpdateShareHook {\n        uint64 poolId;\n        bytes16 scId;\n        bytes32 hook;\n    }\n\n    function deserializeUpdateShareHook(bytes memory data) internal pure returns (UpdateShareHook memory) {\n        require(messageType(data) == MessageType.UpdateShareHook, UnknownMessageType());\n        return UpdateShareHook({poolId: data.toUint64(1), scId: data.toBytes16(9), hook: data.toBytes32(25)});\n    }\n\n    function serialize(UpdateShareHook memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(MessageType.UpdateShareHook, t.poolId, t.scId, t.hook);\n    }\n\n    //---------------------------------------\n    //    TransferShares\n    //---------------------------------------\n\n    struct TransferShares {\n        uint64 poolId;\n        bytes16 scId;\n        bytes32 receiver;\n        uint128 amount;\n    }\n\n    function deserializeTransferShares(bytes memory data) internal pure returns (TransferShares memory) {\n        require(messageType(data) == MessageType.TransferShares, UnknownMessageType());\n        return TransferShares({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            receiver: data.toBytes32(25),\n            amount: data.toUint128(57)\n        });\n    }\n\n    function serialize(TransferShares memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(MessageType.TransferShares, t.poolId, t.scId, t.receiver, t.amount);\n    }\n\n    //---------------------------------------\n    //    UpdateRestriction\n    //---------------------------------------\n\n    struct UpdateRestriction {\n        uint64 poolId;\n        bytes16 scId;\n        bytes payload; // As sequence of bytes\n    }\n\n    function deserializeUpdateRestriction(bytes memory data) internal pure returns (UpdateRestriction memory) {\n        require(messageType(data) == MessageType.UpdateRestriction, UnknownMessageType());\n\n        uint16 payloadLength = data.toUint16(25);\n        return UpdateRestriction({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            payload: data.slice(27, payloadLength)\n        });\n    }\n\n    function serialize(UpdateRestriction memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(MessageType.UpdateRestriction, t.poolId, t.scId, uint16(t.payload.length), t.payload);\n    }\n\n    //---------------------------------------\n    //    UpdateRestrictionMember (submsg)\n    //---------------------------------------\n\n    struct UpdateRestrictionMember {\n        bytes32 user;\n        uint64 validUntil;\n    }\n\n    function deserializeUpdateRestrictionMember(bytes memory data)\n        internal\n        pure\n        returns (UpdateRestrictionMember memory)\n    {\n        require(updateRestrictionType(data) == UpdateRestrictionType.Member, UnknownMessageType());\n\n        return UpdateRestrictionMember({user: data.toBytes32(1), validUntil: data.toUint64(33)});\n    }\n\n    function serialize(UpdateRestrictionMember memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(UpdateRestrictionType.Member, t.user, t.validUntil);\n    }\n\n    //---------------------------------------\n    //    UpdateRestrictionFreeze (submsg)\n    //---------------------------------------\n\n    struct UpdateRestrictionFreeze {\n        bytes32 user;\n    }\n\n    function deserializeUpdateRestrictionFreeze(bytes memory data)\n        internal\n        pure\n        returns (UpdateRestrictionFreeze memory)\n    {\n        require(updateRestrictionType(data) == UpdateRestrictionType.Freeze, UnknownMessageType());\n\n        return UpdateRestrictionFreeze({user: data.toBytes32(1)});\n    }\n\n    function serialize(UpdateRestrictionFreeze memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(UpdateRestrictionType.Freeze, t.user);\n    }\n\n    //---------------------------------------\n    //    UpdateRestrictionUnfreeze (submsg)\n    //---------------------------------------\n\n    struct UpdateRestrictionUnfreeze {\n        bytes32 user;\n    }\n\n    function deserializeUpdateRestrictionUnfreeze(bytes memory data)\n        internal\n        pure\n        returns (UpdateRestrictionUnfreeze memory)\n    {\n        require(updateRestrictionType(data) == UpdateRestrictionType.Unfreeze, UnknownMessageType());\n\n        return UpdateRestrictionUnfreeze({user: data.toBytes32(1)});\n    }\n\n    function serialize(UpdateRestrictionUnfreeze memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(UpdateRestrictionType.Unfreeze, t.user);\n    }\n\n    //---------------------------------------\n    //    UpdateContract\n    //---------------------------------------\n\n    struct UpdateContract {\n        uint64 poolId;\n        bytes16 scId;\n        bytes32 target;\n        bytes payload; // As sequence of bytes\n    }\n\n    function deserializeUpdateContract(bytes memory data) internal pure returns (UpdateContract memory) {\n        require(messageType(data) == MessageType.UpdateContract, UnknownMessageType());\n        uint16 payloadLength = data.toUint16(57);\n        return UpdateContract({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            target: data.toBytes32(25),\n            payload: data.slice(59, payloadLength)\n        });\n    }\n\n    function serialize(UpdateContract memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(\n            MessageType.UpdateContract, t.poolId, t.scId, t.target, uint16(t.payload.length), t.payload\n        );\n    }\n\n    //---------------------------------------\n    //   UpdateContract.VaultUpdate (submsg)\n    //---------------------------------------\n\n    struct UpdateContractVaultUpdate {\n        bytes32 vaultOrFactory;\n        uint128 assetId;\n        uint8 kind;\n    }\n\n    function deserializeUpdateContractVaultUpdate(bytes memory data)\n        internal\n        pure\n        returns (UpdateContractVaultUpdate memory)\n    {\n        require(updateContractType(data) == UpdateContractType.VaultUpdate, UnknownMessageType());\n\n        return UpdateContractVaultUpdate({\n            vaultOrFactory: data.toBytes32(1),\n            assetId: data.toUint128(33),\n            kind: data.toUint8(49)\n        });\n    }\n\n    function serialize(UpdateContractVaultUpdate memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(UpdateContractType.VaultUpdate, t.vaultOrFactory, t.assetId, t.kind);\n    }\n\n    //---------------------------------------\n    //   UpdateContract.UpdateManager (submsg)\n    //---------------------------------------\n\n    struct UpdateContractUpdateManager {\n        bytes32 who;\n        bool canManage;\n    }\n\n    function deserializeUpdateContractUpdateManager(bytes memory data)\n        internal\n        pure\n        returns (UpdateContractUpdateManager memory)\n    {\n        require(updateContractType(data) == UpdateContractType.UpdateManager, UnknownMessageType());\n\n        return UpdateContractUpdateManager({who: data.toBytes32(1), canManage: data.toBool(33)});\n    }\n\n    function serialize(UpdateContractUpdateManager memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(UpdateContractType.UpdateManager, t.who, t.canManage);\n    }\n\n    //---------------------------------------\n    //   UpdateContract.MaxAssetPriceAge (submsg)\n    //---------------------------------------\n\n    struct UpdateContractMaxAssetPriceAge {\n        uint128 assetId;\n        uint64 maxPriceAge;\n    }\n\n    function deserializeUpdateContractMaxAssetPriceAge(bytes memory data)\n        internal\n        pure\n        returns (UpdateContractMaxAssetPriceAge memory)\n    {\n        require(updateContractType(data) == UpdateContractType.MaxAssetPriceAge, UnknownMessageType());\n\n        return UpdateContractMaxAssetPriceAge({assetId: data.toUint128(1), maxPriceAge: data.toUint64(17)});\n    }\n\n    function serialize(UpdateContractMaxAssetPriceAge memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(UpdateContractType.MaxAssetPriceAge, t.assetId, t.maxPriceAge);\n    }\n\n    //---------------------------------------\n    //   UpdateContract.MaxSharePriceAge (submsg)\n    //---------------------------------------\n\n    struct UpdateContractMaxSharePriceAge {\n        uint64 maxPriceAge;\n    }\n\n    function deserializeUpdateContractMaxSharePriceAge(bytes memory data)\n        internal\n        pure\n        returns (UpdateContractMaxSharePriceAge memory)\n    {\n        require(updateContractType(data) == UpdateContractType.MaxSharePriceAge, UnknownMessageType());\n\n        return UpdateContractMaxSharePriceAge({maxPriceAge: data.toUint64(1)});\n    }\n\n    function serialize(UpdateContractMaxSharePriceAge memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(UpdateContractType.MaxSharePriceAge, t.maxPriceAge);\n    }\n\n    //---------------------------------------\n    //   UpdateContract.Valuation (submsg)\n    //---------------------------------------\n\n    struct UpdateContractValuation {\n        bytes32 valuation;\n    }\n\n    function deserializeUpdateContractValuation(bytes memory data)\n        internal\n        pure\n        returns (UpdateContractValuation memory)\n    {\n        require(updateContractType(data) == UpdateContractType.Valuation, UnknownMessageType());\n\n        return UpdateContractValuation({valuation: data.toBytes32(1)});\n    }\n\n    function serialize(UpdateContractValuation memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(UpdateContractType.Valuation, t.valuation);\n    }\n\n    //---------------------------------------\n    //   UpdateContract.SyncDepositMaxReserve (submsg)\n    //---------------------------------------\n\n    struct UpdateContractSyncDepositMaxReserve {\n        uint128 assetId;\n        uint128 maxReserve;\n    }\n\n    function deserializeUpdateContractSyncDepositMaxReserve(bytes memory data)\n        internal\n        pure\n        returns (UpdateContractSyncDepositMaxReserve memory)\n    {\n        require(updateContractType(data) == UpdateContractType.SyncDepositMaxReserve, UnknownMessageType());\n\n        return UpdateContractSyncDepositMaxReserve({assetId: data.toUint128(1), maxReserve: data.toUint128(17)});\n    }\n\n    function serialize(UpdateContractSyncDepositMaxReserve memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(UpdateContractType.SyncDepositMaxReserve, t.assetId, t.maxReserve);\n    }\n\n    //---------------------------------------\n    //    DepositRequest\n    //---------------------------------------\n\n    struct DepositRequest {\n        uint64 poolId;\n        bytes16 scId;\n        bytes32 investor;\n        uint128 assetId;\n        uint128 amount;\n    }\n\n    function deserializeDepositRequest(bytes memory data) internal pure returns (DepositRequest memory) {\n        require(messageType(data) == MessageType.DepositRequest, UnknownMessageType());\n        return DepositRequest({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            investor: data.toBytes32(25),\n            assetId: data.toUint128(57),\n            amount: data.toUint128(73)\n        });\n    }\n\n    function serialize(DepositRequest memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(MessageType.DepositRequest, t.poolId, t.scId, t.investor, t.assetId, t.amount);\n    }\n\n    //---------------------------------------\n    //    RedeemRequest\n    //---------------------------------------\n\n    struct RedeemRequest {\n        uint64 poolId;\n        bytes16 scId;\n        bytes32 investor;\n        uint128 assetId;\n        uint128 amount;\n    }\n\n    function deserializeRedeemRequest(bytes memory data) internal pure returns (RedeemRequest memory) {\n        require(messageType(data) == MessageType.RedeemRequest, UnknownMessageType());\n        return RedeemRequest({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            investor: data.toBytes32(25),\n            assetId: data.toUint128(57),\n            amount: data.toUint128(73)\n        });\n    }\n\n    function serialize(RedeemRequest memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(MessageType.RedeemRequest, t.poolId, t.scId, t.investor, t.assetId, t.amount);\n    }\n\n    //---------------------------------------\n    //    CancelDepositRequest\n    //---------------------------------------\n\n    struct CancelDepositRequest {\n        uint64 poolId;\n        bytes16 scId;\n        bytes32 investor;\n        uint128 assetId;\n    }\n\n    function deserializeCancelDepositRequest(bytes memory data) internal pure returns (CancelDepositRequest memory) {\n        require(messageType(data) == MessageType.CancelDepositRequest, UnknownMessageType());\n        return CancelDepositRequest({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            investor: data.toBytes32(25),\n            assetId: data.toUint128(57)\n        });\n    }\n\n    function serialize(CancelDepositRequest memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(MessageType.CancelDepositRequest, t.poolId, t.scId, t.investor, t.assetId);\n    }\n\n    //---------------------------------------\n    //    CancelRedeemRequest\n    //---------------------------------------\n\n    struct CancelRedeemRequest {\n        uint64 poolId;\n        bytes16 scId;\n        bytes32 investor;\n        uint128 assetId;\n    }\n\n    function deserializeCancelRedeemRequest(bytes memory data) internal pure returns (CancelRedeemRequest memory) {\n        require(messageType(data) == MessageType.CancelRedeemRequest, UnknownMessageType());\n        return CancelRedeemRequest({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            investor: data.toBytes32(25),\n            assetId: data.toUint128(57)\n        });\n    }\n\n    function serialize(CancelRedeemRequest memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(MessageType.CancelRedeemRequest, t.poolId, t.scId, t.investor, t.assetId);\n    }\n\n    //---------------------------------------\n    //    FulfilledDepositRequest\n    //---------------------------------------\n\n    struct FulfilledDepositRequest {\n        uint64 poolId;\n        bytes16 scId;\n        bytes32 investor;\n        uint128 assetId;\n        uint128 assetAmount;\n        uint128 shareAmount;\n    }\n\n    function deserializeFulfilledDepositRequest(bytes memory data)\n        internal\n        pure\n        returns (FulfilledDepositRequest memory)\n    {\n        require(messageType(data) == MessageType.FulfilledDepositRequest, UnknownMessageType());\n        return FulfilledDepositRequest({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            investor: data.toBytes32(25),\n            assetId: data.toUint128(57),\n            assetAmount: data.toUint128(73),\n            shareAmount: data.toUint128(89)\n        });\n    }\n\n    function serialize(FulfilledDepositRequest memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(\n            MessageType.FulfilledDepositRequest, t.poolId, t.scId, t.investor, t.assetId, t.assetAmount, t.shareAmount\n        );\n    }\n\n    //---------------------------------------\n    //    FulfilledRedeemRequest\n    //---------------------------------------\n\n    struct FulfilledRedeemRequest {\n        uint64 poolId;\n        bytes16 scId;\n        bytes32 investor;\n        uint128 assetId;\n        uint128 assetAmount;\n        uint128 shareAmount;\n    }\n\n    function deserializeFulfilledRedeemRequest(bytes memory data)\n        internal\n        pure\n        returns (FulfilledRedeemRequest memory)\n    {\n        require(messageType(data) == MessageType.FulfilledRedeemRequest, UnknownMessageType());\n        return FulfilledRedeemRequest({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            investor: data.toBytes32(25),\n            assetId: data.toUint128(57),\n            assetAmount: data.toUint128(73),\n            shareAmount: data.toUint128(89)\n        });\n    }\n\n    function serialize(FulfilledRedeemRequest memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(\n            MessageType.FulfilledRedeemRequest, t.poolId, t.scId, t.investor, t.assetId, t.assetAmount, t.shareAmount\n        );\n    }\n\n    //---------------------------------------\n    //    FulfilledCancelDepositRequest\n    //---------------------------------------\n\n    struct FulfilledCancelDepositRequest {\n        uint64 poolId;\n        bytes16 scId;\n        bytes32 investor;\n        uint128 assetId;\n        uint128 cancelledAmount;\n    }\n\n    function deserializeFulfilledCancelDepositRequest(bytes memory data)\n        internal\n        pure\n        returns (FulfilledCancelDepositRequest memory)\n    {\n        require(messageType(data) == MessageType.FulfilledCancelDepositRequest, UnknownMessageType());\n        return FulfilledCancelDepositRequest({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            investor: data.toBytes32(25),\n            assetId: data.toUint128(57),\n            cancelledAmount: data.toUint128(73)\n        });\n    }\n\n    function serialize(FulfilledCancelDepositRequest memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(\n            MessageType.FulfilledCancelDepositRequest, t.poolId, t.scId, t.investor, t.assetId, t.cancelledAmount\n        );\n    }\n\n    //---------------------------------------\n    //    FulfilledCancelRedeemRequest\n    //---------------------------------------\n\n    struct FulfilledCancelRedeemRequest {\n        uint64 poolId;\n        bytes16 scId;\n        bytes32 investor;\n        uint128 assetId;\n        uint128 cancelledShares;\n    }\n\n    function deserializeFulfilledCancelRedeemRequest(bytes memory data)\n        internal\n        pure\n        returns (FulfilledCancelRedeemRequest memory)\n    {\n        require(messageType(data) == MessageType.FulfilledCancelRedeemRequest, UnknownMessageType());\n        return FulfilledCancelRedeemRequest({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            investor: data.toBytes32(25),\n            assetId: data.toUint128(57),\n            cancelledShares: data.toUint128(73)\n        });\n    }\n\n    function serialize(FulfilledCancelRedeemRequest memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(\n            MessageType.FulfilledCancelRedeemRequest, t.poolId, t.scId, t.investor, t.assetId, t.cancelledShares\n        );\n    }\n\n    //---------------------------------------\n    //    UpdateHoldingAmount\n    //---------------------------------------\n\n    struct UpdateHoldingAmount {\n        uint64 poolId;\n        bytes16 scId;\n        uint128 assetId;\n        bytes32 who;\n        uint128 amount;\n        uint128 pricePerUnit;\n        uint64 timestamp;\n        bool isIncrease; // Signals whether this is an increase or a decrease\n    }\n\n    function deserializeUpdateHoldingAmount(bytes memory data) internal pure returns (UpdateHoldingAmount memory h) {\n        require(messageType(data) == MessageType.UpdateHoldingAmount, \"UnknownMessageType\");\n\n        return UpdateHoldingAmount({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            assetId: data.toUint128(25),\n            who: data.toBytes32(41),\n            amount: data.toUint128(73),\n            pricePerUnit: data.toUint128(89),\n            timestamp: data.toUint64(105),\n            isIncrease: data.toBool(113)\n        });\n    }\n\n    function serialize(UpdateHoldingAmount memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(\n            MessageType.UpdateHoldingAmount,\n            t.poolId,\n            t.scId,\n            t.assetId,\n            t.who,\n            t.amount,\n            t.pricePerUnit,\n            t.timestamp,\n            t.isIncrease\n        );\n    }\n\n    //---------------------------------------\n    //    UpdateShares\n    //---------------------------------------\n\n    struct UpdateShares {\n        uint64 poolId;\n        bytes16 scId;\n        uint128 shares;\n        uint64 timestamp;\n        bool isIssuance;\n    }\n\n    function deserializeUpdateShares(bytes memory data) internal pure returns (UpdateShares memory) {\n        require(messageType(data) == MessageType.UpdateShares, UnknownMessageType());\n\n        return UpdateShares({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            shares: data.toUint128(25),\n            timestamp: data.toUint64(41),\n            isIssuance: data.toBool(49)\n        });\n    }\n\n    function serialize(UpdateShares memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(MessageType.UpdateShares, t.poolId, t.scId, t.shares, t.timestamp, t.isIssuance);\n    }\n\n    //---------------------------------------\n    //    ApprovedDeposits\n    //---------------------------------------\n\n    struct ApprovedDeposits {\n        uint64 poolId;\n        bytes16 scId;\n        uint128 assetId;\n        uint128 assetAmount;\n        uint128 pricePoolPerAsset;\n    }\n\n    function deserializeApprovedDeposits(bytes memory data) internal pure returns (ApprovedDeposits memory) {\n        require(messageType(data) == MessageType.ApprovedDeposits, UnknownMessageType());\n\n        return ApprovedDeposits({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            assetId: data.toUint128(25),\n            assetAmount: data.toUint128(41),\n            pricePoolPerAsset: data.toUint128(57)\n        });\n    }\n\n    function serialize(ApprovedDeposits memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(\n            MessageType.ApprovedDeposits, t.poolId, t.scId, t.assetId, t.assetAmount, t.pricePoolPerAsset\n        );\n    }\n\n    //---------------------------------------\n    //    IssuedShares\n    //---------------------------------------\n\n    struct IssuedShares {\n        uint64 poolId;\n        bytes16 scId;\n        uint128 shareAmount;\n        uint128 pricePoolPerShare;\n    }\n\n    function deserializeIssuedShares(bytes memory data) internal pure returns (IssuedShares memory) {\n        require(messageType(data) == MessageType.IssuedShares, UnknownMessageType());\n\n        return IssuedShares({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            shareAmount: data.toUint128(25),\n            pricePoolPerShare: data.toUint128(41)\n        });\n    }\n\n    function serialize(IssuedShares memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(MessageType.IssuedShares, t.poolId, t.scId, t.shareAmount, t.pricePoolPerShare);\n    }\n\n    //---------------------------------------\n    //    RevokedShares\n    //---------------------------------------\n\n    struct RevokedShares {\n        uint64 poolId;\n        bytes16 scId;\n        uint128 assetId;\n        uint128 shareAmount;\n        uint128 pricePoolPerShare;\n        uint128 assetAmount;\n    }\n\n    function deserializeRevokedShares(bytes memory data) internal pure returns (RevokedShares memory) {\n        require(messageType(data) == MessageType.RevokedShares, UnknownMessageType());\n\n        return RevokedShares({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            assetId: data.toUint128(25),\n            assetAmount: data.toUint128(41),\n            shareAmount: data.toUint128(57),\n            pricePoolPerShare: data.toUint128(73)\n        });\n    }\n\n    function serialize(RevokedShares memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(\n            MessageType.RevokedShares, t.poolId, t.scId, t.assetId, t.assetAmount, t.shareAmount, t.pricePoolPerShare\n        );\n    }\n\n    //---------------------------------------\n    //    TriggerIssueShares\n    //---------------------------------------\n\n    struct TriggerIssueShares {\n        uint64 poolId;\n        bytes16 scId;\n        bytes32 who;\n        uint128 shares;\n    }\n\n    function deserializeTriggerIssueShares(bytes memory data) internal pure returns (TriggerIssueShares memory) {\n        require(messageType(data) == MessageType.TriggerIssueShares, UnknownMessageType());\n\n        return TriggerIssueShares({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            who: data.toBytes32(25),\n            shares: data.toUint128(57)\n        });\n    }\n\n    function serialize(TriggerIssueShares memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(MessageType.TriggerIssueShares, t.poolId, t.scId, t.who, t.shares);\n    }\n\n    //---------------------------------------\n    //    TriggerSubmitQueuedShares\n    //---------------------------------------\n\n    struct TriggerSubmitQueuedShares {\n        uint64 poolId;\n        bytes16 scId;\n    }\n\n    function deserializeTriggerSubmitQueuedShares(bytes memory data)\n        internal\n        pure\n        returns (TriggerSubmitQueuedShares memory)\n    {\n        require(messageType(data) == MessageType.TriggerSubmitQueuedShares, UnknownMessageType());\n        return TriggerSubmitQueuedShares({poolId: data.toUint64(1), scId: data.toBytes16(9)});\n    }\n\n    function serialize(TriggerSubmitQueuedShares memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(MessageType.TriggerSubmitQueuedShares, t.poolId, t.scId);\n    }\n\n    //---------------------------------------\n    //    TriggerSubmitQueuedAssets\n    //---------------------------------------\n\n    struct TriggerSubmitQueuedAssets {\n        uint64 poolId;\n        bytes16 scId;\n        uint128 assetId;\n    }\n\n    function deserializeTriggerSubmitQueuedAssets(bytes memory data)\n        internal\n        pure\n        returns (TriggerSubmitQueuedAssets memory)\n    {\n        require(messageType(data) == MessageType.TriggerSubmitQueuedAssets, UnknownMessageType());\n        return\n            TriggerSubmitQueuedAssets({poolId: data.toUint64(1), scId: data.toBytes16(9), assetId: data.toUint128(25)});\n    }\n\n    function serialize(TriggerSubmitQueuedAssets memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(MessageType.TriggerSubmitQueuedAssets, t.poolId, t.scId, t.assetId);\n    }\n\n    //---------------------------------------\n    //    SetQueue\n    //---------------------------------------\n\n    struct SetQueue {\n        uint64 poolId;\n        bytes16 scId;\n        bool enabled;\n    }\n\n    function deserializeSetQueue(bytes memory data) internal pure returns (SetQueue memory) {\n        require(messageType(data) == MessageType.SetQueue, UnknownMessageType());\n        return SetQueue({poolId: data.toUint64(1), scId: data.toBytes16(9), enabled: data.toBool(25)});\n    }\n\n    function serialize(SetQueue memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(MessageType.SetQueue, t.poolId, t.scId, t.enabled);\n    }\n}\n"
    },
    "src/common/libraries/MessageProofLib.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\n\nlibrary MessageProofLib {\n    using BytesLib for bytes;\n\n    uint8 constant MESSAGE_PROOF_ID = 1;\n\n    error UnknownMessageProofType();\n\n    function deserializeMessageProof(bytes memory data) internal pure returns (bytes32) {\n        require(data.toUint8(0) == MESSAGE_PROOF_ID, UnknownMessageProofType());\n        return data.toBytes32(1);\n    }\n\n    function serializeMessageProof(bytes32 hash) internal pure returns (bytes memory) {\n        return abi.encodePacked(MESSAGE_PROOF_ID, hash);\n    }\n}\n"
    },
    "src/common/libraries/PricingLib.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IERC20Metadata} from \"src/misc/interfaces/IERC20.sol\";\nimport {IERC6909MetadataExt} from \"src/misc/interfaces/IERC6909.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\n\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\nlibrary PricingLib {\n    using MathLib for *;\n\n    /// @dev Prices are fixed-point integers with 18 decimals\n    uint8 internal constant PRICE_DECIMALS = 18;\n\n    /// -----------------------------------------------------\n    ///  View Methods\n    /// -----------------------------------------------------\n\n    /// @dev Converts the given asset amount to share amount. Returned value is in share decimals.\n    ///\n    /// @dev NOTE: MUST ONLY be used in AsyncRequestManager which rely on priceAssetPerShare that is derived from\n    /// Fulfilled*\n    /// message amounts. Any other codepath must use the variant with pricePoolPerAsset and pricePoolPerShare\n    function assetToShareAmount(\n        address shareToken,\n        address asset,\n        uint256 tokenId,\n        uint128 assetAmount,\n        D18 priceAssetPerShare_,\n        MathLib.Rounding rounding\n    ) internal view returns (uint128 shares) {\n        if (assetAmount == 0 || priceAssetPerShare_.raw() == 0) {\n            return 0;\n        }\n\n        uint8 assetDecimals = getAssetDecimals(asset, tokenId);\n        uint8 shareDecimals = IERC20Metadata(shareToken).decimals();\n\n        return PricingLib.convertWithReciprocalPrice(\n            assetAmount, assetDecimals, shareDecimals, priceAssetPerShare_, rounding\n        ).toUint128();\n    }\n\n    /// @dev Converts the given asset amount to share amount. Returned value is in share decimals.\n    function assetToShareAmount(\n        address shareToken,\n        address asset,\n        uint256 tokenId,\n        uint128 assetAmount,\n        D18 pricePoolPerAsset,\n        D18 pricePoolPerShare,\n        MathLib.Rounding rounding\n    ) internal view returns (uint128 shares) {\n        if (assetAmount == 0 || pricePoolPerShare.raw() == 0 || pricePoolPerAsset.raw() == 0) {\n            return 0;\n        }\n\n        uint8 assetDecimals = getAssetDecimals(asset, tokenId);\n        uint8 shareDecimals = IERC20Metadata(shareToken).decimals();\n\n        return PricingLib.assetToShareAmount(\n            assetAmount, assetDecimals, shareDecimals, pricePoolPerAsset, pricePoolPerShare, rounding\n        ).toUint128();\n    }\n\n    /// @dev Converts the given share amount to asset amount. Returned value is in share decimals.\n    ///\n    /// @dev NOTE: MUST ONLY be used in AsyncRequestManager which rely on priceAssetPerShare that is derived from\n    /// Fulfilled*\n    /// message amounts. Any other codepath must use the variant with pricePoolPerAsset and pricePoolPerShare\n    function shareToAssetAmount(\n        address shareToken,\n        uint128 shareAmount,\n        address asset,\n        uint256 tokenId,\n        D18 priceAssetPerShare_,\n        MathLib.Rounding rounding\n    ) internal view returns (uint128 shares) {\n        if (shareAmount == 0 || priceAssetPerShare_.raw() == 0) {\n            return 0;\n        }\n\n        uint8 assetDecimals = getAssetDecimals(asset, tokenId);\n        uint8 shareDecimals = IERC20Metadata(shareToken).decimals();\n\n        return PricingLib.convertWithPrice(shareAmount, shareDecimals, assetDecimals, priceAssetPerShare_, rounding)\n            .toUint128();\n    }\n\n    /// @dev Converts the given share amount to asset amount. Returned value is in share decimals.\n    function shareToAssetAmount(\n        address shareToken,\n        uint128 shareAmount,\n        address asset,\n        uint256 tokenId,\n        D18 pricePoolPerAsset,\n        D18 pricePoolPerShare,\n        MathLib.Rounding rounding\n    ) internal view returns (uint128 shares) {\n        if (shareAmount == 0 || pricePoolPerShare.raw() == 0 || pricePoolPerAsset.raw() == 0) {\n            return 0;\n        }\n\n        uint8 assetDecimals = getAssetDecimals(asset, tokenId);\n        uint8 shareDecimals = IERC20Metadata(shareToken).decimals();\n\n        return PricingLib.shareToAssetAmount(\n            shareAmount, shareDecimals, assetDecimals, pricePoolPerAsset, pricePoolPerShare, rounding\n        ).toUint128();\n    }\n\n    /// @dev Calculates the asset price per share returns the value in price decimals\n    /// Denominated in ASSET_UNIT/SHARE_UNIT\n    function calculatePriceAssetPerShare(\n        address shareToken,\n        uint128 shares,\n        address asset,\n        uint256 tokenId,\n        uint128 assets,\n        MathLib.Rounding rounding\n    ) internal view returns (uint256 priceAssetPerShare_) {\n        if (assets == 0 || shares == 0) {\n            return 0;\n        }\n\n        uint8 assetDecimals = getAssetDecimals(asset, tokenId);\n        uint8 shareDecimals = IERC20Metadata(shareToken).decimals();\n\n        // NOTE: More precise than d18(assets * 10 ** assetDecimals, shares * 10 ** shareDecimals)\n        return toPriceDecimals(assets, assetDecimals).mulDiv(\n            10 ** PRICE_DECIMALS, toPriceDecimals(shares, shareDecimals), rounding\n        );\n    }\n\n    /// -----------------------------------------------------\n    ///  Pure Methods\n    /// -----------------------------------------------------\n\n    /// @dev Converts an amount using decimals and price with implicit rounding down\n    function convertWithPrice(uint256 baseAmount, uint8 baseDecimals, uint8 quoteDecimals, D18 priceQuotePerBase)\n        internal\n        pure\n        returns (uint256 quoteAmount)\n    {\n        return convertWithPrice(baseAmount, baseDecimals, quoteDecimals, priceQuotePerBase, MathLib.Rounding.Down);\n    }\n\n    /// @dev Converts an amount using decimals and price with explicit rounding.\n    function convertWithPrice(\n        uint256 baseAmount,\n        uint8 baseDecimals,\n        uint8 quoteDecimals,\n        D18 priceQuotePerBase,\n        MathLib.Rounding rounding\n    ) internal pure returns (uint256 quoteAmount) {\n        if (baseDecimals == quoteDecimals) {\n            return priceQuotePerBase.mulUint256(baseAmount, rounding);\n        }\n\n        return\n            priceQuotePerBase.mulUint256(MathLib.mulDiv(baseAmount, 10 ** quoteDecimals, 10 ** baseDecimals), rounding);\n    }\n\n    /// @dev Converts an amount using decimals and reciprocal price.\n    ///\n    /// NOTE: More precise than convertWithPrice(,,,price.reciprocal,)\n    function convertWithReciprocalPrice(\n        uint256 baseAmount,\n        uint8 baseDecimals,\n        uint8 quoteDecimals,\n        D18 priceBasePerQuote,\n        MathLib.Rounding rounding\n    ) internal pure returns (uint256 quoteAmount) {\n        if (baseDecimals == quoteDecimals) {\n            return priceBasePerQuote.reciprocalMulUint256(baseAmount, rounding);\n        }\n\n        return priceBasePerQuote.reciprocalMulUint256(\n            MathLib.mulDiv(baseAmount, 10 ** quoteDecimals, 10 ** baseDecimals), rounding\n        );\n    }\n\n    /// @dev Converts asset amount to share amount.\n    function assetToShareAmount(\n        uint256 assetAmount,\n        uint8 assetDecimals,\n        uint8 shareDecimals,\n        D18 pricePoolPerAsset,\n        D18 pricePoolPerShare,\n        MathLib.Rounding rounding\n    ) internal pure returns (uint256 shareAmount) {\n        return pricePoolPerShare.reciprocalMulUint256(\n            convertWithPrice(assetAmount, assetDecimals, shareDecimals, pricePoolPerAsset, MathLib.Rounding.Down),\n            rounding\n        );\n    }\n\n    /// @dev Converts share amount to asset asset amount.\n    function shareToAssetAmount(\n        uint256 shareAmount,\n        uint8 shareDecimals,\n        uint8 assetDecimals,\n        D18 pricePoolPerAsset,\n        D18 pricePoolPerShare,\n        MathLib.Rounding rounding\n    ) internal pure returns (uint256 assetAmount) {\n        return convertWithReciprocalPrice(\n            pricePoolPerShare.mulUint256(shareAmount, MathLib.Rounding.Down),\n            shareDecimals,\n            assetDecimals,\n            pricePoolPerAsset,\n            rounding\n        );\n    }\n\n    /// @dev Converts pool amount to asset amount.\n    function poolToAssetAmount(\n        uint256 poolAmount,\n        uint8 poolDecimals,\n        uint8 assetDecimals,\n        D18 pricePoolPerAsset,\n        MathLib.Rounding rounding\n    ) internal pure returns (uint256 assetAmount) {\n        return convertWithReciprocalPrice(poolAmount, poolDecimals, assetDecimals, pricePoolPerAsset, rounding);\n    }\n\n    /// @dev Returns the asset price per share denominated in ASSET_UNIT/SHARE_UNIT\n    ///\n    /// @dev NOTE: Should never be used for calculating amounts due to precision loss. Instead, please refer to\n    /// conversion relying on pricePoolPerShare and pricePoolPerAsset.\n    function priceAssetPerShare(D18 pricePoolPerShare, D18 pricePoolPerAsset)\n        internal\n        pure\n        returns (D18 priceAssetPerShare_)\n    {\n        return pricePoolPerShare / pricePoolPerAsset;\n    }\n\n    /// -----------------------------------------------------\n    ///  Private Methods\n    /// -----------------------------------------------------\n\n    /// @dev Returns the asset decimals\n    function getAssetDecimals(address asset, uint256 tokenId) private view returns (uint8 assetDecimals) {\n        return tokenId == 0 ? IERC20Metadata(asset).decimals() : IERC6909MetadataExt(asset).decimals(tokenId);\n    }\n\n    /// @dev When converting assets to shares using the price, all values are normalized to PRICE_DECIMALS\n    /// @dev NOTE: We require all assets to have 2 <= decimals <= 18, see `PoolManager.registerAsset`\n    function toPriceDecimals(uint128 _value, uint8 decimals) private pure returns (uint256) {\n        if (PRICE_DECIMALS == decimals) return uint256(_value);\n        return uint256(_value) * 10 ** (PRICE_DECIMALS - decimals);\n    }\n\n    /// @dev Converts decimals of the value from the price decimals back to the intended decimals\n    /// @dev NOTE: We require all assets to have 2 <= decimals <= 18, see `PoolManager.registerAsset`\n    function fromPriceDecimals(uint256 _value, uint8 decimals) private pure returns (uint128) {\n        if (PRICE_DECIMALS == decimals) return _value.toUint128();\n        return (_value / 10 ** (PRICE_DECIMALS - decimals)).toUint128();\n    }\n}\n"
    },
    "src/common/types/AccountId.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\ntype AccountId is uint32;\n\nfunction raw(AccountId accountId_) pure returns (uint32) {\n    return AccountId.unwrap(accountId_);\n}\n\nusing {raw} for AccountId global;\n"
    },
    "src/common/types/AssetId.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @dev Composite Id of the centrifugeId (uint16) where the asset resides\n///      and a local counter (uint64) that is part of the contract that registers the asset.\ntype AssetId is uint128;\n\nfunction isNull(AssetId assetId) pure returns (bool) {\n    return AssetId.unwrap(assetId) == 0;\n}\n\nfunction addr(AssetId assetId) pure returns (address) {\n    return address(uint160(AssetId.unwrap(assetId)));\n}\n\nfunction raw(AssetId assetId) pure returns (uint128) {\n    return AssetId.unwrap(assetId);\n}\n\nfunction centrifugeId(AssetId assetId) pure returns (uint16) {\n    return uint16(AssetId.unwrap(assetId) >> 112);\n}\n\nfunction newAssetId(uint16 centrifugeId_, uint64 counter) pure returns (AssetId) {\n    return AssetId.wrap((uint128(centrifugeId_) << 112) + counter);\n}\n\nfunction newAssetId(uint32 isoCode) pure returns (AssetId) {\n    return AssetId.wrap(isoCode);\n}\n\nfunction eq(AssetId a, AssetId b) pure returns (bool) {\n    return a.raw() == b.raw();\n}\n\nusing {isNull, addr, raw, centrifugeId, eq} for AssetId global;\n"
    },
    "src/common/types/PoolId.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\n\nusing MathLib for uint256;\n\ntype PoolId is uint64;\n\nfunction centrifugeId(PoolId poolId) pure returns (uint16) {\n    return uint16(PoolId.unwrap(poolId) >> 48);\n}\n\nfunction newPoolId(uint16 centrifugeId_, uint48 localPoolId) pure returns (PoolId) {\n    return PoolId.wrap((uint64(centrifugeId_) << 48) | uint64(localPoolId));\n}\n\nfunction isNull(PoolId poolId) pure returns (bool) {\n    return PoolId.unwrap(poolId) == 0;\n}\n\nfunction raw(PoolId poolId) pure returns (uint64) {\n    return PoolId.unwrap(poolId);\n}\n\nusing {centrifugeId, isNull, raw} for PoolId global;\n"
    },
    "src/common/types/ShareClassId.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\ntype ShareClassId is bytes16;\n\nfunction isNull(ShareClassId scId) pure returns (bool) {\n    return ShareClassId.unwrap(scId) == 0;\n}\n\nfunction equals(ShareClassId left, ShareClassId right) pure returns (bool) {\n    return ShareClassId.unwrap(left) == ShareClassId.unwrap(right);\n}\n\nfunction raw(ShareClassId scId) pure returns (bytes16) {\n    return ShareClassId.unwrap(scId);\n}\n\nfunction newShareClassId(PoolId poolId, uint32 index) pure returns (ShareClassId scId) {\n    return ShareClassId.wrap(bytes16((uint128(PoolId.unwrap(poolId)) << 64) + index));\n}\n\nusing {isNull, raw, equals as ==} for ShareClassId global;\n"
    },
    "src/hooks/FreezeOnly.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {BitmapLib} from \"src/misc/libraries/BitmapLib.sol\";\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {UpdateRestrictionType, MessageLib} from \"src/common/libraries/MessageLib.sol\";\n\nimport {IHook, HookData} from \"src/common/interfaces/IHook.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\nimport {IFreezable} from \"src/hooks/interfaces/IFreezable.sol\";\n\n/// @title  Freeze Only\n/// @notice Hook implementation that:\n///         * Allows any non-frozen account to receive tokens and transfer tokens\n///         * Supports freezing accounts which blocks transfers both to and from them\n///         * Allows authTransferFrom calls\n///\n/// @dev    The last bit of hookData is used to denote whether the account is frozen.\ncontract FreezeOnly is Auth, IFreezable, IHook {\n    using BitmapLib for *;\n    using MessageLib for *;\n    using BytesLib for bytes;\n    using CastLib for bytes32;\n\n    /// @dev Least significant bit\n    uint8 public constant FREEZE_BIT = 0;\n\n    IRoot public immutable root;\n\n    constructor(address root_, address deployer) Auth(deployer) {\n        root = IRoot(root_);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Callback from share token\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IHook\n    function onERC20Transfer(address from, address to, uint256 value, HookData calldata hookData)\n        external\n        virtual\n        returns (bytes4)\n    {\n        require(checkERC20Transfer(from, to, value, hookData), TransferBlocked());\n        return IHook.onERC20Transfer.selector;\n    }\n\n    /// @inheritdoc IHook\n    function onERC20AuthTransfer(\n        address, /* sender */\n        address, /* from */\n        address, /* to */\n        uint256, /* value */\n        HookData calldata /* hookData */\n    ) external pure returns (bytes4) {\n        return IHook.onERC20AuthTransfer.selector;\n    }\n\n    /// @inheritdoc IHook\n    function checkERC20Transfer(address from, address, /* to */ uint256, /* value */ HookData calldata hookData)\n        public\n        view\n        returns (bool)\n    {\n        uint128 fromHookData = uint128(hookData.from);\n        if (fromHookData.getBit(FREEZE_BIT) == true && !root.endorsed(from)) {\n            // Source is frozen and not endorsed\n            return false;\n        }\n\n        uint128 toHookData = uint128(hookData.to);\n        if (toHookData.getBit(FREEZE_BIT) == true) {\n            // Destination is frozen\n            return false;\n        }\n\n        return true;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Restriction updates\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IHook\n    function updateRestriction(address token, bytes memory payload) external auth {\n        UpdateRestrictionType updateId = payload.updateRestrictionType();\n\n        if (updateId == UpdateRestrictionType.Freeze) {\n            MessageLib.UpdateRestrictionFreeze memory m = payload.deserializeUpdateRestrictionFreeze();\n            freeze(token, m.user.toAddress());\n        } else if (updateId == UpdateRestrictionType.Unfreeze) {\n            MessageLib.UpdateRestrictionUnfreeze memory m = payload.deserializeUpdateRestrictionUnfreeze();\n            unfreeze(token, m.user.toAddress());\n        } else {\n            revert InvalidUpdate();\n        }\n    }\n\n    /// @inheritdoc IFreezable\n    function freeze(address token, address user) public auth {\n        require(user != address(0), CannotFreezeZeroAddress());\n        require(!root.endorsed(user), EndorsedUserCannotBeFrozen());\n\n        uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n        IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, true)));\n\n        emit Freeze(token, user);\n    }\n\n    /// @inheritdoc IFreezable\n    function unfreeze(address token, address user) public auth {\n        uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n        IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, false)));\n\n        emit Unfreeze(token, user);\n    }\n\n    /// @inheritdoc IFreezable\n    function isFrozen(address token, address user) public view returns (bool) {\n        return uint128(IShareToken(token).hookDataOf(user)).getBit(FREEZE_BIT);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // ERC-165\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IERC165\n    function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {\n        return interfaceId == type(IHook).interfaceId || interfaceId == type(IERC165).interfaceId;\n    }\n}\n"
    },
    "src/hooks/FullRestrictions.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {BitmapLib} from \"src/misc/libraries/BitmapLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nimport {UpdateRestrictionType, MessageLib} from \"src/common/libraries/MessageLib.sol\";\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\n\nimport {IHook, HookData, ESCROW_HOOK_ID} from \"src/common/interfaces/IHook.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\nimport {IFreezable} from \"src/hooks/interfaces/IFreezable.sol\";\nimport {IMemberlist} from \"src/hooks/interfaces/IMemberlist.sol\";\n\n/// @title  Full Restrictions\n/// @notice Hook implementation that:\n///         * Requires adding accounts to the memberlist before they can receive tokens\n///         * Supports freezing accounts which blocks transfers both to and from them\n///         * Allows authTransferFrom calls\n///\n/// @dev    The first 8 bytes (uint64) of hookData is used for the memberlist valid until date,\n///         the last bit is used to denote whether the account is frozen.\ncontract FullRestrictions is Auth, IMemberlist, IFreezable, IHook {\n    using BitmapLib for *;\n    using MessageLib for *;\n    using BytesLib for bytes;\n    using CastLib for bytes32;\n\n    /// @dev Least significant bit\n    uint8 public constant FREEZE_BIT = 0;\n\n    IRoot public immutable root;\n\n    constructor(address root_, address deployer) Auth(deployer) {\n        root = IRoot(root_);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Callback from share token\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IHook\n    function onERC20Transfer(address from, address to, uint256 value, HookData calldata hookData)\n        external\n        virtual\n        returns (bytes4)\n    {\n        require(checkERC20Transfer(from, to, value, hookData), TransferBlocked());\n        return IHook.onERC20Transfer.selector;\n    }\n\n    /// @inheritdoc IHook\n    function onERC20AuthTransfer(\n        address, /* sender */\n        address, /* from */\n        address, /* to */\n        uint256, /* value */\n        HookData calldata /* hookData */\n    ) external pure returns (bytes4) {\n        return IHook.onERC20AuthTransfer.selector;\n    }\n\n    /// @inheritdoc IHook\n    function checkERC20Transfer(address from, address to, uint256, /* value */ HookData calldata hookData)\n        public\n        view\n        returns (bool)\n    {\n        if (uint128(hookData.from).getBit(FREEZE_BIT) == true && !root.endorsed(from) && from != ESCROW_HOOK_ID) {\n            // Source is frozen and not endorsed\n            return false;\n        }\n\n        if (root.endorsed(to) || to == address(0) || to == ESCROW_HOOK_ID) {\n            // Destination is endorsed or escrow and source was already checked, so the transfer is allowed\n            return true;\n        }\n\n        uint128 toHookData = uint128(hookData.to);\n        if (toHookData.getBit(FREEZE_BIT) == true) {\n            // Destination is frozen\n            return false;\n        }\n\n        if (toHookData >> 64 < block.timestamp) {\n            // Destination is not a member\n            return false;\n        }\n\n        return true;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Restriction updates\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IHook\n    function updateRestriction(address token, bytes memory payload) external auth {\n        UpdateRestrictionType updateId = payload.updateRestrictionType();\n\n        if (updateId == UpdateRestrictionType.Member) {\n            MessageLib.UpdateRestrictionMember memory m = payload.deserializeUpdateRestrictionMember();\n            updateMember(token, m.user.toAddress(), m.validUntil);\n        } else if (updateId == UpdateRestrictionType.Freeze) {\n            MessageLib.UpdateRestrictionFreeze memory m = payload.deserializeUpdateRestrictionFreeze();\n            freeze(token, m.user.toAddress());\n        } else if (updateId == UpdateRestrictionType.Unfreeze) {\n            MessageLib.UpdateRestrictionUnfreeze memory m = payload.deserializeUpdateRestrictionUnfreeze();\n            unfreeze(token, m.user.toAddress());\n        } else {\n            revert InvalidUpdate();\n        }\n    }\n\n    /// @inheritdoc IFreezable\n    function freeze(address token, address user) public auth {\n        require(user != address(0), CannotFreezeZeroAddress());\n        require(!root.endorsed(user), EndorsedUserCannotBeFrozen());\n\n        uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n        IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, true)));\n\n        emit Freeze(token, user);\n    }\n\n    /// @inheritdoc IFreezable\n    function unfreeze(address token, address user) public auth {\n        uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n        IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, false)));\n\n        emit Unfreeze(token, user);\n    }\n\n    /// @inheritdoc IFreezable\n    function isFrozen(address token, address user) public view returns (bool) {\n        return uint128(IShareToken(token).hookDataOf(user)).getBit(FREEZE_BIT);\n    }\n\n    /// @inheritdoc IMemberlist\n    function updateMember(address token, address user, uint64 validUntil) public auth {\n        require(block.timestamp <= validUntil, InvalidValidUntil());\n        require(!root.endorsed(user), EndorsedUserCannotBeUpdated());\n\n        uint128 hookData = uint128(validUntil) << 64;\n        hookData.setBit(FREEZE_BIT, isFrozen(token, user));\n        IShareToken(token).setHookData(user, bytes16(hookData));\n\n        emit UpdateMember(token, user, validUntil);\n    }\n\n    /// @inheritdoc IMemberlist\n    function isMember(address token, address user) external view returns (bool isValid, uint64 validUntil) {\n        validUntil = abi.encodePacked(IShareToken(token).hookDataOf(user)).toUint64(0);\n        isValid = validUntil >= block.timestamp;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // ERC-165\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IERC165\n    function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {\n        return interfaceId == type(IHook).interfaceId || interfaceId == type(IERC165).interfaceId;\n    }\n}\n"
    },
    "src/hooks/RedemptionRestrictions.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {BitmapLib} from \"src/misc/libraries/BitmapLib.sol\";\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {UpdateRestrictionType, MessageLib} from \"src/common/libraries/MessageLib.sol\";\n\nimport {IHook, HookData, ESCROW_HOOK_ID} from \"src/common/interfaces/IHook.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\nimport {IFreezable} from \"src/hooks/interfaces/IFreezable.sol\";\nimport {IMemberlist} from \"src/hooks/interfaces/IMemberlist.sol\";\n\n/// @title  Redemption Restrictions\n/// @notice Hook implementation that:\n///         * Allows any non-frozen account to receive tokens and transfer tokens\n///         * Requires accounts to be added as a member before submitting a redemption request\n///         * Supports freezing accounts which blocks transfers both to and from them\n///         * Allows authTransferFrom calls\n///\n/// @dev    The first 8 bytes (uint64) of hookData is used for the memberlist valid until date,\n///         the last bit is used to denote whether the account is frozen.\ncontract RedemptionRestrictions is Auth, IMemberlist, IFreezable, IHook {\n    using BitmapLib for *;\n    using MessageLib for *;\n    using BytesLib for bytes;\n    using CastLib for bytes32;\n\n    /// @dev Least significant bit\n    uint8 public constant FREEZE_BIT = 0;\n\n    IRoot public immutable root;\n\n    constructor(address root_, address deployer) Auth(deployer) {\n        root = IRoot(root_);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Callback from share token\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IHook\n    function onERC20Transfer(address from, address to, uint256 value, HookData calldata hookData)\n        external\n        virtual\n        returns (bytes4)\n    {\n        require(checkERC20Transfer(from, to, value, hookData), TransferBlocked());\n        return IHook.onERC20Transfer.selector;\n    }\n\n    /// @inheritdoc IHook\n    function onERC20AuthTransfer(\n        address, /* sender */\n        address, /* from */\n        address, /* to */\n        uint256, /* value */\n        HookData calldata /* hookData */\n    ) external pure returns (bytes4) {\n        return IHook.onERC20AuthTransfer.selector;\n    }\n\n    /// @inheritdoc IHook\n    function checkERC20Transfer(address from, address to, uint256, /* value */ HookData calldata hookData)\n        public\n        view\n        returns (bool)\n    {\n        uint128 fromHookData = uint128(hookData.from);\n        if (fromHookData.getBit(FREEZE_BIT) == true && !root.endorsed(from)) {\n            // Source is frozen and not endorsed\n            return false;\n        }\n\n        uint128 toHookData = uint128(hookData.to);\n        if (toHookData.getBit(FREEZE_BIT) == true) {\n            // Destination is frozen\n            return false;\n        }\n\n        if (from == address(0) && to == ESCROW_HOOK_ID) {\n            // Deposit request fulfillment\n            return true;\n        }\n\n        if (to == ESCROW_HOOK_ID && fromHookData >> 64 < block.timestamp) {\n            // Destination is escrow, so it's a redemption request, and the user is not a member\n            return false;\n        }\n\n        return true;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Restriction updates\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IHook\n    function updateRestriction(address token, bytes memory payload) external auth {\n        UpdateRestrictionType updateId = payload.updateRestrictionType();\n\n        if (updateId == UpdateRestrictionType.Member) {\n            MessageLib.UpdateRestrictionMember memory m = payload.deserializeUpdateRestrictionMember();\n            updateMember(token, m.user.toAddress(), m.validUntil);\n        } else if (updateId == UpdateRestrictionType.Freeze) {\n            MessageLib.UpdateRestrictionFreeze memory m = payload.deserializeUpdateRestrictionFreeze();\n            freeze(token, m.user.toAddress());\n        } else if (updateId == UpdateRestrictionType.Unfreeze) {\n            MessageLib.UpdateRestrictionUnfreeze memory m = payload.deserializeUpdateRestrictionUnfreeze();\n            unfreeze(token, m.user.toAddress());\n        } else {\n            revert InvalidUpdate();\n        }\n    }\n\n    /// @inheritdoc IFreezable\n    function freeze(address token, address user) public auth {\n        require(user != address(0), CannotFreezeZeroAddress());\n        require(!root.endorsed(user), EndorsedUserCannotBeFrozen());\n\n        uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n        IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, true)));\n\n        emit Freeze(token, user);\n    }\n\n    /// @inheritdoc IFreezable\n    function unfreeze(address token, address user) public auth {\n        uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n        IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, false)));\n\n        emit Unfreeze(token, user);\n    }\n\n    /// @inheritdoc IFreezable\n    function isFrozen(address token, address user) public view returns (bool) {\n        return uint128(IShareToken(token).hookDataOf(user)).getBit(FREEZE_BIT);\n    }\n\n    /// @inheritdoc IMemberlist\n    function updateMember(address token, address user, uint64 validUntil) public auth {\n        require(block.timestamp <= validUntil, InvalidValidUntil());\n        require(!root.endorsed(user), EndorsedUserCannotBeUpdated());\n\n        uint128 hookData = uint128(validUntil) << 64;\n        hookData.setBit(FREEZE_BIT, isFrozen(token, user));\n        IShareToken(token).setHookData(user, bytes16(hookData));\n\n        emit UpdateMember(token, user, validUntil);\n    }\n\n    /// @inheritdoc IMemberlist\n    function isMember(address token, address user) external view returns (bool isValid, uint64 validUntil) {\n        validUntil = abi.encodePacked(IShareToken(token).hookDataOf(user)).toUint64(0);\n        isValid = validUntil >= block.timestamp;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // ERC-165\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IERC165\n    function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {\n        return interfaceId == type(IHook).interfaceId || interfaceId == type(IERC165).interfaceId;\n    }\n}\n"
    },
    "src/hooks/interfaces/IFreezable.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\ninterface IFreezable {\n    // --- Events ---\n    event Freeze(address indexed token, address indexed user);\n    event Unfreeze(address indexed token, address indexed user);\n\n    // --- Errors ---\n    error CannotFreezeZeroAddress();\n    error EndorsedUserCannotBeFrozen();\n\n    // --- Handling freezes ---\n    /// @notice Freeze a user balance. Frozen users cannot receive nor send tokens\n    function freeze(address token, address user) external;\n\n    /// @notice Unfreeze a user balance\n    function unfreeze(address token, address user) external;\n\n    /// @notice Returns whether the user's tokens are frozen\n    function isFrozen(address token, address user) external view returns (bool);\n}\n"
    },
    "src/hooks/interfaces/IMemberlist.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\ninterface IMemberlist {\n    // --- Events ---\n    event UpdateMember(address indexed token, address indexed user, uint64 validUntil);\n\n    // --- Errors ---\n    error InvalidValidUntil();\n    error EndorsedUserCannotBeUpdated();\n\n    // --- Managing members ---\n    /// @notice Add a member. Non-members cannot receive tokens, but can send tokens to valid members\n    /// @param  validUntil Timestamp until which the user will be a valid member\n    function updateMember(address token, address user, uint64 validUntil) external;\n\n    /// @notice Returns whether the user is a valid member of the token\n    function isMember(address token, address user) external view returns (bool isValid, uint64 validUntil);\n}\n"
    },
    "src/hub/Accounting.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {IAccounting, JournalEntry} from \"src/hub/interfaces/IAccounting.sol\";\nimport {TransientStorageLib} from \"src/misc/libraries/TransientStorageLib.sol\";\n\n/// @notice In a transaction there can be multiple journal entries for different pools,\n/// which can be interleaved. We want entries for the same pool to share the same journal ID.\n/// So we're keeping a journal ID per pool in transient storage.\nlibrary TransientJournal {\n    function journalId(PoolId poolId) internal view returns (uint256) {\n        return TransientStorageLib.tloadUint256(keccak256(abi.encode(\"journalId\", poolId)));\n    }\n\n    function setJournalId(PoolId poolId, uint256 value) internal {\n        TransientStorageLib.tstore(keccak256(abi.encode(\"journalId\", poolId)), value);\n    }\n}\n\n/// @title  Accounting\n/// @notice Double-entry bookkeeping system.\n/// @dev    To add entries, a specific pool needs to be unlocked.\n///         When locking, the debited and credited amounts need to match.\ncontract Accounting is Auth, IAccounting {\n    mapping(PoolId => mapping(AccountId => Account)) public accounts;\n\n    uint128 public transient debited;\n    uint128 public transient credited;\n    PoolId internal transient _currentPoolId;\n    mapping(PoolId => uint64) internal _poolJournalIdCounter;\n\n    constructor(address deployer) Auth(deployer) {}\n\n    //----------------------------------------------------------------------------------------------\n    // Lock/unlock\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IAccounting\n    function unlock(PoolId poolId) external auth {\n        require(PoolId.unwrap(_currentPoolId) == 0, AccountingAlreadyUnlocked());\n        debited = 0;\n        credited = 0;\n        _currentPoolId = poolId;\n\n        if (TransientJournal.journalId(poolId) == 0) {\n            TransientJournal.setJournalId(poolId, _generateJournalId(poolId));\n        }\n        emit StartJournalId(poolId, TransientJournal.journalId(poolId));\n    }\n\n    /// @inheritdoc IAccounting\n    function lock() external auth {\n        require(debited == credited, Unbalanced());\n\n        emit EndJournalId(_currentPoolId, TransientJournal.journalId(_currentPoolId));\n        _currentPoolId = PoolId.wrap(0);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Account creation & metadata\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IAccounting\n    function createAccount(PoolId poolId, AccountId account, bool isDebitNormal) external auth {\n        require(accounts[poolId][account].lastUpdated == 0, AccountExists());\n        accounts[poolId][account] = Account(0, 0, isDebitNormal, uint64(block.timestamp), \"\");\n        emit CreateAccount(poolId, account, isDebitNormal);\n    }\n\n    /// @inheritdoc IAccounting\n    function setAccountMetadata(PoolId poolId, AccountId account, bytes calldata metadata) external auth {\n        require(accounts[poolId][account].lastUpdated != 0, AccountDoesNotExist());\n        accounts[poolId][account].metadata = metadata;\n        emit SetAccountMetadata(poolId, account, metadata);\n    }\n    \n    //----------------------------------------------------------------------------------------------\n    // Account updates\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IAccounting\n    function addDebit(AccountId account, uint128 value) public auth {\n        require(!_currentPoolId.isNull(), AccountingLocked());\n\n        Account storage acc = accounts[_currentPoolId][account];\n        require(acc.lastUpdated != 0, AccountDoesNotExist());\n\n        acc.totalDebit += value;\n        debited += value;\n        acc.lastUpdated = uint64(block.timestamp);\n        emit Debit(_currentPoolId, account, value);\n    }\n\n    /// @inheritdoc IAccounting\n    function addCredit(AccountId account, uint128 value) public auth {\n        require(!_currentPoolId.isNull(), AccountingLocked());\n\n        Account storage acc = accounts[_currentPoolId][account];\n        require(acc.lastUpdated != 0, AccountDoesNotExist());\n\n        acc.totalCredit += value;\n        credited += value;\n        acc.lastUpdated = uint64(block.timestamp);\n        emit Credit(_currentPoolId, account, value);\n    }\n\n    /// @inheritdoc IAccounting\n    function addJournal(JournalEntry[] memory debits, JournalEntry[] memory credits) external auth {\n        for (uint256 i; i < debits.length; i++) {\n            addDebit(debits[i].accountId, debits[i].value);\n        }\n\n        for (uint256 i; i < credits.length; i++) {\n            addCredit(credits[i].accountId, credits[i].value);\n        }\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // View methods\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IAccounting\n    function accountValue(PoolId poolId, AccountId account) external view returns (bool /* isPositive */, uint128) {\n        Account storage acc = accounts[poolId][account];\n        require(acc.lastUpdated != 0, AccountDoesNotExist());\n\n        if (acc.isDebitNormal) {\n            // For debit-normal accounts: Value = Total Debit - Total Credit\n            if (acc.totalDebit >= acc.totalCredit) {\n                return (true, acc.totalDebit - acc.totalCredit);\n            } else {\n                return (false, acc.totalCredit - acc.totalDebit);\n            }\n        } else {\n            // For credit-normal accounts: Value = Total Credit - Total Debit\n            if (acc.totalCredit >= acc.totalDebit) {\n                return (true, acc.totalCredit - acc.totalDebit);\n            } else {\n                return (false, acc.totalDebit - acc.totalCredit);\n            }\n        }\n    }\n\n    /// @inheritdoc IAccounting\n    function exists(PoolId poolId, AccountId account) external view returns (bool) {\n        return accounts[poolId][account].lastUpdated != 0;\n    }\n\n    function _generateJournalId(PoolId poolId) internal returns (uint256) {\n        return uint256((uint256(poolId.raw()) << 128) | ++_poolJournalIdCounter[poolId]);\n    }\n}\n"
    },
    "src/hub/Holdings.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {d18, D18} from \"src/misc/types/D18.sol\";\n\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {IHoldings, Holding} from \"src/hub/interfaces/IHoldings.sol\";\nimport {IHubRegistry} from \"src/hub/interfaces/IHubRegistry.sol\";\nimport {IHoldings, Holding, HoldingAccount} from \"src/hub/interfaces/IHoldings.sol\";\n\n/// @title  Holdings\n/// @notice Bookkeeping of the holdings and its associated accounting IDs for each pool.\ncontract Holdings is Auth, IHoldings {\n    using MathLib for uint256;\n\n    IHubRegistry public immutable hubRegistry;\n\n    mapping(PoolId => mapping(ShareClassId => mapping(AssetId => Holding))) public holding;\n    mapping(PoolId => mapping(ShareClassId => mapping(AssetId => mapping(uint8 kind => AccountId)))) public accountId;\n\n    constructor(IHubRegistry hubRegistry_, address deployer) Auth(deployer) {\n        hubRegistry = hubRegistry_;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Holding creation & updates\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IHoldings\n    function create(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        IERC7726 valuation_,\n        bool isLiability_,\n        HoldingAccount[] memory accounts\n    ) external auth {\n        require(!scId.isNull(), WrongShareClassId());\n        require(address(valuation_) != address(0), WrongValuation());\n\n        holding[poolId][scId][assetId] = Holding(0, 0, valuation_, isLiability_);\n\n        for (uint256 i; i < accounts.length; i++) {\n            accountId[poolId][scId][assetId][accounts[i].kind] = accounts[i].accountId;\n        }\n\n        emit Create(poolId, scId, assetId, valuation_, isLiability_, accounts);\n    }\n\n    /// @inheritdoc IHoldings\n    function setAccountId(PoolId poolId, ShareClassId scId, AssetId assetId, uint8 kind, AccountId accountId_)\n        external\n        auth\n    {\n        Holding storage holding_ = holding[poolId][scId][assetId];\n        require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n        accountId[poolId][scId][assetId][kind] = accountId_;\n\n        emit SetAccountId(poolId, scId, assetId, kind, accountId_);\n    }\n\n    /// @inheritdoc IHoldings\n    function updateValuation(PoolId poolId, ShareClassId scId, AssetId assetId, IERC7726 valuation_) external auth {\n        require(address(valuation_) != address(0), WrongValuation());\n\n        Holding storage holding_ = holding[poolId][scId][assetId];\n        require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n        holding_.valuation = valuation_;\n\n        emit UpdateValuation(poolId, scId, assetId, valuation_);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Value updates\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IHoldings\n    function increase(PoolId poolId, ShareClassId scId, AssetId assetId, D18 pricePoolPerAsset, uint128 amount_)\n        external\n        auth\n        returns (uint128 amountValue)\n    {\n        Holding storage holding_ = holding[poolId][scId][assetId];\n        require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n        amountValue = PricingLib.convertWithPrice(\n            amount_, hubRegistry.decimals(assetId), hubRegistry.decimals(poolId), pricePoolPerAsset\n        ).toUint128();\n\n        holding_.assetAmount += amount_;\n        holding_.assetAmountValue += amountValue;\n\n        emit Increase(poolId, scId, assetId, pricePoolPerAsset, amount_, amountValue);\n    }\n\n    /// @inheritdoc IHoldings\n    function decrease(PoolId poolId, ShareClassId scId, AssetId assetId, D18 pricePoolPerAsset, uint128 amount_)\n        external\n        auth\n        returns (uint128 amountValue)\n    {\n        Holding storage holding_ = holding[poolId][scId][assetId];\n        require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n        amountValue = PricingLib.convertWithPrice(\n            amount_, hubRegistry.decimals(assetId), hubRegistry.decimals(poolId), pricePoolPerAsset\n        ).toUint128();\n\n        holding_.assetAmount -= amount_;\n        holding_.assetAmountValue -= amountValue;\n\n        emit Decrease(poolId, scId, assetId, pricePoolPerAsset, amount_, amountValue);\n    }\n\n    /// @inheritdoc IHoldings\n    function update(PoolId poolId, ShareClassId scId, AssetId assetId)\n        external\n        auth\n        returns (bool isPositive, uint128 diffValue)\n    {\n        Holding storage holding_ = holding[poolId][scId][assetId];\n        require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n        uint128 currentAmountValue = holding_.valuation.getQuote(\n            holding_.assetAmount, assetId.addr(), hubRegistry.currency(poolId).addr()\n        ).toUint128();\n\n        isPositive = currentAmountValue >= holding_.assetAmountValue;\n        diffValue =\n            isPositive ? currentAmountValue - holding_.assetAmountValue : holding_.assetAmountValue - currentAmountValue;\n\n        holding_.assetAmountValue = currentAmountValue;\n\n        emit Update(poolId, scId, assetId, isPositive, diffValue);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // View methods\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IHoldings\n    function value(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (uint128 value_) {\n        Holding storage holding_ = holding[poolId][scId][assetId];\n        require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n        return holding_.assetAmountValue;\n    }\n\n    /// @inheritdoc IHoldings\n    function amount(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (uint128 amount_) {\n        Holding storage holding_ = holding[poolId][scId][assetId];\n        require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n        return holding_.assetAmount;\n    }\n\n    /// @inheritdoc IHoldings\n    function valuation(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (IERC7726) {\n        Holding storage holding_ = holding[poolId][scId][assetId];\n        require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n        return holding_.valuation;\n    }\n\n    /// @inheritdoc IHoldings\n    function isLiability(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (bool) {\n        Holding storage holding_ = holding[poolId][scId][assetId];\n        require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n        return holding_.isLiability;\n    }\n\n    /// @inheritdoc IHoldings\n    function exists(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (bool) {\n        return address(holding[poolId][scId][assetId].valuation) != address(0);\n    }\n}\n"
    },
    "src/hub/Hub.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {D18, d18} from \"src/misc/types/D18.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {Multicall, IMulticall} from \"src/misc/Multicall.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\n\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {IHubGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {IPoolMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\nimport {IHubGuardianActions} from \"src/common/interfaces/IGuardianActions.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nimport {IAccounting, JournalEntry} from \"src/hub/interfaces/IAccounting.sol\";\nimport {IHubRegistry} from \"src/hub/interfaces/IHubRegistry.sol\";\nimport {IShareClassManager} from \"src/hub/interfaces/IShareClassManager.sol\";\nimport {IHoldings, HoldingAccount} from \"src/hub/interfaces/IHoldings.sol\";\nimport {IHub, AccountType} from \"src/hub/interfaces/IHub.sol\";\n\n/// @title  Hub\n/// @notice Central pool management contract, that brings together all functions in one place.\n///         Pools can assign hub managers which have full rights over all actions.\n///\n///         Also acts as the central contract that routes messages from other chains to the Hub contracts.\ncontract Hub is Multicall, Auth, Recoverable, IHub, IHubGatewayHandler, IHubGuardianActions {\n    using MathLib for uint256;\n\n    IHubRegistry public immutable hubRegistry;\n\n    IGateway public gateway;\n    IHoldings public holdings;\n    IAccounting public accounting;\n    IPoolMessageSender public sender;\n    IShareClassManager public shareClassManager;\n\n    constructor(\n        IShareClassManager shareClassManager_,\n        IHubRegistry hubRegistry_,\n        IAccounting accounting_,\n        IHoldings holdings_,\n        IGateway gateway_,\n        address deployer\n    ) Auth(deployer) {\n        shareClassManager = shareClassManager_;\n        hubRegistry = hubRegistry_;\n        accounting = accounting_;\n        holdings = holdings_;\n        gateway = gateway_;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // System methods\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IHub\n    function file(bytes32 what, address data) external {\n        _auth();\n\n        if (what == \"sender\") sender = IPoolMessageSender(data);\n        else if (what == \"holdings\") holdings = IHoldings(data);\n        else if (what == \"accounting\") accounting = IAccounting(data);\n        else if (what == \"shareClassManager\") shareClassManager = IShareClassManager(data);\n        else if (what == \"gateway\") gateway = IGateway(data);\n        else revert FileUnrecognizedParam();\n\n        emit File(what, data);\n    }\n\n    /// @inheritdoc IMulticall\n    /// @notice performs a multicall but all messages sent in the process will be batched\n    function multicall(bytes[] calldata data) public payable override {\n        bool wasBatching = gateway.isBatching();\n        if (!wasBatching) {\n            gateway.startBatching();\n            gateway.payTransaction{value: msg.value}(msg.sender);\n        }\n\n        super.multicall(data);\n\n        if (!wasBatching) {\n            gateway.endBatching();\n        }\n    }\n\n    /// @inheritdoc IHubGuardianActions\n    function createPool(PoolId poolId, address admin, AssetId currency) external payable {\n        _auth();\n\n        require(poolId.centrifugeId() == sender.localCentrifugeId(), InvalidPoolId());\n        hubRegistry.registerPool(poolId, admin, currency);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Permissionless methods\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IHub\n    function notifyDeposit(PoolId poolId, ShareClassId scId, AssetId assetId, bytes32 investor, uint32 maxClaims)\n        external\n        payable\n    {\n        _pay();\n\n        uint128 totalPayoutShareAmount;\n        uint128 totalPaymentAssetAmount;\n        uint128 cancelledAssetAmount;\n\n        for (uint32 i = 0; i < maxClaims; i++) {\n            (uint128 payoutShareAmount, uint128 paymentAssetAmount, uint128 cancelled, bool canClaimAgain) =\n                shareClassManager.claimDeposit(poolId, scId, investor, assetId);\n\n            totalPayoutShareAmount += payoutShareAmount;\n            totalPaymentAssetAmount += paymentAssetAmount;\n\n            // Should be written at most once with non-zero amount iff the last claimable epoch was processed and\n            // the user had a pending cancellation\n            // NOTE: Purposely delaying corresponding message dispatch after deposit fulfillment message\n            if (cancelled > 0) {\n                cancelledAssetAmount = cancelled;\n            }\n\n            if (!canClaimAgain) {\n                break;\n            }\n        }\n\n        sender.sendFulfilledDepositRequest(\n            poolId, scId, assetId, investor, totalPaymentAssetAmount, totalPayoutShareAmount\n        );\n\n        // If cancellation was queued, notify about delayed cancellation\n        if (cancelledAssetAmount > 0) {\n            sender.sendFulfilledCancelDepositRequest(poolId, scId, assetId, investor, cancelledAssetAmount);\n        }\n    }\n\n    /// @inheritdoc IHub\n    function notifyRedeem(PoolId poolId, ShareClassId scId, AssetId assetId, bytes32 investor, uint32 maxClaims)\n        external\n        payable\n    {\n        _pay();\n\n        uint128 totalPayoutAssetAmount;\n        uint128 totalPaymentShareAmount;\n        uint128 cancelledShareAmount;\n\n        for (uint32 i = 0; i < maxClaims; i++) {\n            (uint128 payoutAssetAmount, uint128 paymentShareAmount, uint128 cancelled, bool canClaimAgain) =\n                shareClassManager.claimRedeem(poolId, scId, investor, assetId);\n\n            totalPayoutAssetAmount += payoutAssetAmount;\n            totalPaymentShareAmount += paymentShareAmount;\n\n            // Should be written at most once with non-zero amount iff the last claimable epoch was processed and\n            // the user had a pending cancellation\n            // NOTE: Purposely delaying corresponding message dispatch after redemption fulfillment message\n            if (cancelled > 0) {\n                cancelledShareAmount = cancelled;\n            }\n\n            if (!canClaimAgain) {\n                break;\n            }\n        }\n\n        sender.sendFulfilledRedeemRequest(\n            poolId, scId, assetId, investor, totalPayoutAssetAmount, totalPaymentShareAmount\n        );\n\n        // If cancellation was queued, notify about delayed cancellation\n        if (cancelledShareAmount > 0) {\n            sender.sendFulfilledCancelRedeemRequest(poolId, scId, assetId, investor, cancelledShareAmount);\n        }\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Pool admin methods\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IHub\n    function notifyPool(PoolId poolId, uint16 centrifugeId) external payable {\n        _isManagerAndPaid(poolId);\n\n        emit NotifyPool(centrifugeId, poolId);\n        sender.sendNotifyPool(centrifugeId, poolId);\n    }\n\n    /// @inheritdoc IHub\n    function notifyShareClass(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes32 hook) external payable {\n        _isManagerAndPaid(poolId);\n\n        require(shareClassManager.exists(poolId, scId), IShareClassManager.ShareClassNotFound());\n\n        (string memory name, string memory symbol, bytes32 salt) = shareClassManager.metadata(scId);\n        uint8 decimals = hubRegistry.decimals(poolId);\n\n        emit NotifyShareClass(centrifugeId, poolId, scId);\n        sender.sendNotifyShareClass(centrifugeId, poolId, scId, name, symbol, decimals, salt, hook);\n    }\n\n    /// @inheritdoc IHub\n    function notifyShareMetadata(PoolId poolId, ShareClassId scId, uint16 centrifugeId) public payable {\n        _isManagerAndPaid(poolId);\n\n        (string memory name, string memory symbol,) = shareClassManager.metadata(scId);\n\n        emit NotifyShareMetadata(centrifugeId, poolId, scId, name, symbol);\n        sender.sendNotifyShareMetadata(centrifugeId, poolId, scId, name, symbol);\n    }\n\n    /// @inheritdoc IHub\n    function updateShareHook(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes32 hook) public payable {\n        _isManagerAndPaid(poolId);\n\n        emit UpdateShareHook(centrifugeId, poolId, scId, hook);\n        sender.sendUpdateShareHook(centrifugeId, poolId, scId, hook);\n    }\n\n    /// @inheritdoc IHub\n    function notifySharePrice(PoolId poolId, ShareClassId scId, uint16 centrifugeId) public payable {\n        _isManagerAndPaid(poolId);\n\n        (, D18 poolPerShare) = shareClassManager.metrics(scId);\n\n        emit NotifySharePrice(centrifugeId, poolId, scId, poolPerShare);\n        sender.sendNotifyPricePoolPerShare(centrifugeId, poolId, scId, poolPerShare);\n    }\n\n    /// @inheritdoc IHub\n    function notifyAssetPrice(PoolId poolId, ShareClassId scId, AssetId assetId) public payable {\n        _isManagerAndPaid(poolId);\n        D18 pricePoolPerAsset = _pricePoolPerAsset(poolId, scId, assetId);\n        emit NotifyAssetPrice(assetId.centrifugeId(), poolId, scId, assetId, pricePoolPerAsset);\n        sender.sendNotifyPricePoolPerAsset(poolId, scId, assetId, pricePoolPerAsset);\n    }\n\n    /// @inheritdoc IHub\n    function triggerIssueShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, address who, uint128 shares)\n        public\n        payable\n    {\n        _isManagerAndPaid(poolId);\n\n        sender.sendTriggerIssueShares(centrifugeId, poolId, scId, who, shares);\n    }\n\n    /// @inheritdoc IHub\n    function triggerSubmitQueuedShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId) public payable {\n        _isManagerAndPaid(poolId);\n\n        sender.sendTriggerSubmitQueuedShares(centrifugeId, poolId, scId);\n    }\n\n    /// @inheritdoc IHub\n    function triggerSubmitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) public payable {\n        _isManagerAndPaid(poolId);\n\n        sender.sendTriggerSubmitQueuedAssets(poolId, scId, assetId);\n    }\n\n    /// @inheritdoc IHub\n    function setQueue(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bool enabled) public payable {\n        _isManagerAndPaid(poolId);\n\n        sender.sendSetQueue(centrifugeId, poolId, scId, enabled);\n    }\n\n    /// @inheritdoc IHub\n    function setPoolMetadata(PoolId poolId, bytes calldata metadata) external payable {\n        _isManager(poolId);\n\n        hubRegistry.setMetadata(poolId, metadata);\n    }\n\n    /// @inheritdoc IHub\n    function updateShareClassMetadata(PoolId poolId, ShareClassId scId, string calldata name, string calldata symbol)\n        external\n        payable\n    {\n        _isManager(poolId);\n\n        shareClassManager.updateMetadata(poolId, scId, name, symbol);\n    }\n\n    /// @inheritdoc IHub\n    function updateManager(PoolId poolId, address who, bool canManage) external payable {\n        _isManager(poolId);\n\n        hubRegistry.updateManager(poolId, who, canManage);\n    }\n\n    /// @inheritdoc IHub\n    function addShareClass(PoolId poolId, string calldata name, string calldata symbol, bytes32 salt)\n        external\n        payable\n        returns (ShareClassId scId)\n    {\n        _isManager(poolId);\n\n        return shareClassManager.addShareClass(poolId, name, symbol, salt);\n    }\n\n    /// @inheritdoc IHub\n    function approveDeposits(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId depositAssetId,\n        uint32 nowDepositEpochId,\n        uint128 approvedAssetAmount\n    ) external payable returns (uint128 pendingAssetAmount, uint128 approvedPoolAmount) {\n        _isManagerAndPaid(poolId);\n        D18 pricePoolPerAsset = _pricePoolPerAsset(poolId, scId, depositAssetId);\n        (pendingAssetAmount, approvedPoolAmount) = shareClassManager.approveDeposits(\n            poolId, scId, depositAssetId, nowDepositEpochId, approvedAssetAmount, pricePoolPerAsset\n        );\n\n        sender.sendApprovedDeposits(poolId, scId, depositAssetId, approvedAssetAmount, pricePoolPerAsset);\n    }\n\n    /// @inheritdoc IHub\n    function approveRedeems(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId payoutAssetId,\n        uint32 nowRedeemEpochId,\n        uint128 approvedShareAmount\n    ) external payable returns (uint128 pendingShareAmount) {\n        _isManager(poolId);\n\n        D18 price = _pricePoolPerAsset(poolId, scId, payoutAssetId);\n        (pendingShareAmount) =\n            shareClassManager.approveRedeems(poolId, scId, payoutAssetId, nowRedeemEpochId, approvedShareAmount, price);\n    }\n\n    /// @inheritdoc IHub\n    function issueShares(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId depositAssetId,\n        uint32 nowIssueEpochId,\n        D18 navPoolPerShare\n    ) external payable returns (uint128 issuedShareAmount, uint128 depositAssetAmount, uint128 depositPoolAmount) {\n        _isManagerAndPaid(poolId);\n\n        (issuedShareAmount, depositAssetAmount, depositPoolAmount) =\n            shareClassManager.issueShares(poolId, scId, depositAssetId, nowIssueEpochId, navPoolPerShare);\n\n        sender.sendIssuedShares(poolId, scId, depositAssetId, issuedShareAmount, navPoolPerShare);\n    }\n\n    /// @inheritdoc IHub\n    function revokeShares(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId payoutAssetId,\n        uint32 nowRevokeEpochId,\n        D18 navPoolPerShare\n    ) external payable returns (uint128 revokedShareAmount, uint128 payoutAssetAmount, uint128 payoutPoolAmount) {\n        _isManagerAndPaid(poolId);\n\n        (revokedShareAmount, payoutAssetAmount, payoutPoolAmount) =\n            shareClassManager.revokeShares(poolId, scId, payoutAssetId, nowRevokeEpochId, navPoolPerShare);\n\n        sender.sendRevokedShares(poolId, scId, payoutAssetId, payoutAssetAmount, revokedShareAmount, navPoolPerShare);\n    }\n\n    /// @inheritdoc IHub\n    function updateRestriction(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes calldata payload)\n        external\n        payable\n    {\n        _isManagerAndPaid(poolId);\n\n        require(shareClassManager.exists(poolId, scId), IShareClassManager.ShareClassNotFound());\n\n        emit UpdateRestriction(centrifugeId, poolId, scId, payload);\n        sender.sendUpdateRestriction(centrifugeId, poolId, scId, payload);\n    }\n\n    /// @inheritdoc IHub\n    function updateContract(\n        PoolId poolId,\n        ShareClassId scId,\n        uint16 centrifugeId,\n        bytes32 target,\n        bytes calldata payload\n    ) external payable {\n        _isManagerAndPaid(poolId);\n\n        require(shareClassManager.exists(poolId, scId), IShareClassManager.ShareClassNotFound());\n\n        emit UpdateContract(centrifugeId, poolId, scId, target, payload);\n        sender.sendUpdateContract(centrifugeId, poolId, scId, target, payload);\n    }\n\n    /// @inheritdoc IHub\n    function updatePricePerShare(PoolId poolId, ShareClassId scId, D18 navPoolPerShare) public payable {\n        _isManager(poolId);\n\n        shareClassManager.updatePricePerShare(poolId, scId, navPoolPerShare);\n    }\n\n    /// @inheritdoc IHub\n    function createHolding(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        IERC7726 valuation,\n        AccountId assetAccount,\n        AccountId equityAccount,\n        AccountId gainAccount,\n        AccountId lossAccount\n    ) external payable {\n        _isManager(poolId);\n\n        require(hubRegistry.isRegistered(assetId), IHubRegistry.AssetNotFound());\n        require(\n            accounting.exists(poolId, assetAccount) && accounting.exists(poolId, equityAccount)\n                && accounting.exists(poolId, lossAccount) && accounting.exists(poolId, gainAccount),\n            IAccounting.AccountDoesNotExist()\n        );\n\n        HoldingAccount[] memory accounts = new HoldingAccount[](4);\n        accounts[0] = HoldingAccount(assetAccount, uint8(AccountType.Asset));\n        accounts[1] = HoldingAccount(equityAccount, uint8(AccountType.Equity));\n        accounts[3] = HoldingAccount(gainAccount, uint8(AccountType.Gain));\n        accounts[2] = HoldingAccount(lossAccount, uint8(AccountType.Loss));\n\n        holdings.create(poolId, scId, assetId, valuation, false, accounts);\n    }\n\n    /// @inheritdoc IHub\n    function createLiability(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        IERC7726 valuation,\n        AccountId expenseAccount,\n        AccountId liabilityAccount\n    ) external payable {\n        _isManager(poolId);\n\n        require(hubRegistry.isRegistered(assetId), IHubRegistry.AssetNotFound());\n        require(\n            accounting.exists(poolId, expenseAccount) && accounting.exists(poolId, liabilityAccount),\n            IAccounting.AccountDoesNotExist()\n        );\n\n        HoldingAccount[] memory accounts = new HoldingAccount[](2);\n        accounts[0] = HoldingAccount(expenseAccount, uint8(AccountType.Expense));\n        accounts[1] = HoldingAccount(liabilityAccount, uint8(AccountType.Liability));\n\n        holdings.create(poolId, scId, assetId, valuation, true, accounts);\n    }\n\n    /// @inheritdoc IHub\n    function updateHoldingValue(PoolId poolId, ShareClassId scId, AssetId assetId) public payable {\n        _isManager(poolId);\n\n        accounting.unlock(poolId);\n\n        (bool isPositive, uint128 diff) = holdings.update(poolId, scId, assetId);\n\n        // Save a diff=0 update gas cost\n        if (isPositive && diff > 0) {\n            if (holdings.isLiability(poolId, scId, assetId)) {\n                accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Liability)), diff);\n                accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Expense)), diff);\n            } else {\n                accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Gain)), diff);\n                accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Asset)), diff);\n            }\n        } else if (diff > 0) {\n            if (holdings.isLiability(poolId, scId, assetId)) {\n                accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Expense)), diff);\n                accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Liability)), diff);\n            } else {\n                accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Asset)), diff);\n                accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Loss)), diff);\n            }\n        }\n\n        accounting.lock();\n    }\n\n    /// @inheritdoc IHub\n    function updateHoldingValuation(PoolId poolId, ShareClassId scId, AssetId assetId, IERC7726 valuation)\n        external\n        payable\n    {\n        _isManager(poolId);\n\n        holdings.updateValuation(poolId, scId, assetId, valuation);\n    }\n\n    /// @inheritdoc IHub\n    function setHoldingAccountId(PoolId poolId, ShareClassId scId, AssetId assetId, uint8 kind, AccountId accountId)\n        external\n        payable\n    {\n        _isManager(poolId);\n\n        holdings.setAccountId(poolId, scId, assetId, kind, accountId);\n    }\n\n    /// @inheritdoc IHub\n    function createAccount(PoolId poolId, AccountId account, bool isDebitNormal) public payable {\n        _isManager(poolId);\n\n        accounting.createAccount(poolId, account, isDebitNormal);\n    }\n\n    /// @inheritdoc IHub\n    function setAccountMetadata(PoolId poolId, AccountId account, bytes calldata metadata) external payable {\n        _isManager(poolId);\n\n        accounting.setAccountMetadata(poolId, account, metadata);\n    }\n\n    /// @inheritdoc IHub\n    function updateJournal(PoolId poolId, JournalEntry[] memory debits, JournalEntry[] memory credits) external {\n        _isManager(poolId);\n\n        accounting.unlock(poolId);\n        accounting.addJournal(debits, credits);\n        accounting.lock();\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Gateway owner methods\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IHubGatewayHandler\n    function registerAsset(AssetId assetId, uint8 decimals) external {\n        _auth();\n\n        hubRegistry.registerAsset(assetId, decimals);\n    }\n\n    /// @inheritdoc IHubGatewayHandler\n    function depositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId, uint128 amount)\n        external\n    {\n        _auth();\n\n        shareClassManager.requestDeposit(poolId, scId, amount, investor, depositAssetId);\n    }\n\n    /// @inheritdoc IHubGatewayHandler\n    function redeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId, uint128 amount)\n        external\n    {\n        _auth();\n\n        shareClassManager.requestRedeem(poolId, scId, amount, investor, payoutAssetId);\n    }\n\n    /// @inheritdoc IHubGatewayHandler\n    function cancelDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId)\n        external\n    {\n        _auth();\n\n        uint128 cancelledAssetAmount = shareClassManager.cancelDepositRequest(poolId, scId, investor, depositAssetId);\n\n        // Cancellation might have been queued such that it will be executed in the future during claiming\n        if (cancelledAssetAmount > 0) {\n            sender.sendFulfilledCancelDepositRequest(poolId, scId, depositAssetId, investor, cancelledAssetAmount);\n        }\n    }\n\n    /// @inheritdoc IHubGatewayHandler\n    function cancelRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId) external {\n        _auth();\n\n        uint128 cancelledShareAmount = shareClassManager.cancelRedeemRequest(poolId, scId, investor, payoutAssetId);\n\n        // Cancellation might have been queued such that it will be executed in the future during claiming\n        if (cancelledShareAmount > 0) {\n            sender.sendFulfilledCancelRedeemRequest(poolId, scId, payoutAssetId, investor, cancelledShareAmount);\n        }\n    }\n\n    /// @inheritdoc IHubGatewayHandler\n    function updateHoldingAmount(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        uint128 amount,\n        D18 pricePoolPerAsset,\n        bool isIncrease\n    ) external {\n        _auth();\n\n        accounting.unlock(poolId);\n\n        bool isLiability = holdings.isLiability(poolId, scId, assetId);\n        AccountType debitAccountType = isLiability ? AccountType.Expense : AccountType.Asset;\n        AccountType creditAccountType = isLiability ? AccountType.Liability : AccountType.Equity;\n\n        if (isIncrease) {\n            uint128 value = holdings.increase(poolId, scId, assetId, pricePoolPerAsset, amount);\n            accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(debitAccountType)), value);\n            accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(creditAccountType)), value);\n        } else {\n            uint128 value = holdings.decrease(poolId, scId, assetId, pricePoolPerAsset, amount);\n            accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(creditAccountType)), value);\n            accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(debitAccountType)), value);\n        }\n\n        accounting.lock();\n    }\n\n    /// @inheritdoc IHubGatewayHandler\n    function increaseShareIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external {\n        _auth();\n\n        shareClassManager.increaseShareClassIssuance(poolId, scId, amount);\n    }\n\n    /// @inheritdoc IHubGatewayHandler\n    function decreaseShareIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external {\n        _auth();\n\n        shareClassManager.decreaseShareClassIssuance(poolId, scId, amount);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    //  Internal methods\n    //----------------------------------------------------------------------------------------------\n\n    /// @dev Ensure the sender is authorized\n    function _auth() internal auth {}\n\n    /// @dev Ensure the method can be used without reentrancy issues, and the sender is a pool admin\n    function _isManager(PoolId poolId) internal protected {\n        require(hubRegistry.manager(poolId, msg.sender), IHub.NotManager());\n    }\n\n    /// @dev Ensure the sender is authorized\n    function _isManagerAndPaid(PoolId poolId) internal {\n        _isManager(poolId);\n        _pay();\n    }\n\n    /// @notice Send native tokens to the gateway for transaction payment if it's not in a multicall.\n    function _pay() internal {\n        if (!gateway.isBatching()) {\n            gateway.payTransaction{value: msg.value}(msg.sender);\n        }\n    }\n\n    function _pricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId) internal view returns (D18) {\n        AssetId poolCurrency = hubRegistry.currency(poolId);\n        // NOTE: We assume symmetric prices are provided by holdings valuation\n        IERC7726 valuation = holdings.valuation(poolId, scId, assetId);\n\n        // Retrieve amount of 1 asset unit in pool currency\n        uint128 assetUnitAmount = (10 ** hubRegistry.decimals(assetId.raw())).toUint128();\n        uint128 poolUnitAmount = (10 ** hubRegistry.decimals(poolCurrency.raw())).toUint128();\n        uint128 poolAmountPerAsset =\n            valuation.getQuote(assetUnitAmount, assetId.addr(), poolCurrency.addr()).toUint128();\n\n        // Retrieve price by normalizing by pool denomination\n        return d18(poolAmountPerAsset, poolUnitAmount);\n    }\n}\n"
    },
    "src/hub/HubRegistry.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IERC6909Decimals} from \"src/misc/interfaces/IERC6909.sol\";\n\nimport {PoolId, newPoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {IHubRegistry} from \"src/hub/interfaces/IHubRegistry.sol\";\n\n/// @title  Hub Registry\n/// @notice Registry of all known pools, currencies, and assets.\ncontract HubRegistry is Auth, IHubRegistry {\n    using MathLib for uint256;\n\n    mapping(AssetId => uint8) internal _decimals;\n\n    mapping(PoolId => bytes) public metadata;\n    mapping(PoolId => AssetId) public currency;\n    mapping(bytes32 => address) public dependency;\n    mapping(PoolId => mapping(address => bool)) public manager;\n\n    constructor(address deployer) Auth(deployer) {}\n\n    //----------------------------------------------------------------------------------------------\n    // Registration methods\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IHubRegistry\n    function registerAsset(AssetId assetId, uint8 decimals_) external auth {\n        require(_decimals[assetId] == 0, AssetAlreadyRegistered());\n\n        _decimals[assetId] = decimals_;\n\n        emit NewAsset(assetId, decimals_);\n    }\n\n    /// @inheritdoc IHubRegistry\n    function registerPool(PoolId poolId_, address manager_, AssetId currency_) external auth {\n        require(manager_ != address(0), EmptyAccount());\n        require(!currency_.isNull(), EmptyCurrency());\n        require(currency[poolId_].isNull(), PoolAlreadyRegistered());\n\n        manager[poolId_][manager_] = true;\n        currency[poolId_] = currency_;\n\n        emit NewPool(poolId_, manager_, currency_);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Update methods\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IHubRegistry\n    function updateManager(PoolId poolId_, address manager_, bool canManage) external auth {\n        require(exists(poolId_), NonExistingPool(poolId_));\n        require(manager_ != address(0), EmptyAccount());\n\n        manager[poolId_][manager_] = canManage;\n\n        emit UpdateManager(poolId_, manager_, canManage);\n    }\n\n    /// @inheritdoc IHubRegistry\n    function setMetadata(PoolId poolId_, bytes calldata metadata_) external auth {\n        require(exists(poolId_), NonExistingPool(poolId_));\n\n        metadata[poolId_] = metadata_;\n\n        emit SetMetadata(poolId_, metadata_);\n    }\n\n    /// @inheritdoc IHubRegistry\n    function updateDependency(bytes32 what, address dependency_) external auth {\n        dependency[what] = dependency_;\n\n        emit UpdateDependency(what, dependency_);\n    }\n\n    /// @inheritdoc IHubRegistry\n    function updateCurrency(PoolId poolId_, AssetId currency_) external auth {\n        require(exists(poolId_), NonExistingPool(poolId_));\n        require(!currency_.isNull(), EmptyCurrency());\n\n        currency[poolId_] = currency_;\n\n        emit UpdateCurrency(poolId_, currency_);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // View methods\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IHubRegistry\n    function poolId(uint16 centrifugeId, uint48 postfix) public pure returns (PoolId poolId_) {\n        poolId_ = newPoolId(centrifugeId, postfix);\n    }\n\n    /// @inheritdoc IHubRegistry\n    function decimals(AssetId assetId) public view returns (uint8 decimals_) {\n        decimals_ = _decimals[assetId];\n        require(decimals_ > 0, AssetNotFound());\n    }\n\n    /// @inheritdoc IHubRegistry\n    function decimals(PoolId poolId_) public view returns (uint8 decimals_) {\n        decimals_ = _decimals[currency[poolId_]];\n        require(decimals_ > 0, AssetNotFound());\n    }\n\n    /// @inheritdoc IERC6909Decimals\n    function decimals(uint256 asset_) external view returns (uint8 decimals_) {\n        decimals_ = _decimals[AssetId.wrap(asset_.toUint128())];\n        require(decimals_ > 0, AssetNotFound());\n    }\n\n    /// @inheritdoc IHubRegistry\n    function exists(PoolId poolId_) public view returns (bool) {\n        return !currency[poolId_].isNull();\n    }\n\n    /// @inheritdoc IHubRegistry\n    function isRegistered(AssetId assetId) public view returns (bool) {\n        return _decimals[assetId] != 0;\n    }\n}\n"
    },
    "src/hub/ShareClassManager.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {ShareClassId, newShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\nimport {IHubRegistry} from \"src/hub/interfaces/IHubRegistry.sol\";\nimport {\n    IShareClassManager,\n    EpochInvestAmounts,\n    EpochRedeemAmounts,\n    UserOrder,\n    ShareClassMetadata,\n    ShareClassMetrics,\n    QueuedOrder,\n    RequestType,\n    EpochId\n} from \"src/hub/interfaces/IShareClassManager.sol\";\n\n/// @title  Share Class Manager\n/// @notice Manager for the share classes of a pool, and the core logic for tracking, approving, and fulfilling\n///         requests.\ncontract ShareClassManager is Auth, IShareClassManager {\n    using MathLib for *;\n    using CastLib for *;\n    using BytesLib for bytes;\n\n    IHubRegistry public immutable hubRegistry;\n\n    // Share classes\n    mapping(bytes32 salt => bool) public salts;\n    mapping(PoolId poolId => uint32) public shareClassCount;\n    mapping(ShareClassId scId => ShareClassMetrics) public metrics;\n    mapping(ShareClassId scId => ShareClassMetadata) public metadata;\n    mapping(PoolId poolId => mapping(ShareClassId => bool)) public shareClassIds;\n\n    // Epochs\n    mapping(ShareClassId scId => mapping(AssetId assetId => EpochId)) public epochId;\n    mapping(ShareClassId scId => mapping(AssetId assetId => mapping(uint32 epochId_ => EpochInvestAmounts epoch)))\n        public epochInvestAmounts;\n    mapping(ShareClassId scId => mapping(AssetId assetId => mapping(uint32 epochId_ => EpochRedeemAmounts epoch)))\n        public epochRedeemAmounts;\n\n    // Pending requests\n    mapping(ShareClassId scId => mapping(AssetId payoutAssetId => uint128 pending)) public pendingRedeem;\n    mapping(ShareClassId scId => mapping(AssetId depositAssetId => uint128 pending)) public pendingDeposit;\n    mapping(ShareClassId scId => mapping(AssetId payoutAssetId => mapping(bytes32 investor => UserOrder pending)))\n        public redeemRequest;\n    mapping(ShareClassId scId => mapping(AssetId depositAssetId => mapping(bytes32 investor => UserOrder pending)))\n        public depositRequest;\n\n    // Queued requests\n    mapping(ShareClassId scId => mapping(AssetId payoutAssetId => mapping(bytes32 investor => QueuedOrder queued)))\n        public queuedRedeemRequest;\n    mapping(ShareClassId scId => mapping(AssetId depositAssetId => mapping(bytes32 investor => QueuedOrder queued)))\n        public queuedDepositRequest;\n\n    constructor(IHubRegistry hubRegistry_, address deployer) Auth(deployer) {\n        hubRegistry = hubRegistry_;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Administration\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IShareClassManager\n    function addShareClass(PoolId poolId, string calldata name, string calldata symbol, bytes32 salt)\n        external\n        auth\n        returns (ShareClassId scId_)\n    {\n        scId_ = previewNextShareClassId(poolId);\n\n        uint32 index = ++shareClassCount[poolId];\n        shareClassIds[poolId][scId_] = true;\n\n        _updateMetadata(scId_, name, symbol, salt);\n\n        emit AddShareClass(poolId, scId_, index, name, symbol, salt);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Incoming requests\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IShareClassManager\n    function requestDeposit(PoolId poolId, ShareClassId scId_, uint128 amount, bytes32 investor, AssetId depositAssetId)\n        external\n        auth\n    {\n        require(exists(poolId, scId_), ShareClassNotFound());\n\n        // NOTE: CV ensures amount > 0\n        _updatePending(poolId, scId_, amount, true, investor, depositAssetId, RequestType.Deposit);\n    }\n\n    /// @inheritdoc IShareClassManager\n    function cancelDepositRequest(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId depositAssetId)\n        external\n        auth\n        returns (uint128 cancelledAssetAmount)\n    {\n        require(exists(poolId, scId_), ShareClassNotFound());\n\n        uint128 cancellingAmount = depositRequest[scId_][depositAssetId][investor].pending;\n\n        return _updatePending(poolId, scId_, cancellingAmount, false, investor, depositAssetId, RequestType.Deposit);\n    }\n\n    /// @inheritdoc IShareClassManager\n    function requestRedeem(PoolId poolId, ShareClassId scId_, uint128 amount, bytes32 investor, AssetId payoutAssetId)\n        external\n        auth\n    {\n        require(exists(poolId, scId_), ShareClassNotFound());\n\n        // NOTE: CV ensures amount > 0\n        _updatePending(poolId, scId_, amount, true, investor, payoutAssetId, RequestType.Redeem);\n    }\n\n    /// @inheritdoc IShareClassManager\n    function cancelRedeemRequest(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId payoutAssetId)\n        external\n        auth\n        returns (uint128 cancelledShareAmount)\n    {\n        require(exists(poolId, scId_), ShareClassNotFound());\n\n        uint128 cancellingAmount = redeemRequest[scId_][payoutAssetId][investor].pending;\n\n        return _updatePending(poolId, scId_, cancellingAmount, false, investor, payoutAssetId, RequestType.Redeem);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Manager actions\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IShareClassManager\n    function approveDeposits(\n        PoolId poolId,\n        ShareClassId scId_,\n        AssetId depositAssetId,\n        uint32 nowDepositEpochId,\n        uint128 approvedAssetAmount,\n        D18 pricePoolPerAsset\n    ) external auth returns (uint128 pendingAssetAmount, uint128 approvedPoolAmount) {\n        require(exists(poolId, scId_), ShareClassNotFound());\n        require(\n            nowDepositEpochId == nowDepositEpoch(scId_, depositAssetId),\n            EpochNotInSequence(nowDepositEpochId, nowDepositEpoch(scId_, depositAssetId))\n        );\n\n        // Limit in case approved > pending due to race condition of FM approval and async incoming requests\n        pendingAssetAmount = pendingDeposit[scId_][depositAssetId];\n        require(approvedAssetAmount <= pendingAssetAmount, InsufficientPending());\n        require(approvedAssetAmount > 0, ZeroApprovalAmount());\n\n        approvedPoolAmount = PricingLib.convertWithPrice(\n            approvedAssetAmount, hubRegistry.decimals(depositAssetId), hubRegistry.decimals(poolId), pricePoolPerAsset\n        ).toUint128();\n\n        // Update epoch data\n        EpochInvestAmounts storage epochAmounts = epochInvestAmounts[scId_][depositAssetId][nowDepositEpochId];\n        epochAmounts.approvedAssetAmount = approvedAssetAmount;\n        epochAmounts.approvedPoolAmount = approvedPoolAmount;\n        epochAmounts.pendingAssetAmount = pendingAssetAmount;\n        epochAmounts.pricePoolPerAsset = pricePoolPerAsset;\n\n        // Reduce pending\n        pendingDeposit[scId_][depositAssetId] -= approvedAssetAmount;\n        pendingAssetAmount -= approvedAssetAmount;\n\n        epochId[scId_][depositAssetId].deposit = nowDepositEpochId;\n        emit ApproveDeposits(\n            poolId,\n            scId_,\n            depositAssetId,\n            nowDepositEpochId,\n            approvedPoolAmount,\n            approvedAssetAmount,\n            pendingAssetAmount\n        );\n    }\n\n    /// @inheritdoc IShareClassManager\n    function approveRedeems(\n        PoolId poolId,\n        ShareClassId scId_,\n        AssetId payoutAssetId,\n        uint32 nowRedeemEpochId,\n        uint128 approvedShareAmount,\n        D18 pricePoolPerAsset\n    ) external auth returns (uint128 pendingShareAmount) {\n        require(exists(poolId, scId_), ShareClassNotFound());\n        require(\n            nowRedeemEpochId == nowRedeemEpoch(scId_, payoutAssetId),\n            EpochNotInSequence(nowRedeemEpochId, nowRedeemEpoch(scId_, payoutAssetId))\n        );\n\n        // Limit in case approved > pending due to race condition of FM approval and async incoming requests\n        pendingShareAmount = pendingRedeem[scId_][payoutAssetId];\n        require(approvedShareAmount <= pendingShareAmount, InsufficientPending());\n        require(approvedShareAmount > 0, ZeroApprovalAmount());\n\n        // Update epoch data\n        EpochRedeemAmounts storage epochAmounts = epochRedeemAmounts[scId_][payoutAssetId][nowRedeemEpochId];\n        epochAmounts.approvedShareAmount = approvedShareAmount;\n        epochAmounts.pendingShareAmount = pendingShareAmount;\n        epochAmounts.pricePoolPerAsset = pricePoolPerAsset;\n\n        // Reduce pending\n        pendingRedeem[scId_][payoutAssetId] -= approvedShareAmount;\n        pendingShareAmount -= approvedShareAmount;\n        epochId[scId_][payoutAssetId].redeem = nowRedeemEpochId;\n        emit ApproveRedeems(poolId, scId_, payoutAssetId, nowRedeemEpochId, approvedShareAmount, pendingShareAmount);\n    }\n\n    /// @inheritdoc IShareClassManager\n    function issueShares(\n        PoolId poolId,\n        ShareClassId scId_,\n        AssetId depositAssetId,\n        uint32 nowIssueEpochId,\n        D18 navPoolPerShare\n    ) external auth returns (uint128 issuedShareAmount, uint128 depositAssetAmount, uint128 depositPoolAmount) {\n        require(exists(poolId, scId_), ShareClassNotFound());\n        require(nowIssueEpochId <= epochId[scId_][depositAssetId].deposit, EpochNotFound());\n        require(\n            nowIssueEpochId == nowIssueEpoch(scId_, depositAssetId),\n            EpochNotInSequence(nowIssueEpochId, nowIssueEpoch(scId_, depositAssetId))\n        );\n\n        EpochInvestAmounts storage epochAmounts = epochInvestAmounts[scId_][depositAssetId][nowIssueEpochId];\n        epochAmounts.navPoolPerShare = navPoolPerShare;\n\n        issuedShareAmount = PricingLib.assetToShareAmount(\n            epochAmounts.approvedAssetAmount,\n            hubRegistry.decimals(depositAssetId),\n            hubRegistry.decimals(poolId),\n            epochAmounts.pricePoolPerAsset,\n            navPoolPerShare,\n            MathLib.Rounding.Down\n        ).toUint128();\n\n        metrics[scId_].totalIssuance += issuedShareAmount;\n        epochAmounts.issuedAt = block.timestamp.toUint64();\n        epochId[scId_][depositAssetId].issue = nowIssueEpochId;\n\n        depositAssetAmount = epochAmounts.approvedAssetAmount;\n        depositPoolAmount = epochAmounts.approvedPoolAmount;\n\n        emit IssueShares(\n            poolId,\n            scId_,\n            depositAssetId,\n            nowIssueEpochId,\n            navPoolPerShare,\n            PricingLib.priceAssetPerShare(epochAmounts.navPoolPerShare, epochAmounts.pricePoolPerAsset),\n            issuedShareAmount\n        );\n    }\n\n    /// @inheritdoc IShareClassManager\n    function revokeShares(\n        PoolId poolId,\n        ShareClassId scId_,\n        AssetId payoutAssetId,\n        uint32 nowRevokeEpochId,\n        D18 navPoolPerShare\n    ) external auth returns (uint128 revokedShareAmount, uint128 payoutAssetAmount, uint128 payoutPoolAmount) {\n        require(exists(poolId, scId_), ShareClassNotFound());\n        require(nowRevokeEpochId <= epochId[scId_][payoutAssetId].redeem, EpochNotFound());\n        require(\n            nowRevokeEpochId == nowRevokeEpoch(scId_, payoutAssetId),\n            EpochNotInSequence(nowRevokeEpochId, nowRevokeEpoch(scId_, payoutAssetId))\n        );\n\n        EpochRedeemAmounts storage epochAmounts = epochRedeemAmounts[scId_][payoutAssetId][nowRevokeEpochId];\n        epochAmounts.navPoolPerShare = navPoolPerShare;\n\n        require(epochAmounts.approvedShareAmount <= metrics[scId_].totalIssuance, RevokeMoreThanIssued());\n\n        // NOTE: shares and pool currency have the same decimals - no conversion needed!\n        payoutPoolAmount = navPoolPerShare.mulUint128(epochAmounts.approvedShareAmount, MathLib.Rounding.Down);\n\n        payoutAssetAmount = PricingLib.poolToAssetAmount(\n            payoutPoolAmount,\n            hubRegistry.decimals(poolId),\n            hubRegistry.decimals(payoutAssetId),\n            epochAmounts.pricePoolPerAsset,\n            MathLib.Rounding.Down\n        ).toUint128();\n        revokedShareAmount = epochAmounts.approvedShareAmount;\n\n        metrics[scId_].totalIssuance -= epochAmounts.approvedShareAmount;\n        epochAmounts.payoutAssetAmount = payoutAssetAmount;\n        epochAmounts.revokedAt = block.timestamp.toUint64();\n        epochId[scId_][payoutAssetId].revoke = nowRevokeEpochId;\n\n        emit RevokeShares(\n            poolId,\n            scId_,\n            payoutAssetId,\n            nowRevokeEpochId,\n            navPoolPerShare,\n            PricingLib.priceAssetPerShare(epochAmounts.navPoolPerShare, epochAmounts.pricePoolPerAsset),\n            epochAmounts.approvedShareAmount,\n            payoutAssetAmount,\n            payoutPoolAmount\n        );\n    }\n\n    /// @inheritdoc IShareClassManager\n    function updatePricePerShare(PoolId poolId, ShareClassId scId_, D18 navPoolPerShare) external auth {\n        require(exists(poolId, scId_), ShareClassNotFound());\n\n        ShareClassMetrics storage m = metrics[scId_];\n        m.navPerShare = navPoolPerShare;\n        emit UpdateShareClass(poolId, scId_, navPoolPerShare);\n    }\n\n    /// @inheritdoc IShareClassManager\n    function updateMetadata(PoolId poolId, ShareClassId scId_, string calldata name, string calldata symbol)\n        external\n        auth\n    {\n        require(exists(poolId, scId_), ShareClassNotFound());\n\n        _updateMetadata(scId_, name, symbol, bytes32(0));\n\n        emit UpdateMetadata(poolId, scId_, name, symbol);\n    }\n\n    /// @inheritdoc IShareClassManager\n    function increaseShareClassIssuance(PoolId poolId, ShareClassId scId_, uint128 amount) external auth {\n        require(exists(poolId, scId_), ShareClassNotFound());\n\n        uint128 newIssuance = metrics[scId_].totalIssuance + amount;\n        metrics[scId_].totalIssuance = newIssuance;\n\n        emit RemoteIssueShares(poolId, scId_, amount);\n    }\n\n    /// @inheritdoc IShareClassManager\n    function decreaseShareClassIssuance(PoolId poolId, ShareClassId scId_, uint128 amount) external auth {\n        require(exists(poolId, scId_), ShareClassNotFound());\n        require(metrics[scId_].totalIssuance >= amount, DecreaseMoreThanIssued());\n\n        uint128 newIssuance = metrics[scId_].totalIssuance - amount;\n        metrics[scId_].totalIssuance = newIssuance;\n\n        emit RemoteRevokeShares(poolId, scId_, amount);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Claiming methods\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IShareClassManager\n    function claimDeposit(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId depositAssetId)\n        public\n        auth\n        returns (\n            uint128 payoutShareAmount,\n            uint128 paymentAssetAmount,\n            uint128 cancelledAssetAmount,\n            bool canClaimAgain\n        )\n    {\n        require(exists(poolId, scId_), ShareClassNotFound());\n\n        UserOrder storage userOrder = depositRequest[scId_][depositAssetId][investor];\n        require(userOrder.pending > 0, NoOrderFound());\n        require(userOrder.lastUpdate <= epochId[scId_][depositAssetId].issue, IssuanceRequired());\n        canClaimAgain = userOrder.lastUpdate < epochId[scId_][depositAssetId].issue;\n        EpochInvestAmounts storage epochAmounts = epochInvestAmounts[scId_][depositAssetId][userOrder.lastUpdate];\n\n        paymentAssetAmount = epochAmounts.approvedAssetAmount == 0\n            ? 0\n            : userOrder.pending.mulDiv(epochAmounts.approvedAssetAmount, epochAmounts.pendingAssetAmount).toUint128();\n\n        // NOTE: Due to precision loss, the sum of claimable user amounts is leq than the amount of minted share class\n        // tokens corresponding to the approved share amount (instead of equality). I.e., it is possible for an epoch to\n        // have an excess of a share class tokens which cannot be claimed by anyone.\n        // This excess is at most n-1 share tokens for an epoch with n claimable users.\n        if (paymentAssetAmount > 0) {\n            uint256 paymentPoolAmount = PricingLib.convertWithPrice(\n                paymentAssetAmount,\n                hubRegistry.decimals(depositAssetId),\n                hubRegistry.decimals(poolId),\n                epochAmounts.pricePoolPerAsset\n            );\n            payoutShareAmount =\n                epochAmounts.navPoolPerShare.reciprocalMulUint256(paymentPoolAmount, MathLib.Rounding.Down).toUint128();\n\n            userOrder.pending -= paymentAssetAmount;\n        }\n\n        emit ClaimDeposit(\n            poolId,\n            scId_,\n            userOrder.lastUpdate,\n            investor,\n            depositAssetId,\n            paymentAssetAmount,\n            userOrder.pending,\n            payoutShareAmount,\n            epochAmounts.issuedAt\n        );\n\n        // If there is nothing to claim anymore we can short circuit to the latest epoch\n        if (userOrder.pending == 0) {\n            // The current epoch is always one step ahead of the stored one\n            userOrder.lastUpdate = nowDepositEpoch(scId_, depositAssetId);\n            canClaimAgain = false;\n        } else {\n            userOrder.lastUpdate += 1;\n        }\n\n        // If user claimed up to latest approval epoch, move queued to pending\n        if (userOrder.lastUpdate == nowDepositEpoch(scId_, depositAssetId)) {\n            cancelledAssetAmount =\n                _postClaimUpdateQueued(poolId, scId_, investor, depositAssetId, userOrder, RequestType.Deposit);\n        }\n    }\n\n    /// @inheritdoc IShareClassManager\n    function claimRedeem(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId payoutAssetId)\n        public\n        auth\n        returns (\n            uint128 payoutAssetAmount,\n            uint128 paymentShareAmount,\n            uint128 cancelledShareAmount,\n            bool canClaimAgain\n        )\n    {\n        require(exists(poolId, scId_), ShareClassNotFound());\n\n        UserOrder storage userOrder = redeemRequest[scId_][payoutAssetId][investor];\n        require(userOrder.pending > 0, NoOrderFound());\n        require(userOrder.lastUpdate <= epochId[scId_][payoutAssetId].revoke, RevocationRequired());\n        canClaimAgain = userOrder.lastUpdate < epochId[scId_][payoutAssetId].revoke;\n\n        EpochRedeemAmounts storage epochAmounts = epochRedeemAmounts[scId_][payoutAssetId][userOrder.lastUpdate];\n\n        paymentShareAmount = epochAmounts.approvedShareAmount == 0\n            ? 0\n            : userOrder.pending.mulDiv(epochAmounts.approvedShareAmount, epochAmounts.pendingShareAmount).toUint128();\n\n        // NOTE: Due to precision loss, the sum of claimable user amounts is leq than the amount of minted share class\n        // tokens corresponding to the approved share amount (instead of equality). I.e., it is possible for an epoch to\n        // have an excess of a share class tokens which cannot be claimed by anyone.\n        // This excess is at most n-1 share tokens for an epoch with n claimable users.\n        if (paymentShareAmount > 0) {\n            payoutAssetAmount = PricingLib.shareToAssetAmount(\n                paymentShareAmount,\n                hubRegistry.decimals(poolId),\n                hubRegistry.decimals(payoutAssetId),\n                epochAmounts.pricePoolPerAsset,\n                epochAmounts.navPoolPerShare,\n                MathLib.Rounding.Down\n            ).toUint128();\n\n            userOrder.pending -= paymentShareAmount;\n        }\n\n        emit ClaimRedeem(\n            poolId,\n            scId_,\n            userOrder.lastUpdate,\n            investor,\n            payoutAssetId,\n            paymentShareAmount,\n            userOrder.pending,\n            payoutAssetAmount,\n            epochAmounts.revokedAt\n        );\n\n        // If there is nothing to claim anymore we can short circuit the in between epochs\n        if (userOrder.pending == 0) {\n            // The current epoch is always one step ahead of the stored one\n            userOrder.lastUpdate = nowRedeemEpoch(scId_, payoutAssetId);\n            canClaimAgain = false;\n        } else {\n            userOrder.lastUpdate += 1;\n        }\n\n        if (userOrder.lastUpdate == nowRedeemEpoch(scId_, payoutAssetId)) {\n            cancelledShareAmount =\n                _postClaimUpdateQueued(poolId, scId_, investor, payoutAssetId, userOrder, RequestType.Redeem);\n        }\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // View methods\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IShareClassManager\n    function previewNextShareClassId(PoolId poolId) public view returns (ShareClassId scId) {\n        return newShareClassId(poolId, shareClassCount[poolId] + 1);\n    }\n\n    /// @inheritdoc IShareClassManager\n    function previewShareClassId(PoolId poolId, uint32 index) public pure returns (ShareClassId scId) {\n        return newShareClassId(poolId, index);\n    }\n\n    /// @inheritdoc IShareClassManager\n    function exists(PoolId poolId, ShareClassId scId_) public view returns (bool) {\n        return shareClassIds[poolId][scId_];\n    }\n\n    /// @inheritdoc IShareClassManager\n    function nowDepositEpoch(ShareClassId scId_, AssetId depositAssetId) public view returns (uint32) {\n        return epochId[scId_][depositAssetId].deposit + 1;\n    }\n\n    /// @inheritdoc IShareClassManager\n    function nowIssueEpoch(ShareClassId scId_, AssetId depositAssetId) public view returns (uint32) {\n        return epochId[scId_][depositAssetId].issue + 1;\n    }\n\n    /// @inheritdoc IShareClassManager\n    function nowRedeemEpoch(ShareClassId scId_, AssetId depositAssetId) public view returns (uint32) {\n        return epochId[scId_][depositAssetId].redeem + 1;\n    }\n\n    /// @inheritdoc IShareClassManager\n    function nowRevokeEpoch(ShareClassId scId_, AssetId depositAssetId) public view returns (uint32) {\n        return epochId[scId_][depositAssetId].revoke + 1;\n    }\n\n    /// @inheritdoc IShareClassManager\n    function maxDepositClaims(ShareClassId scId_, bytes32 investor, AssetId depositAssetId)\n        public\n        view\n        returns (uint32)\n    {\n        return _maxClaims(depositRequest[scId_][depositAssetId][investor], epochId[scId_][depositAssetId].deposit);\n    }\n\n    /// @inheritdoc IShareClassManager\n    function maxRedeemClaims(ShareClassId scId_, bytes32 investor, AssetId payoutAssetId)\n        public\n        view\n        returns (uint32)\n    {\n        return _maxClaims(redeemRequest[scId_][payoutAssetId][investor], epochId[scId_][payoutAssetId].redeem);\n    }\n\n    function _maxClaims(UserOrder memory userOrder, uint32 lastEpoch) private pure returns (uint32) {\n        // User order either not set or not processed\n        if (userOrder.pending == 0 || userOrder.lastUpdate > lastEpoch) {\n            return 0;\n        }\n\n        return lastEpoch - userOrder.lastUpdate + 1;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Internal methods\n    //----------------------------------------------------------------------------------------------\n\n    function _updateMetadata(ShareClassId scId_, string calldata name, string calldata symbol, bytes32 salt) private {\n        uint256 nameLen = bytes(name).length;\n        require(nameLen > 0 && nameLen <= 128, InvalidMetadataName());\n\n        uint256 symbolLen = bytes(symbol).length;\n        require(symbolLen > 0 && symbolLen <= 32, InvalidMetadataSymbol());\n\n        ShareClassMetadata storage meta = metadata[scId_];\n\n        // Ensure that the salt is not being updated or is being set for the first time\n        require(\n            (salt == bytes32(0) && meta.salt != bytes32(0)) || (salt != bytes32(0) && meta.salt == bytes32(0)),\n            InvalidSalt()\n        );\n\n        if (salt != bytes32(0) && meta.salt == bytes32(0)) {\n            require(!salts[salt], AlreadyUsedSalt());\n            salts[salt] = true;\n            meta.salt = salt;\n        }\n\n        meta.name = name;\n        meta.symbol = symbol;\n    }\n\n    function _postClaimUpdateQueued(\n        PoolId poolId,\n        ShareClassId scId_,\n        bytes32 investor,\n        AssetId assetId,\n        UserOrder storage userOrder,\n        RequestType requestType\n    ) private returns (uint128 cancelledAmount) {\n        QueuedOrder storage queued = requestType == RequestType.Deposit\n            ? queuedDepositRequest[scId_][assetId][investor]\n            : queuedRedeemRequest[scId_][assetId][investor];\n\n        // Increment pending by queued or cancel everything\n        uint128 updatePendingAmount = queued.isCancelling ? userOrder.pending : queued.amount;\n        if (queued.isCancelling) {\n            cancelledAmount = userOrder.pending + queued.amount;\n            userOrder.pending = 0;\n        } else {\n            userOrder.pending += queued.amount;\n        }\n\n        if (requestType == RequestType.Deposit) {\n            _updatePendingDeposit(\n                poolId,\n                scId_,\n                updatePendingAmount,\n                !queued.isCancelling,\n                investor,\n                assetId,\n                userOrder,\n                QueuedOrder(false, 0)\n            );\n        } else {\n            _updatePendingRedeem(\n                poolId,\n                scId_,\n                updatePendingAmount,\n                !queued.isCancelling,\n                investor,\n                assetId,\n                userOrder,\n                QueuedOrder(false, 0)\n            );\n        }\n\n        // Clear queued\n        queued.isCancelling = false;\n        queued.amount = 0;\n    }\n\n    /// @notice Updates the amount of a deposit or redeem request.\n    ///\n    /// @param poolId Identifier of the pool\n    /// @param scId_ Identifier of the share class\n    /// @param amount Amount which is updated\n    /// @param isIncrement Whether the amount is positive (additional request) or negative (cancellation)\n    /// @param investor Address of the entity which is depositing\n    /// @param assetId Identifier of the asset which the investor either used as deposit or wants to redeem to\n    /// @param requestType Flag indicating whether the request is a deposit or redeem request\n    /// @return cancelledAmount Pending amount which was cancelled\n    function _updatePending(\n        PoolId poolId,\n        ShareClassId scId_,\n        uint128 amount,\n        bool isIncrement,\n        bytes32 investor,\n        AssetId assetId,\n        RequestType requestType\n    ) private returns (uint128 cancelledAmount) {\n        UserOrder storage userOrder = requestType == RequestType.Deposit\n            ? depositRequest[scId_][assetId][investor]\n            : redeemRequest[scId_][assetId][investor];\n        QueuedOrder storage queued = requestType == RequestType.Deposit\n            ? queuedDepositRequest[scId_][assetId][investor]\n            : queuedRedeemRequest[scId_][assetId][investor];\n\n        // We must only update either queued or pending\n        if (_updateQueued(poolId, scId_, amount, isIncrement, investor, assetId, userOrder, queued, requestType)) {\n            return 0;\n        }\n\n        cancelledAmount = isIncrement ? 0 : amount;\n        // NOTE: If we decrease the pending, we decrease usually by the full amount\n        //       We keep subtraction of amount over setting to zero on purpose to not limit future higher level logic\n        userOrder.pending = isIncrement ? userOrder.pending + amount : userOrder.pending - amount;\n\n        userOrder.lastUpdate =\n            requestType == RequestType.Deposit ? nowDepositEpoch(scId_, assetId) : nowRedeemEpoch(scId_, assetId);\n\n        if (requestType == RequestType.Deposit) {\n            _updatePendingDeposit(poolId, scId_, amount, isIncrement, investor, assetId, userOrder, queued);\n        } else {\n            _updatePendingRedeem(poolId, scId_, amount, isIncrement, investor, assetId, userOrder, queued);\n        }\n    }\n\n    /// @notice Checks whether the pending amount can be updated. If not, it updates the queued amount.\n    ///\n    /// @param poolId Identifier of the pool\n    /// @param scId_ Identifier of the share class\n    /// @param amount Amount which is updated\n    /// @param isIncrement Whether the amount is positive (additional request) or negative (cancellation)\n    /// @param investor Address of the entity which is depositing\n    /// @param assetId Identifier of the asset which the investor either used as deposit or wants to redeem to\n    /// @param userOrder User order storage for the deposit or redeem request\n    /// @param requestType Flag indicating whether the request is a deposit or redeem request\n    /// @return skipPendingUpdate Flag indicating whether the pending amount can be updated which is true if the user\n    /// does not need to claim\n    function _updateQueued(\n        PoolId poolId,\n        ShareClassId scId_,\n        uint128 amount,\n        bool isIncrement,\n        bytes32 investor,\n        AssetId assetId,\n        UserOrder storage userOrder,\n        QueuedOrder storage queued,\n        RequestType requestType\n    ) private returns (bool skipPendingUpdate) {\n        uint32 lastEpoch =\n            requestType == RequestType.Deposit ? epochId[scId_][assetId].deposit : epochId[scId_][assetId].redeem;\n        uint32 currentEpoch = lastEpoch + 1;\n\n        // Short circuit if user can mutate pending, i.e. last update happened after latest approval or is first update\n        if (userOrder.lastUpdate == currentEpoch || userOrder.pending == 0 || lastEpoch == 0) {\n            return false;\n        }\n\n        // Block increasing queued amount if cancelling is already queued\n        // NOTE: Can only happen due to race condition as CV blocks requests if cancellation is in progress\n        require(!(queued.isCancelling && amount > 0), CancellationQueued());\n\n        if (!isIncrement) {\n            queued.isCancelling = true;\n        } else {\n            queued.amount += amount;\n        }\n\n        if (requestType == RequestType.Deposit) {\n            uint128 pendingTotal = pendingDeposit[scId_][assetId];\n            emit UpdateDepositRequest(\n                poolId,\n                scId_,\n                assetId,\n                currentEpoch,\n                investor,\n                userOrder.pending,\n                pendingTotal,\n                queued.amount,\n                queued.isCancelling\n            );\n        } else {\n            uint128 pendingTotal = pendingRedeem[scId_][assetId];\n\n            emit UpdateRedeemRequest(\n                poolId,\n                scId_,\n                assetId,\n                currentEpoch,\n                investor,\n                userOrder.pending,\n                pendingTotal,\n                queued.amount,\n                queued.isCancelling\n            );\n        }\n\n        return true;\n    }\n\n    function _updatePendingDeposit(\n        PoolId poolId,\n        ShareClassId scId_,\n        uint128 amount,\n        bool isIncrement,\n        bytes32 investor,\n        AssetId assetId,\n        UserOrder storage userOrder,\n        QueuedOrder memory queued\n    ) private {\n        uint128 pendingTotal = pendingDeposit[scId_][assetId];\n        pendingTotal = isIncrement ? pendingTotal + amount : pendingTotal - amount;\n        pendingDeposit[scId_][assetId] = pendingTotal;\n\n        emit UpdateDepositRequest(\n            poolId,\n            scId_,\n            assetId,\n            nowDepositEpoch(scId_, assetId),\n            investor,\n            userOrder.pending,\n            pendingTotal,\n            queued.amount,\n            queued.isCancelling\n        );\n    }\n\n    function _updatePendingRedeem(\n        PoolId poolId,\n        ShareClassId scId_,\n        uint128 amount,\n        bool isIncrement,\n        bytes32 investor,\n        AssetId assetId,\n        UserOrder storage userOrder,\n        QueuedOrder memory queued\n    ) private {\n        uint128 pendingTotal = pendingRedeem[scId_][assetId];\n        pendingTotal = isIncrement ? pendingTotal + amount : pendingTotal - amount;\n        pendingRedeem[scId_][assetId] = pendingTotal;\n\n        emit UpdateRedeemRequest(\n            poolId,\n            scId_,\n            assetId,\n            nowRedeemEpoch(scId_, assetId),\n            investor,\n            userOrder.pending,\n            pendingTotal,\n            queued.amount,\n            queued.isCancelling\n        );\n    }\n}\n"
    },
    "src/hub/interfaces/IAccounting.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nstruct JournalEntry {\n    uint128 value;\n    AccountId accountId;\n}\n\ninterface IAccounting {\n    /// @notice Emitted when a an entry is done\n    event Credit(PoolId indexed poolId, AccountId indexed account, uint128 value);\n    event Debit(PoolId indexed poolId, AccountId indexed account, uint128 value);\n\n    /// @notice Emitted at the beginning and end of a journal entry\n    event StartJournalId(PoolId indexed poolId, uint256 journalId);\n    event EndJournalId(PoolId indexed poolId, uint256 journalId);\n\n    /// @notice Emitted when a new account is created\n    event CreateAccount(PoolId indexed poolId, AccountId indexed account, bool isDebitNormal);\n\n    /// @notice Emitted when metadata is set for an account\n    event SetAccountMetadata(PoolId indexed poolId, AccountId indexed account, bytes metadata);\n\n    /// @notice Dispatched when the pool is already unlocked.\n    error AccountingAlreadyUnlocked();\n\n    /// @notice Dispatched when the pool is not unlocked to interact with.\n    error AccountingLocked();\n\n    /// @notice Dispatched when the debit and credit side do not match at the end of a transaction.\n    error Unbalanced();\n\n    /// @notice Dispatched when trying to create an account that already exists.\n    error AccountExists();\n\n    /// @notice Dispatched when trying debit or credit an account that doesn't exists.\n    error AccountDoesNotExist();\n\n    /// @notice Represents an account\n    struct Account {\n        uint128 totalDebit;\n        uint128 totalCredit;\n        bool isDebitNormal;\n        uint64 lastUpdated;\n        bytes metadata;\n    }\n\n    /// @notice Debits an account. Increase the value of debit-normal accounts, decrease for credit-normal ones.\n    /// @param account The account to debit\n    /// @param value Amount being debited\n    function addDebit(AccountId account, uint128 value) external;\n\n    /// @notice Credits an account. Decrease the value of debit-normal accounts, increase for credit-normal ones.\n    /// @param account The account to credit\n    /// @param value Amount being credited\n    function addCredit(AccountId account, uint128 value) external;\n\n    /// @notice Apply addDebit and addCredit to each journal entry\n    function addJournal(JournalEntry[] memory debits, JournalEntry[] memory credits) external;\n\n    /// @notice Unlocks a pool for journal entries\n    /// @param poolId The pool to unlock\n    function unlock(PoolId poolId) external;\n\n    /// @notice Closes the transaction and checks if the entries are balanced.\n    function lock() external;\n\n    /// @notice Creates an account.\n    /// @param poolId The pool the account belongs to\n    /// @param account The account to create\n    /// @param isDebitNormal Whether the account is debit-normal or credit-normal\n    function createAccount(PoolId poolId, AccountId account, bool isDebitNormal) external;\n\n    /// @notice Sets metadata associated to an existent account.\n    /// @param poolId The pool the account belongs to\n    /// @param account The account to set metadata for\n    /// @param metadata The metadata to set\n    function setAccountMetadata(PoolId poolId, AccountId account, bytes calldata metadata) external;\n\n    /// @notice Returns the value of an account\n    /// @param poolId The pool the account belongs to\n    /// @param account The account to get the value of\n    /// @return isPositive Indicates whether value is a positive or negative value\n    /// @return value The value of the account\n    function accountValue(PoolId poolId, AccountId account) external view returns (bool isPositive, uint128 value);\n\n    /// @notice Returns whether an account exists\n    /// @param poolId The pool the account belongs to\n    /// @param account The account to check\n    /// @return True if the account exists, false otherwise\n    function exists(PoolId poolId, AccountId account) external view returns (bool);\n}\n"
    },
    "src/hub/interfaces/IHoldings.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\nimport {D18} from \"src/misc/types/D18.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nstruct Holding {\n    uint128 assetAmount;\n    uint128 assetAmountValue;\n    IERC7726 valuation; // Used for existence\n    bool isLiability;\n}\n\nstruct HoldingAccount {\n    AccountId accountId;\n    uint8 kind;\n}\n\ninterface IHoldings {\n    /// @notice Emitted when a holding is created\n    event Create(\n        PoolId indexed,\n        ShareClassId indexed scId,\n        AssetId indexed assetId,\n        IERC7726 valuation,\n        bool isLiability,\n        HoldingAccount[] accounts\n    );\n\n    /// @notice Emitted when a holding is increased\n    event Increase(\n        PoolId indexed,\n        ShareClassId indexed scId,\n        AssetId indexed assetId,\n        D18 pricePoolPerAsset,\n        uint128 amount,\n        uint128 increasedValue\n    );\n\n    /// @notice Emitted when a holding is decreased\n    event Decrease(\n        PoolId indexed,\n        ShareClassId indexed scId,\n        AssetId indexed assetId,\n        D18 pricePoolPerAsset,\n        uint128 amount,\n        uint128 decreasedValue\n    );\n\n    /// @notice Emitted when the holding is updated\n    event Update(\n        PoolId indexed, ShareClassId indexed scId, AssetId indexed assetId, bool isPositive, uint128 diffValue\n    );\n\n    /// @notice Emitted when a holding valuation is updated\n    event UpdateValuation(PoolId indexed, ShareClassId indexed scId, AssetId indexed assetId, IERC7726 valuation);\n\n    /// @notice Emitted when an account is for a holding is set\n    event SetAccountId(\n        PoolId indexed, ShareClassId indexed scId, AssetId indexed assetId, uint8 kind, AccountId accountId\n    );\n\n    /// @notice Item was not found for a required action\n    error HoldingNotFound();\n\n    /// @notice Valuation is not valid.\n    error WrongValuation();\n\n    /// @notice ShareClassId is not valid.\n    error WrongShareClassId();\n\n    /// @notice AssetId is not valid.\n    error WrongAssetId();\n\n    /// @notice Creates a new holding in a pool using a valuation\n    function create(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        IERC7726 valuation,\n        bool isLiability,\n        HoldingAccount[] memory accounts\n    ) external;\n\n    /// @notice Increments the amount of a holding and updates the value for that increment.\n    /// @return value The value the holding has increment.\n    function increase(PoolId poolId, ShareClassId scId, AssetId assetId, D18 pricePoolPerAsset, uint128 amount)\n        external\n        returns (uint128 value);\n\n    /// @notice Decrements the amount of a holding and updates the value for that decrement.\n    /// @return value The value the holding has decrement.\n    function decrease(PoolId poolId, ShareClassId scId, AssetId assetId, D18 pricePoolPerAsset, uint128 amount)\n        external\n        returns (uint128 value);\n\n    /// @notice Reset the value of a holding using the current valuation.\n    /// @return isPositive Indicates whether the diffValue is positive or negative\n    /// @return diffValue The difference in value after the new valuation.\n    function update(PoolId poolId, ShareClassId scId, AssetId assetId)\n        external\n        returns (bool isPositive, uint128 diffValue);\n\n    /// @notice Updates the valuation method used for this holding.\n    function updateValuation(PoolId poolId, ShareClassId scId, AssetId assetId, IERC7726 valuation) external;\n\n    /// @notice Sets an account id for an specific kind\n    function setAccountId(PoolId poolId, ShareClassId scId, AssetId assetId, uint8 kind, AccountId accountId)\n        external;\n\n    /// @notice Returns the value of this holding.\n    function value(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (uint128 value);\n\n    /// @notice Returns the amount of this holding.\n    function amount(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (uint128 amount);\n\n    /// @notice Returns the valuation method used for this holding.\n    function valuation(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (IERC7726);\n\n    /// @notice Returns if the holding is a liability\n    function isLiability(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (bool);\n\n    /// @notice Returns an account id for an specific kind\n    function accountId(PoolId poolId, ShareClassId scId, AssetId assetId, uint8 kind)\n        external\n        view\n        returns (AccountId);\n\n    /// @notice Tells if the holding exists for an asset in a share class\n    function exists(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (bool);\n}\n"
    },
    "src/hub/interfaces/IHub.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18} from \"src/misc/types/D18.sol\";\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\n\nimport {VaultUpdateKind} from \"src/common/libraries/MessageLib.sol\";\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {IPoolMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {IShareClassManager} from \"src/hub/interfaces/IShareClassManager.sol\";\nimport {IAccounting, JournalEntry} from \"src/hub/interfaces/IAccounting.sol\";\nimport {IHubRegistry} from \"src/hub/interfaces/IHubRegistry.sol\";\nimport {IHoldings} from \"src/hub/interfaces/IHoldings.sol\";\n\n/// @notice Account types used by Hub\nenum AccountType {\n    /// @notice Debit normal account for tracking assets\n    Asset,\n    /// @notice Credit normal account for tracking equities\n    Equity,\n    /// @notice Credit normal account for tracking losses\n    Loss,\n    /// @notice Credit normal account for tracking profits\n    Gain,\n    /// @notice Debit normal account for tracking expenses\n    Expense,\n    /// @notice Credit normal account for tracking liabilities\n    Liability\n}\n\n/// @notice Interface with all methods available in the system used by actors\ninterface IHub {\n    event NotifyPool(uint16 indexed centrifugeId, PoolId indexed poolId);\n    event NotifyShareClass(uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId);\n    event NotifyShareMetadata(\n        uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, string name, string symbol\n    );\n    event UpdateShareHook(uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, bytes32 hook);\n    event NotifySharePrice(uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, D18 poolPerShare);\n    event NotifyAssetPrice(\n        uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, AssetId assetId, D18 pricePoolPerAsset\n    );\n    event UpdateRestriction(uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, bytes payload);\n    event UpdateContract(\n        uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, bytes32 target, bytes payload\n    );\n\n    /// @notice Emitted when a call to `file()` was performed.\n    event File(bytes32 what, address addr);\n\n    /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n    error FileUnrecognizedParam();\n\n    /// @notice Dispatched when the pool is already unlocked.\n    /// It means when calling to `execute()` inside `execute()`.\n    error PoolAlreadyUnlocked();\n\n    /// @notice Dispatched when the pool can not be unlocked by the caller\n    error NotManager();\n\n    /// @notice Dispatched when an invalid centrifuge ID is set in the pool ID.\n    error InvalidPoolId();\n\n    function gateway() external view returns (IGateway);\n    function holdings() external view returns (IHoldings);\n    function accounting() external view returns (IAccounting);\n    function hubRegistry() external view returns (IHubRegistry);\n    function sender() external view returns (IPoolMessageSender);\n    function shareClassManager() external view returns (IShareClassManager);\n\n    /// @notice Updates a contract parameter.\n    /// @param what Name of the parameter to update.\n    /// Accepts a `bytes32` representation of 'hubRegistry', 'assetRegistry', 'accounting', 'holdings', 'gateway' and '\n    /// sender' as string value.\n    function file(bytes32 what, address data) external;\n\n    /// @notice Notify a deposit for an investor address located in the chain where the asset belongs\n    function notifyDeposit(PoolId poolId, ShareClassId scId, AssetId depositAssetId, bytes32 investor, uint32 maxClaims)\n        external\n        payable;\n\n    /// @notice Notify a redemption for an investor address located in the chain where the asset belongs\n    function notifyRedeem(PoolId poolId, ShareClassId scId, AssetId payoutAssetId, bytes32 investor, uint32 maxClaims)\n        external\n        payable;\n\n    /// @notice Notify to a CV instance that a new pool is available\n    /// @param centrifugeId Chain where CV instance lives\n    function notifyPool(PoolId poolId, uint16 centrifugeId) external payable;\n\n    /// @notice Notify to a CV instance that a new share class is available\n    /// @param centrifugeId Chain where CV instance lives\n    /// @param hook The hook address of the share class\n    function notifyShareClass(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes32 hook) external payable;\n\n    /// @notice Notify to a CV instance that share metadata has updated\n    function notifyShareMetadata(PoolId poolId, ShareClassId scId, uint16 centrifugeId) external payable;\n\n    /// @notice Update on a CV instance the hook of a share token\n    function updateShareHook(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes32 hook) external payable;\n\n    /// @notice Notify to a CV instance the latest available price in POOL_UNIT / SHARE_UNIT\n    /// @dev The receiving centrifugeId is derived from the provided assetId\n    /// @param centrifugeId Chain to where the share price is notified\n    /// @param scId Identifier of the share class\n    function notifySharePrice(PoolId poolId, ShareClassId scId, uint16 centrifugeId) external payable;\n\n    /// @notice Notify to a CV instance the latest available price in POOL_UNIT / ASSET_UNIT\n    /// @dev The receiving centrifugeId is derived from the provided assetId\n    /// @param scId Identifier of the share class\n    /// @param assetId Identifier of the asset\n    function notifyAssetPrice(PoolId poolId, ShareClassId scId, AssetId assetId) external payable;\n\n    /// @notice Attach custom data to a pool\n    function setPoolMetadata(PoolId poolId, bytes calldata metadata) external payable;\n\n    /// @notice Update name & symbol of share class\n    function updateShareClassMetadata(PoolId poolId, ShareClassId scId, string calldata name, string calldata symbol)\n        external\n        payable;\n\n    /// @notice Allow/disallow an account to interact as pool manager\n    function updateManager(PoolId poolId, address who, bool canManage) external payable;\n\n    /// @notice Add a new share class to the pool\n    function addShareClass(PoolId poolId, string calldata name, string calldata symbol, bytes32 salt)\n        external\n        payable\n        returns (ShareClassId scId);\n\n    /// @notice Approves an asset amount of all deposit requests for the given triplet of pool id, share class id and\n    /// deposit asset id.\n    /// @param scId Identifier of the share class\n    /// @param depositAssetId Identifier of the asset locked for the deposit request\n    /// @param nowDepositEpochId The epoch for which deposits will be approved.\n    /// @param approvedAssetAmount Ampunt of assets that will be approved\n    function approveDeposits(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId depositAssetId,\n        uint32 nowDepositEpochId,\n        uint128 approvedAssetAmount\n    ) external payable returns (uint128 pendingAssetAmount, uint128 approvedPoolAmount);\n\n    /// @notice Approves a percentage of all redemption requests for the given triplet of pool id, share class id and\n    /// deposit asset id.\n    /// @param scId Identifier of the share class\n    /// @param payoutAssetId Identifier of the asset for which all requests want to exchange their share class tokens\n    /// @param nowRedeemEpochId The epoch for which redemptions will be approved.\n    /// @param approvedShareAmount Amount of shares that will be approved\n    function approveRedeems(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId payoutAssetId,\n        uint32 nowRedeemEpochId,\n        uint128 approvedShareAmount\n    ) external payable returns (uint128 pendingShareAmount);\n\n    /// @notice Emits new shares for the given identifier based on the provided NAV per share.\n    /// @param depositAssetId Identifier of the deposit asset for which shares should be issued\n    /// @param nowIssueEpochId The epoch for which shares will be issued.\n    /// @param navPoolPerShare Total value of assets of the share class per share\n    function issueShares(\n        PoolId poolId,\n        ShareClassId id,\n        AssetId depositAssetId,\n        uint32 nowIssueEpochId,\n        D18 navPoolPerShare\n    ) external payable returns (uint128 issuedShareAmount, uint128 depositAssetAmount, uint128 depositPoolAmount);\n\n    /// @notice Take back shares for the given identifier based on the provided NAV per share.\n    /// deposit asset id.\n    /// @param payoutAssetId Identifier of the asset for which all requests want to exchange their share class tokens\n    /// @param nowRevokeEpochId The epoch for which shares will be issued.\n    /// @param navPoolPerShare Total value of assets of the share class per share\n    function revokeShares(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId payoutAssetId,\n        uint32 nowRevokeEpochId,\n        D18 navPoolPerShare\n    ) external payable returns (uint128 revokedShareAmount, uint128 payoutAssetAmount, uint128 payoutPoolAmount);\n\n    /// @notice Tells the BalanceSheet to issue/revoke shares.\n    function triggerIssueShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, address who, uint128 shares)\n        external\n        payable;\n\n    /// @notice Tell the BalanceSheet to send a message back with the queued issued/revoked shares.\n    function triggerSubmitQueuedShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId) external payable;\n\n    /// @notice  Tell the BalanceSheet to send a message back with the queued deposits/withdrawals.\n    /// @param assetId Identifier of the asset which has queued deposits/withdrawals\n    function triggerSubmitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) external payable;\n\n    /// @notice Tell the BalanceSheet to enable or disable the shares queue.\n    function setQueue(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bool enabled) external payable;\n\n    /// @notice Update remotely a restriction.\n    /// @param centrifugeId Chain where CV instance lives.\n    /// @param payload content of the restriction update to execute.\n    function updateRestriction(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes calldata payload)\n        external\n        payable;\n\n    /// @notice Update remotely an existing vault.\n    /// @param centrifugeId Chain where CV instance lives.\n    /// @param target contract where to execute in CV. Check IUpdateContract interface.\n    /// @param payload content of the update to execute.\n    function updateContract(\n        PoolId poolId,\n        ShareClassId scId,\n        uint16 centrifugeId,\n        bytes32 target,\n        bytes calldata payload\n    ) external payable;\n\n    /// @notice Update the price per share of a share class\n    /// @param scId The share class identifier\n    /// @param pricePoolPerShare The new price per share\n    function updatePricePerShare(PoolId poolId, ShareClassId scId, D18 pricePoolPerShare) external payable;\n\n    /// @notice Create a new holding associated to the asset in a share class.\n    /// It will register the different accounts used for holdings.\n    /// The accounts have to be created beforehand.\n    /// The same account can be used for different kinds.\n    /// e.g.: The equity, gain, and loss account can be the same account.\n    /// They can also be shared across assets.\n    /// e.g.: All assets can use the same equity account.\n    /// @param valuation Used to transform between payment assets and pool currency\n    /// @param assetAccount Used to track the asset value\n    /// @param equityAccount Used to track the equity value\n    /// @param gainAccount Used to track the gain value\n    /// @param lossAccount Used to track the loss value\n    function createHolding(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        IERC7726 valuation,\n        AccountId assetAccount,\n        AccountId equityAccount,\n        AccountId gainAccount,\n        AccountId lossAccount\n    ) external payable;\n\n    /// @notice Create a new liablity associated to the asset in a share class.\n    /// It will register the different accounts used for holdings.\n    /// The accounts have to be created beforehand.\n    /// @param valuation Used to transform between the holding asset and pool currency\n    /// @param expenseAccount Used to track the expense value\n    /// @param liabilityAccount Used to track the liability value\n    function createLiability(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        IERC7726 valuation,\n        AccountId expenseAccount,\n        AccountId liabilityAccount\n    ) external payable;\n\n    /// @notice Updates the pool currency value of this holding based of the associated valuation.\n    function updateHoldingValue(PoolId poolId, ShareClassId scId, AssetId assetId) external payable;\n\n    /// @notice Updates the valuation used by a holding\n    /// @param valuation Used to transform between the holding asset and pool currency\n    function updateHoldingValuation(PoolId poolId, ShareClassId scId, AssetId assetId, IERC7726 valuation)\n        external\n        payable;\n\n    /// @notice Set an account of a holding\n    function setHoldingAccountId(PoolId poolId, ShareClassId scId, AssetId assetId, uint8 kind, AccountId accountId)\n        external\n        payable;\n\n    /// @notice Creates an account\n    /// @param accountId Then new AccountId used\n    /// @param isDebitNormal Determines if the account should be used as debit-normal or credit-normal\n    function createAccount(PoolId poolId, AccountId accountId, bool isDebitNormal) external payable;\n\n    /// @notice Attach custom data to an account\n    function setAccountMetadata(PoolId poolId, AccountId account, bytes calldata metadata) external payable;\n\n    /// @notice Perform an accounting entries update.\n    function updateJournal(PoolId poolId, JournalEntry[] memory debits, JournalEntry[] memory credits) external;\n}\n"
    },
    "src/hub/interfaces/IHubRegistry.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IERC6909Decimals} from \"src/misc/interfaces/IERC6909.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {IShareClassManager} from \"src/hub/interfaces/IShareClassManager.sol\";\n\ninterface IHubRegistry is IERC6909Decimals {\n    event NewAsset(AssetId indexed assetId, uint8 decimals);\n    event NewPool(PoolId poolId, address indexed manager, AssetId indexed currency);\n    event UpdateManager(PoolId indexed poolId, address indexed manager, bool canManage);\n    event SetMetadata(PoolId indexed poolId, bytes metadata);\n    event UpdateDependency(bytes32 indexed what, address dependency);\n    event UpdateCurrency(PoolId indexed poolId, AssetId currency);\n\n    error NonExistingPool(PoolId id);\n    error AssetAlreadyRegistered();\n    error PoolAlreadyRegistered();\n    error EmptyAccount();\n    error EmptyCurrency();\n    error EmptyShareClassManager();\n    error AssetNotFound();\n\n    /// @notice Register a new asset.\n    function registerAsset(AssetId assetId, uint8 decimals_) external;\n\n    /// @notice Register a new pool.\n    function registerPool(PoolId poolId, address manager, AssetId currency) external;\n\n    /// @notice allow/disallow an address as a manager for the pool\n    function updateManager(PoolId poolId, address newManager, bool canManage) external;\n\n    /// @notice sets metadata for this pool\n    function setMetadata(PoolId poolId, bytes calldata metadata) external;\n\n    /// @notice updates a dependency of the system\n    function updateDependency(bytes32 what, address dependency) external;\n\n    /// @notice updates the currency of the pool\n    function updateCurrency(PoolId poolId, AssetId currency) external;\n\n    /// @notice returns the metadata attached to the pool, if any.\n    function metadata(PoolId poolId) external view returns (bytes memory);\n\n    /// @notice returns the currency of the pool\n    function currency(PoolId poolId) external view returns (AssetId);\n\n    /// @notice returns the dependency used in the system\n    function dependency(bytes32 what) external view returns (address);\n\n    /// @notice returns whether the account is a manager\n    function manager(PoolId poolId, address who) external view returns (bool);\n\n    /// @notice compute a pool ID given an ID postfix\n    function poolId(uint16 centrifugeId, uint48 postfix) external view returns (PoolId poolId);\n\n    /// @notice returns the decimals for an asset\n    function decimals(AssetId assetId) external view returns (uint8);\n\n    /// @notice returns the decimals for a pool\n    function decimals(PoolId poolId) external view returns (uint8);\n\n    /// @notice checks the existence of a pool\n    function exists(PoolId poolId) external view returns (bool);\n\n    /// @notice checks the existence of an asset\n    function isRegistered(AssetId assetId) external view returns (bool);\n}\n"
    },
    "src/hub/interfaces/IShareClassManager.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18} from \"src/misc/types/D18.sol\";\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nstruct EpochRedeemAmounts {\n    /// @dev Amount of shares pending to be redeemed at time of epoch\n    uint128 pendingShareAmount;\n    /// @dev Total approved amount of redeemed share class tokens\n    uint128 approvedShareAmount;\n    /// @dev Total asset amount of revoked share class tokens\n    uint128 payoutAssetAmount;\n    /// @dev The amount of pool currency per unit of asset at time of approval\n    D18 pricePoolPerAsset;\n    /// @dev The amount of pool currency per unit of share at time of revocation\n    D18 navPoolPerShare;\n    /// @dev block timestamp when shares of epoch were revoked\n    uint64 revokedAt;\n}\n\nstruct EpochInvestAmounts {\n    /// @dev Total pending asset amount of deposit asset at time of epoch\n    uint128 pendingAssetAmount;\n    /// @dev Total approved asset amount of deposit asset\n    uint128 approvedAssetAmount;\n    /// @dev Total approved pool amount of deposit asset\n    uint128 approvedPoolAmount;\n    /// @dev The amount of pool currency per unit of asset at time of approval\n    D18 pricePoolPerAsset;\n    /// @dev The amount of pool currency per unit of share at time of issuance\n    D18 navPoolPerShare;\n    /// @dev block timestamp when shares of epoch were issued\n    uint64 issuedAt;\n}\n\nstruct UserOrder {\n    /// @dev Pending amount in deposit asset denomination\n    uint128 pending;\n    /// @dev Index of epoch in which last order was made\n    uint32 lastUpdate;\n}\n\nstruct ShareClassMetadata {\n    /// @dev The name of the share class token\n    string name;\n    /// @dev The symbol of the share class token\n    string symbol;\n    /// @dev The salt of the share class token\n    bytes32 salt;\n}\n\nstruct ShareClassMetrics {\n    /// @dev Total number of shares\n    uint128 totalIssuance;\n    /// @dev The latest net asset value per share class token\n    D18 navPerShare;\n}\n\nstruct QueuedOrder {\n    /// @dev Whether the user requested a cancellation which is now queued\n    bool isCancelling;\n    /// @dev The queued increased request amount\n    uint128 amount;\n}\n\nenum RequestType {\n    /// @dev Whether the request is a deposit one\n    Deposit,\n    /// @dev Whether the request is a redeem one\n    Redeem\n}\n\nstruct EpochId {\n    uint32 deposit;\n    uint32 redeem;\n    uint32 issue;\n    uint32 revoke;\n}\n\ninterface IShareClassManager {\n    /// Events\n    event AddShareClass(\n        PoolId indexed poolId, ShareClassId indexed scId, uint32 indexed index, string name, string symbol, bytes32 salt\n    );\n    event UpdateMetadata(PoolId indexed poolId, ShareClassId indexed scId, string name, string symbol);\n    event ApproveDeposits(\n        PoolId indexed poolId,\n        ShareClassId indexed scId,\n        AssetId indexed depositAssetId,\n        uint32 epoch,\n        uint128 approvedPoolAmount,\n        uint128 approvedAssetAmount,\n        uint128 pendingAssetAmount\n    );\n    event ApproveRedeems(\n        PoolId indexed poolId,\n        ShareClassId indexed scId,\n        AssetId indexed payoutAssetId,\n        uint32 epoch,\n        uint128 approvedShareAmount,\n        uint128 pendingShareAmount\n    );\n    event IssueShares(\n        PoolId indexed poolId,\n        ShareClassId indexed scId,\n        AssetId indexed depositAssetId,\n        uint32 epoch,\n        D18 navPoolPerShare,\n        D18 navAssetPerShare,\n        uint128 issuedShareAmount\n    );\n    event RemoteIssueShares(PoolId indexed poolId, ShareClassId indexed scId, uint128 issuedShareAmount);\n    event RevokeShares(\n        PoolId indexed poolId,\n        ShareClassId indexed scId,\n        AssetId indexed payoutAssetId,\n        uint32 epoch,\n        D18 navPoolPerShare,\n        D18 navAssetPerShare,\n        uint128 revokedShareAmount,\n        uint128 revokedAssetAmount,\n        uint128 revokedPoolAmount\n    );\n    event RemoteRevokeShares(PoolId indexed poolId, ShareClassId indexed scId, uint128 revokedAssetAmount);\n    event ClaimDeposit(\n        PoolId indexed poolId,\n        ShareClassId indexed scId,\n        uint32 epoch,\n        bytes32 investor,\n        AssetId indexed depositAssetId,\n        uint128 paymentAssetAmount,\n        uint128 pendingAssetAmount,\n        uint128 claimedShareAmount,\n        uint64 issuedAt\n    );\n    event ClaimRedeem(\n        PoolId indexed poolId,\n        ShareClassId indexed scId,\n        uint32 epoch,\n        bytes32 investor,\n        AssetId indexed payoutAssetId,\n        uint128 paymentShareAmount,\n        uint128 pendingShareAmount,\n        uint128 claimedAssetAmount,\n        uint64 revokedAt\n    );\n    event AddShareClass(PoolId indexed poolId, ShareClassId indexed scId, uint32 indexed index);\n    event UpdateShareClass(PoolId indexed poolId, ShareClassId indexed scId, D18 navPoolPerShare);\n    event UpdateDepositRequest(\n        PoolId indexed poolId,\n        ShareClassId indexed scId,\n        AssetId indexed depositAssetId,\n        uint32 epoch,\n        bytes32 investor,\n        uint128 pendingUserAssetAmount,\n        uint128 pendingTotalAssetAmount,\n        uint128 queuedUserAssetAmount,\n        bool pendingCancellation\n    );\n    event UpdateRedeemRequest(\n        PoolId indexed poolId,\n        ShareClassId indexed scId,\n        AssetId indexed payoutAssetId,\n        uint32 epoch,\n        bytes32 investor,\n        uint128 pendingUserShareAmount,\n        uint128 pendingTotalShareAmount,\n        uint128 queuedUserShareAmount,\n        bool pendingCancellation\n    );\n\n    /// Errors\n    error EpochNotInSequence(uint32 providedEpoch, uint32 nowEpoch);\n    error NoOrderFound();\n    error InsufficientPending();\n    error ApprovalRequired();\n    error IssuanceRequired();\n    error AlreadyIssued();\n    error RevocationRequired();\n    error ZeroApprovalAmount();\n    error InvalidMetadataSize();\n    error InvalidMetadataName();\n    error InvalidMetadataSymbol();\n    error InvalidSalt();\n    error AlreadyUsedSalt();\n    error RevokeMoreThanIssued();\n    error PoolMissing();\n    error ShareClassNotFound();\n    error EpochNotFound();\n    error DecreaseMoreThanIssued();\n    error CancellationQueued();\n\n    /// Functions\n\n    /// @notice Creates or updates a request to deposit (exchange) an asset amount for share class tokens.\n    ///\n    /// @param poolId Identifier of the pool\n    /// @param scId Identifier of the share class\n    /// @param amount Asset token amount which is deposited\n    /// @param investor Centrifuge Vault address of the entity which is depositing\n    /// @param depositAssetId Identifier of the asset which the investor used for their deposit request\n    function requestDeposit(PoolId poolId, ShareClassId scId, uint128 amount, bytes32 investor, AssetId depositAssetId)\n        external;\n\n    /// @notice Cancels a pending deposit request.\n    ///\n    /// @param poolId Identifier of the pool\n    /// @param scId Identifier of the share class\n    /// @param investor Centrifuge Vault address of the entity which is cancelling\n    /// @param depositAssetId Identifier of the asset which the investor used for their deposit request\n    /// @return cancelledAssetAmount The deposit amount which was previously pending and is now cancelled. This amount\n    /// was not potentially (partially) swapped to the pool amount in case the deposit asset cannot be exchanged 1:1\n    /// into the pool token\n    function cancelDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId)\n        external\n        returns (uint128 cancelledAssetAmount);\n\n    /// @notice Creates or updates a request to redeem (exchange) share class tokens for some asset.\n    ///\n    /// @param poolId Identifier of the pool\n    /// @param scId Identifier of the share class\n    /// @param amount Share class token amount which should be redeemed\n    /// @param investor Centrifuge Vault address of the entity which is redeeming\n    /// @param payoutAssetId Identifier of the asset which the investor eventually receives back for their redeemed\n    /// share class tokens\n    function requestRedeem(PoolId poolId, ShareClassId scId, uint128 amount, bytes32 investor, AssetId payoutAssetId)\n        external;\n\n    /// @notice Cancels a pending redeem request.\n    ///\n    /// @param poolId Identifier of the pool\n    /// @param scId Identifier of the share class\n    /// @param investor Centrifuge Vault address of the entity which is cancelling\n    /// @param payoutAssetId Identifier of the asset which the investor eventually receives back for their redeemed\n    /// share class tokens\n    /// @return cancelledShareAmount The redeem amount which was previously pending and is now cancelled\n    function cancelRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId)\n        external\n        returns (uint128 cancelledShareAmount);\n\n    /// @notice Approves an asset amount of all deposit requests for the given triplet of pool id, share class id and\n    /// deposit asset id.\n    /// @dev nowDepositEpochId MUST be called sequentially.\n    ///\n    /// @param poolId Identifier of the pool\n    /// @param scId Identifier of the share class\n    /// @param depositAssetId Identifier of the asset locked for the deposit request\n    /// @param nowDepositEpochId The epoch for which shares will be approved.\n    /// @param approvedAssetAmount Amount of assets that will be approved for deposit\n    /// @param pricePoolPerAsset Amount of pool unit one gets for a unit of asset\n    /// @return pendingAssetAmount Amount of assets still pending for deposit\n    /// @return approvedPoolAmount  Amount of pool units approved for deposit\n    function approveDeposits(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId depositAssetId,\n        uint32 nowDepositEpochId,\n        uint128 approvedAssetAmount,\n        D18 pricePoolPerAsset\n    ) external returns (uint128 pendingAssetAmount, uint128 approvedPoolAmount);\n\n    /// @notice Approves a share class token amount of all redeem requests for the given triplet of pool id, share class\n    /// id and payout asset id.\n    /// @dev nowRedeemEpochId MUST be called sequentially.\n    ///\n    /// @param poolId Identifier of the pool\n    /// @param scId Identifier of the share class\n    /// @param payoutAssetId Identifier of the asset for which all requests want to exchange their share class tokens\n    /// for\n    /// @param nowRedeemEpochId The epoch for which shares will be approved.\n    /// @param approvedShareAmount Amount of shares that will be approved for redemption\n    /// @param pricePoolPerAsset Amount of pool unit one gets for a unit of asset\n    /// @return pendingShareAmount Sum of redemption request amounts in share class token amount which was not approved\n    function approveRedeems(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId payoutAssetId,\n        uint32 nowRedeemEpochId,\n        uint128 approvedShareAmount,\n        D18 pricePoolPerAsset\n    ) external returns (uint128 pendingShareAmount);\n\n    /// @notice Emits new shares for the given identifier based on the provided NAV per share.\n    /// @dev nowIssueEpochId MUST be called sequentially.\n    ///\n    /// @param poolId Identifier of the pool\n    /// @param scId Identifier of the share class\n    /// @param depositAssetId Identifier of the deposit asset for which shares should be issued\n    /// @param nowIssueEpochId The epoch for which shares will be issued.\n    /// @param navPoolPerShare The nav per share value of the share class (in the pool currency denomination. Conversion\n    /// to asset price is done onchain based on the valuation of the asset at approval)\n    /// @return issuedShareAmount Amount of shares that have been issued\n    function issueShares(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId depositAssetId,\n        uint32 nowIssueEpochId,\n        D18 navPoolPerShare\n    ) external returns (uint128 issuedShareAmount, uint128 depositAssetAmount, uint128 depositPoolAmount);\n\n    /// @notice Take back shares for the given identifier based on the provided NAV per share.\n    /// @dev nowRevokeEpochId MUST be called sequentially.\n    ///\n    /// @param poolId Identifier of the pool\n    /// @param scId Identifier of the share class\n    /// @param payoutAssetId Identifier of the payout asset\n    /// @param nowRevokeEpochId The epoch for which shares will be revoked.\n    /// @param navPoolPerShare The nav per share value of the share class (in the pool currency denomination. Conversion\n    /// to asset price is done onchain based on the valuation of the asset at approval)\n    /// @return revokedShareAmount Amount of shares that have been revoked\n    /// @return payoutAssetAmount Converted amount of payout asset based on number of revoked shares\n    /// @return payoutPoolAmount Converted amount of pool currency based on number of revoked shares\n    function revokeShares(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId payoutAssetId,\n        uint32 nowRevokeEpochId,\n        D18 navPoolPerShare\n    ) external returns (uint128 revokedShareAmount, uint128 payoutAssetAmount, uint128 payoutPoolAmount);\n\n    /// @notice Collects shares for an investor after their deposit request was (partially) approved and new shares were\n    /// issued.\n    ///\n    /// @param poolId Identifier of the pool\n    /// @param scId Identifier of the share class\n    /// @param investor Centrifuge Vault address of the recipient of the claimed share class tokens\n    /// @param depositAssetId Identifier of the asset which the investor used for their deposit request\n    /// @return payoutShareAmount Amount of shares which the investor receives\n    /// @return paymentAssetAmount Amount of deposit asset which was taken as payment\n    /// @return cancelledAssetAmount Amount of deposit asset which was cancelled due to being queued\n    /// @return canClaimAgain Whether another call to claimRedeem is needed until investor has fully claimed investments\n    function claimDeposit(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId)\n        external\n        returns (\n            uint128 payoutShareAmount,\n            uint128 paymentAssetAmount,\n            uint128 cancelledAssetAmount,\n            bool canClaimAgain\n        );\n\n    /// @notice Collects an asset amount for an investor after their redeem request was (partially) approved and shares\n    /// were revoked.\n    ///\n    /// @param poolId Identifier of the pool\n    /// @param scId Identifier of the share class\n    /// @param investor Centrifuge Vault address of the recipient of the claimed asset amount\n    /// @param payoutAssetId Identifier of the asset which the investor requested to receive back for their redeemed\n    /// shares\n    /// @return payoutAssetAmount Amount of payout amount which the investor receives\n    /// @return paymentShareAmount Amount of shares which the investor redeemed\n    /// @return cancelledShareAmount Amount of shares which were cancelled due to being queued\n    /// @return canClaimAgain Whether another call to claimRedeem is needed until investor has fully claimed redemptions\n    function claimRedeem(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId)\n        external\n        returns (\n            uint128 payoutAssetAmount,\n            uint128 paymentShareAmount,\n            uint128 cancelledShareAmount,\n            bool canClaimAgain\n        );\n\n    /// @notice Increases the share class issuance\n    ///\n    /// @param poolId Identifier of the pool\n    /// @param scId Identifier of the share class\n    /// @param amount The amount to increase the share class issuance by\n    function increaseShareClassIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external;\n\n    /// @notice Decreases the share class issuance\n    ///\n    /// @param poolId Identifier of the pool\n    /// @param scId Identifier of the share class\n    /// @param amount The amount to decrease the share class issuance by\n    function decreaseShareClassIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external;\n\n    /// @notice Adds a new share class to the given pool.\n    ///\n    /// @param poolId Identifier of the pool\n    /// @param name The name of the share class\n    /// @param symbol The symbol of the share class\n    /// @param salt The salt used for deploying the share class tokens\n    /// @return scId Identifier of the newly added share class\n    function addShareClass(PoolId poolId, string calldata name, string calldata symbol, bytes32 salt)\n        external\n        returns (ShareClassId scId);\n\n    /// @notice Updates the price pool unit per share unit of a share class\n    ///\n    /// @param poolId Identifier of the pool\n    /// @param scId Identifier of the share class\n    /// @param pricePoolPerShare The price per share of the share class (in the pool currency denomination)\n    function updatePricePerShare(PoolId poolId, ShareClassId scId, D18 pricePoolPerShare) external;\n\n    /// @notice Updates the metadata of a share class.\n    ///\n    /// @param poolId Identifier of the pool\n    /// @param scId Identifier of the share class\n    /// @param name The name of the share class\n    /// @param symbol The symbol of the share class\n    function updateMetadata(PoolId poolId, ShareClassId scId, string calldata name, string calldata symbol) external;\n\n    /// @notice Returns the number of share classes for the given pool\n    ///\n    /// @param poolId Identifier of the pool in question\n    /// @return count Number of share classes for the given pool\n    function shareClassCount(PoolId poolId) external view returns (uint32 count);\n\n    /// @notice Checks the existence of a share class.\n    ///\n    /// @param poolId Identifier of the pool\n    /// @param scId Identifier of the share class\n    function exists(PoolId poolId, ShareClassId scId) external view returns (bool);\n\n    /// @notice Returns the current ongoing epoch id for deposits\n    ///\n    /// @param scId Identifier of the share class\n    /// @param depositAssetId AssetId of the payment asset\n    function nowDepositEpoch(ShareClassId scId, AssetId depositAssetId) external view returns (uint32);\n\n    /// @notice Returns the epoch for which will be issued next\n    ///\n    /// @param scId Identifier of the share class\n    /// @param depositAssetId AssetId of the payment asset\n    function nowIssueEpoch(ShareClassId scId, AssetId depositAssetId) external view returns (uint32);\n\n    /// @notice Returns the current ongoing epoch id for deposits\n    ///\n    /// @param scId Identifier of the share class\n    /// @param payoutAssetId AssetId of the payment asset\n    function nowRedeemEpoch(ShareClassId scId, AssetId payoutAssetId) external view returns (uint32);\n\n    /// @notice Returns the epoch for which will be revoked next\n    ///\n    /// @param scId Identifier of the share class\n    /// @param depositAssetId AssetId of the payment asset\n    function nowRevokeEpoch(ShareClassId scId, AssetId depositAssetId) external view returns (uint32);\n\n    /// @notice Returns an upper bound for possible calls to `function claimDeposit(..)`\n    ///\n    /// @param scId Identifier of the share class\n    /// @param investor Recipient of the share class tokens\n    /// @param depositAssetId AssetId of the payment asset\n    function maxDepositClaims(ShareClassId scId, bytes32 investor, AssetId depositAssetId)\n        external\n        view\n        returns (uint32 maxClaims);\n\n    /// @notice Returns an upper bound for possible calls to `function claimRedeem(..)`\n    ///\n    /// @param scId Identifier of the share class\n    /// @param investor Recipient of the payout assets\n    /// @param payoutAssetId AssetId of the payout asset\n    function maxRedeemClaims(ShareClassId scId, bytes32 investor, AssetId payoutAssetId)\n        external\n        view\n        returns (uint32 maxClaims);\n\n    /// @notice Exposes relevant metrics for a share class\n    ///\n    /// @return totalIssuance The total number of shares known to the CP side\n    /// @return pricePoolPerShare The amount of pool units per unit share\n    function metrics(ShareClassId scId) external view returns (uint128 totalIssuance, D18 pricePoolPerShare);\n\n    /// @notice Determines the next share class id for the given pool.\n    ///\n    /// @param poolId Identifier of the pool\n    /// @return scId Identifier of the next share class\n    function previewNextShareClassId(PoolId poolId) external view returns (ShareClassId scId);\n\n    /// @notice Determines the share class id for the given pool and index.\n    ///\n    /// @param poolId Identifier of the pool\n    /// @param index The pool-internal index of the share class id\n    /// @return scId Identifier of the underlying share class\n    function previewShareClassId(PoolId poolId, uint32 index) external pure returns (ShareClassId scId);\n\n    /// @notice returns The metadata of the share class.\n    ///\n    /// @param scId Identifier of the share class\n    /// @return name The registered name of the share class token\n    /// @return symbol The registered symbol of the share class token\n    /// @return salt The registered salt of the share class token, used for deterministic deployments\n    function metadata(ShareClassId scId) external returns (string memory name, string memory symbol, bytes32 salt);\n}\n"
    },
    "src/misc/Auth.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\n\n/// @title  Auth\n/// @notice Simple authentication pattern\n/// @author Based on code from https://github.com/makerdao/dss\nabstract contract Auth is IAuth {\n    /// @inheritdoc IAuth\n    mapping(address => uint256) public wards;\n\n    constructor(address initialWard) {\n        wards[initialWard] = 1;\n        emit Rely(initialWard);\n    }\n\n    /// @dev Check if the msg.sender has permissions\n    modifier auth() {\n        require(wards[msg.sender] == 1, NotAuthorized());\n        _;\n    }\n\n    /// @inheritdoc IAuth\n    function rely(address user) public auth {\n        wards[user] = 1;\n        emit Rely(user);\n    }\n\n    /// @inheritdoc IAuth\n    function deny(address user) public auth {\n        wards[user] = 0;\n        emit Deny(user);\n    }\n}\n"
    },
    "src/misc/BaseValuation.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IBaseValuation} from \"src/misc/interfaces/IBaseValuation.sol\";\nimport {IERC6909Decimals} from \"src/misc/interfaces/IERC6909.sol\";\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nabstract contract BaseValuation is Auth, IBaseValuation {\n    /// @notice ERC6909 dependency.\n    IERC6909Decimals public erc6909;\n\n    constructor(IERC6909Decimals erc6909_, address deployer) Auth(deployer) {\n        erc6909 = erc6909_;\n    }\n\n    /// @inheritdoc IBaseValuation\n    function file(bytes32 what, address data) external auth {\n        if (what == \"erc6909\") erc6909 = IERC6909Decimals(data);\n        else revert FileUnrecognizedParam();\n\n        emit File(what, data);\n    }\n\n    /// @notice Obtain the correct decimals given an asset address\n    function _getDecimals(address asset) internal view returns (uint8) {\n        return erc6909.decimals(uint160(asset));\n    }\n}\n"
    },
    "src/misc/ERC20.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {EIP712Lib} from \"src/misc/libraries/EIP712Lib.sol\";\nimport {SignatureLib} from \"src/misc/libraries/SignatureLib.sol\";\n\nimport {IERC20, IERC20Metadata, IERC20Permit} from \"src/misc/interfaces/IERC20.sol\";\n\n/// @title  ERC20\n/// @notice Standard ERC-20 implementation, with mint/burn functionality and permit logic.\n/// @author Modified from https://github.com/makerdao/xdomain-dss/blob/master/src/Dai.sol\ncontract ERC20 is Auth, IERC20Metadata, IERC20Permit {\n    error FileUnrecognizedParam();\n\n    /// @inheritdoc IERC20Metadata\n    string public name;\n    /// @inheritdoc IERC20Metadata\n    string public symbol;\n    /// @inheritdoc IERC20Metadata\n    uint8 public immutable decimals;\n    /// @inheritdoc IERC20\n    uint256 public totalSupply;\n\n    mapping(address => uint256) private balances;\n\n    /// @inheritdoc IERC20\n    mapping(address => mapping(address => uint256)) public allowance;\n    /// @inheritdoc IERC20Permit\n    mapping(address => uint256) public nonces;\n\n    // --- EIP712 ---\n    bytes32 private immutable nameHash;\n    bytes32 private immutable versionHash;\n    uint256 public immutable deploymentChainId;\n    bytes32 private immutable _DOMAIN_SEPARATOR;\n    bytes32 public constant PERMIT_TYPEHASH =\n        keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n\n    // --- Events ---\n    event File(bytes32 indexed what, string data);\n\n    constructor(uint8 decimals_) Auth(msg.sender) {\n        decimals = decimals_;\n\n        nameHash = keccak256(bytes(\"Centrifuge\"));\n        versionHash = keccak256(bytes(\"1\"));\n        deploymentChainId = block.chainid;\n        _DOMAIN_SEPARATOR = EIP712Lib.calculateDomainSeparator(nameHash, versionHash);\n    }\n\n    function _balanceOf(address user) internal view virtual returns (uint256) {\n        return balances[user];\n    }\n\n    /// @inheritdoc IERC20\n    function balanceOf(address user) public view virtual returns (uint256) {\n        return _balanceOf(user);\n    }\n\n    function _setBalance(address user, uint256 value) internal virtual {\n        balances[user] = value;\n    }\n\n    /// @inheritdoc IERC20Permit\n    function DOMAIN_SEPARATOR() public view returns (bytes32) {\n        return block.chainid == deploymentChainId\n            ? _DOMAIN_SEPARATOR\n            : EIP712Lib.calculateDomainSeparator(nameHash, versionHash);\n    }\n\n    // --- Administration ---\n    function file(bytes32 what, string memory data) public virtual auth {\n        if (what == \"name\") name = data;\n        else if (what == \"symbol\") symbol = data;\n        else revert FileUnrecognizedParam();\n        emit File(what, data);\n    }\n\n    // --- ERC20 Mutations ---\n    /// @inheritdoc IERC20\n    function transfer(address to, uint256 value) public virtual returns (bool) {\n        require(to != address(0) && to != address(this), InvalidAddress());\n        uint256 balance = balanceOf(msg.sender);\n        require(balance >= value, InsufficientBalance());\n\n        unchecked {\n            _setBalance(msg.sender, balance - value);\n            // note: we don't need an overflow check here b/c sum of all balances == totalSupply\n            _setBalance(to, _balanceOf(to) + value);\n        }\n\n        emit Transfer(msg.sender, to, value);\n\n        return true;\n    }\n\n    /// @inheritdoc IERC20\n    function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {\n        return _transferFrom(msg.sender, from, to, value);\n    }\n\n    function _transferFrom(address sender, address from, address to, uint256 value) internal virtual returns (bool) {\n        require(to != address(0) && to != address(this), InvalidAddress());\n        uint256 balance = balanceOf(from);\n        require(balance >= value, InsufficientBalance());\n\n        if (from != sender) {\n            uint256 allowed = allowance[from][sender];\n            if (allowed != type(uint256).max) {\n                require(allowed >= value, InsufficientAllowance());\n                unchecked {\n                    allowance[from][sender] = allowed - value;\n                }\n            }\n        }\n\n        unchecked {\n            _setBalance(from, balance - value);\n            // note: we don't need an overflow check here b/c sum of all balances == totalSupply\n            _setBalance(to, _balanceOf(to) + value);\n        }\n\n        emit Transfer(from, to, value);\n\n        return true;\n    }\n\n    /// @inheritdoc IERC20\n    function approve(address spender, uint256 value) external returns (bool) {\n        allowance[msg.sender][spender] = value;\n\n        emit Approval(msg.sender, spender, value);\n\n        return true;\n    }\n\n    // --- Mint/Burn ---\n    function mint(address to, uint256 value) public virtual auth {\n        require(to != address(0) && to != address(this), InvalidAddress());\n        unchecked {\n            // We don't need an overflow check here b/c balances[to] <= totalSupply\n            // and there is an overflow check below\n            _setBalance(to, _balanceOf(to) + value);\n        }\n        totalSupply += value;\n\n        emit Transfer(address(0), to, value);\n    }\n\n    function burn(address from, uint256 value) public virtual auth {\n        uint256 balance = balanceOf(from);\n        require(balance >= value, InsufficientBalance());\n\n        if (from != msg.sender) {\n            uint256 allowed = allowance[from][msg.sender];\n            if (allowed != type(uint256).max) {\n                require(allowed >= value, InsufficientAllowance());\n\n                unchecked {\n                    allowance[from][msg.sender] = allowed - value;\n                }\n            }\n        }\n\n        unchecked {\n            // We don't need overflow checks b/c require(balance >= value) and balance <= totalSupply\n            _setBalance(from, balance - value);\n            totalSupply -= value;\n        }\n\n        emit Transfer(from, address(0), value);\n    }\n\n    // --- Approve by signature ---\n    function permit(address owner, address spender, uint256 value, uint256 deadline, bytes memory signature) public {\n        require(block.timestamp <= deadline, PermitExpired());\n\n        uint256 nonce;\n        unchecked {\n            nonce = nonces[owner]++;\n        }\n\n        bytes32 digest = keccak256(\n            abi.encodePacked(\n                \"\\x19\\x01\",\n                DOMAIN_SEPARATOR(),\n                keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonce, deadline))\n            )\n        );\n\n        require(SignatureLib.isValidSignature(owner, digest, signature), InvalidPermit());\n\n        allowance[owner][spender] = value;\n        emit Approval(owner, spender, value);\n    }\n\n    /// @inheritdoc IERC20Permit\n    function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)\n        external\n    {\n        permit(owner, spender, value, deadline, abi.encodePacked(r, s, v));\n    }\n}\n"
    },
    "src/misc/IdentityValuation.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {d18} from \"src/misc/types/D18.sol\";\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\nimport {IIdentityValuation} from \"src/misc/interfaces/IIdentityValuation.sol\";\nimport {IERC6909Decimals} from \"src/misc/interfaces/IERC6909.sol\";\nimport {BaseValuation} from \"src/misc/BaseValuation.sol\";\n\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\ncontract IdentityValuation is BaseValuation, IIdentityValuation {\n    constructor(IERC6909Decimals erc6909, address deployer) BaseValuation(erc6909, deployer) {}\n\n    /// @inheritdoc IERC7726\n    function getQuote(uint256 baseAmount, address base, address quote) external view returns (uint256 quoteAmount) {\n        return PricingLib.convertWithPrice(baseAmount, _getDecimals(base), _getDecimals(quote), d18(1e18));\n    }\n}\n"
    },
    "src/misc/Multicall.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\n// NOTE: This file has warning disabled due https://github.com/ethereum/solidity/issues/14359\n// If perform any change on it, please ensure no other warnings appears\n\nimport {IMulticall} from \"src/misc/interfaces/IMulticall.sol\";\nimport {ReentrancyProtection} from \"src/misc/ReentrancyProtection.sol\";\n\nabstract contract Multicall is ReentrancyProtection, IMulticall {\n    function multicall(bytes[] calldata data) public payable virtual protected {\n        uint256 totalBytes = data.length;\n        for (uint256 i; i < totalBytes; ++i) {\n            (bool success, bytes memory returnData) = address(this).delegatecall(data[i]);\n            if (!success) {\n                uint256 length = returnData.length;\n                require(length != 0, CallFailedWithEmptyRevert());\n\n                assembly (\"memory-safe\") {\n                    revert(add(32, returnData), length)\n                }\n            }\n        }\n    }\n}\n"
    },
    "src/misc/Recoverable.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {IERC6909} from \"src/misc/interfaces/IERC6909.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\n\nimport {IRecoverable, ETH_ADDRESS} from \"src/misc/interfaces/IRecoverable.sol\";\n\nabstract contract Recoverable is Auth, IRecoverable {\n    /// @inheritdoc IRecoverable\n    function recoverTokens(address token, address receiver, uint256 amount) public auth {\n        if (token == ETH_ADDRESS) {\n            SafeTransferLib.safeTransferETH(receiver, amount);\n        } else {\n            SafeTransferLib.safeTransfer(token, receiver, amount);\n        }\n    }\n\n    /// @inheritdoc IRecoverable\n    function recoverTokens(address token, uint256 tokenId, address receiver, uint256 amount) external auth {\n        if (tokenId == 0) {\n            recoverTokens(token, receiver, amount);\n        } else {\n            IERC6909(token).transfer(receiver, tokenId, amount);\n        }\n    }\n}\n"
    },
    "src/misc/ReentrancyProtection.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\n// NOTE: This file has warning disabled due https://github.com/ethereum/solidity/issues/14359\n// If perform any change on it, please ensure no other warnings appears\n\nabstract contract ReentrancyProtection {\n    /// @notice Dispatched when there is a re-entrancy issue\n    error UnauthorizedSender();\n\n    address private transient _initiator;\n\n    /// @dev The method is protected for reentrancy issues.\n    modifier protected() {\n        if (_initiator == address(0)) {\n            // Single call re-entrancy lock\n            _initiator = msg.sender;\n            _;\n            _initiator = address(0);\n        } else {\n            // Multicall re-entrancy lock\n            require(msg.sender == _initiator, UnauthorizedSender());\n            _;\n        }\n    }\n}\n"
    },
    "src/misc/interfaces/IAuth.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\ninterface IAuth {\n    event Rely(address indexed user);\n    event Deny(address indexed user);\n\n    error NotAuthorized();\n\n    /// @notice Returns whether the target is a ward (has admin access)\n    function wards(address target) external view returns (uint256);\n\n    /// @notice Make user a ward (give them admin access)\n    function rely(address user) external;\n\n    /// @notice Remove user as a ward (remove admin access)\n    function deny(address user) external;\n}\n"
    },
    "src/misc/interfaces/IBaseValuation.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\n\n/// Provides a base implementation for all ERC7726 valuation in the system\ninterface IBaseValuation is IERC7726 {\n    /// @notice Emitted when a call to `file()` was performed.\n    event File(bytes32 indexed what, address addr);\n\n    /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n    error FileUnrecognizedParam();\n\n    /// @notice Updates a contract parameter.\n    /// @param what Name of the parameter to update.\n    /// Accepts a `bytes32` representation of 'assetRegistry' string value.\n    /// @param data New value given to the `what` parameter\n    function file(bytes32 what, address data) external;\n}\n"
    },
    "src/misc/interfaces/IERC20.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/// @title  IERC20\n/// @dev    Interface of the ERC20 standard as defined in the EIP.\n/// @author Modified from OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\ninterface IERC20 {\n    error InvalidAddress();\n    error InsufficientBalance();\n    error InsufficientAllowance();\n\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the value of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the value of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the\n     * allowance mechanism. `value` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n */\ninterface IERC20Metadata is IERC20 {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n *     doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n *     token.safeTransferFrom(msg.sender, address(this), value);\n *     ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n    error PermitExpired();\n    error InvalidPermit();\n\n    /**\n     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n     * given ``owner``'s signed approval.\n     *\n     * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n     * ordering also apply here.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `deadline` must be a timestamp in the future.\n     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n     * over the EIP712-formatted function arguments.\n     * - the signature must use ``owner``'s current nonce (see {nonces}).\n     *\n     * For more information on the signature format, see the\n     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n     * section].\n     *\n     * CAUTION: See Security Considerations above.\n     */\n    function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)\n        external;\n\n    /**\n     * @dev Returns the current nonce for `owner`. This value must be\n     * included whenever a signature is generated for {permit}.\n     *\n     * Every successful call to {permit} increases ``owner``'s nonce by one. This\n     * prevents a signature from being used multiple times.\n     */\n    function nonces(address owner) external view returns (uint256);\n\n    /**\n     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\ninterface IERC20Wrapper {\n    /**\n     * @dev Returns the address of the underlying ERC-20 token that is being wrapped.\n     */\n    function underlying() external view returns (address);\n\n    /**\n     * @dev Allow a user to deposit underlying tokens and mint the corresponding number of wrapped tokens.\n     */\n    function depositFor(address account, uint256 value) external returns (bool);\n\n    /**\n     * @dev Allow a user to burn a number of wrapped tokens and withdraw the corresponding number of underlying tokens.\n     */\n    function withdrawTo(address account, uint256 value) external returns (bool);\n}\n"
    },
    "src/misc/interfaces/IERC6909.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IERC165} from \"forge-std/interfaces/IERC165.sol\";\n\ninterface IERC6909 is IERC165 {\n    error EmptyOwner();\n    error EmptyAmount();\n    error InvalidTokenId();\n    error InsufficientBalance(address owner, uint256 tokenId);\n    error InsufficientAllowance(address sender, uint256 tokenId);\n\n    event OperatorSet(address indexed owner, address indexed operator, bool approved);\n    event Approval(address indexed owner, address indexed spender, uint256 indexed tokenId, uint256 amount);\n    event Transfer(address caller, address indexed from, address indexed to, uint256 indexed tokenId, uint256 amount);\n\n    /// @notice           Owner balance of a tokenId.\n    /// @param owner      The address of the owner.\n    /// @param tokenId    The id of the token.\n    /// @return amount    The balance of the token.\n    function balanceOf(address owner, uint256 tokenId) external view returns (uint256 amount);\n\n    /// @notice           Spender allowance of a tokenId.\n    /// @param owner      The address of the owner.\n    /// @param spender    The address of the spender.\n    /// @param tokenId    The id of the token.\n    /// @return amount    The allowance of the token.\n    function allowance(address owner, address spender, uint256 tokenId) external view returns (uint256 amount);\n\n    /// @notice           Checks if a spender is approved by an owner as an operator.\n    /// @param owner      The address of the owner.\n    /// @param spender    The address of the spender.\n    /// @return approved  The approval status.\n    function isOperator(address owner, address spender) external view returns (bool approved);\n\n    /// @notice           Transfers an amount of a tokenId from the caller to a receiver.\n    /// @param receiver   The address of the receiver.\n    /// @param tokenId    The id of the token.\n    /// @param amount     The amount of the token.\n    /// @return bool      True, always, unless the function reverts.\n    function transfer(address receiver, uint256 tokenId, uint256 amount) external returns (bool);\n\n    /// @notice           Transfers an amount of a tokenId from a sender to a receiver.\n    /// @param sender     The address of the sender.\n    /// @param receiver   The address of the receiver.\n    /// @param tokenId    The id of the token.\n    /// @param amount     The amount of the token.\n    /// @return bool      True, always, unless the function reverts.\n    function transferFrom(address sender, address receiver, uint256 tokenId, uint256 amount) external returns (bool);\n\n    /// @notice           Approves an amount of a tokenId to a spender.\n    /// @param spender    The address of the spender.\n    /// @param tokenId    The id of the token.\n    /// @param amount     The amount of the token.\n    /// @return bool      True, always.\n    function approve(address spender, uint256 tokenId, uint256 amount) external returns (bool);\n\n    /// @notice           Sets or removes an operator for the caller.\n    /// @param operator   The address of the operator.\n    /// @param approved   The approval status.\n    /// @return bool      True, always.\n    function setOperator(address operator, bool approved) external returns (bool);\n}\n\ninterface IERC6909URIExt {\n    event TokenURISet(uint256 indexed tokenId, string uri);\n    event ContractURISet(address indexed target, string uri);\n\n    error EmptyURI();\n\n    /// @return uri     Returns the common token URI.\n    function contractURI() external view returns (string memory);\n\n    /// @dev            Returns empty string if tokenId does not exist.\n    ///                 MAY implemented to throw MissingURI(tokenId) error.\n    /// @param tokenId  The token to query URI for.\n    /// @return uri     A string representing the uri for the specific tokenId.\n    function tokenURI(uint256 tokenId) external view returns (string memory);\n}\n\ninterface IERC6909NFT is IERC6909, IERC6909URIExt {\n    error UnknownTokenId(address owner, uint256 tokenId);\n    error LessThanMinimalDecimal(uint8 minimal, uint8 actual);\n\n    /// @notice             Provide URI for a specific tokenId.\n    /// @param tokenId      Token Id.\n    /// @param URI          URI to a document defining the collection as a whole.\n    function setTokenURI(uint256 tokenId, string memory URI) external;\n\n    /// @dev                Optional method to set up the contract URI if needed.\n    /// @param URI          URI to a document defining the collection as a whole.\n    function setContractURI(string memory URI) external;\n\n    /// @notice             Mint new tokens for a given owner and sets tokenURI.\n    /// @dev                For non-fungible tokens, call with amount = 1, for fungible it could be any amount.\n    ///                     TokenId is auto incremented by one.\n    ///\n    /// @param owner        Creates supply of a given tokenId by amount for owner.\n    /// @param tokenURI     URI fortestBurningToken the newly minted token.\n    /// @return tokenId     Id of the newly minted token.\n    function mint(address owner, string memory tokenURI) external returns (uint256 tokenId);\n\n    /// @notice             Destroy supply of a given tokenId by amount.\n    /// @dev                The msg.sender MUST be the owner.\n    ///\n    /// @param tokenId      Item which have reduced supply.\n    function burn(uint256 tokenId) external;\n}\n\n/// @notice Extension of ERC6909 Standard for tracking total supply\ninterface IERC6909TotalSupplyExt {\n    /// @notice         The totalSupply for a token id.\n    ///\n    /// @param tokenId  Id of the token\n    /// @return supply  Total supply for a given `tokenId`\n    function totalSupply(uint256 tokenId) external returns (uint256 supply);\n}\n\ninterface IERC6909Decimals {\n    /// @notice             Used to retrieve the decimals of an asset\n    /// @dev                address is used but the value corresponds to a AssetId\n    function decimals(uint256 assetId) external view returns (uint8);\n}\n\ninterface IERC6909MetadataExt is IERC6909Decimals {\n    /// @notice             Used to retrieve the decimals of an asset\n    /// @dev                address is used but the value corresponds to a AssetId\n    function decimals(uint256 assetId) external view returns (uint8);\n\n    /// @notice             Used to retrieve the name of an asset\n    /// @dev                address is used but the value corresponds to a AssetId\n    function name(uint256 assetId) external view returns (string memory);\n\n    /// @notice             Used to retrieve the symbol of an asset\n    /// @dev                address is used but the value corresponds to a AssetId\n    function symbol(uint256 assetId) external view returns (string memory);\n}\n\ninterface IERC6909Fungible is IERC6909 {\n    /// @notice             Mint new tokens for a specific tokenid and assign them to an owner\n    ///\n    /// @param owner        Creates supply of a given `tokenId` by `amount` for owner.\n    /// @param tokenId      Id of the item\n    /// @param amount       Adds `amount` to the total supply of the given `tokenId`\n    function mint(address owner, uint256 tokenId, uint256 amount) external;\n\n    /// @notice             Destroy supply of a given tokenId by amount.\n    /// @dev                The msg.sender MUST be the owner.\n    ///\n    /// @param owner        Owner of the `tokenId`\n    /// @param tokenId      Id of the item.\n    /// @param amount       Subtract `amount` from the total supply of the given `tokenId`\n    function burn(address owner, uint256 tokenId, uint256 amount) external;\n\n    /// @notice             Enforces a transfer from `spender` point of view.\n    ///\n    ///\n    /// @param sender       The owner of the `tokenId`\n    /// @param receiver     Address of the receiving party\n    /// @param tokenId      Token Id\n    /// @param amount       Amount to be transferred\n    function authTransferFrom(address sender, address receiver, uint256 tokenId, uint256 amount)\n        external\n        returns (bool);\n}\n\n/// @dev  A factory contract to deploy new collateral contracts implementing IERC6909.\ninterface IERC6909Factory {\n    /// Events\n    event NewTokenDeployment(address indexed owner, address instance);\n\n    /// @notice       Deploys new install of a contract that implements IERC6909.\n    /// @dev          Factory should deploy deterministically if possible.\n    ///\n    /// @param owner  Owner of the deployed collateral contract which has initial full rights.\n    /// @param salt   Used to make a deterministic deployment.\n    /// @return       An address of the newly deployed contract.\n    function deploy(address owner, bytes32 salt) external returns (address);\n\n    /// @notice       Generates a new deterministic address based on the owner and the salt.\n    ///\n    /// @param owner  Owner of the deployed collateral contract which has initial full rights.\n    /// @param salt   Used to make a deterministic deployment.\n    /// @return       An address of the newly deployed contract.\n    function previewAddress(address owner, bytes32 salt) external returns (address);\n}\n"
    },
    "src/misc/interfaces/IERC7540.sol": {
      "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.5.0;\n\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\nimport {IERC7575, IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\ninterface IERC7540Operator {\n    /**\n     * @dev The event emitted when an operator is set.\n     *\n     * @param controller The address of the controller.\n     * @param operator The address of the operator.\n     * @param approved The approval status.\n     */\n    event OperatorSet(address indexed controller, address indexed operator, bool approved);\n\n    /**\n     * @dev Sets or removes an operator for the caller.\n     *\n     * @param operator The address of the operator.\n     * @param approved The approval status.\n     * @return Whether the call was executed successfully or not\n     */\n    function setOperator(address operator, bool approved) external returns (bool);\n\n    /**\n     * @dev Returns `true` if the `operator` is approved as an operator for an `controller`.\n     *\n     * @param controller The address of the controller.\n     * @param operator The address of the operator.\n     * @return status The approval status\n     */\n    function isOperator(address controller, address operator) external view returns (bool status);\n}\n\ninterface IERC7540Deposit is IERC7540Operator {\n    event DepositRequest(\n        address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets\n    );\n    /**\n     * @dev Transfers assets from sender into the Vault and submits a Request for asynchronous deposit.\n     *\n     * - MUST support ERC-20 approve / transferFrom on asset as a deposit Request flow.\n     * - MUST revert if all of assets cannot be requested for deposit.\n     * - owner MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n     *    approval of ERC-20 tokens from owner to sender is NOT enough.\n     *\n     * @param assets the amount of deposit assets to transfer from owner\n     * @param controller the controller of the request who will be able to operate the request\n     * @param owner the source of the deposit assets\n     *\n     * NOTE: most implementations will require pre-approval of the Vault with the Vault's underlying asset token.\n     */\n\n    function requestDeposit(uint256 assets, address controller, address owner) external returns (uint256 requestId);\n\n    /**\n     * @dev Returns the amount of requested assets in Pending state.\n     *\n     * - MUST NOT include any assets in Claimable state for deposit or mint.\n     * - MUST NOT show any variations depending on the caller.\n     * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n     */\n    function pendingDepositRequest(uint256 requestId, address controller)\n        external\n        view\n        returns (uint256 pendingAssets);\n\n    /**\n     * @dev Returns the amount of requested assets in Claimable state for the controller to deposit or mint.\n     *\n     * - MUST NOT include any assets in Pending state.\n     * - MUST NOT show any variations depending on the caller.\n     * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n     */\n    function claimableDepositRequest(uint256 requestId, address controller)\n        external\n        view\n        returns (uint256 claimableAssets);\n\n    /**\n     * @dev Mints shares Vault shares to receiver by claiming the Request of the controller.\n     *\n     * - MUST emit the Deposit event.\n     * - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator.\n     */\n    function deposit(uint256 assets, address receiver, address controller) external returns (uint256 shares);\n\n    /**\n     * @dev Mints exactly shares Vault shares to receiver by claiming the Request of the controller.\n     *\n     * - MUST emit the Deposit event.\n     * - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator.\n     */\n    function mint(uint256 shares, address receiver, address controller) external returns (uint256 assets);\n}\n\ninterface IERC7540Redeem is IERC7540Operator {\n    event RedeemRequest(\n        address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets\n    );\n\n    /**\n     * @dev Assumes control of shares from sender into the Vault and submits a Request for asynchronous redeem.\n     *\n     * - MUST support a redeem Request flow where the control of shares is taken from sender directly\n     *   where msg.sender has ERC-20 approval over the shares of owner.\n     * - MUST revert if all of shares cannot be requested for redeem.\n     *\n     * @param shares the amount of shares to be redeemed to transfer from owner\n     * @param controller the controller of the request who will be able to operate the request\n     * @param owner the source of the shares to be redeemed\n     *\n     * NOTE: most implementations will require pre-approval of the Vault with the Vault's share token.\n     */\n    function requestRedeem(uint256 shares, address controller, address owner) external returns (uint256 requestId);\n\n    /**\n     * @dev Returns the amount of requested shares in Pending state.\n     *\n     * - MUST NOT include any shares in Claimable state for redeem or withdraw.\n     * - MUST NOT show any variations depending on the caller.\n     * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n     */\n    function pendingRedeemRequest(uint256 requestId, address controller)\n        external\n        view\n        returns (uint256 pendingShares);\n\n    /**\n     * @dev Returns the amount of requested shares in Claimable state for the controller to redeem or withdraw.\n     *\n     * - MUST NOT include any shares in Pending state for redeem or withdraw.\n     * - MUST NOT show any variations depending on the caller.\n     * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n     */\n    function claimableRedeemRequest(uint256 requestId, address controller)\n        external\n        view\n        returns (uint256 claimableShares);\n}\n\ninterface IERC7887Deposit {\n    event CancelDepositRequest(address indexed controller, uint256 indexed requestId, address sender);\n    event CancelDepositClaim(\n        address indexed controller, address indexed receiver, uint256 indexed requestId, address sender, uint256 assets\n    );\n\n    /**\n     * @dev Submits a Request for cancelling the pending deposit Request\n     *\n     * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n     *    approval of ERC-20 tokens from controller to sender is NOT enough.\n     * - MUST set pendingCancelDepositRequest to `true` for the returned requestId after request\n     * - MUST increase claimableCancelDepositRequest for the returned requestId after fulfillment\n     * - SHOULD be claimable using `claimCancelDepositRequest`\n     * Note: while `pendingCancelDepositRequest` is `true`, `requestDeposit` cannot be called\n     */\n    function cancelDepositRequest(uint256 requestId, address controller) external;\n\n    /**\n     * @dev Returns whether the deposit Request is pending cancelation\n     *\n     * - MUST NOT show any variations depending on the caller.\n     */\n    function pendingCancelDepositRequest(uint256 requestId, address controller)\n        external\n        view\n        returns (bool isPending);\n\n    /**\n     * @dev Returns the amount of assets that were canceled from a deposit Request, and can now be claimed.\n     *\n     * - MUST NOT show any variations depending on the caller.\n     */\n    function claimableCancelDepositRequest(uint256 requestId, address controller)\n        external\n        view\n        returns (uint256 claimableAssets);\n\n    /**\n     * @dev Claims the canceled deposit assets, and removes the pending cancelation Request\n     *\n     * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n     *    approval of ERC-20 tokens from controller to sender is NOT enough.\n     * - MUST set pendingCancelDepositRequest to `false` for the returned requestId after request\n     * - MUST set claimableCancelDepositRequest to 0 for the returned requestId after fulfillment\n     */\n    function claimCancelDepositRequest(uint256 requestId, address receiver, address controller)\n        external\n        returns (uint256 assets);\n}\n\ninterface IERC7887Redeem {\n    event CancelRedeemRequest(address indexed controller, uint256 indexed requestId, address sender);\n    event CancelRedeemClaim(\n        address indexed controller, address indexed receiver, uint256 indexed requestId, address sender, uint256 shares\n    );\n\n    /**\n     * @dev Submits a Request for cancelling the pending redeem Request\n     *\n     * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n     *    approval of ERC-20 tokens from controller to sender is NOT enough.\n     * - MUST set pendingCancelRedeemRequest to `true` for the returned requestId after request\n     * - MUST increase claimableCancelRedeemRequest for the returned requestId after fulfillment\n     * - SHOULD be claimable using `claimCancelRedeemRequest`\n     * Note: while `pendingCancelRedeemRequest` is `true`, `requestRedeem` cannot be called\n     */\n    function cancelRedeemRequest(uint256 requestId, address controller) external;\n\n    /**\n     * @dev Returns whether the redeem Request is pending cancelation\n     *\n     * - MUST NOT show any variations depending on the caller.\n     */\n    function pendingCancelRedeemRequest(uint256 requestId, address controller) external view returns (bool isPending);\n\n    /**\n     * @dev Returns the amount of shares that were canceled from a redeem Request, and can now be claimed.\n     *\n     * - MUST NOT show any variations depending on the caller.\n     */\n    function claimableCancelRedeemRequest(uint256 requestId, address controller)\n        external\n        view\n        returns (uint256 claimableShares);\n\n    /**\n     * @dev Claims the canceled redeem shares, and removes the pending cancelation Request\n     *\n     * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n     *    approval of ERC-20 tokens from controller to sender is NOT enough.\n     * - MUST set pendingCancelRedeemRequest to `false` for the returned requestId after request\n     * - MUST set claimableCancelRedeemRequest to 0 for the returned requestId after fulfillment\n     */\n    function claimCancelRedeemRequest(uint256 requestId, address receiver, address controller)\n        external\n        returns (uint256 shares);\n}\n\ninterface IERC7741 {\n    /**\n     * @dev Grants or revokes permissions for `operator` to manage Requests on behalf of the\n     *      `msg.sender`, using an [EIP-712](./eip-712.md) signature.\n     */\n    function authorizeOperator(\n        address controller,\n        address operator,\n        bool approved,\n        bytes32 nonce,\n        uint256 deadline,\n        bytes memory signature\n    ) external returns (bool);\n\n    /**\n     * @dev Revokes the given `nonce` for `msg.sender` as the `owner`.\n     */\n    function invalidateNonce(bytes32 nonce) external;\n\n    /**\n     * @dev Returns whether the given `nonce` has been used for the `controller`.\n     */\n    function authorizations(address controller, bytes32 nonce) external view returns (bool used);\n\n    /**\n     * @dev Returns the `DOMAIN_SEPARATOR` as defined according to EIP-712. The `DOMAIN_SEPARATOR\n     *      should be unique to the contract and chain to prevent replay attacks from other domains,\n     *      and satisfy the requirements of EIP-712, but is otherwise unconstrained.\n     */\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\ninterface IERC7714 {\n    /**\n     * @dev Returns `true` if the `user` is permissioned to interact with the contract.\n     */\n    function isPermissioned(address controller) external view returns (bool);\n}\n"
    },
    "src/misc/interfaces/IERC7575.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others.\n */\ninterface IERC165 {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\ninterface IERC7575 is IERC165 {\n    event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);\n    event Withdraw(\n        address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares\n    );\n\n    /**\n     * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.\n     *\n     * - MUST be an ERC-20 token contract.\n     * - MUST NOT revert.\n     */\n    function asset() external view returns (address assetTokenAddress);\n\n    /**\n     * @dev Returns the address of the share token\n     *\n     * - MUST be an ERC-20 token contract.\n     * - MUST NOT revert.\n     */\n    function share() external view returns (address shareTokenAddress);\n\n    /**\n     * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal\n     * scenario where all the conditions are met.\n     *\n     * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n     * - MUST NOT show any variations depending on the caller.\n     * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n     * - MUST NOT revert.\n     *\n     * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n     * from.\n     */\n    function convertToShares(uint256 assets) external view returns (uint256 shares);\n\n    /**\n     * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal\n     * scenario where all the conditions are met.\n     *\n     * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n     * - MUST NOT show any variations depending on the caller.\n     * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n     * - MUST NOT revert.\n     *\n     * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n     * from.\n     */\n    function convertToAssets(uint256 shares) external view returns (uint256 assets);\n\n    /**\n     * @dev Returns the total amount of the underlying asset that is “managed” by Vault.\n     *\n     * - SHOULD include any compounding that occurs from yield.\n     * - MUST be inclusive of any fees that are charged against assets in the Vault.\n     * - MUST NOT revert.\n     */\n    function totalAssets() external view returns (uint256 totalManagedAssets);\n\n    /**\n     * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,\n     * through a deposit call.\n     *\n     * - MUST return a limited value if receiver is subject to some deposit limit.\n     * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.\n     * - MUST NOT revert.\n     */\n    function maxDeposit(address receiver) external view returns (uint256 maxAssets);\n\n    /**\n     * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given\n     * current on-chain conditions.\n     *\n     * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit\n     *   call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called\n     *   in the same transaction.\n     * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the\n     *   deposit would be accepted, regardless if the user has enough tokens approved, etc.\n     * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n     * - MUST NOT revert.\n     *\n     * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in\n     * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n     */\n    function previewDeposit(uint256 assets) external view returns (uint256 shares);\n\n    /**\n     * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.\n     *\n     * - MUST emit the Deposit event.\n     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n     *   deposit execution, and are accounted for during deposit.\n     * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not\n     *   approving enough underlying tokens to the Vault contract, etc).\n     *\n     * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n     */\n    function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n    /**\n     * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.\n     * - MUST return a limited value if receiver is subject to some mint limit.\n     * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.\n     * - MUST NOT revert.\n     */\n    function maxMint(address receiver) external view returns (uint256 maxShares);\n\n    /**\n     * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given\n     * current on-chain conditions.\n     *\n     * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call\n     *   in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the\n     *   same transaction.\n     * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint\n     *   would be accepted, regardless if the user has enough tokens approved, etc.\n     * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n     * - MUST NOT revert.\n     *\n     * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in\n     * share price or some other type of condition, meaning the depositor will lose assets by minting.\n     */\n    function previewMint(uint256 shares) external view returns (uint256 assets);\n\n    /**\n     * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.\n     *\n     * - MUST emit the Deposit event.\n     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint\n     *   execution, and are accounted for during mint.\n     * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not\n     *   approving enough underlying tokens to the Vault contract, etc).\n     *\n     * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n     */\n    function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n    /**\n     * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the\n     * Vault, through a withdraw call.\n     *\n     * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n     * - MUST NOT revert.\n     */\n    function maxWithdraw(address owner) external view returns (uint256 maxAssets);\n\n    /**\n     * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,\n     * given current on-chain conditions.\n     *\n     * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw\n     *   call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if\n     *   called\n     *   in the same transaction.\n     * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though\n     *   the withdrawal would be accepted, regardless if the user has enough shares, etc.\n     * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n     * - MUST NOT revert.\n     *\n     * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in\n     * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n     */\n    function previewWithdraw(uint256 assets) external view returns (uint256 shares);\n\n    /**\n     * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.\n     *\n     * - MUST emit the Withdraw event.\n     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n     *   withdraw execution, and are accounted for during withdraw.\n     * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner\n     *   not having enough shares, etc).\n     *\n     * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n     * Those methods should be performed separately.\n     */\n    function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);\n\n    /**\n     * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,\n     * through a redeem call.\n     *\n     * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n     * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.\n     * - MUST NOT revert.\n     */\n    function maxRedeem(address owner) external view returns (uint256 maxShares);\n\n    /**\n     * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,\n     * given current on-chain conditions.\n     *\n     * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call\n     *   in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the\n     *   same transaction.\n     * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the\n     *   redemption would be accepted, regardless if the user has enough shares, etc.\n     * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n     * - MUST NOT revert.\n     *\n     * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in\n     * share price or some other type of condition, meaning the depositor will lose assets by redeeming.\n     */\n    function previewRedeem(uint256 shares) external view returns (uint256 assets);\n\n    /**\n     * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.\n     *\n     * - MUST emit the Withdraw event.\n     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n     *   redeem execution, and are accounted for during redeem.\n     * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner\n     *   not having enough shares, etc).\n     *\n     * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n     * Those methods should be performed separately.\n     */\n    function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);\n}\n\ninterface IERC7575Share is IERC165 {\n    event VaultUpdate(address indexed asset, address vault);\n\n    /**\n     * @dev Returns the address of the Vault for the given asset.\n     *\n     * @param asset the ERC-20 token to deposit with into the Vault\n     */\n    function vault(address asset) external view returns (address);\n}\n"
    },
    "src/misc/interfaces/IERC7726.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/// [ERC-7726](https://eips.ethereum.org/EIPS/eip-7726): Common Quote Oracle\n/// Interface for asset conversions.\ninterface IERC7726 {\n    /// @notice Returns the value of baseAmount of base in quote terms, e.g. 10 ETH (base) in USDC (quote).\n    /// @param base The asset in which the baseAmount is denominated in\n    /// @param quote The asset in which the user needs to value the baseAmount\n    /// @param baseAmount The amount of base in base terms.\n    function getQuote(uint256 baseAmount, address base, address quote) external view returns (uint256 quoteAmount);\n}\n"
    },
    "src/misc/interfaces/IIdentityValuation.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\n\n/// @notice An IERC7726 valuation that always values 1:1.\ninterface IIdentityValuation is IERC7726 {}\n"
    },
    "src/misc/interfaces/IMulticall.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/// @notice Allows to call several calls of the same contract in a single transaction\ninterface IMulticall {\n    /// @notice Dispatched when an empty revert is dispatched in a method in the multicall\n    error CallFailedWithEmptyRevert();\n\n    /// @notice Allows caller to execute multiple (batched) messages calls in one transaction.\n    /// @param data An array of encoded methods of the same contract.\n    /// @dev No reentrant execution is allowed.\n    /// If one call fails, it reverts the whole transaction.\n    /// In order to provide the correct value for functions that require top up,\n    /// the caller must estimate separately, in advance, how much each of the message call will cost.\n    /// The `msg.value` when calling this method must be the sum of all estimates.\n    function multicall(bytes[] calldata data) external payable;\n}\n"
    },
    "src/misc/interfaces/IRecoverable.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\naddress constant ETH_ADDRESS = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);\n\ninterface IRecoverable {\n    /// @notice Used to recover any ERC-20 token.\n    /// @dev    This method is called only by authorized entities\n    /// @param  token It could be 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\n    ///         to recover locked native ETH or token compatible with ERC20.\n    /// @param  to Receiver of the funds\n    /// @param  amount Amount to send to the receiver.\n    function recoverTokens(address token, address to, uint256 amount) external;\n\n    /// @notice Used to recover any ERC-20 or ERC-6909 token.\n    /// @dev    This method is called only by authorized entities\n    /// @param  token It could be 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\n    ///         to recover locked native ETH or token compatible with ERC20 or ERC6909.\n    /// @param  tokenId The token id, i.e. non-zero if the underlying token is ERC6909 and else zero.\n    /// @param  to Receiver of the funds\n    /// @param  amount Amount to send to the receiver.\n    function recoverTokens(address token, uint256 tokenId, address to, uint256 amount) external;\n}\n"
    },
    "src/misc/libraries/ArrayLib.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title  ArrayLib\nlibrary ArrayLib {\n    error InvalidValues();\n\n    function countNonZeroValues(uint16[8] memory arr) internal pure returns (uint8 count) {\n        uint256 elementsCount = arr.length;\n        for (uint256 i; i < elementsCount; i++) {\n            if (arr[i] != 0) ++count;\n        }\n    }\n\n    function decreaseFirstNValues(uint16[8] storage arr, uint8 numValues) internal {\n        uint256 elementsCount = arr.length;\n        for (uint256 i; i < elementsCount; i++) {\n            if (numValues == 0) return;\n\n            if (arr[i] != 0) {\n                arr[i] -= 1;\n                numValues--;\n            }\n        }\n\n        require(numValues == 0, InvalidValues());\n    }\n\n    function isEmpty(uint16[8] memory arr) internal pure returns (bool) {\n        uint256 elementsCount = arr.length;\n        for (uint256 i; i < elementsCount; i++) {\n            if (arr[i] != 0) return false;\n        }\n        return true;\n    }\n}\n"
    },
    "src/misc/libraries/BitmapLib.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title  BitmapLib\nlibrary BitmapLib {\n    function setBit(uint128 bitmap, uint128 index, bool isTrue) internal pure returns (uint128) {\n        if (isTrue) {\n            return bitmap | (uint128(1) << index);\n        }\n\n        return bitmap & ~(uint128(1) << index);\n    }\n\n    function getBit(uint128 bitmap, uint128 index) internal pure returns (bool) {\n        uint128 bitAtIndex = uint128(bitmap & (1 << index));\n        return bitAtIndex != 0;\n    }\n}\n"
    },
    "src/misc/libraries/BytesLib.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title  Bytes Lib\n/// @dev    Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.\n///         The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.\n/// @author Modified from Solidity Bytes Arrays Utils v0.8.0\nlibrary BytesLib {\n    error SliceOverflow();\n    error SliceOutOfBounds();\n\n    function sliceZeroPadded(bytes memory _bytes, uint256 _start, uint256 _length)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        require(_length + 31 >= _length, SliceOverflow());\n\n        bytes memory tempBytes;\n\n        assembly {\n            switch iszero(_length)\n            case 0 {\n                // Get a location of some free memory and store it in tempBytes as\n                // Solidity does for memory variables.\n                tempBytes := mload(0x40)\n\n                // The first word of the slice result is potentially a partial\n                // word read from the original array. To read it, we calculate\n                // the length of that partial word and start copying that many\n                // bytes into the array. The first word we copy will start with\n                // data we don't care about, but the last `lengthmod` bytes will\n                // land at the beginning of the contents of the new array. When\n                // we're done copying, we overwrite the full first word with\n                // the actual length of the slice.\n                let lengthmod := and(_length, 31)\n\n                // The multiplication in the next line is necessary\n                // because when slicing multiples of 32 bytes (lengthmod == 0)\n                // the following copy loop was copying the origin's length\n                // and then ending prematurely not copying everything it should.\n                let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))\n                let end := add(mc, _length)\n\n                for {\n                    // The multiplication in the next line has the same exact purpose\n                    // as the one above.\n                    let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)\n                } lt(mc, end) {\n                    mc := add(mc, 0x20)\n                    cc := add(cc, 0x20)\n                } { mstore(mc, mload(cc)) }\n\n                mstore(tempBytes, _length)\n\n                //update free-memory pointer\n                //allocating the array padded to 32 bytes like the compiler does now\n                mstore(0x40, and(add(mc, 31), not(31)))\n            }\n            //if we want a zero-length slice let's just return a zero-length array\n            default {\n                tempBytes := mload(0x40)\n                //zero out the 32 bytes slice we are about to return\n                //we need to do it because Solidity does not garbage collect\n                mstore(tempBytes, 0)\n\n                mstore(0x40, add(tempBytes, 0x20))\n            }\n        }\n\n        return tempBytes;\n    }\n\n    function slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) {\n        require(_bytes.length >= _start + _length, SliceOutOfBounds());\n        return sliceZeroPadded(_bytes, _start, _length);\n    }\n\n    function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {\n        require(_bytes.length >= _start + 20, SliceOutOfBounds());\n        address tempAddress;\n\n        assembly {\n            tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)\n        }\n\n        return tempAddress;\n    }\n\n    function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {\n        require(_bytes.length >= _start + 1, SliceOutOfBounds());\n        uint8 tempUint;\n\n        assembly {\n            tempUint := mload(add(add(_bytes, 0x1), _start))\n        }\n\n        return tempUint;\n    }\n\n    function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {\n        require(_bytes.length >= _start + 2, SliceOutOfBounds());\n        uint16 tempUint;\n\n        assembly {\n            tempUint := mload(add(add(_bytes, 0x2), _start))\n        }\n\n        return tempUint;\n    }\n\n    function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {\n        require(_bytes.length >= _start + 4, SliceOutOfBounds());\n        uint32 tempUint;\n\n        assembly {\n            tempUint := mload(add(add(_bytes, 0x4), _start))\n        }\n\n        return tempUint;\n    }\n\n    function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {\n        require(_bytes.length >= _start + 8, SliceOutOfBounds());\n        uint64 tempUint;\n\n        assembly {\n            tempUint := mload(add(add(_bytes, 0x8), _start))\n        }\n\n        return tempUint;\n    }\n\n    function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {\n        require(_bytes.length >= _start + 16, SliceOutOfBounds());\n        uint128 tempUint;\n\n        assembly {\n            tempUint := mload(add(add(_bytes, 0x10), _start))\n        }\n\n        return tempUint;\n    }\n\n    function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {\n        require(_bytes.length >= _start + 32, SliceOutOfBounds());\n        uint256 tempUint;\n\n        assembly {\n            tempUint := mload(add(add(_bytes, 0x20), _start))\n        }\n\n        return tempUint;\n    }\n\n    function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {\n        require(_bytes.length >= _start + 32, SliceOutOfBounds());\n        bytes32 tempBytes32;\n\n        assembly {\n            tempBytes32 := mload(add(add(_bytes, 0x20), _start))\n        }\n\n        return tempBytes32;\n    }\n\n    function toBytes16(bytes memory _bytes, uint256 _start) internal pure returns (bytes16) {\n        require(_bytes.length >= _start + 16, SliceOutOfBounds());\n        bytes16 tempBytes16;\n\n        assembly {\n            tempBytes16 := mload(add(add(_bytes, 0x20), _start))\n        }\n\n        return tempBytes16;\n    }\n\n    function toBool(bytes memory _bytes, uint256 _start) internal pure returns (bool) {\n        require(_bytes.length > _start, SliceOutOfBounds());\n        return _bytes[_start] != 0;\n    }\n}\n"
    },
    "src/misc/libraries/CastLib.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title  CastLib\nlibrary CastLib {\n    function toAddressLeftPadded(bytes32 addr) internal pure returns (address) {\n        require(bytes12(addr) == 0, \"First 12 bytes should be zero\");\n        return address(uint160(uint256(addr)));\n    }\n\n    function toBytes32LeftPadded(address addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(addr)));\n    }\n\n    function toAddress(bytes32 addr) internal pure returns (address) {\n        require(uint96(uint256(addr)) == 0, \"Input should be 20 bytes\");\n        return address(bytes20(addr));\n    }\n\n    function toString(address addr) internal pure returns (string memory) {\n        return string(abi.encodePacked(addr));\n    }\n\n    function toBytes32(address addr) internal pure returns (bytes32) {\n        return bytes32(bytes20(addr));\n    }\n\n    /// @dev Adds zero padding\n    function toBytes32(string memory source) internal pure returns (bytes32) {\n        return bytes32(bytes(source));\n    }\n\n    /// @dev Removes zero padding\n    function bytes128ToString(bytes memory _bytes128) internal pure returns (string memory) {\n        require(_bytes128.length == 128, \"Input should be 128 bytes\");\n\n        uint8 i = 0;\n        while (i < 128 && _bytes128[i] != 0) {\n            i++;\n        }\n\n        bytes memory bytesArray = new bytes(i);\n\n        for (uint8 j; j < i; j++) {\n            bytesArray[j] = _bytes128[j];\n        }\n\n        return string(bytesArray);\n    }\n\n    function toString(bytes32 _bytes32) internal pure returns (string memory) {\n        uint8 i = 0;\n        while (i < 32 && _bytes32[i] != 0) {\n            i++;\n        }\n        bytes memory bytesArray = new bytes(i);\n        for (i = 0; i < 32 && _bytes32[i] != 0; i++) {\n            bytesArray[i] = _bytes32[i];\n        }\n        return string(bytesArray);\n    }\n}\n"
    },
    "src/misc/libraries/EIP712Lib.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title  EIP712 Lib\nlibrary EIP712Lib {\n    // keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\")\n    bytes32 public constant EIP712_DOMAIN_TYPEHASH = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f;\n\n    function calculateDomainSeparator(bytes32 nameHash, bytes32 versionHash) internal view returns (bytes32) {\n        return keccak256(abi.encode(EIP712_DOMAIN_TYPEHASH, nameHash, versionHash, block.chainid, address(this)));\n    }\n}\n"
    },
    "src/misc/libraries/MathLib.sol": {
      "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.28;\n\nlibrary MathLib {\n    enum Rounding {\n        Down, // Toward negative infinity\n        Up, // Toward infinity\n        Zero // Toward zero\n\n    }\n\n    error MulDiv_Overflow();\n    error Uint8_Overflow();\n    error Uint32_Overflow();\n    error Uint64_Overflow();\n    error Uint128_Overflow();\n    error Int128_Overflow();\n\n    uint256 public constant One27 = 10 ** 27;\n\n    /// @notice Returns x^n with rounding precision of base\n    ///\n    /// @dev Source: https://github.com/makerdao/dss/blob/fa4f6630afb0624d04a003e920b0d71a00331d98/src/jug.sol#L62\n    ///\n    /// @param x The base value which should be exponentiated\n    /// @param n The exponent\n    /// @param base The scaling base, typically used for fix-point calculations\n    function rpow(uint256 x, uint256 n, uint256 base) public pure returns (uint256 z) {\n        assembly {\n            switch x\n            case 0 {\n                switch n\n                case 0 { z := base }\n                default { z := 0 }\n            }\n            default {\n                switch mod(n, 2)\n                case 0 { z := base }\n                default { z := x }\n                let half := div(base, 2) // for rounding.\n                for { n := div(n, 2) } n { n := div(n, 2) } {\n                    let xx := mul(x, x)\n                    if iszero(eq(div(xx, x), x)) { revert(0, 0) }\n                    let xxRound := add(xx, half)\n                    if lt(xxRound, xx) { revert(0, 0) }\n                    x := div(xxRound, base)\n                    if mod(n, 2) {\n                        let zx := mul(z, x)\n                        if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0, 0) }\n                        let zxRound := add(zx, half)\n                        if lt(zxRound, zx) { revert(0, 0) }\n                        z := div(zxRound, base)\n                    }\n                }\n            }\n        }\n    }\n\n    /// @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or\n    ///         denominator == 0\n    /// @dev    Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n    ///         with further edits by Uniswap Labs also under MIT license.\n    // slither-disable-start divide-before-multiply\n    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n        unchecked {\n            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n            // variables such that product = prod1 * 2^256 + prod0.\n            uint256 prod0; // Least significant 256 bits of the product\n            uint256 prod1; // Most significant 256 bits of the product\n            assembly {\n                let mm := mulmod(x, y, not(0))\n                prod0 := mul(x, y)\n                prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n            }\n\n            // Handle non-overflow cases, 256 by 256 division.\n            if (prod1 == 0) {\n                // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n                // The surrounding unchecked block does not change this fact.\n                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n                return prod0 / denominator;\n            }\n\n            // Make sure the result is less than 2^256. Also prevents denominator == 0.\n            require(denominator > prod1, MulDiv_Overflow());\n\n            ///////////////////////////////////////////////\n            // 512 by 256 division.\n            ///////////////////////////////////////////////\n\n            // Make division exact by subtracting the remainder from [prod1 prod0].\n            uint256 remainder;\n            assembly {\n                // Compute remainder using mulmod.\n                remainder := mulmod(x, y, denominator)\n\n                // Subtract 256 bit number from 512 bit number.\n                prod1 := sub(prod1, gt(remainder, prod0))\n                prod0 := sub(prod0, remainder)\n            }\n\n            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.\n            // Always >= 1.\n            // See https://cs.stackexchange.com/q/138556/92363.\n\n            // Does not overflow because the denominator cannot be zero at this stage in the function.\n            uint256 twos = denominator & (~denominator + 1);\n            assembly {\n                // Divide denominator by twos.\n                denominator := div(denominator, twos)\n\n                // Divide [prod1 prod0] by twos.\n                prod0 := div(prod0, twos)\n\n                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n                twos := add(div(sub(0, twos), twos), 1)\n            }\n\n            // Shift in bits from prod1 into prod0.\n            prod0 |= prod1 * twos;\n\n            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n            // four bits. That is, denominator * inv = 1 mod 2^4.\n            uint256 inverse = (3 * denominator) ^ 2;\n\n            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also\n            // works\n            // in modular arithmetic, doubling the correct bits in each step.\n            inverse *= 2 - denominator * inverse; // inverse mod 2^8\n            inverse *= 2 - denominator * inverse; // inverse mod 2^16\n            inverse *= 2 - denominator * inverse; // inverse mod 2^32\n            inverse *= 2 - denominator * inverse; // inverse mod 2^64\n            inverse *= 2 - denominator * inverse; // inverse mod 2^128\n            inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n            // is no longer required.\n            result = prod0 * inverse;\n            return result;\n        }\n    }\n    // slither-disable-end divide-before-multiply\n\n    /// @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n        uint256 result = mulDiv(x, y, denominator);\n        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n            result += 1;\n        }\n        return result;\n    }\n\n    /// @notice Safe type conversion from uint256 to uint8.\n    function toUint8(uint256 value) internal pure returns (uint8) {\n        require(value <= type(uint8).max, Uint8_Overflow());\n        return uint8(value);\n    }\n\n    function toUint32(uint256 value) internal pure returns (uint32) {\n        require(value <= type(uint32).max, Uint32_Overflow());\n        return uint32(value);\n    }\n\n    function toUint64(uint256 value) internal pure returns (uint64) {\n        require(value <= type(uint64).max, Uint64_Overflow());\n        return uint64(value);\n    }\n\n    /// @notice Safe type conversion from uint256 to uint128.\n    function toUint128(uint256 value) internal pure returns (uint128) {\n        require(value <= type(uint128).max, Uint128_Overflow());\n        return uint128(value);\n    }\n\n    /// @notice Returns the smallest of two numbers.\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a > b ? b : a;\n    }\n\n    /// @notice Returns the largest of two numbers.\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a > b ? a : b;\n    }\n}\n"
    },
    "src/misc/libraries/SafeTransferLib.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC20} from \"src/misc/interfaces/IERC20.sol\";\n\n/// @title  Safe Transfer Lib\n/// @author Modified from Uniswap v3 Periphery (libraries/TransferHelper.sol)\nlibrary SafeTransferLib {\n    error NoCode();\n    error SafeTransferFromFailed();\n    error SafeTransferFailed();\n    error SafeApproveFailed();\n    error SafeTransferEthFailed();\n\n    /// @notice Transfers tokens from the targeted address to the given destination\n    /// @notice Errors if transfer fails\n    /// @param token The contract address of the token to be transferred\n    /// @param from The originating address from which the tokens will be transferred\n    /// @param to The destination address of the transfer\n    /// @param value The amount to be transferred\n    function safeTransferFrom(address token, address from, address to, uint256 value) internal {\n        require(address(token).code.length > 0, NoCode());\n\n        (bool success, bytes memory data) = token.call(abi.encodeCall(IERC20.transferFrom, (from, to, value)));\n        require(success && (data.length == 0 || abi.decode(data, (bool))), SafeTransferFromFailed());\n    }\n\n    /// @notice Transfers tokens from msg.sender to a recipient\n    /// @dev Errors if transfer fails\n    /// @param token The contract address of the token which will be transferred\n    /// @param to The recipient of the transfer\n    /// @param value The value of the transfer\n    function safeTransfer(address token, address to, uint256 value) internal {\n        require(address(token).code.length > 0, NoCode());\n\n        (bool success, bytes memory data) = token.call(abi.encodeCall(IERC20.transfer, (to, value)));\n        require(success && (data.length == 0 || abi.decode(data, (bool))), SafeTransferFailed());\n    }\n\n    /// @notice Approves the stipulated contract to spend the given allowance in the given token\n    /// @dev Errors if approval fails\n    /// @param token The contract address of the token to be approved\n    /// @param to The target of the approval\n    /// @param value The amount of the given token the target will be allowed to spend\n    function safeApprove(address token, address to, uint256 value) internal {\n        require(address(token).code.length > 0, NoCode());\n\n        (bool success, bytes memory data) = token.call(abi.encodeCall(IERC20.approve, (to, value)));\n        require(success && (data.length == 0 || abi.decode(data, (bool))), SafeApproveFailed());\n    }\n\n    /// @notice Transfers ETH to the recipient address\n    /// @dev Fails with `STE`\n    /// @dev Make sure that method that is using this function is protected from reentrancy\n    /// @param to The destination of the transfer\n    /// @param value The value to be transferred\n    function safeTransferETH(address to, uint256 value) internal {\n        (bool success,) = to.call{value: value}(new bytes(0));\n        require(success, SafeTransferEthFailed());\n    }\n}\n"
    },
    "src/misc/libraries/SignatureLib.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\ninterface IERC1271 {\n    function isValidSignature(bytes32, bytes memory) external view returns (bytes4);\n}\n\n/// @title  Signature Lib\nlibrary SignatureLib {\n    error InvalidSigner();\n\n    function isValidSignature(address signer, bytes32 digest, bytes memory signature)\n        internal\n        view\n        returns (bool valid)\n    {\n        require(signer != address(0), InvalidSigner());\n\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            if (signer == ecrecover(digest, v, r, s)) {\n                return true;\n            }\n        }\n\n        if (signer.code.length > 0) {\n            (bool success, bytes memory result) =\n                signer.staticcall(abi.encodeCall(IERC1271.isValidSignature, (digest, signature)));\n            valid =\n                (success && result.length == 32 && abi.decode(result, (bytes4)) == IERC1271.isValidSignature.selector);\n        }\n    }\n}\n"
    },
    "src/misc/libraries/StringLib.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nlibrary StringLib {\n    function isEmpty(string memory value) internal pure returns (bool) {\n        return bytes(value).length == 0;\n    }\n}\n"
    },
    "src/misc/libraries/TransientArrayLib.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {TransientStorageLib} from \"src/misc/libraries/TransientStorageLib.sol\";\n\n/// @title  TransientArrayLib\nlibrary TransientArrayLib {\n    using TransientStorageLib for bytes32;\n\n    function push(bytes32 key, bytes32 value) internal {\n        bytes32 lengthSlot = keccak256(abi.encodePacked(key, type(uint256).max));\n        uint256 length_ = lengthSlot.tloadUint256();\n        lengthSlot.tstore(length_ + 1);\n\n        bytes32 slot = keccak256(abi.encodePacked(key, length_));\n        slot.tstore(value);\n    }\n\n    function getBytes32(bytes32 key) internal view returns (bytes32[] memory) {\n        uint256 length_ = length(key);\n\n        bytes32[] memory data = new bytes32[](length_);\n        for (uint256 i = 0; i < length_; i++) {\n            bytes32 slot = keccak256(abi.encodePacked(key, i));\n            data[i] = slot.tloadBytes32();\n        }\n\n        return data;\n    }\n\n    function length(bytes32 key) internal view returns (uint256) {\n        return keccak256(abi.encodePacked(key, type(uint256).max)).tloadUint256();\n    }\n\n    function clear(bytes32 key) internal {\n        bytes32 lengthSlot = keccak256(abi.encodePacked(key, type(uint256).max));\n        lengthSlot.tstore(uint256(0));\n    }\n}\n"
    },
    "src/misc/libraries/TransientBytesLib.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {TransientStorageLib} from \"src/misc/libraries/TransientStorageLib.sol\";\n\n/// @title  TransientBytesLib\nlibrary TransientBytesLib {\n    using TransientStorageLib for bytes32;\n    using BytesLib for bytes;\n\n    function append(bytes32 key, bytes memory value) internal {\n        bytes32 lengthSlot = keccak256(abi.encodePacked(key, type(uint256).max));\n        uint256 prevLength = lengthSlot.tloadUint256();\n\n        uint256 startChunk = prevLength / 32;\n        uint256 offset = prevLength % 32;\n\n        lengthSlot.tstore(prevLength + value.length);\n\n        bytes32 joinSlot = keccak256(abi.encodePacked(key, startChunk));\n        bytes memory firstPart = abi.encodePacked(joinSlot.tloadBytes32()).sliceZeroPadded(0, offset);\n        bytes memory secondPart = value.sliceZeroPadded(0, 32 - offset);\n        joinSlot.tstore(bytes32(bytes.concat(firstPart, secondPart)));\n\n        uint256 valueOffset = 32 - offset;\n        uint256 chunkIndex = startChunk + 1;\n        for (; valueOffset < value.length; chunkIndex++) {\n            bytes32 slot = keccak256(abi.encodePacked(key, chunkIndex));\n            slot.tstore(bytes32(value.sliceZeroPadded(valueOffset, 32)));\n            valueOffset += 32;\n        }\n    }\n\n    function get(bytes32 key) internal view returns (bytes memory) {\n        bytes memory data;\n        uint256 length = keccak256(abi.encodePacked(key, type(uint256).max)).tloadUint256();\n        if (length == 0) return data;\n\n        uint256 chunks = length / 32 + 1;\n        for (uint256 i = 0; i < chunks; i++) {\n            bytes32 slot = keccak256(abi.encodePacked(key, i));\n            data = bytes.concat(data, slot.tloadBytes32());\n        }\n\n        return data.slice(0, length);\n    }\n\n    function clear(bytes32 key) internal {\n        bytes32 lengthSlot = keccak256(abi.encodePacked(key, type(uint256).max));\n        lengthSlot.tstore(uint256(0));\n    }\n}\n"
    },
    "src/misc/libraries/TransientStorageLib.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title  TransientStorageLib\nlibrary TransientStorageLib {\n    function tstore(bytes32 slot, address value) internal {\n        assembly (\"memory-safe\") {\n            tstore(slot, value)\n        }\n    }\n\n    function tstore(bytes32 slot, uint256 value) internal {\n        assembly (\"memory-safe\") {\n            tstore(slot, value)\n        }\n    }\n\n    function tstore(bytes32 slot, bytes32 value) internal {\n        assembly (\"memory-safe\") {\n            tstore(slot, value)\n        }\n    }\n\n    function tstore(bytes32 slot, bool value) internal {\n        assembly (\"memory-safe\") {\n            tstore(slot, value)\n        }\n    }\n\n    function tloadAddress(bytes32 slot) internal view returns (address value) {\n        assembly (\"memory-safe\") {\n            value := tload(slot)\n        }\n    }\n\n    function tloadUint128(bytes32 slot) internal view returns (uint128 value) {\n        assembly (\"memory-safe\") {\n            value := tload(slot)\n        }\n    }\n\n    function tloadUint256(bytes32 slot) internal view returns (uint256 value) {\n        assembly (\"memory-safe\") {\n            value := tload(slot)\n        }\n    }\n\n    function tloadBytes32(bytes32 slot) internal view returns (bytes32 value) {\n        assembly (\"memory-safe\") {\n            value := tload(slot)\n        }\n    }\n\n    function tloadBool(bytes32 slot) internal view returns (bool value) {\n        assembly (\"memory-safe\") {\n            value := tload(slot)\n        }\n    }\n}\n"
    },
    "src/misc/types/D18.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.28;\n\n// Small library to handle fixed point number operations with 18 decimals with static typing support.\n\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\n\ntype D18 is uint128;\n\nusing MathLib for uint256;\n\n/// @dev add two D18 types\nfunction add(D18 d1, D18 d2) pure returns (D18) {\n    return D18.wrap(D18.unwrap(d1) + D18.unwrap(d2));\n}\n\n/// @dev substract two D18 types\nfunction sub(D18 d1, D18 d2) pure returns (D18) {\n    return D18.wrap(D18.unwrap(d1) - D18.unwrap(d2));\n}\n\n/// @dev Divides one D18 by another one while retaining precision:\n/// - nominator (decimal): 50e18\n/// - denominator (decimal):  2e19\n/// - result (decimal): 25e17\nfunction divD18(D18 d1, D18 d2) pure returns (D18) {\n    return D18.wrap(MathLib.mulDiv(D18.unwrap(d1), 1e18, D18.unwrap(d2)).toUint128());\n}\n\n/// @dev Multiplies one D18 with another one while retaining precision:\n/// - value1 (decimal): 50e18\n/// - value2 (decimal):  2e19\n/// - result (decimal): 100e19\nfunction mulD18(D18 d1, D18 d2) pure returns (D18) {\n    return D18.wrap(MathLib.mulDiv(D18.unwrap(d1), D18.unwrap(d2), 1e18).toUint128());\n}\n\n/// @dev sugar for getting the inner representation of a D18\nfunction inner(D18 d1) pure returns (uint128) {\n    return D18.unwrap(d1);\n}\n\n/// @dev Returns the reciprocal of a D18 decimal, i.e. 1 / d.\n///      Example: if d = 2.0 (2e18 internally), reciprocal(d) = 0.5 (5e17 internally).\nfunction reciprocal(D18 d) pure returns (D18) {\n    uint128 val = D18.unwrap(d);\n    require(val != 0, \"D18/division-by-zero\");\n    return d18(1e18, val);\n}\n\n/// @dev Multiplies a decimal by an integer. i.e:\n/// - d (decimal):      1_500_000_000_000_000_000\n/// - value (integer):  4_000_000_000_000_000_000\n/// - result (integer): 6_000_000_000_000_000_000\nfunction mulUint128(D18 d, uint128 value, MathLib.Rounding rounding) pure returns (uint128) {\n    return MathLib.mulDiv(D18.unwrap(d), value, 1e18, rounding).toUint128();\n}\n\n/// @dev Multiplies a decimal by an integer. i.e:\n/// - d (decimal):      1_500_000_000_000_000_000\n/// - value (integer):  4_000_000_000_000_000_000\n/// - result (integer): 6_000_000_000_000_000_000\nfunction mulUint256(D18 d, uint256 value, MathLib.Rounding rounding) pure returns (uint256) {\n    return MathLib.mulDiv(D18.unwrap(d), value, 1e18, rounding);\n}\n\n/// @dev  Divides an integer by a decimal, i.e.\n/// @dev  Same as mulDiv for integers, i.e:\n/// - d (decimal):      2_000_000_000_000_000_000\n/// - value (integer):  100_000_000_000_000_000_000\n/// - result (integer): 50_000_000_000_000_000_000\nfunction reciprocalMulUint128(D18 d, uint128 value, MathLib.Rounding rounding) pure returns (uint128) {\n    return MathLib.mulDiv(value, 1e18, d.inner(), rounding).toUint128();\n}\n\n/// @dev  Divides an integer by a decimal, i.e.\n/// @dev  Same as mulDiv for integers, i.e:\n/// - d (decimal):      2_000_000_000_000_000_000\n/// - value (integer):  100_000_000_000_000_000_000\n/// - result (integer): 50_000_000_000_000_000_000\nfunction reciprocalMulUint256(D18 d, uint256 value, MathLib.Rounding rounding) pure returns (uint256) {\n    return MathLib.mulDiv(value, 1e18, d.inner(), rounding);\n}\n\n/// @dev Easy way to construct a decimal number\nfunction d18(uint128 value) pure returns (D18) {\n    return D18.wrap(value);\n}\n\n/// @dev Easy way to construct a decimal number\nfunction d18(uint128 num, uint128 den) pure returns (D18) {\n    return D18.wrap(MathLib.mulDiv(num, 1e18, den).toUint128());\n}\n\nfunction eq(D18 a, D18 b) pure returns (bool) {\n    return D18.unwrap(a) == D18.unwrap(b);\n}\n\nfunction raw(D18 d) pure returns (uint128) {\n    return D18.unwrap(d);\n}\n\nusing {\n    add as +,\n    sub as -,\n    divD18 as /,\n    inner,\n    eq,\n    mulD18 as *,\n    mulUint128,\n    mulUint256,\n    reciprocalMulUint128,\n    reciprocalMulUint256,\n    reciprocal,\n    raw\n} for D18 global;\n"
    },
    "src/vaults/AsyncRequestManager.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\n\nimport {MessageLib} from \"src/common/libraries/MessageLib.sol\";\nimport {IVaultMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\nimport {IRequestManagerGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\nimport {IPoolManager, VaultDetails} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IBalanceSheet} from \"src/vaults/interfaces/IBalanceSheet.sol\";\nimport {IAsyncRequestManager, AsyncInvestmentState} from \"src/vaults/interfaces/investments/IAsyncRequestManager.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\nimport {IAsyncDepositManager} from \"src/vaults/interfaces/investments/IAsyncDepositManager.sol\";\nimport {IDepositManager} from \"src/vaults/interfaces/investments/IDepositManager.sol\";\nimport {IRedeemManager} from \"src/vaults/interfaces/investments/IRedeemManager.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IAsyncVault, IBaseVault, IAsyncRedeemVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {BaseRequestManager} from \"src/vaults/BaseRequestManager.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {ESCROW_HOOK_ID} from \"src/common/interfaces/IHook.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\n/// @title  Investment Manager\n/// @notice This is the main contract vaults interact with for\n///         both incoming and outgoing investment transactions.\ncontract AsyncRequestManager is BaseRequestManager, IAsyncRequestManager {\n    using CastLib for *;\n    using MessageLib for *;\n    using BytesLib for bytes;\n    using MathLib for uint256;\n\n    IVaultMessageSender public sender;\n    IBalanceSheet public balanceSheet;\n\n    mapping(IBaseVault vault => mapping(address investor => AsyncInvestmentState)) public investments;\n\n    constructor(IEscrow globalEscrow_, address root_, address deployer)\n        BaseRequestManager(globalEscrow_, root_, deployer)\n    {}\n\n    //----------------------------------------------------------------------------------------------\n    // Administration\n    //----------------------------------------------------------------------------------------------\n\n    function file(bytes32 what, address data) external override(IBaseRequestManager, BaseRequestManager) auth {\n        if (what == \"sender\") sender = IVaultMessageSender(data);\n        else if (what == \"poolManager\") poolManager = IPoolManager(data);\n        else if (what == \"balanceSheet\") balanceSheet = IBalanceSheet(data);\n        else if (what == \"poolEscrowProvider\") poolEscrowProvider = IPoolEscrowProvider(data);\n        else revert FileUnrecognizedParam();\n        emit File(what, data);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Async investment handlers\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IAsyncDepositManager\n    function requestDeposit(IBaseVault vault_, uint256 assets, address controller, address, address)\n        public\n        auth\n        returns (bool)\n    {\n        uint128 assets_ = assets.toUint128();\n        require(assets_ != 0, ZeroAmountNotAllowed());\n\n        VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n        PoolId poolId = vault_.poolId();\n        ShareClassId scId = vault_.scId();\n\n        require(poolManager.isLinked(poolId, scId, vaultDetails.asset, vault_), AssetNotAllowed());\n\n        require(_canTransfer(vault_, address(0), controller, convertToShares(vault_, assets_)), TransferNotAllowed());\n\n        AsyncInvestmentState storage state = investments[vault_][controller];\n        require(state.pendingCancelDepositRequest != true, CancellationIsPending());\n\n        state.pendingDepositRequest += assets_;\n        sender.sendDepositRequest(poolId, scId, controller.toBytes32(), vaultDetails.assetId, assets_);\n\n        return true;\n    }\n\n    /// @inheritdoc IAsyncRedeemManager\n    function requestRedeem(IBaseVault vault_, uint256 shares, address controller, address owner, address)\n        public\n        auth\n        returns (bool)\n    {\n        uint128 shares_ = shares.toUint128();\n        require(shares_ != 0, ZeroAmountNotAllowed());\n\n        VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n        PoolId poolId = vault_.poolId();\n        ShareClassId scId = vault_.scId();\n\n        require(poolManager.isLinked(poolId, scId, vaultDetails.asset, vault_), AssetNotAllowed());\n\n        require(\n            _canTransfer(vault_, owner, ESCROW_HOOK_ID, shares)\n                && _canTransfer(vault_, controller, ESCROW_HOOK_ID, shares),\n            TransferNotAllowed()\n        );\n\n        AsyncInvestmentState storage state = investments[vault_][controller];\n        require(state.pendingCancelRedeemRequest != true, CancellationIsPending());\n\n        state.pendingRedeemRequest = state.pendingRedeemRequest + shares_;\n        sender.sendRedeemRequest(poolId, scId, controller.toBytes32(), vaultDetails.assetId, shares_);\n\n        return true;\n    }\n\n    /// @inheritdoc IAsyncDepositManager\n    function cancelDepositRequest(IBaseVault vault_, address controller, address) public auth {\n        AsyncInvestmentState storage state = investments[vault_][controller];\n        require(state.pendingDepositRequest > 0, NoPendingRequest());\n        require(state.pendingCancelDepositRequest != true, CancellationIsPending());\n        state.pendingCancelDepositRequest = true;\n\n        VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n\n        sender.sendCancelDepositRequest(vault_.poolId(), vault_.scId(), controller.toBytes32(), vaultDetails.assetId);\n    }\n\n    /// @inheritdoc IAsyncRedeemManager\n    function cancelRedeemRequest(IBaseVault vault_, address controller, address) public auth {\n        uint256 approximateSharesPayout = pendingRedeemRequest(vault_, controller);\n        require(approximateSharesPayout > 0, NoPendingRequest());\n        require(_canTransfer(vault_, address(0), controller, approximateSharesPayout), TransferNotAllowed());\n\n        AsyncInvestmentState storage state = investments[vault_][controller];\n        require(state.pendingCancelRedeemRequest != true, CancellationIsPending());\n        state.pendingCancelRedeemRequest = true;\n\n        VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n\n        sender.sendCancelRedeemRequest(vault_.poolId(), vault_.scId(), controller.toBytes32(), vaultDetails.assetId);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Gateway handlers\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IRequestManagerGatewayHandler\n    function approvedDeposits(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        uint128 assetAmount,\n        D18 pricePoolPerAsset\n    ) external auth {\n        (address asset, uint256 tokenId) = poolManager.idToAsset(assetId);\n\n        // Note deposit and transfer from global escrow into the pool escrow,\n        // to make assets available for managers of the balance sheet\n        balanceSheet.overridePricePoolPerAsset(poolId, scId, assetId, pricePoolPerAsset);\n        balanceSheet.noteDeposit(poolId, scId, asset, tokenId, address(globalEscrow), assetAmount);\n\n        address poolEscrow = address(poolEscrowProvider.escrow(poolId));\n        globalEscrow.authTransferTo(asset, tokenId, poolEscrow, assetAmount);\n    }\n\n    /// @inheritdoc IRequestManagerGatewayHandler\n    function issuedShares(PoolId poolId, ShareClassId scId, uint128 shareAmount, D18 pricePoolPerShare) external auth {\n        balanceSheet.overridePricePoolPerShare(poolId, scId, pricePoolPerShare);\n        balanceSheet.issue(poolId, scId, address(globalEscrow), shareAmount);\n    }\n\n    /// @inheritdoc IRequestManagerGatewayHandler\n    function revokedShares(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        uint128 assetAmount,\n        uint128 shareAmount,\n        D18 pricePoolPerShare\n    ) external auth {\n        // Lock assets to ensure they are not withdrawn and are available for the redeeming user\n        (address asset, uint256 tokenId) = poolManager.idToAsset(assetId);\n        poolEscrowProvider.escrow(poolId).reserveIncrease(scId, asset, tokenId, assetAmount);\n\n        balanceSheet.overridePricePoolPerShare(poolId, scId, pricePoolPerShare);\n        balanceSheet.revoke(poolId, scId, address(globalEscrow), shareAmount);\n    }\n\n    /// @inheritdoc IRequestManagerGatewayHandler\n    function fulfillDepositRequest(\n        PoolId poolId,\n        ShareClassId scId,\n        address user,\n        AssetId assetId,\n        uint128 assets,\n        uint128 shares\n    ) public auth {\n        IAsyncVault vault_ = IAsyncVault(address(vault[poolId][scId][assetId]));\n\n        AsyncInvestmentState storage state = investments[vault_][user];\n        require(state.pendingDepositRequest != 0, NoPendingRequest());\n        state.depositPrice = _calculatePriceAssetPerShare(\n            vault_, state.maxMint + shares, _maxDeposit(vault_, user) + assets, MathLib.Rounding.Down\n        );\n        state.maxMint = state.maxMint + shares;\n        state.pendingDepositRequest = state.pendingDepositRequest > assets ? state.pendingDepositRequest - assets : 0;\n\n        if (state.pendingDepositRequest == 0) delete state.pendingCancelDepositRequest;\n\n        vault_.onDepositClaimable(user, assets, shares);\n    }\n\n    /// @inheritdoc IRequestManagerGatewayHandler\n    function fulfillRedeemRequest(\n        PoolId poolId,\n        ShareClassId scId,\n        address user,\n        AssetId assetId,\n        uint128 assets,\n        uint128 shares\n    ) public auth {\n        IAsyncRedeemVault vault_ = IAsyncRedeemVault(address(vault[poolId][scId][assetId]));\n\n        AsyncInvestmentState storage state = investments[vault_][user];\n        require(state.pendingRedeemRequest != 0, NoPendingRequest());\n\n        // Calculate new weighted average redeem price and update order book values\n        state.redeemPrice = _calculatePriceAssetPerShare(\n            vault_, ((maxRedeem(vault_, user)) + shares).toUint128(), state.maxWithdraw + assets, MathLib.Rounding.Down\n        );\n        state.maxWithdraw = state.maxWithdraw + assets;\n        state.pendingRedeemRequest = state.pendingRedeemRequest > shares ? state.pendingRedeemRequest - shares : 0;\n\n        if (state.pendingRedeemRequest == 0) delete state.pendingCancelRedeemRequest;\n\n        vault_.onRedeemClaimable(user, assets, shares);\n    }\n\n    /// @inheritdoc IRequestManagerGatewayHandler\n    function fulfillCancelDepositRequest(\n        PoolId poolId,\n        ShareClassId scId,\n        address user,\n        AssetId assetId,\n        uint128 assets,\n        uint128 fulfillment\n    ) public auth {\n        IAsyncVault vault_ = IAsyncVault(address(vault[poolId][scId][assetId]));\n\n        AsyncInvestmentState storage state = investments[vault_][user];\n        require(state.pendingCancelDepositRequest == true, NoPendingRequest());\n\n        state.claimableCancelDepositRequest = state.claimableCancelDepositRequest + assets;\n        state.pendingDepositRequest =\n            state.pendingDepositRequest > fulfillment ? state.pendingDepositRequest - fulfillment : 0;\n\n        if (state.pendingDepositRequest == 0) delete state.pendingCancelDepositRequest;\n\n        vault_.onCancelDepositClaimable(user, assets);\n    }\n\n    /// @inheritdoc IRequestManagerGatewayHandler\n    function fulfillCancelRedeemRequest(PoolId poolId, ShareClassId scId, address user, AssetId assetId, uint128 shares)\n        public\n        auth\n    {\n        IAsyncRedeemVault vault_ = IAsyncRedeemVault(address(vault[poolId][scId][assetId]));\n        AsyncInvestmentState storage state = investments[vault_][user];\n        require(state.pendingCancelRedeemRequest == true, NoPendingRequest());\n\n        state.claimableCancelRedeemRequest = state.claimableCancelRedeemRequest + shares;\n        state.pendingRedeemRequest = state.pendingRedeemRequest > shares ? state.pendingRedeemRequest - shares : 0;\n\n        if (state.pendingRedeemRequest == 0) delete state.pendingCancelRedeemRequest;\n\n        vault_.onCancelRedeemClaimable(user, shares);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Sync investment handlers\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IDepositManager\n    function deposit(IBaseVault vault_, uint256 assets, address receiver, address controller)\n        public\n        auth\n        returns (uint256 shares)\n    {\n        require(assets <= _maxDeposit(vault_, controller), ExceedsMaxDeposit());\n\n        AsyncInvestmentState storage state = investments[vault_][controller];\n\n        uint128 sharesUp = _assetToShareAmount(vault_, assets.toUint128(), state.depositPrice, MathLib.Rounding.Up);\n        uint128 sharesDown = _assetToShareAmount(vault_, assets.toUint128(), state.depositPrice, MathLib.Rounding.Down);\n        shares = uint256(sharesDown);\n        _processDeposit(state, sharesUp, sharesDown, vault_, receiver);\n    }\n\n    /// @inheritdoc IDepositManager\n    function mint(IBaseVault vault_, uint256 shares, address receiver, address controller)\n        public\n        auth\n        returns (uint256 assets)\n    {\n        AsyncInvestmentState storage state = investments[vault_][controller];\n        uint128 shares_ = shares.toUint128();\n\n        assets = uint256(_shareToAssetAmount(vault_, shares_, state.depositPrice, MathLib.Rounding.Up));\n        _processDeposit(state, shares_, shares_, vault_, receiver);\n    }\n\n    function _processDeposit(\n        AsyncInvestmentState storage state,\n        uint128 sharesUp,\n        uint128 sharesDown,\n        IBaseVault vault_,\n        address receiver\n    ) internal {\n        require(sharesUp <= state.maxMint, ExceedsDepositLimits());\n        state.maxMint = state.maxMint > sharesUp ? state.maxMint - sharesUp : 0;\n\n        if (sharesDown > 0) {\n            globalEscrow.authTransferTo(vault_.share(), receiver, sharesDown);\n        }\n    }\n\n    /// @inheritdoc IRedeemManager\n    function redeem(IBaseVault vault_, uint256 shares, address receiver, address controller)\n        public\n        auth\n        returns (uint256 assets)\n    {\n        require(shares <= maxRedeem(vault_, controller), ExceedsMaxRedeem());\n\n        AsyncInvestmentState storage state = investments[vault_][controller];\n\n        uint128 assetsUp = _shareToAssetAmount(vault_, shares.toUint128(), state.redeemPrice, MathLib.Rounding.Up);\n        uint128 assetsDown = _shareToAssetAmount(vault_, shares.toUint128(), state.redeemPrice, MathLib.Rounding.Down);\n        _processRedeem(state, assetsUp, assetsDown, vault_, receiver, controller);\n        assets = uint256(assetsDown);\n    }\n\n    /// @inheritdoc IRedeemManager\n    function withdraw(IBaseVault vault_, uint256 assets, address receiver, address controller)\n        public\n        auth\n        returns (uint256 shares)\n    {\n        AsyncInvestmentState storage state = investments[vault_][controller];\n        uint128 assets_ = assets.toUint128();\n        _processRedeem(state, assets_, assets_, vault_, receiver, controller);\n\n        shares = uint256(_assetToShareAmount(vault_, assets_, state.redeemPrice, MathLib.Rounding.Up));\n    }\n\n    function _processRedeem(\n        AsyncInvestmentState storage state,\n        uint128 assetsUp,\n        uint128 assetsDown,\n        IBaseVault vault_,\n        address receiver,\n        address controller\n    ) internal {\n        if (controller != receiver) {\n            require(\n                _canTransfer(vault_, controller, receiver, convertToShares(vault_, assetsDown)), TransferNotAllowed()\n            );\n        }\n\n        require(_canTransfer(vault_, receiver, address(0), convertToShares(vault_, assetsDown)), TransferNotAllowed());\n\n        require(assetsUp <= state.maxWithdraw, ExceedsRedeemLimits());\n        state.maxWithdraw = state.maxWithdraw > assetsUp ? state.maxWithdraw - assetsUp : 0;\n\n        if (assetsDown > 0) {\n            _withdraw(vault_, receiver, assetsDown);\n        }\n    }\n\n    /// @dev Transfer funds from escrow to receiver and update holdings\n    function _withdraw(IBaseVault vault_, address receiver, uint128 assets) internal {\n        VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n\n        PoolId poolId = vault_.poolId();\n        ShareClassId scId = vault_.scId();\n\n        poolEscrowProvider.escrow(poolId).reserveDecrease(scId, vaultDetails.asset, vaultDetails.tokenId, assets);\n        balanceSheet.withdraw(poolId, scId, vaultDetails.asset, vaultDetails.tokenId, receiver, assets);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Cancellation claim handlers\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IAsyncDepositManager\n    function claimCancelDepositRequest(IBaseVault vault_, address receiver, address controller)\n        public\n        auth\n        returns (uint256 assets)\n    {\n        AsyncInvestmentState storage state = investments[vault_][controller];\n        assets = state.claimableCancelDepositRequest;\n        state.claimableCancelDepositRequest = 0;\n        uint256 shares = convertToShares(vault_, assets);\n\n        if (controller != receiver) {\n            require(_canTransfer(vault_, controller, receiver, shares), TransferNotAllowed());\n        }\n        require(_canTransfer(vault_, receiver, address(0), shares), TransferNotAllowed());\n\n        if (assets > 0) {\n            VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n            globalEscrow.authTransferTo(vaultDetails.asset, vaultDetails.tokenId, receiver, assets);\n        }\n    }\n\n    /// @inheritdoc IAsyncRedeemManager\n    function claimCancelRedeemRequest(IBaseVault vault_, address receiver, address controller)\n        public\n        auth\n        returns (uint256 shares)\n    {\n        AsyncInvestmentState storage state = investments[vault_][controller];\n        shares = state.claimableCancelRedeemRequest;\n        state.claimableCancelRedeemRequest = 0;\n\n        if (shares > 0) {\n            globalEscrow.authTransferTo(vault_.share(), receiver, shares);\n        }\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // View methods\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IDepositManager\n    function maxDeposit(IBaseVault vault_, address user) public view returns (uint256 assets) {\n        if (!_canTransfer(vault_, ESCROW_HOOK_ID, user, 0)) {\n            return 0;\n        }\n        assets = uint256(_maxDeposit(vault_, user));\n    }\n\n    function _maxDeposit(IBaseVault vault_, address user) internal view returns (uint128 assets) {\n        AsyncInvestmentState memory state = investments[vault_][user];\n\n        assets = _shareToAssetAmount(vault_, state.maxMint, state.depositPrice, MathLib.Rounding.Down);\n    }\n\n    /// @inheritdoc IDepositManager\n    function maxMint(IBaseVault vault_, address user) public view returns (uint256 shares) {\n        if (!_canTransfer(vault_, ESCROW_HOOK_ID, user, 0)) {\n            return 0;\n        }\n        shares = uint256(investments[vault_][user].maxMint);\n    }\n\n    /// @inheritdoc IRedeemManager\n    function maxWithdraw(IBaseVault vault_, address user) public view returns (uint256 assets) {\n        if (!_canTransfer(vault_, user, address(0), 0)) return 0;\n        assets = uint256(investments[vault_][user].maxWithdraw);\n    }\n\n    /// @inheritdoc IRedeemManager\n    function maxRedeem(IBaseVault vault_, address user) public view returns (uint256 shares) {\n        if (!_canTransfer(vault_, user, address(0), 0)) return 0;\n        AsyncInvestmentState memory state = investments[vault_][user];\n\n        shares = uint256(_assetToShareAmount(vault_, state.maxWithdraw, state.redeemPrice, MathLib.Rounding.Down));\n    }\n\n    /// @inheritdoc IAsyncDepositManager\n    function pendingDepositRequest(IBaseVault vault_, address user) public view returns (uint256 assets) {\n        assets = uint256(investments[vault_][user].pendingDepositRequest);\n    }\n\n    /// @inheritdoc IAsyncRedeemManager\n    function pendingRedeemRequest(IBaseVault vault_, address user) public view returns (uint256 shares) {\n        shares = uint256(investments[vault_][user].pendingRedeemRequest);\n    }\n\n    /// @inheritdoc IAsyncDepositManager\n    function pendingCancelDepositRequest(IBaseVault vault_, address user) public view returns (bool isPending) {\n        isPending = investments[vault_][user].pendingCancelDepositRequest;\n    }\n\n    /// @inheritdoc IAsyncRedeemManager\n    function pendingCancelRedeemRequest(IBaseVault vault_, address user) public view returns (bool isPending) {\n        isPending = investments[vault_][user].pendingCancelRedeemRequest;\n    }\n\n    /// @inheritdoc IAsyncDepositManager\n    function claimableCancelDepositRequest(IBaseVault vault_, address user) public view returns (uint256 assets) {\n        assets = investments[vault_][user].claimableCancelDepositRequest;\n    }\n\n    /// @inheritdoc IAsyncRedeemManager\n    function claimableCancelRedeemRequest(IBaseVault vault_, address user) public view returns (uint256 shares) {\n        shares = investments[vault_][user].claimableCancelRedeemRequest;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Helpers\n    //----------------------------------------------------------------------------------------------\n\n    /// @dev    Checks transfer restrictions for the vault shares. Sender (from) and receiver (to) have to both pass\n    ///         the restrictions for a successful share transfer.\n    function _canTransfer(IBaseVault vault_, address from, address to, uint256 value) internal view returns (bool) {\n        IShareToken share = IShareToken(vault_.share());\n        return share.checkTransferRestriction(from, to, value);\n    }\n\n    function _assetToShareAmount(\n        IBaseVault vault_,\n        uint128 assets,\n        uint256 priceAssetPerShare,\n        MathLib.Rounding rounding\n    ) internal view returns (uint128 shares) {\n        VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n        address shareToken = vault_.share();\n\n        return PricingLib.assetToShareAmount(\n            shareToken, vaultDetails.asset, vaultDetails.tokenId, assets, d18(priceAssetPerShare.toUint128()), rounding\n        );\n    }\n\n    function _shareToAssetAmount(\n        IBaseVault vault_,\n        uint128 shares,\n        uint256 priceAssetPerShare,\n        MathLib.Rounding rounding\n    ) internal view returns (uint128 assets) {\n        VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n        address shareToken = vault_.share();\n\n        return PricingLib.shareToAssetAmount(\n            shareToken, shares, vaultDetails.asset, vaultDetails.tokenId, d18(priceAssetPerShare.toUint128()), rounding\n        );\n    }\n\n    function _calculatePriceAssetPerShare(IBaseVault vault_, uint128 shares, uint128 assets, MathLib.Rounding rounding)\n        internal\n        view\n        returns (uint256 price)\n    {\n        VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n        address shareToken = vault_.share();\n\n        return PricingLib.calculatePriceAssetPerShare(\n            shareToken, shares, vaultDetails.asset, vaultDetails.tokenId, assets, rounding\n        );\n    }\n}\n"
    },
    "src/vaults/AsyncVault.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport \"src/misc/interfaces/IERC7540.sol\";\nimport \"src/misc/interfaces/IERC7575.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\nimport {IERC20} from \"src/misc/interfaces/IERC20.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IAsyncRedeemVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {BaseVault, BaseAsyncRedeemVault} from \"src/vaults/BaseVaults.sol\";\nimport {IAsyncVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IAsyncRequestManager} from \"src/vaults/interfaces/investments/IAsyncRequestManager.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\n/// @title  AsyncVault\n/// @notice Asynchronous Tokenized Vault standard implementation for Centrifuge pools\n///\n/// @dev    Each vault issues shares of Centrifuge share class tokens as restricted ERC-20 tokens\n///         against asset deposits based on the current share price.\n///\n///         ERC-7540 is an extension of the ERC-4626 standard by 'requestDeposit' & 'requestRedeem' methods, where\n///         deposit and redeem orders are submitted to the pools to be included in the execution of the following epoch.\n///         After execution users can use the deposit, mint, redeem and withdraw functions to get their shares\n///         and/or assets from the pools.\ncontract AsyncVault is BaseAsyncRedeemVault, IAsyncVault {\n    constructor(\n        PoolId poolId_,\n        ShareClassId scId_,\n        address asset_,\n        IShareToken token_,\n        address root_,\n        IAsyncRequestManager manager_\n    ) BaseVault(poolId_, scId_, asset_, token_, root_, manager_) BaseAsyncRedeemVault(manager_) {}\n\n    //----------------------------------------------------------------------------------------------\n    // ERC-7540 deposit\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IERC7540Deposit\n    function requestDeposit(uint256 assets, address controller, address owner) public returns (uint256) {\n        require(owner == msg.sender || isOperator[owner][msg.sender], InvalidOwner());\n        require(IERC20(asset).balanceOf(owner) >= assets, InsufficientBalance());\n\n        require(asyncManager().requestDeposit(this, assets, controller, owner, msg.sender), RequestDepositFailed());\n        SafeTransferLib.safeTransferFrom(asset, owner, address(manager.globalEscrow()), assets);\n\n        emit DepositRequest(controller, owner, REQUEST_ID, msg.sender, assets);\n        return REQUEST_ID;\n    }\n\n    /// @inheritdoc IERC7540Deposit\n    function pendingDepositRequest(uint256, address controller) public view returns (uint256 pendingAssets) {\n        pendingAssets = asyncManager().pendingDepositRequest(this, controller);\n    }\n\n    /// @inheritdoc IERC7540Deposit\n    function claimableDepositRequest(uint256, address controller) external view returns (uint256 claimableAssets) {\n        claimableAssets = maxDeposit(controller);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // ERC-7887\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IERC7887Deposit\n    function cancelDepositRequest(uint256, address controller) external {\n        _validateController(controller);\n        asyncManager().cancelDepositRequest(this, controller, msg.sender);\n        emit CancelDepositRequest(controller, REQUEST_ID, msg.sender);\n    }\n\n    /// @inheritdoc IERC7887Deposit\n    function pendingCancelDepositRequest(uint256, address controller) public view returns (bool isPending) {\n        isPending = asyncManager().pendingCancelDepositRequest(this, controller);\n    }\n\n    /// @inheritdoc IERC7887Deposit\n    function claimableCancelDepositRequest(uint256, address controller) public view returns (uint256 claimableAssets) {\n        claimableAssets = asyncManager().claimableCancelDepositRequest(this, controller);\n    }\n\n    /// @inheritdoc IERC7887Deposit\n    function claimCancelDepositRequest(uint256, address receiver, address controller)\n        external\n        returns (uint256 assets)\n    {\n        _validateController(controller);\n        assets = asyncManager().claimCancelDepositRequest(this, receiver, controller);\n        emit CancelDepositClaim(controller, receiver, REQUEST_ID, msg.sender, assets);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // ERC-165\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IERC165\n    function supportsInterface(bytes4 interfaceId) public pure override(BaseAsyncRedeemVault, IERC165) returns (bool) {\n        return interfaceId == type(IERC7540Deposit).interfaceId || interfaceId == type(IERC7887Deposit).interfaceId\n            || super.supportsInterface(interfaceId);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // ERC-7540 claim\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IERC7575\n    function maxDeposit(address controller) public view returns (uint256 maxAssets) {\n        maxAssets = asyncManager().maxDeposit(this, controller);\n    }\n\n    /// @inheritdoc IERC7540Deposit\n    function deposit(uint256 assets, address receiver, address controller) public returns (uint256 shares) {\n        _validateController(controller);\n        shares = asyncManager().deposit(this, assets, receiver, controller);\n        emit Deposit(controller, receiver, assets, shares);\n    }\n\n    /// @inheritdoc IERC7575\n    /// @notice     When claiming deposit requests using deposit(), there can be some precision loss leading to dust.\n    ///             It is recommended to use mint() to claim deposit requests instead.\n    function deposit(uint256 assets, address receiver) external returns (uint256 shares) {\n        shares = deposit(assets, receiver, msg.sender);\n    }\n\n    /// @inheritdoc IERC7575\n    function maxMint(address controller) public view returns (uint256 maxShares) {\n        maxShares = asyncManager().maxMint(this, controller);\n    }\n\n    /// @inheritdoc IERC7540Deposit\n    function mint(uint256 shares, address receiver, address controller) public returns (uint256 assets) {\n        _validateController(controller);\n        assets = asyncManager().mint(this, shares, receiver, controller);\n        emit Deposit(controller, receiver, assets, shares);\n    }\n\n    /// @inheritdoc IERC7575\n    function mint(uint256 shares, address receiver) public returns (uint256 assets) {\n        assets = mint(shares, receiver, msg.sender);\n    }\n\n    /// @dev Strongly-typed accessor to the generic async redeem manager\n    function asyncManager() public view returns (IAsyncRequestManager) {\n        return IAsyncRequestManager(address(IAsyncRedeemVault(this).asyncRedeemManager()));\n    }\n\n    /// @dev Preview functions for ERC-7540 vaults revert\n    function previewDeposit(uint256) external pure returns (uint256) {\n        revert();\n    }\n\n    /// @dev Preview functions for ERC-7540 vaults revert\n    function previewMint(uint256) external pure returns (uint256) {\n        revert();\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Event emitters\n    //----------------------------------------------------------------------------------------------\n\n    function onDepositClaimable(address controller, uint256 assets, uint256 shares) public virtual auth {\n        emit DepositClaimable(controller, REQUEST_ID, assets, shares);\n    }\n\n    function onCancelDepositClaimable(address controller, uint256 assets) public virtual auth {\n        emit CancelDepositClaimable(controller, REQUEST_ID, assets);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // IBaseVault view\n    //----------------------------------------------------------------------------------------------\n\n    function vaultKind() public pure returns (VaultKind vaultKind_) {\n        return VaultKind.Async;\n    }\n}\n"
    },
    "src/vaults/BalanceSheet.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\nimport {IERC6909} from \"src/misc/interfaces/IERC6909.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\nimport {TransientStorageLib} from \"src/misc/libraries/TransientStorageLib.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {MessageLib, UpdateContractType} from \"src/common/libraries/MessageLib.sol\";\nimport {IVaultMessageSender} from \"../common/interfaces/IGatewaySenders.sol\";\nimport {IBalanceSheetGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\n\nimport {IPoolManager} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IBalanceSheet, QueueAmount} from \"src/vaults/interfaces/IBalanceSheet.sol\";\nimport {IPoolEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {IUpdateContract} from \"src/vaults/interfaces/IUpdateContract.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\n\n/// @title  Balance Sheet\n/// @notice Management contract that integrates all balance sheet functions of a pool:\n///         - Issuing and revoking shares\n///         - Depositing and withdrawing assets\n///         - Force transferring shares\n///\n///         Share and asset updates to the Hub are optionally queued, to reduce the cost\n///         per transaction. Dequeuing can be triggered locally by the manager or from the Hub.\ncontract BalanceSheet is Auth, Recoverable, IBalanceSheet, IBalanceSheetGatewayHandler, IUpdateContract {\n    using MathLib for *;\n    using CastLib for bytes32;\n\n    IRoot public immutable root;\n\n    IPoolManager public poolManager;\n    IVaultMessageSender public sender;\n    IPoolEscrowProvider public poolEscrowProvider;\n\n    mapping(PoolId => mapping(address => bool)) public manager;\n    mapping(PoolId poolId => mapping(ShareClassId scId => bool)) public queueEnabled;\n    mapping(PoolId poolId => mapping(ShareClassId scId => QueueAmount)) public queuedShares;\n    mapping(PoolId poolId => mapping(ShareClassId scId => mapping(AssetId assetId => QueueAmount))) public queuedAssets;\n\n    constructor(IRoot root_, address deployer) Auth(deployer) {\n        root = root_;\n    }\n\n    /// @dev Check if the msg.sender is ward or a manager\n    modifier authOrManager(PoolId poolId) {\n        require(wards[msg.sender] == 1 || manager[poolId][msg.sender], IAuth.NotAuthorized());\n        _;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Administration\n    //----------------------------------------------------------------------------------------------\n\n    function file(bytes32 what, address data) external auth {\n        if (what == \"poolManager\") poolManager = IPoolManager(data);\n        else if (what == \"sender\") sender = IVaultMessageSender(data);\n        else if (what == \"poolEscrowProvider\") poolEscrowProvider = IPoolEscrowProvider(data);\n        else revert FileUnrecognizedParam();\n        emit File(what, data);\n    }\n\n    function update(PoolId poolId, ShareClassId, /* scId */ bytes calldata payload) external auth {\n        uint8 kind = uint8(MessageLib.updateContractType(payload));\n\n        if (kind == uint8(UpdateContractType.UpdateManager)) {\n            MessageLib.UpdateContractUpdateManager memory m = MessageLib.deserializeUpdateContractUpdateManager(payload);\n            address who = m.who.toAddress();\n\n            manager[poolId][who] = m.canManage;\n            emit UpdateManager(poolId, who, m.canManage);\n        } else {\n            revert UnknownUpdateContractType();\n        }\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Management functions\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IBalanceSheet\n    function deposit(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, address owner, uint128 amount)\n        external\n        authOrManager(poolId)\n    {\n        AssetId assetId = poolManager.assetToId(asset, tokenId);\n        _noteDeposit(poolId, scId, assetId, asset, tokenId, owner, amount);\n        _executeDeposit(poolId, asset, tokenId, owner, amount);\n    }\n\n    /// @inheritdoc IBalanceSheet\n    /// @dev This function is mostly useful to keep higher level integrations CEI adherent.\n    function noteDeposit(\n        PoolId poolId,\n        ShareClassId scId,\n        address asset,\n        uint256 tokenId,\n        address owner,\n        uint128 amount\n    ) external authOrManager(poolId) {\n        AssetId assetId = poolManager.assetToId(asset, tokenId);\n        _noteDeposit(poolId, scId, assetId, asset, tokenId, owner, amount);\n    }\n\n    /// @inheritdoc IBalanceSheet\n    function withdraw(\n        PoolId poolId,\n        ShareClassId scId,\n        address asset,\n        uint256 tokenId,\n        address receiver,\n        uint128 amount\n    ) external authOrManager(poolId) {\n        AssetId assetId = poolManager.assetToId(asset, tokenId);\n        _withdraw(poolId, scId, assetId, asset, tokenId, receiver, amount);\n    }\n\n    /// @inheritdoc IBalanceSheet\n    function issue(PoolId poolId, ShareClassId scId, address to, uint128 shares) external authOrManager(poolId) {\n        _issue(poolId, scId, to, shares);\n    }\n\n    /// @inheritdoc IBalanceSheet\n    function revoke(PoolId poolId, ShareClassId scId, address from, uint128 shares) external authOrManager(poolId) {\n        _noteRevoke(poolId, scId, from, shares);\n        _executeRevoke(poolId, scId, from, shares);\n    }\n\n    /// @inheritdoc IBalanceSheet\n    /// @dev This function is mostly useful to keep higher level integrations CEI adherent.\n    function noteRevoke(PoolId poolId, ShareClassId scId, address from, uint128 shares)\n        external\n        authOrManager(poolId)\n    {\n        _noteRevoke(poolId, scId, from, shares);\n    }\n\n    /// @inheritdoc IBalanceSheet\n    function transferSharesFrom(PoolId poolId, ShareClassId scId, address from, address to, uint256 amount)\n        external\n        authOrManager(poolId)\n    {\n        require(!root.endorsed(from), CannotTransferFromEndorsedContract());\n        IShareToken token = IShareToken(poolManager.shareToken(poolId, scId));\n        token.authTransferFrom(from, from, to, amount);\n    }\n\n    /// @inheritdoc IBalanceSheet\n    function overridePricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, D18 value)\n        external\n        authOrManager(poolId)\n    {\n        TransientStorageLib.tstore(keccak256(abi.encode(\"pricePoolPerAsset\", poolId, scId, assetId)), value.raw());\n        TransientStorageLib.tstore(keccak256(abi.encode(\"pricePoolPerAssetIsSet\", poolId, scId, assetId)), true);\n    }\n\n    /// @inheritdoc IBalanceSheet\n    function overridePricePoolPerShare(PoolId poolId, ShareClassId scId, D18 value) external authOrManager(poolId) {\n        TransientStorageLib.tstore(keccak256(abi.encode(\"pricePoolPerShare\", poolId, scId)), value.raw());\n        TransientStorageLib.tstore(keccak256(abi.encode(\"pricePoolPerShareIsSet\", poolId, scId)), true);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Gateway handlers\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IBalanceSheetGatewayHandler\n    function triggerDeposit(PoolId poolId, ShareClassId scId, AssetId assetId, address owner, uint128 amount)\n        external\n        auth\n    {\n        (address asset, uint256 tokenId) = poolManager.idToAsset(assetId);\n        _noteDeposit(poolId, scId, assetId, asset, tokenId, owner, amount);\n        _executeDeposit(poolId, asset, tokenId, owner, amount);\n    }\n\n    /// @inheritdoc IBalanceSheetGatewayHandler\n    function triggerWithdraw(PoolId poolId, ShareClassId scId, AssetId assetId, address receiver, uint128 amount)\n        external\n        auth\n    {\n        (address asset, uint256 tokenId) = poolManager.idToAsset(assetId);\n        _withdraw(poolId, scId, assetId, asset, tokenId, receiver, amount);\n    }\n\n    /// @inheritdoc IBalanceSheetGatewayHandler\n    function triggerIssueShares(PoolId poolId, ShareClassId scId, address receiver, uint128 shares) external auth {\n        _issue(poolId, scId, receiver, shares);\n    }\n\n    /// @inheritdoc IBalanceSheetGatewayHandler\n    function setQueue(PoolId poolId, ShareClassId scId, bool enabled) external auth {\n        queueEnabled[poolId][scId] = enabled;\n    }\n\n    /// @inheritdoc IBalanceSheetGatewayHandler\n    function submitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) external authOrManager(poolId) {\n        _submitQueuedAssets(poolId, scId, assetId);\n    }\n\n    /// @inheritdoc IBalanceSheetGatewayHandler\n    function submitQueuedShares(PoolId poolId, ShareClassId scId) external authOrManager(poolId) {\n        _submitQueuedShares(poolId, scId);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Internal\n    //----------------------------------------------------------------------------------------------\n\n    function _noteDeposit(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        address asset,\n        uint256 tokenId,\n        address owner,\n        uint128 amount\n    ) internal {\n        IPoolEscrow escrow = poolEscrowProvider.escrow(poolId);\n        escrow.deposit(scId, asset, tokenId, amount);\n\n        D18 pricePoolPerAsset_ = _pricePoolPerAsset(poolId, scId, assetId);\n        emit Deposit(poolId, scId, asset, tokenId, owner, amount, pricePoolPerAsset_);\n\n        if (queueEnabled[poolId][scId]) {\n            queuedAssets[poolId][scId][assetId].increase += amount;\n        } else {\n            sender.sendUpdateHoldingAmount(poolId, scId, assetId, owner, amount, pricePoolPerAsset_, true);\n        }\n    }\n\n    function _executeDeposit(PoolId poolId, address asset, uint256 tokenId, address owner, uint128 amount) internal {\n        IPoolEscrow escrow = poolEscrowProvider.escrow(poolId);\n        if (tokenId == 0) {\n            SafeTransferLib.safeTransferFrom(asset, owner, address(escrow), amount);\n        } else {\n            IERC6909(asset).transferFrom(owner, address(escrow), tokenId, amount);\n        }\n    }\n\n    function _withdraw(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        address asset,\n        uint256 tokenId,\n        address receiver,\n        uint128 amount\n    ) internal {\n        IPoolEscrow escrow = poolEscrowProvider.escrow(poolId);\n        escrow.withdraw(scId, asset, tokenId, amount);\n\n        D18 pricePoolPerAsset_ = _pricePoolPerAsset(poolId, scId, assetId);\n        emit Withdraw(poolId, scId, asset, tokenId, receiver, amount, pricePoolPerAsset_);\n\n        if (queueEnabled[poolId][scId]) {\n            queuedAssets[poolId][scId][assetId].decrease += amount;\n        } else {\n            sender.sendUpdateHoldingAmount(poolId, scId, assetId, receiver, amount, pricePoolPerAsset_, false);\n        }\n\n        escrow.authTransferTo(asset, tokenId, receiver, amount);\n    }\n\n    function _issue(PoolId poolId, ShareClassId scId, address to, uint128 shares) internal {\n        emit Issue(poolId, scId, to, _pricePoolPerShare(poolId, scId), shares);\n\n        if (queueEnabled[poolId][scId]) {\n            queuedShares[poolId][scId].increase += shares;\n        } else {\n            sender.sendUpdateShares(poolId, scId, shares, true);\n        }\n\n        IShareToken token = poolManager.shareToken(poolId, scId);\n        token.mint(to, shares);\n    }\n\n    function _noteRevoke(PoolId poolId, ShareClassId scId, address from, uint128 shares) internal {\n        emit Revoke(poolId, scId, from, _pricePoolPerShare(poolId, scId), shares);\n\n        if (queueEnabled[poolId][scId]) {\n            queuedShares[poolId][scId].decrease += shares;\n        } else {\n            sender.sendUpdateShares(poolId, scId, shares, false);\n        }\n    }\n\n    function _executeRevoke(PoolId poolId, ShareClassId scId, address from, uint128 shares) internal {\n        IShareToken token = poolManager.shareToken(poolId, scId);\n        token.authTransferFrom(from, from, address(this), shares);\n        token.burn(address(this), shares);\n    }\n\n    function _submitQueuedShares(PoolId poolId, ShareClassId scId) internal {\n        QueueAmount storage queue = queuedShares[poolId][scId];\n\n        if (queue.increase > queue.decrease) {\n            sender.sendUpdateShares(poolId, scId, queue.increase - queue.decrease, true);\n        } else if (queue.decrease > queue.increase) {\n            sender.sendUpdateShares(poolId, scId, queue.decrease - queue.increase, false);\n        }\n\n        queue.increase = 0;\n        queue.decrease = 0;\n    }\n\n    function _submitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) internal {\n        QueueAmount storage queue = queuedAssets[poolId][scId][assetId];\n\n        D18 pricePoolPerAsset = _pricePoolPerAsset(poolId, scId, assetId);\n        if (queue.increase > queue.decrease) {\n            sender.sendUpdateHoldingAmount(\n                poolId, scId, assetId, address(0), queue.increase - queue.decrease, pricePoolPerAsset, true\n            );\n        } else if (queue.decrease > queue.increase) {\n            sender.sendUpdateHoldingAmount(\n                poolId, scId, assetId, address(0), queue.decrease - queue.increase, pricePoolPerAsset, false\n            );\n        }\n\n        queue.increase = 0;\n        queue.decrease = 0;\n    }\n\n    function _pricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId) internal view returns (D18) {\n        if (TransientStorageLib.tloadBool(keccak256(abi.encode(\"pricePoolPerAssetIsSet\", poolId, scId, assetId)))) {\n            return\n                d18(TransientStorageLib.tloadUint128(keccak256(abi.encode(\"pricePoolPerAsset\", poolId, scId, assetId))));\n        }\n\n        D18 pricePoolPerAsset = poolManager.pricePoolPerAsset(poolId, scId, assetId, true);\n        return pricePoolPerAsset;\n    }\n\n    function _pricePoolPerShare(PoolId poolId, ShareClassId scId) internal view returns (D18) {\n        if (TransientStorageLib.tloadBool(keccak256(abi.encode(\"pricePoolPerShareIsSet\", poolId, scId)))) {\n            return d18(TransientStorageLib.tloadUint128(keccak256(abi.encode(\"pricePoolPerShare\", poolId, scId))));\n        }\n\n        D18 pricePoolPerShare = poolManager.pricePoolPerShare(poolId, scId, true);\n        return pricePoolPerShare;\n    }\n}\n"
    },
    "src/vaults/BaseRequestManager.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {D18} from \"src/misc/types/D18.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\n\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IPoolManager, VaultDetails} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IBaseVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IPoolEscrow, IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\nabstract contract BaseRequestManager is Auth, Recoverable, IBaseRequestManager {\n    using MathLib for uint256;\n\n    address public immutable root;\n    IEscrow public immutable globalEscrow;\n\n    IPoolManager public poolManager;\n    IPoolEscrowProvider public poolEscrowProvider;\n\n    mapping(PoolId poolId => mapping(ShareClassId scId => mapping(AssetId assetId => IBaseVault vault))) public vault;\n\n    constructor(IEscrow globalEscrow_, address root_, address deployer) Auth(deployer) {\n        globalEscrow = globalEscrow_;\n        root = root_;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Administration\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IBaseRequestManager\n    function file(bytes32 what, address data) external virtual auth {\n        if (what == \"poolManager\") poolManager = IPoolManager(data);\n        else if (what == \"poolEscrowProvider\") poolEscrowProvider = IPoolEscrowProvider(data);\n        else revert FileUnrecognizedParam();\n        emit File(what, data);\n    }\n\n    /// @inheritdoc IBaseRequestManager\n    function addVault(PoolId poolId, ShareClassId scId, IBaseVault vault_, address asset_, AssetId assetId)\n        public\n        virtual\n        auth\n    {\n        address token = vault_.share();\n\n        require(vault_.asset() == asset_, AssetMismatch());\n        require(address(vault[poolId][scId][assetId]) == address(0), VaultAlreadyExists());\n\n        vault[poolId][scId][assetId] = IBaseVault(address(vault_));\n        IAuth(token).rely(address(vault_));\n        IShareToken(token).updateVault(vault_.asset(), address(vault_));\n        rely(address(vault_));\n    }\n\n    /// @inheritdoc IBaseRequestManager\n    function removeVault(PoolId poolId, ShareClassId scId, IBaseVault vault_, address asset_, AssetId assetId)\n        public\n        virtual\n        auth\n    {\n        address token = vault_.share();\n\n        require(vault_.asset() == asset_, AssetMismatch());\n        require(address(vault[poolId][scId][assetId]) != address(0), VaultDoesNotExist());\n\n        delete vault[poolId][scId][assetId];\n\n        IAuth(token).deny(address(vault_));\n        IShareToken(token).updateVault(vault_.asset(), address(0));\n        deny(address(vault_));\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // View methods\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IBaseRequestManager\n    function convertToShares(IBaseVault vault_, uint256 assets) public view virtual returns (uint256 shares) {\n        VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n        (D18 pricePoolPerAsset, D18 pricePoolPerShare) =\n            poolManager.pricesPoolPer(vault_.poolId(), vault_.scId(), vaultDetails.assetId, false);\n\n        return _assetToShareAmount(\n            vault_, vaultDetails, assets, pricePoolPerAsset, pricePoolPerShare, MathLib.Rounding.Down\n        );\n    }\n\n    /// @inheritdoc IBaseRequestManager\n    function convertToAssets(IBaseVault vault_, uint256 shares) public view virtual returns (uint256 assets) {\n        VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n        (D18 pricePoolPerAsset, D18 pricePoolPerShare) =\n            poolManager.pricesPoolPer(vault_.poolId(), vault_.scId(), vaultDetails.assetId, false);\n\n        return _shareToAssetAmount(\n            vault_, vaultDetails, shares, pricePoolPerAsset, pricePoolPerShare, MathLib.Rounding.Down\n        );\n    }\n\n    /// @inheritdoc IBaseRequestManager\n    function priceLastUpdated(IBaseVault vault_) public view virtual returns (uint64 lastUpdated) {\n        VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n\n        (uint64 shareLastUpdated,,) = poolManager.markersPricePoolPerShare(vault_.poolId(), vault_.scId());\n        (uint64 assetLastUpdated,,) =\n            poolManager.markersPricePoolPerAsset(vault_.poolId(), vault_.scId(), vaultDetails.assetId);\n\n        // Choose the latest update to be the marker\n        lastUpdated = MathLib.max(shareLastUpdated, assetLastUpdated).toUint64();\n    }\n\n    /// @inheritdoc IBaseRequestManager\n    function poolEscrow(PoolId poolId) public view returns (IPoolEscrow) {\n        return poolEscrowProvider.escrow(poolId);\n    }\n\n    /// @inheritdoc IBaseRequestManager\n    function vaultByAssetId(PoolId poolId, ShareClassId scId, AssetId assetId) public view returns (IBaseVault) {\n        return vault[poolId][scId][assetId];\n    }\n\n    function _assetToShareAmount(\n        IBaseVault vault_,\n        VaultDetails memory vaultDetails,\n        uint256 assets,\n        D18 pricePoolPerAsset,\n        D18 pricePoolPerShare,\n        MathLib.Rounding rounding\n    ) internal view returns (uint256 shares) {\n        return PricingLib.assetToShareAmount(\n            vault_.share(),\n            vaultDetails.asset,\n            vaultDetails.tokenId,\n            assets.toUint128(),\n            pricePoolPerAsset,\n            pricePoolPerShare,\n            rounding\n        );\n    }\n\n    function _shareToAssetAmount(\n        IBaseVault vault_,\n        VaultDetails memory vaultDetails,\n        uint256 shares,\n        D18 pricePoolPerAsset,\n        D18 pricePoolPerShare,\n        MathLib.Rounding rounding\n    ) internal view returns (uint256 assets) {\n        return PricingLib.shareToAssetAmount(\n            vault_.share(),\n            shares.toUint128(),\n            vaultDetails.asset,\n            vaultDetails.tokenId,\n            pricePoolPerAsset,\n            pricePoolPerShare,\n            rounding\n        );\n    }\n}\n"
    },
    "src/vaults/BaseVaults.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport \"src/misc/interfaces/IERC7540.sol\";\nimport \"src/misc/interfaces/IERC7575.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {IERC20Metadata} from \"src/misc/interfaces/IERC20.sol\";\nimport {EIP712Lib} from \"src/misc/libraries/EIP712Lib.sol\";\nimport {SignatureLib} from \"src/misc/libraries/SignatureLib.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IBaseVault, IAsyncRedeemVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IERC7575} from \"src/misc/interfaces/IERC7575.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\nimport {ISyncDepositManager} from \"src/vaults/interfaces/investments/ISyncDepositManager.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\nabstract contract BaseVault is Auth, Recoverable, IBaseVault {\n    /// @dev Requests for Centrifuge pool are non-fungible and all have ID = 0\n    uint256 internal constant REQUEST_ID = 0;\n\n    IRoot public immutable root;\n    /// @dev this naming MUST NEVER change - due to legacy v2 vaults\n    IBaseRequestManager public manager;\n\n    /// @inheritdoc IBaseVault\n    PoolId public immutable poolId;\n    /// @inheritdoc IBaseVault\n    ShareClassId public immutable scId;\n\n    /// @inheritdoc IERC7575\n    address public immutable asset;\n\n    /// @inheritdoc IERC7575\n    address public immutable share;\n    uint8 internal immutable _shareDecimals;\n\n    /// --- ERC7741 ---\n    bytes32 private immutable nameHash;\n    bytes32 private immutable versionHash;\n    uint256 public immutable deploymentChainId;\n    bytes32 private immutable _DOMAIN_SEPARATOR;\n    bytes32 public constant AUTHORIZE_OPERATOR_TYPEHASH =\n        keccak256(\"AuthorizeOperator(address controller,address operator,bool approved,bytes32 nonce,uint256 deadline)\");\n\n    /// @inheritdoc IERC7741\n    mapping(address controller => mapping(bytes32 nonce => bool used)) public authorizations;\n\n    /// @inheritdoc IERC7540Operator\n    mapping(address => mapping(address => bool)) public isOperator;\n\n    constructor(\n        PoolId poolId_,\n        ShareClassId scId_,\n        address asset_,\n        IShareToken token_,\n        address root_,\n        IBaseRequestManager manager_\n    ) Auth(msg.sender) {\n        poolId = poolId_;\n        scId = scId_;\n        asset = asset_;\n        share = address(token_);\n        _shareDecimals = IERC20Metadata(share).decimals();\n        root = IRoot(root_);\n        manager = IBaseRequestManager(manager_);\n\n        nameHash = keccak256(bytes(\"Centrifuge\"));\n        versionHash = keccak256(bytes(\"1\"));\n        deploymentChainId = block.chainid;\n        _DOMAIN_SEPARATOR = EIP712Lib.calculateDomainSeparator(nameHash, versionHash);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Administration\n    //----------------------------------------------------------------------------------------------\n\n    function file(bytes32 what, address data) external virtual auth {\n        if (what == \"manager\") manager = IBaseRequestManager(data);\n        else revert FileUnrecognizedParam();\n        emit File(what, data);\n    }\n\n    /// @inheritdoc IERC7540Operator\n    function setOperator(address operator, bool approved) public virtual returns (bool success) {\n        require(msg.sender != operator, CannotSetSelfAsOperator());\n        isOperator[msg.sender][operator] = approved;\n        emit OperatorSet(msg.sender, operator, approved);\n        success = true;\n    }\n\n    /// @inheritdoc IBaseVault\n    function setEndorsedOperator(address owner, bool approved) public virtual {\n        require(msg.sender != owner, CannotSetSelfAsOperator());\n        require(root.endorsed(msg.sender), NotEndorsed());\n        isOperator[owner][msg.sender] = approved;\n        emit OperatorSet(owner, msg.sender, approved);\n    }\n\n    /// @inheritdoc IERC7741\n    function DOMAIN_SEPARATOR() public view returns (bytes32) {\n        return block.chainid == deploymentChainId\n            ? _DOMAIN_SEPARATOR\n            : EIP712Lib.calculateDomainSeparator(nameHash, versionHash);\n    }\n\n    /// @inheritdoc IERC7741\n    function authorizeOperator(\n        address controller,\n        address operator,\n        bool approved,\n        bytes32 nonce,\n        uint256 deadline,\n        bytes memory signature\n    ) external returns (bool success) {\n        require(controller != operator, CannotSetSelfAsOperator());\n        require(block.timestamp <= deadline, ExpiredAuthorization());\n        require(!authorizations[controller][nonce], AlreadyUsedAuthorization());\n\n        authorizations[controller][nonce] = true;\n\n        bytes32 digest = keccak256(\n            abi.encodePacked(\n                \"\\x19\\x01\",\n                DOMAIN_SEPARATOR(),\n                keccak256(abi.encode(AUTHORIZE_OPERATOR_TYPEHASH, controller, operator, approved, nonce, deadline))\n            )\n        );\n\n        require(SignatureLib.isValidSignature(controller, digest, signature), InvalidAuthorization());\n\n        isOperator[controller][operator] = approved;\n        emit OperatorSet(controller, operator, approved);\n\n        success = true;\n    }\n\n    /// @inheritdoc IERC7741\n    function invalidateNonce(bytes32 nonce) external {\n        authorizations[msg.sender][nonce] = true;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // ERC-165\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IERC165\n    function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {\n        return interfaceId == type(IERC7540Operator).interfaceId || interfaceId == type(IERC7741).interfaceId\n            || interfaceId == type(IERC7714).interfaceId || interfaceId == type(IERC7575).interfaceId\n            || interfaceId == type(IERC165).interfaceId;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // ERC-4626\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IERC7575\n    function totalAssets() external view returns (uint256) {\n        return convertToAssets(IERC20Metadata(share).totalSupply());\n    }\n\n    /// @inheritdoc IERC7575\n    /// @notice     The calculation is based on the token price from the most recent epoch retrieved from Centrifuge.\n    ///             The actual conversion MAY change between order submission and execution.\n    function convertToShares(uint256 assets) public view returns (uint256 shares) {\n        shares = manager.convertToShares(this, assets);\n    }\n\n    /// @inheritdoc IERC7575\n    /// @notice     The calculation is based on the token price from the most recent epoch retrieved from Centrifuge.\n    ///             The actual conversion MAY change between order submission and execution.\n    function convertToAssets(uint256 shares) public view returns (uint256 assets) {\n        assets = manager.convertToAssets(this, shares);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Helpers\n    //----------------------------------------------------------------------------------------------\n\n    /// @notice Price of 1 unit of share, quoted in the decimals of the asset.\n    function pricePerShare() external view returns (uint256) {\n        return convertToAssets(10 ** _shareDecimals);\n    }\n\n    /// @notice Returns timestamp of the last share price update.\n    function priceLastUpdated() external view returns (uint64) {\n        return manager.priceLastUpdated(this);\n    }\n\n    /// @inheritdoc IERC7714\n    function isPermissioned(address controller) external view returns (bool) {\n        return IShareToken(share).checkTransferRestriction(address(0), controller, 0);\n    }\n\n    /// @notice Ensures msg.sender can operate on behalf of controller.\n    function _validateController(address controller) internal view {\n        require(controller == msg.sender || isOperator[controller][msg.sender], InvalidController());\n    }\n}\n\nabstract contract BaseAsyncRedeemVault is BaseVault, IAsyncRedeemVault {\n    IAsyncRedeemManager public asyncRedeemManager;\n\n    constructor(IAsyncRedeemManager asyncRequestManager_) {\n        asyncRedeemManager = asyncRequestManager_;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Administration\n    //----------------------------------------------------------------------------------------------\n\n    function file(bytes32 what, address data) external virtual override auth {\n        if (what == \"manager\") manager = IBaseRequestManager(data);\n        else if (what == \"asyncRedeemManager\") asyncRedeemManager = IAsyncRedeemManager(data);\n        else revert FileUnrecognizedParam();\n        emit File(what, data);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // ERC-7540 redeem\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IERC7540Redeem\n    function requestRedeem(uint256 shares, address controller, address owner) public returns (uint256) {\n        require(IShareToken(share).balanceOf(owner) >= shares, InsufficientBalance());\n\n        // If msg.sender is operator of owner, the transfer is executed as if\n        // the sender is the owner, to bypass the allowance check\n        address sender = isOperator[owner][msg.sender] ? owner : msg.sender;\n\n        require(asyncRedeemManager.requestRedeem(this, shares, controller, owner, sender), RequestRedeemFailed());\n        IShareToken(share).authTransferFrom(sender, owner, address(manager.globalEscrow()), shares);\n\n        emit RedeemRequest(controller, owner, REQUEST_ID, msg.sender, shares);\n        return REQUEST_ID;\n    }\n\n    /// @inheritdoc IERC7540Redeem\n    function pendingRedeemRequest(uint256, address controller) public view returns (uint256 pendingShares) {\n        pendingShares = asyncRedeemManager.pendingRedeemRequest(this, controller);\n    }\n\n    /// @inheritdoc IERC7540Redeem\n    function claimableRedeemRequest(uint256, address controller) external view returns (uint256 claimableShares) {\n        claimableShares = maxRedeem(controller);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // ERC-7887\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IERC7887Redeem\n    function cancelRedeemRequest(uint256, address controller) external {\n        _validateController(controller);\n        asyncRedeemManager.cancelRedeemRequest(this, controller, msg.sender);\n        emit CancelRedeemRequest(controller, REQUEST_ID, msg.sender);\n    }\n\n    /// @inheritdoc IERC7887Redeem\n    function pendingCancelRedeemRequest(uint256, address controller) public view returns (bool isPending) {\n        isPending = asyncRedeemManager.pendingCancelRedeemRequest(this, controller);\n    }\n\n    /// @inheritdoc IERC7887Redeem\n    function claimableCancelRedeemRequest(uint256, address controller) public view returns (uint256 claimableShares) {\n        claimableShares = asyncRedeemManager.claimableCancelRedeemRequest(this, controller);\n    }\n\n    /// @inheritdoc IERC7887Redeem\n    function claimCancelRedeemRequest(uint256, address receiver, address controller)\n        external\n        returns (uint256 shares)\n    {\n        _validateController(controller);\n        shares = asyncRedeemManager.claimCancelRedeemRequest(this, receiver, controller);\n        emit CancelRedeemClaim(receiver, controller, REQUEST_ID, msg.sender, shares);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // ERC-7540 claim\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IERC7575\n    /// @notice     DOES NOT support controller != msg.sender since shares are already transferred on requestRedeem\n    function withdraw(uint256 assets, address receiver, address controller) public returns (uint256 shares) {\n        _validateController(controller);\n        shares = asyncRedeemManager.withdraw(this, assets, receiver, controller);\n        emit Withdraw(msg.sender, receiver, controller, assets, shares);\n    }\n\n    /// @inheritdoc IERC7575\n    /// @notice     DOES NOT support controller != msg.sender since shares are already transferred on requestRedeem.\n    ///             When claiming redemption requests using redeem(), there can be some precision loss leading to dust.\n    ///             It is recommended to use withdraw() to claim redemption requests instead.\n    function redeem(uint256 shares, address receiver, address controller) external returns (uint256 assets) {\n        _validateController(controller);\n        assets = asyncRedeemManager.redeem(this, shares, receiver, controller);\n        emit Withdraw(msg.sender, receiver, controller, assets, shares);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Event emitters\n    //----------------------------------------------------------------------------------------------\n\n    function onRedeemRequest(address controller, address owner, uint256 shares) public virtual auth {\n        emit RedeemRequest(controller, owner, REQUEST_ID, msg.sender, shares);\n    }\n\n    function onRedeemClaimable(address controller, uint256 assets, uint256 shares) public virtual auth {\n        emit RedeemClaimable(controller, REQUEST_ID, assets, shares);\n    }\n\n    function onCancelRedeemClaimable(address controller, uint256 shares) public virtual auth {\n        emit CancelRedeemClaimable(controller, REQUEST_ID, shares);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // View methods\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IERC165\n    function supportsInterface(bytes4 interfaceId) public pure virtual override(BaseVault, IERC165) returns (bool) {\n        return super.supportsInterface(interfaceId) || interfaceId == type(IERC7540Redeem).interfaceId\n            || interfaceId == type(IERC7887Redeem).interfaceId;\n    }\n\n    /// @inheritdoc IERC7575\n    function maxWithdraw(address controller) public view returns (uint256 maxAssets) {\n        maxAssets = asyncRedeemManager.maxWithdraw(this, controller);\n    }\n\n    /// @inheritdoc IERC7575\n    function maxRedeem(address controller) public view returns (uint256 maxShares) {\n        maxShares = asyncRedeemManager.maxRedeem(this, controller);\n    }\n\n    /// @dev Preview functions for ERC-7540 vaults revert\n    function previewWithdraw(uint256) external pure returns (uint256) {\n        revert();\n    }\n\n    /// @dev Preview functions for ERC-7540 vaults revert\n    function previewRedeem(uint256) external pure returns (uint256) {\n        revert();\n    }\n}\n\nabstract contract BaseSyncDepositVault is BaseVault {\n    ISyncDepositManager public syncDepositManager;\n\n    constructor(ISyncDepositManager syncRequestManager_) {\n        syncDepositManager = syncRequestManager_;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // ERC-4626\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IERC7575\n    function maxDeposit(address owner) public view returns (uint256 maxAssets) {\n        maxAssets = syncDepositManager.maxDeposit(this, owner);\n    }\n\n    /// @inheritdoc IERC7575\n    function previewDeposit(uint256 assets) external view override returns (uint256 shares) {\n        shares = syncDepositManager.previewDeposit(this, msg.sender, assets);\n    }\n\n    /// @inheritdoc IERC7575\n    function deposit(uint256 assets, address receiver) external returns (uint256 shares) {\n        shares = syncDepositManager.deposit(this, assets, receiver, msg.sender);\n        // NOTE: For security reasons, transfer must stay at end of call despite the fact that it logically should\n        // happen before depositing in the manager\n        SafeTransferLib.safeTransferFrom(asset, msg.sender, address(manager.poolEscrow(poolId)), assets);\n        emit Deposit(receiver, msg.sender, assets, shares);\n    }\n\n    /// @inheritdoc IERC7575\n    function maxMint(address owner) public view returns (uint256 maxShares) {\n        maxShares = syncDepositManager.maxMint(this, owner);\n    }\n\n    /// @inheritdoc IERC7575\n    function previewMint(uint256 shares) external view returns (uint256 assets) {\n        assets = syncDepositManager.previewMint(this, msg.sender, shares);\n    }\n\n    /// @inheritdoc IERC7575\n    function mint(uint256 shares, address receiver) public returns (uint256 assets) {\n        assets = syncDepositManager.mint(this, shares, receiver, msg.sender);\n        // NOTE: For security reasons, transfer must stay at end of call\n        SafeTransferLib.safeTransferFrom(asset, msg.sender, address(manager.poolEscrow(poolId)), assets);\n        emit Deposit(receiver, msg.sender, assets, shares);\n    }\n\n    /// @inheritdoc IERC165\n    function supportsInterface(bytes4 interfaceId) public pure virtual override(BaseVault) returns (bool) {\n        return super.supportsInterface(interfaceId);\n    }\n}\n"
    },
    "src/vaults/Escrow.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IERC20} from \"src/misc/interfaces/IERC20.sol\";\nimport {IERC6909} from \"src/misc/interfaces/IERC6909.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {Holding, IPoolEscrow, IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\n\ncontract Escrow is Auth, IEscrow {\n    constructor(address deployer) Auth(deployer) {}\n\n    /// @inheritdoc IEscrow\n    function authTransferTo(address asset, uint256 tokenId, address receiver, uint256 amount) public auth {\n        if (tokenId == 0) {\n            uint256 balance = IERC20(asset).balanceOf(address(this));\n            require(balance >= amount, InsufficientBalance(asset, tokenId, amount, balance));\n\n            SafeTransferLib.safeTransfer(asset, receiver, amount);\n        } else {\n            uint256 balance = IERC6909(asset).balanceOf(address(this), tokenId);\n            require(balance >= amount, InsufficientBalance(asset, tokenId, amount, balance));\n\n            IERC6909(asset).transfer(receiver, tokenId, amount);\n        }\n\n        emit AuthTransferTo(asset, tokenId, receiver, amount);\n    }\n\n    /// @inheritdoc IEscrow\n    function authTransferTo(address asset, address receiver, uint256 amount) external auth {\n        authTransferTo(asset, 0, receiver, amount);\n    }\n}\n\n/// @title  Escrow\n/// @notice Escrow contract that holds assets for a specific pool separated by share classes.\n///         Only wards can approve funds to be taken out.\ncontract PoolEscrow is Escrow, Recoverable, IPoolEscrow {\n    /// @dev The underlying pool id\n    PoolId public immutable poolId;\n\n    mapping(ShareClassId scId => mapping(address asset => mapping(uint256 tokenId => Holding))) public holding;\n\n    constructor(PoolId poolId_, address deployer) Escrow(deployer) {\n        poolId = poolId_;\n    }\n\n    receive() external payable {}\n\n    /// @inheritdoc IPoolEscrow\n    function deposit(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external auth {\n        holding[scId][asset][tokenId].total += value;\n\n        emit Deposit(asset, tokenId, poolId, scId, value);\n    }\n\n    /// @inheritdoc IPoolEscrow\n    function withdraw(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external auth {\n        Holding storage holding_ = holding[scId][asset][tokenId];\n        uint128 balance = holding_.total - holding_.reserved;\n        require(balance >= value, InsufficientBalance(asset, tokenId, value, balance));\n\n        holding_.total -= value;\n\n        emit Withdraw(asset, tokenId, poolId, scId, value);\n    }\n\n    /// @inheritdoc IPoolEscrow\n    function reserveIncrease(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external auth {\n        uint128 newValue = holding[scId][asset][tokenId].reserved + value;\n        holding[scId][asset][tokenId].reserved = newValue;\n\n        emit IncreaseReserve(asset, tokenId, poolId, scId, value, newValue);\n    }\n\n    /// @inheritdoc IPoolEscrow\n    function reserveDecrease(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external auth {\n        uint128 prevValue = holding[scId][asset][tokenId].reserved;\n        uint128 value_ = value;\n        require(prevValue >= value_, InsufficientReservedAmount());\n\n        uint128 newValue = prevValue - value_;\n        holding[scId][asset][tokenId].reserved = newValue;\n\n        emit DecreaseReserve(asset, tokenId, poolId, scId, value, newValue);\n    }\n\n    /// @inheritdoc IPoolEscrow\n    function availableBalanceOf(ShareClassId scId, address asset, uint256 tokenId) public view returns (uint128) {\n        Holding storage holding_ = holding[scId][asset][tokenId];\n        if (holding_.total < holding_.reserved) return 0;\n        return holding_.total - holding_.reserved;\n    }\n}\n"
    },
    "src/vaults/PoolManager.sol": {
      "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.28;\n\nimport {IERC20Metadata, IERC20Wrapper} from \"src/misc/interfaces/IERC20.sol\";\nimport {IERC6909MetadataExt} from \"src/misc/interfaces/IERC6909.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\nimport {D18} from \"src/misc/types/D18.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\nimport {ReentrancyProtection} from \"src/misc/ReentrancyProtection.sol\";\n\nimport {VaultUpdateKind, MessageLib, UpdateContractType} from \"src/common/libraries/MessageLib.sol\";\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {IPoolManagerGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {IVaultMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\nimport {newAssetId, AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\nimport {IVaultFactory} from \"src/vaults/interfaces/factories/IVaultFactory.sol\";\nimport {IBaseVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {ITokenFactory} from \"src/vaults/interfaces/factories/ITokenFactory.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IPoolEscrowFactory} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IHook} from \"src/common/interfaces/IHook.sol\";\nimport {IUpdateContract} from \"src/vaults/interfaces/IUpdateContract.sol\";\nimport {\n    AssetIdKey,\n    Pool,\n    ShareClassDetails,\n    Price,\n    VaultDetails,\n    IPoolManager\n} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IAsyncRequestManager} from \"src/vaults/interfaces/investments/IAsyncRequestManager.sol\";\nimport {ISyncRequestManager} from \"src/vaults/interfaces/investments/ISyncRequestManager.sol\";\nimport {IPoolEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\n\n/// @title  Pool Manager\n/// @notice This contract manages which pools & share classes exist,\n///         as well as managing allowed pool currencies, and incoming and outgoing transfers.\ncontract PoolManager is\n    Auth,\n    Recoverable,\n    ReentrancyProtection,\n    IPoolManager,\n    IUpdateContract,\n    IPoolManagerGatewayHandler\n{\n    using CastLib for *;\n    using MessageLib for *;\n    using BytesLib for bytes;\n    using MathLib for uint256;\n\n    uint8 internal constant MIN_DECIMALS = 2;\n    uint8 internal constant MAX_DECIMALS = 18;\n\n    IGateway public gateway;\n    address public balanceSheet;\n    ITokenFactory public tokenFactory;\n    IVaultMessageSender public sender;\n    IPoolEscrowFactory public poolEscrowFactory;\n    IAsyncRequestManager public asyncRequestManager;\n    ISyncRequestManager public syncRequestManager;\n\n    uint64 internal _assetCounter;\n\n    mapping(PoolId poolId => Pool) public pools;\n    mapping(IVaultFactory factory => bool) public vaultFactory;\n\n    mapping(IBaseVault => VaultDetails) internal _vaultDetails;\n    mapping(AssetId assetId => AssetIdKey) internal _idToAsset;\n    mapping(address asset => mapping(uint256 tokenId => AssetId assetId)) internal _assetToId;\n\n    constructor(ITokenFactory tokenFactory_, address deployer) Auth(deployer) {\n        tokenFactory = tokenFactory_;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Administration\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IPoolManager\n    function file(bytes32 what, address data) external auth {\n        if (what == \"sender\") sender = IVaultMessageSender(data);\n        else if (what == \"tokenFactory\") tokenFactory = ITokenFactory(data);\n        else if (what == \"gateway\") gateway = IGateway(data);\n        else if (what == \"balanceSheet\") balanceSheet = data;\n        else if (what == \"poolEscrowFactory\") poolEscrowFactory = IPoolEscrowFactory(data);\n        else if (what == \"asyncRequestManager\") asyncRequestManager = IAsyncRequestManager(data);\n        else if (what == \"syncRequestManager\") syncRequestManager = ISyncRequestManager(data);\n        else revert FileUnrecognizedParam();\n        emit File(what, data);\n    }\n\n    /// @inheritdoc IPoolManager\n    function file(bytes32 what, address factory, bool status) external auth {\n        if (what == \"vaultFactory\") {\n            vaultFactory[IVaultFactory(factory)] = status;\n        } else {\n            revert FileUnrecognizedParam();\n        }\n        emit File(what, factory, status);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Outgoing methods\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IPoolManager\n    function transferShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 receiver, uint128 amount)\n        external\n        payable\n        protected\n    {\n        IShareToken share = IShareToken(shareToken(poolId, scId));\n        require(centrifugeId != sender.localCentrifugeId(), LocalTransferNotAllowed());\n        require(\n            share.checkTransferRestriction(msg.sender, address(uint160(centrifugeId)), amount),\n            CrossChainTransferNotAllowed()\n        );\n\n        gateway.payTransaction{value: msg.value}(msg.sender);\n\n        share.authTransferFrom(msg.sender, msg.sender, address(this), amount);\n        share.burn(address(this), amount);\n\n        emit TransferShares(centrifugeId, poolId, scId, msg.sender, receiver, amount);\n        sender.sendTransferShares(centrifugeId, poolId, scId, receiver, amount);\n    }\n\n    // @inheritdoc IPoolManager\n    function registerAsset(uint16 centrifugeId, address asset, uint256 tokenId)\n        external\n        payable\n        protected\n        returns (AssetId assetId)\n    {\n        string memory name;\n        string memory symbol;\n        uint8 decimals;\n\n        decimals = _safeGetAssetDecimals(asset, tokenId);\n        require(decimals >= MIN_DECIMALS, TooFewDecimals());\n        require(decimals <= MAX_DECIMALS, TooManyDecimals());\n\n        gateway.payTransaction{value: msg.value}(msg.sender);\n\n        if (tokenId == 0) {\n            IERC20Metadata meta = IERC20Metadata(asset);\n            name = meta.name();\n            symbol = meta.symbol();\n        } else {\n            IERC6909MetadataExt meta = IERC6909MetadataExt(asset);\n            name = meta.name(tokenId);\n            symbol = meta.symbol(tokenId);\n        }\n\n        assetId = _assetToId[asset][tokenId];\n        if (assetId.raw() == 0) {\n            _assetCounter++;\n            assetId = newAssetId(sender.localCentrifugeId(), _assetCounter);\n\n            _idToAsset[assetId] = AssetIdKey(asset, tokenId);\n            _assetToId[asset][tokenId] = assetId;\n\n            emit RegisterAsset(assetId, asset, tokenId, name, symbol, decimals);\n        }\n\n        sender.sendRegisterAsset(centrifugeId, assetId, decimals);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Incoming\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IPoolManagerGatewayHandler\n    function addPool(PoolId poolId) public auth {\n        Pool storage pool = pools[poolId];\n        require(pool.createdAt == 0, PoolAlreadyAdded());\n        pool.createdAt = block.timestamp;\n\n        IPoolEscrow escrow = poolEscrowFactory.newEscrow(poolId);\n        gateway.setRefundAddress(PoolId.wrap(poolId.raw()), escrow);\n\n        emit AddPool(poolId);\n    }\n\n    /// @inheritdoc IPoolManagerGatewayHandler\n    function addShareClass(\n        PoolId poolId,\n        ShareClassId scId,\n        string memory name,\n        string memory symbol,\n        uint8 decimals,\n        bytes32 salt,\n        address hook\n    ) public auth {\n        require(decimals >= MIN_DECIMALS, TooFewDecimals());\n        require(decimals <= MAX_DECIMALS, TooManyDecimals());\n        require(isPoolActive(poolId), InvalidPool());\n\n        Pool storage pool = pools[poolId];\n        require(address(pool.shareClasses[scId].shareToken) == address(0), ShareClassAlreadyRegistered());\n\n        // Hook can be address zero if the share token is fully permissionless and has no custom logic\n        require(hook == address(0) || _isValidHook(hook), InvalidHook());\n\n        address[] memory tokenWards = new address[](2);\n        tokenWards[0] = address(this);\n        // BalanceSheet needs this in order to mint shares\n        tokenWards[1] = balanceSheet;\n\n        IShareToken shareToken_ = tokenFactory.newToken(name, symbol, decimals, salt, tokenWards);\n\n        if (hook != address(0)) {\n            shareToken_.file(\"hook\", hook);\n        }\n\n        pool.shareClasses[scId].shareToken = shareToken_;\n\n        emit AddShareClass(poolId, scId, shareToken_);\n    }\n\n    /// @inheritdoc IPoolManagerGatewayHandler\n    function updateShareMetadata(PoolId poolId, ShareClassId scId, string memory name, string memory symbol)\n        public\n        auth\n    {\n        IShareToken shareToken_ = shareToken(poolId, scId);\n\n        require(\n            keccak256(bytes(shareToken_.name())) != keccak256(bytes(name))\n                || keccak256(bytes(shareToken_.symbol())) != keccak256(bytes(symbol)),\n            OldMetadata()\n        );\n\n        shareToken_.file(\"name\", name);\n        shareToken_.file(\"symbol\", symbol);\n    }\n\n    /// @inheritdoc IPoolManagerGatewayHandler\n    function updatePricePoolPerShare(PoolId poolId, ShareClassId scId, uint128 price, uint64 computedAt) public auth {\n        ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n\n        require(computedAt >= shareClass.pricePoolPerShare.computedAt, CannotSetOlderPrice());\n\n        shareClass.pricePoolPerShare = Price(price, computedAt, shareClass.pricePoolPerShare.maxAge);\n        emit PriceUpdate(poolId, scId, price, computedAt);\n    }\n\n    /// @inheritdoc IPoolManagerGatewayHandler\n    function updatePricePoolPerAsset(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        uint128 poolPerAsset_,\n        uint64 computedAt\n    ) public auth {\n        ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n\n        (address asset, uint256 tokenId) = idToAsset(assetId);\n        Price storage poolPerAsset = shareClass.pricePoolPerAsset[asset][tokenId];\n        require(computedAt >= poolPerAsset.computedAt, CannotSetOlderPrice());\n\n        // Disable expiration of the price\n        if (poolPerAsset.computedAt == 0) {\n            poolPerAsset.maxAge = type(uint64).max;\n        }\n        poolPerAsset.price = poolPerAsset_;\n        poolPerAsset.computedAt = computedAt;\n\n        emit PriceUpdate(poolId, scId, asset, tokenId, poolPerAsset_, computedAt);\n    }\n\n    /// @inheritdoc IPoolManagerGatewayHandler\n    function updateRestriction(PoolId poolId, ShareClassId scId, bytes memory update_) public auth {\n        IShareToken shareToken_ = shareToken(poolId, scId);\n        address hook = shareToken_.hook();\n        require(hook != address(0), InvalidHook());\n        IHook(hook).updateRestriction(address(shareToken_), update_);\n    }\n\n    /// @inheritdoc IPoolManagerGatewayHandler\n    function updateContract(PoolId poolId, ShareClassId scId, address target, bytes memory update_) public auth {\n        if (target == address(this)) {\n            update(poolId, scId, update_);\n        } else {\n            IUpdateContract(target).update(poolId, scId, update_);\n        }\n\n        emit UpdateContract(poolId, scId, target, update_);\n    }\n\n    /// @inheritdoc IPoolManagerGatewayHandler\n    function updateShareHook(PoolId poolId, ShareClassId scId, address hook) public auth {\n        IShareToken shareToken_ = shareToken(poolId, scId);\n        require(hook != shareToken_.hook(), OldHook());\n        shareToken_.file(\"hook\", hook);\n    }\n\n    /// @inheritdoc IPoolManagerGatewayHandler\n    function handleTransferShares(PoolId poolId, ShareClassId scId, address destinationAddress, uint128 amount)\n        public\n        auth\n    {\n        IShareToken shareToken_ = shareToken(poolId, scId);\n\n        shareToken_.mint(destinationAddress, amount);\n    }\n\n    /// @inheritdoc IUpdateContract\n    /// @notice The pool manager either deploys the vault if a factory address is provided\n    ///         or it simply links/unlinks the vault.\n    function update(PoolId poolId, ShareClassId scId, bytes memory payload) public auth {\n        uint8 kind = uint8(MessageLib.updateContractType(payload));\n\n        if (kind == uint8(UpdateContractType.VaultUpdate)) {\n            MessageLib.UpdateContractVaultUpdate memory m = MessageLib.deserializeUpdateContractVaultUpdate(payload);\n\n            if (m.kind == uint8(VaultUpdateKind.DeployAndLink)) {\n                IVaultFactory factory = IVaultFactory(m.vaultOrFactory.toAddress());\n\n                IBaseVault vault = deployVault(poolId, scId, AssetId.wrap(m.assetId), factory);\n                linkVault(poolId, scId, AssetId.wrap(m.assetId), vault);\n            } else {\n                IBaseVault vault = IBaseVault(m.vaultOrFactory.toAddress());\n\n                // Needed as safeguard against non-validated vaults\n                // I.e. we only accept vaults that have been deployed by the pool manager\n                require(_vaultDetails[vault].asset != address(0), UnknownVault());\n\n                if (m.kind == uint8(VaultUpdateKind.Link)) {\n                    linkVault(poolId, scId, AssetId.wrap(m.assetId), vault);\n                } else if (m.kind == uint8(VaultUpdateKind.Unlink)) {\n                    unlinkVault(poolId, scId, AssetId.wrap(m.assetId), vault);\n                } else {\n                    revert MalformedVaultUpdateMessage();\n                }\n            }\n        } else if (kind == uint8(UpdateContractType.MaxAssetPriceAge)) {\n            MessageLib.UpdateContractMaxAssetPriceAge memory m =\n                MessageLib.deserializeUpdateContractMaxAssetPriceAge(payload);\n\n            ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n            require(m.assetId != 0, UnknownAsset());\n\n            (address asset, uint256 tokenId) = idToAsset(AssetId.wrap(m.assetId));\n            shareClass.pricePoolPerAsset[asset][tokenId].maxAge = m.maxPriceAge;\n            emit UpdateMaxAssetPriceAge(poolId, scId, asset, tokenId, m.maxPriceAge);\n        } else if (kind == uint8(UpdateContractType.MaxSharePriceAge)) {\n            MessageLib.UpdateContractMaxSharePriceAge memory m =\n                MessageLib.deserializeUpdateContractMaxSharePriceAge(payload);\n\n            ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n\n            shareClass.pricePoolPerShare.maxAge = m.maxPriceAge;\n            emit UpdateMaxSharePriceAge(poolId, scId, m.maxPriceAge);\n        } else {\n            revert UnknownUpdateContractType();\n        }\n    }\n\n    /// @inheritdoc IPoolManager\n    function linkVault(PoolId poolId, ShareClassId scId, AssetId assetId, IBaseVault vault) public auth {\n        _shareClass(poolId, scId);\n\n        AssetIdKey memory assetIdKey = _idToAsset[assetId];\n\n        IBaseRequestManager manager = vault.manager();\n        manager.addVault(poolId, scId, vault, assetIdKey.asset, assetId);\n\n        _vaultDetails[vault].isLinked = true;\n\n        emit LinkVault(poolId, scId, assetIdKey.asset, assetIdKey.tokenId, vault);\n    }\n\n    /// @inheritdoc IPoolManager\n    function unlinkVault(PoolId poolId, ShareClassId scId, AssetId assetId, IBaseVault vault) public auth {\n        _shareClass(poolId, scId);\n\n        AssetIdKey memory assetIdKey = _idToAsset[assetId];\n\n        IBaseRequestManager manager = vault.manager();\n        manager.removeVault(poolId, scId, vault, assetIdKey.asset, assetId);\n\n        _vaultDetails[vault].isLinked = false;\n\n        emit UnlinkVault(poolId, scId, assetIdKey.asset, assetIdKey.tokenId, vault);\n    }\n\n    /// @inheritdoc IPoolManager\n    function deployVault(PoolId poolId, ShareClassId scId, AssetId assetId, IVaultFactory factory)\n        public\n        auth\n        returns (IBaseVault)\n    {\n        ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n        require(vaultFactory[factory], InvalidFactory());\n\n        // Rely investment manager on vault so it can mint tokens\n        address[] memory vaultWards = new address[](0);\n\n        // Deploy vault\n        AssetIdKey memory assetIdKey = _idToAsset[assetId];\n        IBaseVault vault = IVaultFactory(factory).newVault(\n            poolId, scId, assetIdKey.asset, assetIdKey.tokenId, shareClass.shareToken, vaultWards\n        );\n\n        // Check whether asset is an ERC20 token wrapper\n        (bool success, bytes memory data) =\n            assetIdKey.asset.staticcall(abi.encodeWithSelector(IERC20Wrapper.underlying.selector));\n        // On success, the returned 20 byte address is padded to 32 bytes\n        bool isWrappedERC20 = success && data.length == 32;\n        _vaultDetails[vault] = VaultDetails(assetId, assetIdKey.asset, assetIdKey.tokenId, isWrappedERC20, false);\n\n        // NOTE - Reverting the manager approvals is not easy. We SHOULD do that if we phase-out a manager\n        VaultKind vaultKind = _relyShareToken(vault, shareClass.shareToken);\n\n        emit DeployVault(poolId, scId, assetIdKey.asset, assetIdKey.tokenId, factory, vault, vaultKind);\n        return vault;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // View methods\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IPoolManager\n    function isPoolActive(PoolId poolId) public view returns (bool) {\n        return pools[poolId].createdAt > 0;\n    }\n\n    /// @inheritdoc IPoolManager\n    function shareToken(PoolId poolId, ShareClassId scId) public view returns (IShareToken) {\n        ShareClassDetails storage shareClass = pools[poolId].shareClasses[scId];\n        require(address(shareClass.shareToken) != address(0), UnknownToken());\n        return shareClass.shareToken;\n    }\n\n    /// @inheritdoc IPoolManager\n    function vaultDetails(IBaseVault vault) public view returns (VaultDetails memory details) {\n        details = _vaultDetails[vault];\n        require(details.asset != address(0), UnknownVault());\n    }\n\n    /// @inheritdoc IPoolManager\n    function isLinked(PoolId, /* poolId */ ShareClassId, /* scId */ address, /* asset */ IBaseVault vault)\n        public\n        view\n        returns (bool)\n    {\n        return _vaultDetails[vault].isLinked;\n    }\n\n    /// @inheritdoc IPoolManager\n    function idToAsset(AssetId assetId) public view returns (address asset, uint256 tokenId) {\n        AssetIdKey memory assetIdKey = _idToAsset[assetId];\n        require(assetIdKey.asset != address(0), UnknownAsset());\n        return (assetIdKey.asset, assetIdKey.tokenId);\n    }\n\n    /// @inheritdoc IPoolManager\n    function assetToId(address asset, uint256 tokenId) public view returns (AssetId assetId) {\n        assetId = _assetToId[asset][tokenId];\n        require(assetId.raw() != 0, UnknownAsset());\n    }\n\n    /// @inheritdoc IPoolManager\n    function priceAssetPerShare(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n        public\n        view\n        returns (D18 price)\n    {\n        (Price memory poolPerAsset, Price memory poolPerShare) = _pricesPoolPer(poolId, scId, assetId, checkValidity);\n\n        price = PricingLib.priceAssetPerShare(poolPerShare.asPrice(), poolPerAsset.asPrice());\n    }\n\n    /// @inheritdoc IPoolManager\n    function pricePoolPerShare(PoolId poolId, ShareClassId scId, bool checkValidity) public view returns (D18 price) {\n        ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n\n        if (checkValidity) {\n            require(shareClass.pricePoolPerShare.isValid(), InvalidPrice());\n        }\n\n        price = shareClass.pricePoolPerShare.asPrice();\n    }\n\n    /// @inheritdoc IPoolManager\n    function pricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n        public\n        view\n        returns (D18 price)\n    {\n        (Price memory poolPerAsset,) = _pricesPoolPer(poolId, scId, assetId, false);\n\n        if (checkValidity) {\n            require(poolPerAsset.isValid(), InvalidPrice());\n        }\n\n        price = poolPerAsset.asPrice();\n    }\n\n    /// @inheritdoc IPoolManager\n    function pricesPoolPer(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n        public\n        view\n        returns (D18 pricePoolPerAsset_, D18 pricePoolPerShare_)\n    {\n        (Price memory poolPerAsset, Price memory poolPerShare) = _pricesPoolPer(poolId, scId, assetId, checkValidity);\n        return (poolPerAsset.asPrice(), poolPerShare.asPrice());\n    }\n\n    /// @inheritdoc IPoolManager\n    function markersPricePoolPerShare(PoolId poolId, ShareClassId scId)\n        external\n        view\n        returns (uint64 computedAt, uint64 maxAge, uint64 validUntil)\n    {\n        ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n        computedAt = shareClass.pricePoolPerShare.computedAt;\n        maxAge = shareClass.pricePoolPerShare.maxAge;\n        validUntil = shareClass.pricePoolPerShare.validUntil();\n    }\n\n    /// @inheritdoc IPoolManager\n    function markersPricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId)\n        external\n        view\n        returns (uint64 computedAt, uint64 maxAge, uint64 validUntil)\n    {\n        (Price memory poolPerAsset,) = _pricesPoolPer(poolId, scId, assetId, false);\n        computedAt = poolPerAsset.computedAt;\n        maxAge = poolPerAsset.maxAge;\n        validUntil = poolPerAsset.validUntil();\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Internal methods\n    //----------------------------------------------------------------------------------------------\n\n    function _pricesPoolPer(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n        internal\n        view\n        returns (Price memory poolPerAsset, Price memory poolPerShare)\n    {\n        ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n\n        (address asset, uint256 tokenId) = idToAsset(assetId);\n        poolPerAsset = shareClass.pricePoolPerAsset[asset][tokenId];\n        poolPerShare = shareClass.pricePoolPerShare;\n\n        if (checkValidity) {\n            require(poolPerAsset.isValid(), InvalidPrice());\n            require(poolPerShare.isValid(), InvalidPrice());\n        }\n    }\n\n    /// @dev Sets up approval permissions for pool, i.e. the pool escrow, the base vault manager and potentially a\n    ///      secondary manager (in case of partially sync vault)\n    function _relyShareToken(IBaseVault vault, IShareToken shareToken_) internal returns (VaultKind) {\n        IBaseRequestManager manager = vault.manager();\n        IAuth(address(shareToken_)).rely(address(manager));\n\n        // For sync deposit & async redeem vault, also repeat above for async manager\n        VaultKind vaultKind = vault.vaultKind();\n        if (vaultKind == VaultKind.SyncDepositAsyncRedeem) {\n            IAuth(address(shareToken_)).rely(address(asyncRequestManager));\n        }\n\n        return vaultKind;\n    }\n\n    function _safeGetAssetDecimals(address asset, uint256 tokenId) private view returns (uint8) {\n        bytes memory callData;\n\n        if (tokenId == 0) {\n            callData = abi.encodeWithSignature(\"decimals()\");\n        } else {\n            callData = abi.encodeWithSignature(\"decimals(uint256)\", tokenId);\n        }\n\n        (bool success, bytes memory data) = asset.staticcall(callData);\n        require(success && data.length >= 32, AssetMissingDecimals());\n\n        return abi.decode(data, (uint8));\n    }\n\n    function _isValidHook(address hook) internal view returns (bool) {\n        (bool success, bytes memory data) =\n            hook.staticcall(abi.encodeWithSelector(IERC165.supportsInterface.selector, type(IHook).interfaceId));\n\n        return success && data.length == 32 && abi.decode(data, (bool));\n    }\n\n    function _shareClass(PoolId poolId, ShareClassId scId)\n        internal\n        view\n        returns (ShareClassDetails storage shareClass)\n    {\n        shareClass = pools[poolId].shareClasses[scId];\n        require(address(shareClass.shareToken) != address(0), ShareTokenDoesNotExist());\n    }\n}\n"
    },
    "src/vaults/SyncDepositVault.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {BaseVault, BaseAsyncRedeemVault, BaseSyncDepositVault} from \"src/vaults/BaseVaults.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\nimport {ISyncDepositManager} from \"src/vaults/interfaces/investments/ISyncDepositManager.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\n/// @title  SyncDepositVault\n/// @notice Partially (a)synchronous Tokenized Vault implementation with synchronous deposits\n///         and asynchronous redemptions following ERC-7540.\n///\n/// @dev    Each vault issues shares of Centrifuge share class tokens as restricted ERC-20 tokens\n///         against asset deposits based on the current share price.\ncontract SyncDepositVault is BaseSyncDepositVault, BaseAsyncRedeemVault {\n    constructor(\n        PoolId poolId_,\n        ShareClassId scId_,\n        address asset_,\n        IShareToken token_,\n        address root_,\n        ISyncDepositManager syncDepositManager_,\n        IAsyncRedeemManager asyncRedeemManager_\n    )\n        BaseVault(poolId_, scId_, asset_, token_, root_, syncDepositManager_)\n        BaseSyncDepositVault(syncDepositManager_)\n        BaseAsyncRedeemVault(asyncRedeemManager_)\n    {}\n\n    //----------------------------------------------------------------------------------------------\n    // Administration\n    //----------------------------------------------------------------------------------------------\n\n    function file(bytes32 what, address data) external override(BaseAsyncRedeemVault, BaseVault) auth {\n        if (what == \"manager\") manager = IBaseRequestManager(data);\n        else if (what == \"asyncRedeemManager\") asyncRedeemManager = IAsyncRedeemManager(data);\n        else if (what == \"syncDepositManager\") syncDepositManager = ISyncDepositManager(data);\n        else revert FileUnrecognizedParam();\n        emit File(what, data);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // ERC-165\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IERC165\n    function supportsInterface(bytes4 interfaceId)\n        public\n        pure\n        override(BaseAsyncRedeemVault, BaseSyncDepositVault)\n        returns (bool)\n    {\n        return super.supportsInterface(interfaceId);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // IBaseVault view\n    //----------------------------------------------------------------------------------------------\n\n    function vaultKind() public pure returns (VaultKind vaultKind_) {\n        return VaultKind.SyncDepositAsyncRedeem;\n    }\n}\n"
    },
    "src/vaults/SyncRequestManager.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC165} from \"forge-std/interfaces/IERC165.sol\";\nimport {IERC7540Redeem} from \"src/misc/interfaces/IERC7540.sol\";\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\nimport {d18, D18} from \"src/misc/types/D18.sol\";\n\nimport {MessageLib, UpdateContractType} from \"src/common/libraries/MessageLib.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\nimport {BaseRequestManager} from \"src/vaults/BaseRequestManager.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IAsyncRedeemVault, IBaseVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IPoolManager, VaultDetails} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IBalanceSheet} from \"src/vaults/interfaces/IBalanceSheet.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {\n    ISyncRequestManager,\n    Prices,\n    ISyncDepositValuation\n} from \"src/vaults/interfaces/investments/ISyncRequestManager.sol\";\nimport {IDepositManager} from \"src/vaults/interfaces/investments/IDepositManager.sol\";\nimport {ISyncDepositManager} from \"src/vaults/interfaces/investments/ISyncDepositManager.sol\";\nimport {IUpdateContract} from \"src/vaults/interfaces/IUpdateContract.sol\";\nimport {IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\n\n/// @title  Sync Investment Manager\n/// @notice This is the main contract vaults interact with for\n///         both incoming and outgoing investment transactions.\ncontract SyncRequestManager is BaseRequestManager, ISyncRequestManager {\n    using BytesLib for bytes;\n    using MathLib for *;\n    using CastLib for *;\n    using MessageLib for *;\n\n    IBalanceSheet public balanceSheet;\n\n    mapping(PoolId => mapping(ShareClassId scId => ISyncDepositValuation)) public valuation;\n    mapping(PoolId => mapping(ShareClassId scId => mapping(address asset => mapping(uint256 tokenId => uint128))))\n        public maxReserve;\n\n    constructor(IEscrow globalEscrow_, address root_, address deployer)\n        BaseRequestManager(globalEscrow_, root_, deployer)\n    {}\n\n    //----------------------------------------------------------------------------------------------\n    // Administration\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IBaseRequestManager\n    function file(bytes32 what, address data) external override(IBaseRequestManager, BaseRequestManager) auth {\n        if (what == \"poolManager\") poolManager = IPoolManager(data);\n        else if (what == \"balanceSheet\") balanceSheet = IBalanceSheet(data);\n        else if (what == \"poolEscrowProvider\") poolEscrowProvider = IPoolEscrowProvider(data);\n        else revert FileUnrecognizedParam();\n        emit File(what, data);\n    }\n\n    /// @inheritdoc IUpdateContract\n    function update(PoolId poolId, ShareClassId scId, bytes memory payload) external auth {\n        uint8 kind = uint8(MessageLib.updateContractType(payload));\n\n        if (kind == uint8(UpdateContractType.Valuation)) {\n            MessageLib.UpdateContractValuation memory m = MessageLib.deserializeUpdateContractValuation(payload);\n\n            require(address(poolManager.shareToken(poolId, scId)) != address(0), ShareTokenDoesNotExist());\n\n            setValuation(poolId, scId, m.valuation.toAddress());\n        } else if (kind == uint8(UpdateContractType.SyncDepositMaxReserve)) {\n            MessageLib.UpdateContractSyncDepositMaxReserve memory m =\n                MessageLib.deserializeUpdateContractSyncDepositMaxReserve(payload);\n\n            require(address(poolManager.shareToken(poolId, scId)) != address(0), ShareTokenDoesNotExist());\n            (address asset, uint256 tokenId) = poolManager.idToAsset(AssetId.wrap(m.assetId));\n\n            setMaxReserve(poolId, scId, asset, tokenId, m.maxReserve);\n        } else {\n            revert UnknownUpdateContractType();\n        }\n    }\n\n    /// @inheritdoc IBaseRequestManager\n    function addVault(PoolId poolId, ShareClassId scId, IBaseVault vault_, address asset_, AssetId assetId)\n        public\n        override(BaseRequestManager, IBaseRequestManager)\n        auth\n    {\n        super.addVault(poolId, scId, vault_, asset_, assetId);\n\n        (, uint256 tokenId) = poolManager.idToAsset(assetId);\n        setMaxReserve(poolId, scId, asset_, tokenId, type(uint128).max);\n\n        VaultKind vaultKind_ = vault_.vaultKind();\n        if (vaultKind_ == VaultKind.SyncDepositAsyncRedeem) {\n            IAsyncRedeemManager asyncRequestManager = IAsyncRedeemVault(address(vault_)).asyncRedeemManager();\n            require(address(asyncRequestManager) != address(0), SecondaryManagerDoesNotExist());\n            asyncRequestManager.addVault(poolId, scId, vault_, asset_, assetId);\n        }\n    }\n\n    /// @inheritdoc IBaseRequestManager\n    function removeVault(PoolId poolId, ShareClassId scId, IBaseVault vault_, address asset_, AssetId assetId)\n        public\n        override(BaseRequestManager, IBaseRequestManager)\n        auth\n    {\n        super.removeVault(poolId, scId, vault_, asset_, assetId);\n\n        (, uint256 tokenId) = poolManager.idToAsset(assetId);\n        delete maxReserve[poolId][scId][asset_][tokenId];\n\n        VaultKind vaultKind_ = vault_.vaultKind();\n        if (vaultKind_ == VaultKind.SyncDepositAsyncRedeem) {\n            IAsyncRedeemManager asyncRequestManager = IAsyncRedeemVault(address(vault_)).asyncRedeemManager();\n            require(address(asyncRequestManager) != address(0), SecondaryManagerDoesNotExist());\n            asyncRequestManager.removeVault(poolId, scId, vault_, asset_, assetId);\n        }\n    }\n\n    /// @inheritdoc ISyncRequestManager\n    function setValuation(PoolId poolId, ShareClassId scId, address valuation_) public auth {\n        valuation[poolId][scId] = ISyncDepositValuation(valuation_);\n\n        emit SetValuation(poolId, scId, address(valuation_));\n    }\n\n    /// @inheritdoc ISyncRequestManager\n    function setMaxReserve(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, uint128 maxReserve_)\n        public\n        auth\n    {\n        maxReserve[poolId][scId][asset][tokenId] = maxReserve_;\n\n        emit SetMaxReserve(poolId, scId, asset, tokenId, maxReserve_);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Deposit handlers\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IDepositManager\n    function mint(IBaseVault vault_, uint256 shares, address receiver, address owner)\n        external\n        auth\n        returns (uint256 assets)\n    {\n        require(maxMint(vault_, owner) >= shares, ExceedsMaxMint());\n        assets = previewMint(vault_, owner, shares);\n\n        _issueShares(vault_, shares.toUint128(), receiver, owner, assets.toUint128());\n    }\n\n    /// @inheritdoc IDepositManager\n    function deposit(IBaseVault vault_, uint256 assets, address receiver, address owner)\n        external\n        auth\n        returns (uint256 shares)\n    {\n        VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n        require(poolManager.isLinked(vault_.poolId(), vault_.scId(), vaultDetails.asset, vault_), AssetNotAllowed());\n\n        require(maxDeposit(vault_, owner) >= assets, ExceedsMaxDeposit());\n        shares = previewDeposit(vault_, owner, assets);\n\n        _issueShares(vault_, shares.toUint128(), receiver, owner, assets.toUint128());\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // View methods\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc ISyncDepositManager\n    function previewMint(IBaseVault vault_, address, /* sender */ uint256 shares)\n        public\n        view\n        returns (uint256 assets)\n    {\n        return _shareToAssetAmount(vault_, shares, MathLib.Rounding.Up);\n    }\n\n    /// @inheritdoc ISyncDepositManager\n    function previewDeposit(IBaseVault vault_, address, /* sender */ uint256 assets)\n        public\n        view\n        returns (uint256 shares)\n    {\n        return convertToShares(vault_, assets);\n    }\n\n    /// @inheritdoc IDepositManager\n    function maxMint(IBaseVault vault_, address /* owner */ ) public view returns (uint256) {\n        VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n        uint128 maxAssets = _maxDeposit(vault_.poolId(), vault_.scId(), vaultDetails.asset, vaultDetails.tokenId);\n        return convertToShares(vault_, maxAssets);\n    }\n\n    /// @inheritdoc IDepositManager\n    function maxDeposit(IBaseVault vault_, address /* owner */ ) public view returns (uint256) {\n        VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n        return _maxDeposit(vault_.poolId(), vault_.scId(), vaultDetails.asset, vaultDetails.tokenId);\n    }\n\n    /// @inheritdoc IBaseRequestManager\n    function convertToShares(IBaseVault vault_, uint256 assets)\n        public\n        view\n        override(IBaseRequestManager, BaseRequestManager)\n        returns (uint256 shares)\n    {\n        VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n        Prices memory prices_ = prices(vault_.poolId(), vault_.scId(), vaultDetails.assetId);\n\n        return super._assetToShareAmount(\n            vault_, vaultDetails, assets, prices_.poolPerAsset, prices_.poolPerShare, MathLib.Rounding.Down\n        );\n    }\n\n    /// @inheritdoc IBaseRequestManager\n    function convertToAssets(IBaseVault vault_, uint256 shares)\n        public\n        view\n        override(IBaseRequestManager, BaseRequestManager)\n        returns (uint256 assets)\n    {\n        return _shareToAssetAmount(vault_, shares, MathLib.Rounding.Down);\n    }\n\n    /// @inheritdoc ISyncDepositValuation\n    function pricePoolPerShare(PoolId poolId, ShareClassId scId) public view returns (D18 price) {\n        ISyncDepositValuation valuation_ = valuation[poolId][scId];\n\n        if (address(valuation_) == address(0)) {\n            price = poolManager.pricePoolPerShare(poolId, scId, true);\n        } else {\n            price = valuation_.pricePoolPerShare(poolId, scId);\n        }\n    }\n\n    /// @inheritdoc ISyncRequestManager\n    function prices(PoolId poolId, ShareClassId scId, AssetId assetId) public view returns (Prices memory priceData) {\n        priceData.poolPerShare = pricePoolPerShare(poolId, scId);\n        priceData.poolPerAsset = poolManager.pricePoolPerAsset(poolId, scId, assetId, true);\n        priceData.assetPerShare = PricingLib.priceAssetPerShare(priceData.poolPerShare, priceData.poolPerAsset);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Internal\n    //----------------------------------------------------------------------------------------------\n\n    /// @dev Issues shares to the receiver and instruct the balance sheet\n    //       to react on the issuance and the updated holding.\n    function _issueShares(IBaseVault vault_, uint128 shares, address receiver, address, /* owner */ uint128 assets)\n        internal\n    {\n        PoolId poolId = vault_.poolId();\n        ShareClassId scId = vault_.scId();\n        VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n\n        balanceSheet.overridePricePoolPerShare(poolId, scId, prices(poolId, scId, vaultDetails.assetId).poolPerShare);\n        balanceSheet.issue(poolId, scId, receiver, shares);\n\n        // Note deposit into the pool escrow, to make assets available for managers of the balance sheet\n        // ERC-20 transfer is handled by the vault to the pool escrow afterwards\n        balanceSheet.noteDeposit(poolId, scId, vaultDetails.asset, vaultDetails.tokenId, receiver, assets);\n    }\n\n    function _maxDeposit(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId)\n        internal\n        view\n        returns (uint128 maxDeposit_)\n    {\n        uint128 availableBalance = poolEscrowProvider.escrow(poolId).availableBalanceOf(scId, asset, tokenId);\n        uint128 maxReserve_ = maxReserve[poolId][scId][asset][tokenId];\n\n        if (maxReserve_ < availableBalance) {\n            maxDeposit_ = 0;\n        } else {\n            maxDeposit_ = maxReserve_ - availableBalance;\n        }\n    }\n\n    function _shareToAssetAmount(IBaseVault vault_, uint256 assets, MathLib.Rounding rounding)\n        internal\n        view\n        returns (uint256 shares)\n    {\n        VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n        Prices memory prices_ = prices(vault_.poolId(), vault_.scId(), vaultDetails.assetId);\n        return super._shareToAssetAmount(\n            vault_, vaultDetails, assets, prices_.poolPerAsset, prices_.poolPerShare, rounding\n        );\n    }\n}\n"
    },
    "src/vaults/VaultRouter.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {Multicall, IMulticall} from \"src/misc/Multicall.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {IERC20, IERC20Permit, IERC20Wrapper} from \"src/misc/interfaces/IERC20.sol\";\nimport {IERC7540Deposit} from \"src/misc/interfaces/IERC7540.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\n\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {IMessageDispatcher} from \"src/common/interfaces/IMessageDispatcher.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IAsyncVault, IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IVaultRouter} from \"src/vaults/interfaces/IVaultRouter.sol\";\nimport {IPoolManager, VaultDetails} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {BaseSyncDepositVault} from \"src/vaults/BaseVaults.sol\";\n\n/// @title  VaultRouter\n/// @notice This is a helper contract, designed to be the entrypoint for EOAs.\n///         It removes the need to know about all other contracts and simplifies the way to interact with the protocol.\n///         It also adds the need to fully pay for each step of the transaction execution. VaultRouter allows\n///         the caller to execute multiple function into a single transaction by taking advantage of\n///         the multicall functionality which batches message calls into a single one.\n/// @dev    It is critical to ensure that at the end of any transaction, no funds remain in the\n///         VaultRouter. Any funds that do remain are at risk of being taken by other users.\ncontract VaultRouter is Auth, Multicall, Recoverable, IVaultRouter {\n    using CastLib for address;\n\n    /// @dev Requests for Centrifuge pool are non-fungible and all have ID = 0\n    uint256 private constant REQUEST_ID = 0;\n\n    IEscrow public immutable escrow;\n    IGateway public immutable gateway;\n    IPoolManager public immutable poolManager;\n    IMessageDispatcher public immutable messageDispatcher;\n\n    /// @inheritdoc IVaultRouter\n    mapping(address controller => mapping(IBaseVault vault => uint256 amount)) public lockedRequests;\n\n    constructor(\n        address escrow_,\n        IGateway gateway_,\n        IPoolManager poolManager_,\n        IMessageDispatcher messageDispatcher_,\n        address deployer\n    ) Auth(deployer) {\n        escrow = IEscrow(escrow_);\n        gateway = gateway_;\n        poolManager = poolManager_;\n        messageDispatcher = messageDispatcher_;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Administration\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IMulticall\n    /// @notice performs a multicall but all message sent in the process will be batched\n    function multicall(bytes[] calldata data) public payable override(Multicall, IMulticall) {\n        bool wasBatching = gateway.isBatching();\n        if (!wasBatching) {\n            gateway.startBatching();\n            gateway.payTransaction{value: msg.value}(msg.sender);\n        }\n\n        super.multicall(data);\n\n        if (!wasBatching) {\n            gateway.endBatching();\n        }\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Enable interactions\n    //----------------------------------------------------------------------------------------------\n\n    function enable(IBaseVault vault) public payable protected {\n        vault.setEndorsedOperator(msg.sender, true);\n    }\n\n    function disable(IBaseVault vault) external payable protected {\n        vault.setEndorsedOperator(msg.sender, false);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Deposit\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IVaultRouter\n    function requestDeposit(IAsyncVault vault, uint256 amount, address controller, address owner)\n        external\n        payable\n        protected\n    {\n        require(owner == msg.sender || owner == address(this), InvalidOwner());\n\n        VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n        if (owner == address(this)) {\n            _approveMax(vaultDetails.asset, address(vault));\n        }\n\n        _pay();\n        vault.requestDeposit(amount, controller, owner);\n    }\n\n    /// @inheritdoc IVaultRouter\n    function deposit(BaseSyncDepositVault vault, uint256 assets, address receiver, address owner)\n        external\n        payable\n        protected\n    {\n        require(owner == msg.sender || owner == address(this), InvalidOwner());\n        require(!vault.supportsInterface(type(IERC7540Deposit).interfaceId), NonSyncDepositVault());\n\n        VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n        SafeTransferLib.safeTransferFrom(vaultDetails.asset, owner, address(this), assets);\n        _approveMax(vaultDetails.asset, address(vault));\n\n        _pay();\n        vault.deposit(assets, receiver);\n    }\n\n    /// @inheritdoc IVaultRouter\n    function lockDepositRequest(IBaseVault vault, uint256 amount, address controller, address owner)\n        public\n        payable\n        protected\n    {\n        require(owner == msg.sender || owner == address(this), InvalidOwner());\n        require(vault.supportsInterface(type(IERC7540Deposit).interfaceId), NonAsyncVault());\n\n        lockedRequests[controller][vault] += amount;\n\n        VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n        SafeTransferLib.safeTransferFrom(vaultDetails.asset, owner, address(escrow), amount);\n\n        emit LockDepositRequest(vault, controller, owner, msg.sender, amount);\n    }\n\n    /// @inheritdoc IVaultRouter\n    function enableLockDepositRequest(IBaseVault vault, uint256 amount) external payable protected {\n        enable(vault);\n\n        VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n\n        uint256 assetBalance;\n        assetBalance = IERC20(vaultDetails.asset).balanceOf(msg.sender);\n\n        if (vaultDetails.isWrapper && assetBalance < amount) {\n            wrap(vaultDetails.asset, amount, address(this), msg.sender);\n            lockDepositRequest(vault, amount, msg.sender, address(this));\n        } else {\n            lockDepositRequest(vault, amount, msg.sender, msg.sender);\n        }\n    }\n\n    /// @inheritdoc IVaultRouter\n    function unlockDepositRequest(IBaseVault vault, address receiver) external payable protected {\n        uint256 lockedRequest = lockedRequests[msg.sender][vault];\n        require(lockedRequest != 0, NoLockedBalance());\n        lockedRequests[msg.sender][vault] = 0;\n\n        VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n        escrow.authTransferTo(vaultDetails.asset, receiver, lockedRequest);\n\n        emit UnlockDepositRequest(vault, msg.sender, receiver);\n    }\n\n    /// @inheritdoc IVaultRouter\n    function executeLockedDepositRequest(IAsyncVault vault, address controller) external payable protected {\n        uint256 lockedRequest = lockedRequests[controller][vault];\n        require(lockedRequest != 0, NoLockedRequest());\n        lockedRequests[controller][vault] = 0;\n\n        VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n        escrow.authTransferTo(vaultDetails.asset, address(this), lockedRequest);\n\n        _pay();\n        _approveMax(vaultDetails.asset, address(vault));\n        vault.requestDeposit(lockedRequest, controller, address(this));\n        emit ExecuteLockedDepositRequest(vault, controller, msg.sender);\n    }\n\n    /// @inheritdoc IVaultRouter\n    function claimDeposit(IAsyncVault vault, address receiver, address controller) external payable protected {\n        _canClaim(vault, receiver, controller);\n        uint256 maxMint = vault.maxMint(controller);\n        vault.mint(maxMint, receiver, controller);\n    }\n\n    /// @inheritdoc IVaultRouter\n    function cancelDepositRequest(IAsyncVault vault) external payable protected {\n        _pay();\n        vault.cancelDepositRequest(REQUEST_ID, msg.sender);\n    }\n\n    /// @inheritdoc IVaultRouter\n    function claimCancelDepositRequest(IAsyncVault vault, address receiver, address controller)\n        external\n        payable\n        protected\n    {\n        _canClaim(vault, receiver, controller);\n        vault.claimCancelDepositRequest(REQUEST_ID, receiver, controller);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Redeem\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IVaultRouter\n    function requestRedeem(IAsyncVault vault, uint256 amount, address controller, address owner)\n        external\n        payable\n        protected\n    {\n        require(owner == msg.sender || owner == address(this), InvalidOwner());\n        _pay();\n        vault.requestRedeem(amount, controller, owner);\n    }\n\n    /// @inheritdoc IVaultRouter\n    function claimRedeem(IBaseVault vault, address receiver, address controller) external payable protected {\n        _canClaim(vault, receiver, controller);\n        uint256 maxWithdraw = vault.maxWithdraw(controller);\n\n        VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n        if (vaultDetails.isWrapper && controller != msg.sender) {\n            // Auto-unwrap if permissionlessly claiming for another controller\n            vault.withdraw(maxWithdraw, address(this), controller);\n            unwrap(vaultDetails.asset, maxWithdraw, receiver);\n        } else {\n            vault.withdraw(maxWithdraw, receiver, controller);\n        }\n    }\n\n    /// @inheritdoc IVaultRouter\n    function cancelRedeemRequest(IAsyncVault vault) external payable protected {\n        _pay();\n        vault.cancelRedeemRequest(REQUEST_ID, msg.sender);\n    }\n\n    /// @inheritdoc IVaultRouter\n    function claimCancelRedeemRequest(IAsyncVault vault, address receiver, address controller)\n        external\n        payable\n        protected\n    {\n        _canClaim(vault, receiver, controller);\n        vault.claimCancelRedeemRequest(REQUEST_ID, receiver, controller);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // ERC-20 permits & wrapping\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IVaultRouter\n    function permit(address asset, address spender, uint256 assets, uint256 deadline, uint8 v, bytes32 r, bytes32 s)\n        external\n        payable\n        protected\n    {\n        try IERC20Permit(asset).permit(msg.sender, spender, assets, deadline, v, r, s) {} catch {}\n    }\n\n    function wrap(address wrapper, uint256 amount, address receiver, address owner) public payable protected {\n        require(owner == msg.sender || owner == address(this), InvalidOwner());\n        address underlying = IERC20Wrapper(wrapper).underlying();\n\n        amount = MathLib.min(amount, IERC20(underlying).balanceOf(owner));\n        require(amount != 0, ZeroBalance());\n        SafeTransferLib.safeTransferFrom(underlying, owner, address(this), amount);\n\n        _approveMax(underlying, wrapper);\n        require(IERC20Wrapper(wrapper).depositFor(receiver, amount), WrapFailed());\n    }\n\n    function unwrap(address wrapper, uint256 amount, address receiver) public payable protected {\n        amount = MathLib.min(amount, IERC20(wrapper).balanceOf(address(this)));\n        require(amount != 0, ZeroBalance());\n\n        require(IERC20Wrapper(wrapper).withdrawTo(receiver, amount), UnwrapFailed());\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // View methods\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IVaultRouter\n    function getVault(PoolId poolId, ShareClassId scId, address asset) external view returns (address) {\n        return IPoolManager(poolManager).shareToken(poolId, scId).vault(asset);\n    }\n\n    /// @inheritdoc IVaultRouter\n    function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256) {\n        return messageDispatcher.estimate(centrifugeId, payload);\n    }\n\n    /// @inheritdoc IVaultRouter\n    function hasPermissions(IBaseVault vault, address controller) external view returns (bool) {\n        return vault.isPermissioned(controller);\n    }\n\n    /// @inheritdoc IVaultRouter\n    function isEnabled(IBaseVault vault, address controller) public view returns (bool) {\n        return vault.isOperator(controller, address(this));\n    }\n\n    /// @notice Gives the max approval to `to` for spending the given `asset` if not already approved.\n    /// @dev    Assumes that `type(uint256).max` is large enough to never have to increase the allowance again.\n    function _approveMax(address asset, address spender) internal {\n        if (IERC20(asset).allowance(address(this), spender) == 0) {\n            SafeTransferLib.safeApprove(asset, spender, type(uint256).max);\n        }\n    }\n\n    /// @notice Send native tokens to the gateway for transaction payment if it's not in a multicall.\n    function _pay() internal {\n        if (!gateway.isBatching()) {\n            gateway.payTransaction{value: msg.value}(msg.sender);\n        }\n    }\n\n    /// @notice Ensures msg.sender is either the controller, or can permissionlessly claim\n    ///         on behalf of the controller.\n    function _canClaim(IBaseVault vault, address receiver, address controller) internal view {\n        require(controller == msg.sender || (controller == receiver && isEnabled(vault, controller)), InvalidSender());\n    }\n}\n"
    },
    "src/vaults/factories/AsyncVaultFactory.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {AsyncVault} from \"src/vaults/AsyncVault.sol\";\nimport {IVaultFactory} from \"src/vaults/interfaces/factories/IVaultFactory.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IAsyncRequestManager} from \"src/vaults/interfaces/investments/IAsyncRequestManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\n/// @title  ERC7540 Vault Factory\n/// @dev    Utility for deploying new vault contracts\ncontract AsyncVaultFactory is Auth, IVaultFactory {\n    address public immutable root;\n    IAsyncRequestManager public immutable asyncRequestManager;\n\n    constructor(address root_, IAsyncRequestManager asyncRequestManager_, address deployer) Auth(deployer) {\n        root = root_;\n        asyncRequestManager = asyncRequestManager_;\n    }\n\n    /// @inheritdoc IVaultFactory\n    function newVault(\n        PoolId poolId,\n        ShareClassId scId,\n        address asset,\n        uint256 tokenId,\n        IShareToken token,\n        address[] calldata wards_\n    ) public auth returns (IBaseVault) {\n        require(tokenId == 0, UnsupportedTokenId());\n        AsyncVault vault = new AsyncVault(poolId, scId, asset, token, root, asyncRequestManager);\n\n        vault.rely(root);\n        vault.rely(address(asyncRequestManager));\n        uint256 wardsCount = wards_.length;\n        for (uint256 i; i < wardsCount; i++) {\n            vault.rely(wards_[i]);\n        }\n\n        vault.deny(address(this));\n        return vault;\n    }\n}\n"
    },
    "src/vaults/factories/PoolEscrowFactory.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nimport {IPoolEscrowProvider, IPoolEscrowFactory} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IPoolEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {PoolEscrow} from \"src/vaults/Escrow.sol\";\n\ncontract PoolEscrowFactory is Auth, IPoolEscrowFactory {\n    address public immutable root;\n\n    address public gateway;\n    address public poolManager;\n    address public balanceSheet;\n    address public asyncRequestManager;\n\n    constructor(address root_, address deployer) Auth(deployer) {\n        root = root_;\n    }\n\n    /// @inheritdoc IPoolEscrowFactory\n    function file(bytes32 what, address data) external auth {\n        if (what == \"poolManager\") poolManager = data;\n        else if (what == \"gateway\") gateway = data;\n        else if (what == \"balanceSheet\") balanceSheet = data;\n        else if (what == \"asyncRequestManager\") asyncRequestManager = data;\n        else revert FileUnrecognizedParam();\n        emit File(what, data);\n    }\n\n    /// @inheritdoc IPoolEscrowFactory\n    function newEscrow(PoolId poolId) public auth returns (IPoolEscrow) {\n        PoolEscrow escrow_ = new PoolEscrow{salt: bytes32(uint256(poolId.raw()))}(poolId, address(this));\n\n        escrow_.rely(root);\n        escrow_.rely(gateway);\n        escrow_.rely(poolManager);\n        escrow_.rely(balanceSheet);\n        escrow_.rely(asyncRequestManager);\n\n        escrow_.deny(address(this));\n\n        emit DeployPoolEscrow(poolId, address(escrow_));\n        return IPoolEscrow(escrow_);\n    }\n\n    /// @inheritdoc IPoolEscrowProvider\n    function escrow(PoolId poolId) external view returns (IPoolEscrow) {\n        bytes32 salt = bytes32(uint256(poolId.raw()));\n        bytes32 hash = keccak256(\n            abi.encodePacked(\n                bytes1(0xff),\n                address(this),\n                salt,\n                keccak256(abi.encodePacked(type(PoolEscrow).creationCode, abi.encode(poolId, address(this))))\n            )\n        );\n\n        return IPoolEscrow(address(uint160(uint256(hash))));\n    }\n}\n"
    },
    "src/vaults/factories/SyncDepositVaultFactory.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {SyncDepositVault} from \"src/vaults/SyncDepositVault.sol\";\nimport {IVaultFactory} from \"src/vaults/interfaces/factories/IVaultFactory.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\nimport {ISyncDepositManager} from \"src/vaults/interfaces/investments/ISyncDepositManager.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\n/// @title  Sync Vault Factory\n/// @dev    Utility for deploying new vault contracts\ncontract SyncDepositVaultFactory is Auth, IVaultFactory {\n    address public immutable root;\n    ISyncDepositManager public immutable syncDepositManager;\n    IAsyncRedeemManager public immutable asyncRedeemManager;\n\n    constructor(\n        address root_,\n        ISyncDepositManager syncDepositManager_,\n        IAsyncRedeemManager asyncRedeemManager_,\n        address deployer\n    ) Auth(deployer) {\n        root = root_;\n        syncDepositManager = syncDepositManager_;\n        asyncRedeemManager = asyncRedeemManager_;\n    }\n\n    /// @inheritdoc IVaultFactory\n    function newVault(\n        PoolId poolId,\n        ShareClassId scId,\n        address asset,\n        uint256 tokenId,\n        IShareToken token,\n        address[] calldata wards_\n    ) public auth returns (IBaseVault) {\n        require(tokenId == 0, UnsupportedTokenId());\n        SyncDepositVault vault =\n            new SyncDepositVault(poolId, scId, asset, token, root, syncDepositManager, asyncRedeemManager);\n\n        vault.rely(root);\n        vault.rely(address(syncDepositManager));\n        vault.rely(address(asyncRedeemManager));\n\n        uint256 wardsCount = wards_.length;\n        for (uint256 i; i < wardsCount; i++) {\n            vault.rely(wards_[i]);\n        }\n\n        vault.deny(address(this));\n        return vault;\n    }\n}\n"
    },
    "src/vaults/factories/TokenFactory.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nimport {ShareToken} from \"src/vaults/token/ShareToken.sol\";\nimport {ITokenFactory} from \"src/vaults/interfaces/factories/ITokenFactory.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\n/// @title  Share Token Factory\n/// @dev    Utility for deploying new share class token contracts\n///         Ensures the addresses are deployed at a deterministic address\n///         based on the pool id and share class id.\ncontract TokenFactory is Auth, ITokenFactory {\n    address public immutable root;\n\n    constructor(address _root, address deployer) Auth(deployer) {\n        root = _root;\n    }\n\n    /// @inheritdoc ITokenFactory\n    function newToken(\n        string memory name,\n        string memory symbol,\n        uint8 decimals,\n        bytes32 salt,\n        address[] calldata tokenWards\n    ) public auth returns (IShareToken) {\n        ShareToken token = new ShareToken{salt: salt}(decimals);\n\n        token.file(\"name\", name);\n        token.file(\"symbol\", symbol);\n\n        token.rely(root);\n        uint256 wardsCount = tokenWards.length;\n        for (uint256 i; i < wardsCount; i++) {\n            token.rely(tokenWards[i]);\n        }\n        token.deny(address(this));\n\n        return token;\n    }\n\n    /// @inheritdoc ITokenFactory\n    function getAddress(uint8 decimals, bytes32 salt) external view returns (address) {\n        bytes32 hash = keccak256(\n            abi.encodePacked(\n                bytes1(0xff),\n                address(this),\n                salt,\n                keccak256(abi.encodePacked(type(ShareToken).creationCode, abi.encode(decimals)))\n            )\n        );\n\n        return address(uint160(uint256(hash)));\n    }\n}\n"
    },
    "src/vaults/interfaces/IBalanceSheet.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18, d18} from \"src/misc/types/D18.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\n\nstruct QueueAmount {\n    // Issuances of shares / deposits of assets\n    uint128 increase;\n    // Revocations of shares / withdraws of assets\n    uint128 decrease;\n}\n\ninterface IBalanceSheet {\n    // --- Events ---\n    event File(bytes32 indexed what, address data);\n    event UpdateManager(PoolId indexed poolId, address who, bool canManage);\n    event Withdraw(\n        PoolId indexed poolId,\n        ShareClassId indexed scId,\n        address asset,\n        uint256 tokenId,\n        address receiver,\n        uint128 amount,\n        D18 pricePoolPerAsset\n    );\n    event Deposit(\n        PoolId indexed poolId,\n        ShareClassId indexed scId,\n        address asset,\n        uint256 tokenId,\n        address provider,\n        uint128 amount,\n        D18 pricePoolPerAsset\n    );\n    event Issue(PoolId indexed poolId, ShareClassId indexed scId, address to, D18 pricePoolPerShare, uint128 shares);\n    event Revoke(PoolId indexed poolId, ShareClassId indexed scId, address from, D18 pricePoolPerShare, uint128 shares);\n\n    // --- Errors ---\n    error FileUnrecognizedParam();\n    error CannotTransferFromEndorsedContract();\n\n    /// @notice Overloaded increase with asset transfer\n    function deposit(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, address provider, uint128 amount)\n        external;\n\n    function noteDeposit(\n        PoolId poolId,\n        ShareClassId scId,\n        address asset,\n        uint256 tokenId,\n        address provider,\n        uint128 amount\n    ) external;\n\n    function withdraw(\n        PoolId poolId,\n        ShareClassId scId,\n        address asset,\n        uint256 tokenId,\n        address receiver,\n        uint128 amount\n    ) external;\n\n    function issue(PoolId poolId, ShareClassId scId, address to, uint128 shares) external;\n\n    function revoke(PoolId poolId, ShareClassId scId, address from, uint128 shares) external;\n\n    function noteRevoke(PoolId poolId, ShareClassId scId, address from, uint128 shares) external;\n\n    function transferSharesFrom(PoolId poolId, ShareClassId scId, address from, address to, uint256 amount) external;\n\n    function overridePricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, D18 value) external;\n\n    function overridePricePoolPerShare(PoolId poolId, ShareClassId scId, D18 value) external;\n}\n"
    },
    "src/vaults/interfaces/IBaseVaults.sol": {
      "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.5.0;\n\nenum VaultKind {\n    /// @dev Refers to AsyncVault\n    Async,\n    /// @dev not yet supported\n    Sync,\n    /// @dev Refers to SyncDepositVault\n    SyncDepositAsyncRedeem\n}\n\nimport {IERC7575, IERC165} from \"src/misc/interfaces/IERC7575.sol\";\nimport {\n    IERC7540Operator,\n    IERC7714,\n    IERC7741,\n    IERC7540Redeem,\n    IERC7887Redeem,\n    IERC7887Deposit,\n    IERC7540Deposit\n} from \"src/misc/interfaces/IERC7540.sol\";\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\n\n/// @notice Interface for the all vault contracts\n/// @dev Must be implemented by all vaults\ninterface IBaseVault is IERC7540Operator, IERC7741, IERC7714, IERC7575, IRecoverable {\n    error FileUnrecognizedParam();\n    error NotEndorsed();\n    error CannotSetSelfAsOperator();\n    error ExpiredAuthorization();\n    error AlreadyUsedAuthorization();\n    error InvalidAuthorization();\n    error InvalidController();\n    error InsufficientBalance();\n    error RequestRedeemFailed();\n    error TransferFromFailed();\n\n    event File(bytes32 indexed what, address data);\n\n    /// @notice Identifier of the Centrifuge pool\n    function poolId() external view returns (PoolId);\n\n    /// @notice Identifier of the share class of the Centrifuge pool\n    function scId() external view returns (ShareClassId);\n\n    /// @notice Set msg.sender as operator of owner, to `approved` status\n    /// @dev    MUST be called by endorsed sender\n    function setEndorsedOperator(address owner, bool approved) external;\n\n    /// @notice Returns the base investment manager contract handling the vault.\n    /// @dev This naming MUST NOT change due to requirements of legacy vaults (v2)\n    /// @return IBaseRequestManager The address of the manager contract that is between vault and gateway\n    function manager() external view returns (IBaseRequestManager);\n\n    /// @notice Checks whether the vault is partially (a)synchronous.\n    ///\n    /// @return vaultKind_ The kind of the vault\n    function vaultKind() external view returns (VaultKind vaultKind_);\n}\n\n/**\n * @title  IAsyncRedeemVault\n * @dev    This is the specific set of interfaces used by the Centrifuge implementation of ERC7540,\n *         as a fully asynchronous Vault, with cancellation support, and authorize operator signature support.\n */\ninterface IAsyncRedeemVault is IERC7540Redeem, IERC7887Redeem, IBaseVault {\n    event RedeemClaimable(address indexed controller, uint256 indexed requestId, uint256 assets, uint256 shares);\n    event CancelRedeemClaimable(address indexed controller, uint256 indexed requestId, uint256 shares);\n\n    /// @notice Callback when a redeem Request is triggered externally;\n    function onRedeemRequest(address controller, address owner, uint256 shares) external;\n\n    /// @notice Callback when a redeem Request becomes claimable\n    function onRedeemClaimable(address owner, uint256 assets, uint256 shares) external;\n\n    /// @notice Callback when a claim redeem Request becomes claimable\n    function onCancelRedeemClaimable(address owner, uint256 shares) external;\n\n    /// @notice Retrieve the asynchronous redeem manager\n    function asyncRedeemManager() external view returns (IAsyncRedeemManager);\n}\n\ninterface IAsyncVault is IERC7540Deposit, IERC7887Deposit, IAsyncRedeemVault {\n    event DepositClaimable(address indexed controller, uint256 indexed requestId, uint256 assets, uint256 shares);\n    event CancelDepositClaimable(address indexed controller, uint256 indexed requestId, uint256 assets);\n\n    error InvalidOwner();\n    error RequestDepositFailed();\n\n    /// @notice Callback when a deposit Request becomes claimable\n    function onDepositClaimable(address owner, uint256 assets, uint256 shares) external;\n\n    /// @notice Callback when a claim deposit Request becomes claimable\n    function onCancelDepositClaimable(address owner, uint256 assets) external;\n}\n"
    },
    "src/vaults/interfaces/IEscrow.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IRecoverable} from \"src/misc/Recoverable.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\n/// @title  Escrow for holding assets\ninterface IEscrow {\n    // --- Events ---\n    /// @notice Emitted when an authTransferTo is made\n    /// @dev Needed as allowances increase attack surface\n    event AuthTransferTo(address indexed asset, uint256 indexed tokenId, address reciver, uint256 value);\n\n    /// @notice Emitted when the escrow has insufficient balance for an action - virtual or actual balance\n    error InsufficientBalance(address asset, uint256 tokenId, uint256 value, uint256 balance);\n\n    /// @notice\n    function authTransferTo(address asset, uint256 tokenId, address receiver, uint256 value) external;\n\n    /// @notice\n    function authTransferTo(address asset, address receiver, uint256 value) external;\n}\n\nstruct Holding {\n    uint128 total;\n    uint128 reserved;\n}\n\n/// @title PerPoolEscrow separating funds by pool and share class\ninterface IPoolEscrow is IEscrow, IRecoverable {\n    // --- Events ---\n    /// @notice Emitted when a deposit is made\n    /// @param asset The address of the deposited asset\n    /// @param tokenId The id of the asset - 0 for ERC20\n    /// @param poolId The id of the pool\n    /// @param scId The id of the share class\n    /// @param value The amount deposited\n    event Deposit(\n        address indexed asset, uint256 indexed tokenId, PoolId indexed poolId, ShareClassId scId, uint128 value\n    );\n\n    /// @notice Emitted when an amount is reserved\n    /// @param asset The address of the reserved asset\n    /// @param tokenId The id of the asset - 0 for ERC20\n    /// @param poolId The id of the pool\n    /// @param scId The id of the share class\n    /// @param value The delta amount reserved\n    /// @param value The new absolute amount reserved\n    event IncreaseReserve(\n        address indexed asset,\n        uint256 indexed tokenId,\n        PoolId indexed poolId,\n        ShareClassId scId,\n        uint256 delta,\n        uint128 value\n    );\n\n    /// @notice Emitted when an amount is unreserved\n    /// @param asset The address of the reserved asset\n    /// @param tokenId The id of the asset - 0 for ERC20\n    /// @param poolId The id of the pool\n    /// @param scId The id of the share class\n    /// @param value The delta amount unreserved\n    /// @param value The new absolute amount reserved\n    event DecreaseReserve(\n        address indexed asset,\n        uint256 indexed tokenId,\n        PoolId indexed poolId,\n        ShareClassId scId,\n        uint256 delta,\n        uint128 value\n    );\n\n    /// @notice Emitted when a withdraw is made\n    /// @param asset The address of the withdrawn asset\n    /// @param tokenId The id of the asset - 0 for ERC20\n    /// @param poolId The id of the pool\n    /// @param scId The id of the share class\n    /// @param value The amount withdrawn\n    event Withdraw(\n        address indexed asset, uint256 indexed tokenId, PoolId indexed poolId, ShareClassId scId, uint128 value\n    );\n\n    // --- Errors ---\n    /// @notice Dispatched when the balance of the escrow did not increase sufficiently\n    error InsufficientDeposit();\n\n    /// @notice Dispatched when the outstanding reserved amount is insufficient for the decrease\n    error InsufficientReservedAmount();\n\n    // --- Functions ---\n    /// @notice Deposits `value` of `asset` in underlying `poolId` and given `scId`\n    ///\n    /// @dev NOTE: Must ensure balance sufficiency, i.e. that the depositing amount does not exceed the balance of\n    /// escrow\n    ///\n    /// @param scId The id of the share class\n    /// @param asset The address of the asset to be deposited\n    /// @param tokenId The id of the asset - 0 for ERC20\n    /// @param value The amount to deposit\n    function deposit(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external;\n\n    /// @notice Withdraws `value` of `asset` in underlying `poolId` and given `scId`\n    /// @dev MUST ensure that reserved amounts are not withdrawn\n    /// @param scId The id of the share class\n    /// @param asset The address of the asset to be withdrawn\n    /// @param tokenId The id of the asset - 0 for ERC20\n    /// @param value The amount to withdraw\n    function withdraw(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external;\n\n    /// @notice Increases the reserved amount of `value` for `asset` in underlying `poolId` and given `scId`\n    /// @dev MUST prevent the reserved amount from being withdrawn\n    /// @param scId The id of the share class\n    /// @param asset The address of the asset to be reserved\n    /// @param tokenId The id of the asset - 0 for ERC20\n    /// @param value The amount to reserve\n    function reserveIncrease(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external;\n\n    /// @notice Decreases the reserved amount of `value` for `asset` in underlying `poolId` and given `scId`\n    /// @dev MUST fail if `value` is greater than the current reserved amount\n    /// @param scId The id of the share class\n    /// @param asset The address of the asset to be reserved\n    /// @param tokenId The id of the asset - 0 for ERC20\n    /// @param value The amount to decrease\n    function reserveDecrease(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external;\n\n    /// @notice Provides the available balance of `asset` in underlying `poolId` and given `scId`\n    /// @dev MUST return the balance minus the reserved amount\n    /// @param scId The id of the share class\n    /// @param asset The address of the asset to be checked\n    /// @param tokenId The id of the asset - 0 for ERC20\n    /// @return The available balance\n    function availableBalanceOf(ShareClassId scId, address asset, uint256 tokenId) external view returns (uint128);\n}\n"
    },
    "src/vaults/interfaces/IPoolManager.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18, d18} from \"src/misc/types/D18.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\n\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IVaultFactory} from \"src/vaults/interfaces/factories/IVaultFactory.sol\";\nimport {IBaseVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\n/// @dev Centrifuge pools\nstruct Pool {\n    uint256 createdAt;\n    mapping(ShareClassId scId => ShareClassDetails) shareClasses;\n}\n\n/// @dev Each Centrifuge pool is associated to 1 or more shar classes\nstruct ShareClassDetails {\n    IShareToken shareToken;\n    /// @dev Each share class has an individual price per share class unit in pool denomination (POOL_UNIT/SHARE_UNIT)\n    Price pricePoolPerShare;\n    /// @dev Each share class can have multiple vaults deployed,\n    ///      multiple vaults can be linked to the same asset.\n    ///      A vault in this storage DOES NOT mean the vault can be used\n    mapping(address asset => mapping(uint256 tokenId => IBaseVault[])) vaults;\n    /// @dev For each share class, we store the price per pool unit in asset denomination (POOL_UNIT/ASSET_UNIT)\n    mapping(address asset => mapping(uint256 tokenId => Price)) pricePoolPerAsset;\n}\n\n/// @dev Price struct that contains a price, the timestamp at which it was computed and the max age of the price.\nstruct Price {\n    uint128 price;\n    uint64 computedAt;\n    uint64 maxAge;\n}\n\n/// @dev Checks if a price is valid. Returns false if price is 0 or computedAt is 0. Otherwise checks for block\n/// timestamp <= computedAt + maxAge\nfunction isValid(Price memory price) view returns (bool) {\n    if (price.computedAt != 0 && price.price != 0) {\n        return block.timestamp <= price.validUntil();\n    } else {\n        return false;\n    }\n}\n\n/// @dev Computes the timestamp until the price is valid. Saturates at uint64.MAX.\nfunction validUntil(Price memory price) pure returns (uint64) {\n    unchecked {\n        uint64 validUntil_ = price.computedAt + price.maxAge;\n        if (validUntil_ < price.computedAt) {\n            return type(uint64).max;\n        }\n        return validUntil_;\n    }\n}\n\n/// @dev Retrieves the price as an D18 from the struct\nfunction asPrice(Price memory price) pure returns (D18) {\n    return d18(price.price);\n}\n\nusing {isValid, asPrice, validUntil} for Price global;\n\nstruct VaultDetails {\n    /// @dev AssetId of the asset\n    AssetId assetId;\n    /// @dev Address of the asset\n    address asset;\n    /// @dev TokenId of the asset - zero if asset is ERC20, non-zero if asset is ERC6909\n    uint256 tokenId;\n    /// @dev Whether this wrapper conforms to the IERC20Wrapper interface\n    bool isWrapper;\n    /// @dev Whether the vault is linked to a share class atm\n    bool isLinked;\n}\n\nstruct AssetIdKey {\n    /// @dev The address of the asset\n    address asset;\n    /// @dev The ERC6909 token id or 0, if the underlying asset is an ERC20\n    uint256 tokenId;\n}\n\ninterface IPoolManager {\n    event File(bytes32 indexed what, address data);\n    event RegisterAsset(\n        AssetId indexed assetId,\n        address indexed asset,\n        uint256 indexed tokenId,\n        string name,\n        string symbol,\n        uint8 decimals\n    );\n    event File(bytes32 indexed what, address factory, bool status);\n    event AddPool(PoolId indexed poolId);\n    event AddShareClass(PoolId indexed poolId, ShareClassId indexed scId, IShareToken token);\n    event DeployVault(\n        PoolId indexed poolId,\n        ShareClassId indexed scId,\n        address indexed asset,\n        uint256 tokenId,\n        IVaultFactory factory,\n        IBaseVault vault,\n        VaultKind kind\n    );\n    event PriceUpdate(\n        PoolId indexed poolId,\n        ShareClassId indexed scId,\n        address indexed asset,\n        uint256 tokenId,\n        uint256 price,\n        uint64 computedAt\n    );\n    event PriceUpdate(PoolId indexed poolId, ShareClassId indexed scId, uint256 price, uint64 computedAt);\n    event TransferShares(\n        uint16 centrifugeId,\n        PoolId indexed poolId,\n        ShareClassId indexed scId,\n        address indexed sender,\n        bytes32 destinationAddress,\n        uint128 amount\n    );\n    event UpdateContract(PoolId indexed poolId, ShareClassId indexed scId, address target, bytes payload);\n    event LinkVault(\n        PoolId indexed poolId, ShareClassId indexed scId, address indexed asset, uint256 tokenId, IBaseVault vault\n    );\n    event UnlinkVault(\n        PoolId indexed poolId, ShareClassId indexed scId, address indexed asset, uint256 tokenId, IBaseVault vault\n    );\n    event UpdateMaxSharePriceAge(PoolId indexed poolId, ShareClassId indexed scId, uint64 maxPriceAge);\n    event UpdateMaxAssetPriceAge(\n        PoolId indexed poolId, ShareClassId indexed scId, address indexed asset, uint256 tokenId, uint64 maxPriceAge\n    );\n\n    error FileUnrecognizedParam();\n    error TooFewDecimals();\n    error TooManyDecimals();\n    error PoolAlreadyAdded();\n    error InvalidPool();\n    error ShareClassAlreadyRegistered();\n    error InvalidHook();\n    error OldMetadata();\n    error CannotSetOlderPrice();\n    error OldHook();\n    error UnknownVault();\n    error UnknownAsset();\n    error MalformedVaultUpdateMessage();\n    error UnknownToken();\n    error InvalidFactory();\n    error InvalidPrice();\n    error AssetMissingDecimals();\n    error ShareTokenDoesNotExist();\n    error LocalTransferNotAllowed();\n    error CrossChainTransferNotAllowed();\n    error ShareTokenTransferFailed();\n    error TransferFromFailed();\n\n    /// @notice Returns the asset address and tokenId associated with a given asset id.\n    /// @dev Reverts if asset id does not exist\n    ///\n    /// @param assetId The underlying internal uint128 assetId.\n    /// @return asset The address of the asset linked to the given asset id.\n    /// @return tokenId The token id corresponding to the asset, i.e. zero if ERC20 or non-zero if ERC6909.\n    function idToAsset(AssetId assetId) external view returns (address asset, uint256 tokenId);\n\n    /// @notice Returns assetId given the asset address and tokenId.\n    /// @dev Reverts if asset id does not exist\n    ///\n    /// @param asset The address of the asset linked to the given asset id.\n    /// @param tokenId The token id corresponding to the asset, i.e. zero if ERC20 or non-zero if ERC6909.\n    /// @return assetId The underlying internal uint128 assetId.\n    function assetToId(address asset, uint256 tokenId) external view returns (AssetId assetId);\n\n    /// @notice Updates a contract parameter\n    /// @param what Accepts a bytes32 representation of 'gateway', 'investmentManager', 'tokenFactory',\n    ///                'vaultFactory', or 'gasService'\n    function file(bytes32 what, address data) external;\n\n    /// @notice Updates a contract parameter\n    /// @param what Accepts a bytes32 representation of 'vaultFactory'\n    function file(bytes32 what, address factory, bool status) external;\n\n    /// @notice transfers share class tokens to a cross-chain recipient address\n    /// @dev    To transfer to evm chains, pad a 20 byte evm address with 12 bytes of 0\n    /// @param  centrifugeId The destination chain id\n    /// @param  poolId The centrifuge pool id\n    /// @param  scId The share class id\n    /// @param  receiver A bytes32 representation of the receiver address\n    /// @param  amount The amount of tokens to transfer\n    function transferShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 receiver, uint128 amount)\n        external\n        payable;\n\n    /// @notice Registers an ERC-20 or ERC-6909 asset in another chain.\n    /// @dev `decimals()` MUST return a `uint8` value between 2 and 18.\n    /// @dev `name()` and `symbol()` MAY return no values.\n    ///\n    /// @param centrifugeId The centrifuge id of chain to where the shares are transferred\n    /// @param asset The address of the asset to be registered\n    /// @param tokenId The token id corresponding to the asset, i.e. zero if ERC20 or non-zero if ERC6909.\n    /// @return assetId The underlying internal uint128 assetId.\n    function registerAsset(uint16 centrifugeId, address asset, uint256 tokenId)\n        external\n        payable\n        returns (AssetId assetId);\n\n    /// @notice Deploys a new vault\n    ///\n    /// @param poolId The pool id\n    /// @param scId The share class id\n    /// @param assetId The asset id for which we want to deploy a vault\n    /// @param factory The address of the corresponding vault factory\n    /// @return address The address of the deployed vault\n    function deployVault(PoolId poolId, ShareClassId scId, AssetId assetId, IVaultFactory factory)\n        external\n        returns (IBaseVault);\n\n    /// @notice Links a deployed vault to the given pool, share class and asset.\n    ///\n    /// @param poolId The pool id\n    /// @param scId The share class id\n    /// @param assetId The asset id for which we want to deploy a vault\n    /// @param vault The address of the deployed vault\n    function linkVault(PoolId poolId, ShareClassId scId, AssetId assetId, IBaseVault vault) external;\n\n    /// @notice Removes the link between a vault and the given pool, share class and asset.\n    ///\n    /// @param poolId The pool id\n    /// @param scId The share class id\n    /// @param assetId The asset id for which we want to deploy a vault\n    /// @param vault The address of the deployed vault\n    function unlinkVault(PoolId poolId, ShareClassId scId, AssetId assetId, IBaseVault vault) external;\n\n    /// @notice Returns whether the given pool id is active\n    function isPoolActive(PoolId poolId) external view returns (bool);\n\n    /// @notice Returns the share class token for a given pool and share class id.\n    /// @dev Reverts if share class does not exists\n    ///\n    /// @param poolId The pool id\n    /// @param scId The share class id\n    /// @return address The address of the share token\n    function shareToken(PoolId poolId, ShareClassId scId) external view returns (IShareToken);\n\n    /// @notice Function to get the details of a vault\n    /// @dev    Reverts if vault does not exist\n    ///\n    /// @param vault The address of the vault to be checked for\n    /// @return details The details of the vault including the underlying asset address, token id, asset id\n    function vaultDetails(IBaseVault vault) external view returns (VaultDetails memory details);\n\n    /// @notice Checks whether a given asset-vault pair is eligible for investing into a share class of a pool\n    ///\n    /// @param poolId The pool id\n    /// @param scId The share class id\n    /// @param asset The address of the asset\n    /// @param vault The address of the vault\n    /// @return bool Whether vault is to a share class\n    function isLinked(PoolId poolId, ShareClassId scId, address asset, IBaseVault vault) external view returns (bool);\n\n    /// @notice Returns the price per share for a given pool, share class, asset, and asset id. The provided price is\n    /// defined as ASSET_UNIT/SHARE_UNIT.\n    /// @dev Conditionally checks if price is valid.\n    ///\n    /// @dev NOTE: Should never be used for calculating amounts due to precision loss. Instead, please refer to\n    /// conversion relying on pricePoolPerShare and pricePoolPerAsset. See PricingLib for more information.\n    ///\n    /// @param poolId The pool id\n    /// @param scId The share class id\n    /// @param assetId The asset id for which we want to know the ASSET_UNIT/SHARE_UNIT price\n    /// @param checkValidity Whether to check if the price is valid\n    /// @return price The asset price per share\n    function priceAssetPerShare(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n        external\n        view\n        returns (D18 price);\n\n    /// @notice Returns the price per share for a given pool and share class. The Provided price is defined as\n    /// POOL_UNIT/SHARE_UNIT.\n    /// @dev Conditionally checks if price is valid.\n    ///\n    /// @param poolId The pool id\n    /// @param scId The share class id\n    /// @param checkValidity Whether to check if the price is valid\n    /// @return price The pool price per share\n    function pricePoolPerShare(PoolId poolId, ShareClassId scId, bool checkValidity)\n        external\n        view\n        returns (D18 price);\n\n    /// @notice Returns the price per asset for a given pool, share class and the underlying asset id. The Provided\n    /// price is defined as POOL_UNIT/ASSET_UNIT.\n    /// @dev Conditionally checks if price is valid.\n    ///\n    /// @param poolId The pool id\n    /// @param scId The share class id\n    /// @param assetId The asset id for which we want to know the POOL_UNIT/ASSET_UNIT.\n    /// @param checkValidity Whether to check if the price is valid\n    /// @return price The pool price per asset unit\n    function pricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n        external\n        view\n        returns (D18 price);\n\n    /// @notice Returns the both prices per pool for a given pool, share class and the underlying asset id. The Provided\n    /// prices is defined as POOL_UNIT/ASSET_UNIT and POOL_UNIT/SHARE_UNIT.\n    /// @dev Conditionally checks if prices are valid.\n    ///\n    /// @param poolId The pool id\n    /// @param scId The share class id\n    /// @param assetId The asset id for which we want to know pool price per asset\n    /// @param checkValidity Whether to check if the prices are valid\n    /// @return pricePoolPerAsset The pool price per asset unit, i.e. POOL_UNIT/ASSET_UNIT\n    /// @return pricePoolPerShare The pool price per share unit, i.e. POOL_UNIT/SHARE_UNIT\n    function pricesPoolPer(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n        external\n        view\n        returns (D18 pricePoolPerAsset, D18 pricePoolPerShare);\n\n    /// @notice Returns the age related markers for a share class price\n    ///\n    /// @param poolId The pool id\n    /// @param scId The share class id\n    /// @return computedAt The timestamp when this price was computed\n    /// @return maxAge The maximum age this price is allowed to have\n    /// @return validUntil The timestamp until this price is valid\n    function markersPricePoolPerShare(PoolId poolId, ShareClassId scId)\n        external\n        view\n        returns (uint64 computedAt, uint64 maxAge, uint64 validUntil);\n\n    /// @notice Returns the age related markers for an asset price\n    ///\n    /// @param poolId The pool id\n    /// @param scId The share class id\n    /// @param assetId The asset id for which we want to know pool price per asset\n    /// @return computedAt The timestamp when this price was computed\n    /// @return maxAge The maximum age this price is allowed to have\n    /// @return validUntil The timestamp until this price is valid\n    function markersPricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId)\n        external\n        view\n        returns (uint64 computedAt, uint64 maxAge, uint64 validUntil);\n}\n"
    },
    "src/vaults/interfaces/IUpdateContract.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\ninterface IUpdateContract {\n    error UnknownUpdateContractType();\n\n    /// @notice Triggers an update on the target contract.\n    /// @param  poolId The centrifuge pool id\n    /// @param  scId The share class id\n    /// @param  payload The payload to be processed by the target address\n    function update(PoolId poolId, ShareClassId scId, bytes calldata payload) external;\n}\n"
    },
    "src/vaults/interfaces/IVaultRouter.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IMulticall} from \"src/misc/interfaces/IMulticall.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {IBaseVault, IAsyncVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {BaseSyncDepositVault} from \"src/vaults/BaseVaults.sol\";\n\ninterface IVaultRouter is IMulticall {\n    // --- Events ---\n    event LockDepositRequest(\n        IBaseVault indexed vault, address indexed controller, address indexed owner, address sender, uint256 amount\n    );\n    event UnlockDepositRequest(IBaseVault indexed vault, address indexed controller, address indexed receiver);\n    event ExecuteLockedDepositRequest(IBaseVault indexed vault, address indexed controller, address sender);\n\n    error InvalidOwner();\n    error NoLockedBalance();\n    error NoLockedRequest();\n    error ZeroBalance();\n    error WrapFailed();\n    error UnwrapFailed();\n    error InvalidSender();\n    error NonSyncDepositVault();\n    error NonAsyncVault();\n\n    /// @notice Check how much of the `vault`'s asset is locked for the current `controller`.\n    /// @dev    This is a getter method\n    function lockedRequests(address controller, IBaseVault vault) external view returns (uint256 amount);\n\n    // --- Manage permissionless claiming ---\n    /// @notice Enable permissionless claiming\n    /// @dev    After this is called, anyone can claim tokens to msg.sender.\n    ///         Even any requests submitted directly to the vault (not through the VaultRouter) will be\n    ///         permissionlessly claimable through the VaultRouter, until `disable()` is called.\n    function enable(IBaseVault vault) external payable;\n\n    /// @notice Disable permissionless claiming\n    function disable(IBaseVault vault) external payable;\n\n    // --- Deposit ---\n    /// @notice Check `IERC7540Deposit.requestDeposit`.\n    /// @dev    This adds a mandatory prepayment for all the costs that will incur during the transaction.\n    ///         The caller must call `VaultRouter.estimate` to get estimates how much the deposit will cost.\n    ///\n    /// @param  vault The vault to deposit into\n    /// @param  amount Check @param IERC7540Deposit.requestDeposit.assets\n    /// @param  controller Check @param IERC7540Deposit.requestDeposit.controller\n    /// @param  owner Check @param IERC7540Deposit.requestDeposit.owner\n    function requestDeposit(IAsyncVault vault, uint256 amount, address controller, address owner) external payable;\n\n    /// @notice Check `IERC4626.deposit`.\n    /// @dev    This adds a mandatory prepayment for all the costs that will incur during the transaction.\n    ///         The caller must call `VaultRouter.estimate` to get estimates how much the deposit will cost.\n    ///\n    /// @param  vault The vault to deposit into\n    /// @param  assets Check @param IERC4626.deposit.assets\n    /// @param  receiver Check @param IERC4626.deposit.receiver\n    /// @param  owner User from which to transfer the assets, either msg.sender or the VaultRouter\n    function deposit(BaseSyncDepositVault vault, uint256 assets, address receiver, address owner) external payable;\n\n    /// @notice Locks `amount` of `vault`'s asset in an escrow before actually sending a deposit LockDepositRequest\n    ///         There are users that would like to interact with the protocol but don't have permissions yet. They can\n    ///         lock the funds they would like to deposit beforehand.\n    ///         Once permissions are granted, anyone can deposit on\n    ///         their behalf by calling `executeLockedDepositRequest`.\n    ///\n    ///         Example: DAO with onchain governance, that wants to invest their treasury\n    ///             The process that doesn't include calling this method is as follows:\n    ///\n    ///                 1. The DAO signs the legal agreements for the pool => no onchain action,\n    ///                    but only after this the issuer can call update_member to add them as a whitelisted investor\n    ///                 2. Call `requestDeposit` to lock funds\n    ///                 3. After the pool has fulfilled their request, call `deposit` to claim their share class tokens\n    ///\n    ///\n    ///             With the new router function the steps are as follows:\n    ///\n    ///                 1. DAO signs the legal agreement + calls  `openLockDepositRequest`  in 1 governance proposal\n    ///\n    ///                 2. Issuer then gives them permissions, then calls `executeLockDepositFunds` for them,\n    ///                    then fulfills the request, then calls `claimDeposit` for them\n    ///\n    /// @dev    For initial interaction better use `openLockDepositRequest` which includes some of the message calls\n    ///         that the caller must do execute before calling `lockDepositRequest`\n    ///\n    /// @param  vault The address of the vault to invest in\n    /// @param  amount Amount to invest\n    /// @param  controller Address of the owner of the position\n    /// @param  owner Where the  funds to be deposited will be take from\n    function lockDepositRequest(IBaseVault vault, uint256 amount, address controller, address owner) external payable;\n\n    /// @notice Helper method to lock a deposit request, and enable permissionless claiming of that vault in 1 call.\n    /// @dev    It starts interaction with the vault by calling `open`.\n    ///         Vaults support assets that are wrapped one. When user calls this method\n    ///         and the vault's asset is a wrapped one, first the balance of the wrapped asset is checked.\n    ///         If balance >= `amount`, then this asset is used\n    ///         else  amount is treat as an underlying asset one and it is wrapped.\n    /// @param  vault Address of the vault\n    /// @param  amount Amount to be deposited\n    function enableLockDepositRequest(IBaseVault vault, uint256 amount) external payable;\n\n    /// @notice Unlocks all deposited assets of the current caller for a given vault\n    ///\n    /// @param  vault Address of the vault for which funds were locked\n    /// @param  receiver Address of the received of the unlocked funds\n    function unlockDepositRequest(IBaseVault vault, address receiver) external payable;\n\n    /// @notice After the controller is given permissions, anyone can call this method and\n    ///         actually request a deposit with the locked funds on the behalf of the `controller`\n    /// @param  vault The vault for which funds are locked\n    /// @param  controller Owner of the deposit position\n    function executeLockedDepositRequest(IAsyncVault vault, address controller) external payable;\n\n    /// @notice Check IERC7540Deposit.mint\n    /// @param  vault Address of the vault\n    /// @param  receiver Check IERC7540Deposit.mint.receiver\n    /// @param  controller Check IERC7540Deposit.mint.owner\n    function claimDeposit(IAsyncVault vault, address receiver, address controller) external payable;\n\n    // --- Redeem ---\n    /// @notice Check `IERC7887Deposit.cancelDepositRequest`.\n    /// @dev    This adds a mandatory prepayment for all the costs that will incur during the transaction.\n    ///         The caller must call `VaultRouter.estimate` to get estimates how much the deposit will cost.\n    ///\n    /// @param  vault The vault where the deposit was initiated\n    function cancelDepositRequest(IAsyncVault vault) external payable;\n\n    /// @notice Check IERC7887Deposit.claimCancelDepositRequest\n    ///\n    /// @param  vault Address of the vault\n    /// @param  receiver Check  IERC7887Deposit.claimCancelDepositRequest.receiver\n    /// @param  controller Check  IERC7887Deposit.claimCancelDepositRequest.controller\n    function claimCancelDepositRequest(IAsyncVault vault, address receiver, address controller) external payable;\n\n    // --- Redeem ---\n    /// @notice Check `IERC7540Redeem.requestRedeem`.\n    /// @dev    This adds a mandatory prepayment for all the costs that will incur during the transaction.\n    ///         The caller must call `VaultRouter.estimate` to get estimates how much the deposit will cost.\n    ///\n    /// @param  vault The vault to deposit into\n    /// @param  amount Check @param IERC7540Redeem.requestRedeem.shares\n    /// @param  controller Check @param IERC7540Redeem.requestRedeem.controller\n    /// @param  owner Check @param IERC7540Redeem.requestRedeem.owner\n    function requestRedeem(IAsyncVault vault, uint256 amount, address controller, address owner) external payable;\n\n    /// @notice Check IERC7575.withdraw\n    /// @dev    If the underlying vault asset is a wrapped one,\n    ///         `VaultRouter.unwrap` is called and the unwrapped\n    ///         asset is sent to the receiver\n    /// @param  vault Address of the vault\n    /// @param  receiver Check IERC7575.withdraw.receiver\n    /// @param  controller Check IERC7575.withdraw.owner\n    function claimRedeem(IBaseVault vault, address receiver, address controller) external payable;\n\n    /// @notice Check `IERC7887Redeem.cancelRedeemRequest`.\n    /// @dev    This adds a mandatory prepayment for all the costs that will incur during the transaction.\n    ///         The caller must call `VaultRouter.estimate` to get estimates how much the deposit will cost.\n    ///\n    /// @param  vault The vault where the deposit was initiated\n    function cancelRedeemRequest(IAsyncVault vault) external payable;\n\n    /// @notice Check IERC7887Redeem.claimableCancelRedeemRequest\n    ///\n    /// @param  vault Address of the vault\n    /// @param  receiver Check  IERC7887Redeem.claimCancelRedeemRequest.receiver\n    /// @param  controller Check  IERC7887Redeem.claimCancelRedeemRequest.controller\n    function claimCancelRedeemRequest(IAsyncVault vault, address receiver, address controller) external payable;\n\n    // --- ERC20 permit ---\n    /// @notice Check IERC20.permit\n    function permit(address asset, address spender, uint256 assets, uint256 deadline, uint8 v, bytes32 r, bytes32 s)\n        external\n        payable;\n\n    // --- ERC20 wrapping ---\n    /// @notice There are vault which underlying asset is actuall a wrapped one.\n    ///\n    /// @param  wrapper The address of the wrapper\n    /// @param  amount  Amount to be wrapped\n    /// @param  receiver Receiver of the wrapped tokens\n    /// @param  owner The address from which `amount` is taken from\n    function wrap(address wrapper, uint256 amount, address receiver, address owner) external payable;\n\n    /// @notice There are vault which underlying asset is actuall a wrapped one.\n    /// @dev    Wrapped tokens need to be held by the VaultRouter to be unwrapped.\n    /// @param  wrapper The address of the wrapper\n    /// @param  amount  Amount to be wrapped\n    /// @param  receiver Receiver of the unwrapped tokens\n    function unwrap(address wrapper, uint256 amount, address receiver) external payable;\n\n    // --- View Methods ---\n    /// @notice Check IPoolManager.getVault\n    function getVault(PoolId poolId, ShareClassId scId, address asset) external view returns (address);\n\n    /// @notice Check IGateway.estimate\n    ///         If the destination and source chain ID are the same, this will always return 0.\n    /// @param centrifugeId destination chain\n    function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256 amount);\n\n    /// @notice Called to check if `user` has permissions on `vault` to execute requests\n    ///\n    /// @param vault Address of the `vault` the `user` wants to operate on\n    /// @param user Address of the `user` that will operates on the `vault`\n    /// @return Whether `user` has permissions to operate on `vault`\n    function hasPermissions(IBaseVault vault, address user) external view returns (bool);\n\n    /// @notice Returns whether the controller has called `enable()` for the given `vault`\n    function isEnabled(IBaseVault vault, address controller) external view returns (bool);\n}\n"
    },
    "src/vaults/interfaces/factories/IPoolEscrowFactory.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nimport {IPoolEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\n\ninterface IPoolEscrowProvider {\n    /// @notice Returns the deterministic address of an escrow contract based on a given pool id wrapped into the\n    /// corresponding interface.\n    ///\n    /// @dev Does not check, whether the escrow was already deployed.\n    function escrow(PoolId poolId) external view returns (IPoolEscrow);\n}\n\ninterface IPoolEscrowFactory is IPoolEscrowProvider {\n    event DeployPoolEscrow(PoolId indexed poolId, address indexed escrow);\n    event File(bytes32 what, address data);\n\n    error FileUnrecognizedParam();\n    error EscrowAlreadyDeployed();\n\n    /// @notice Deploys new escrow and returns it.\n    /// @dev All share classes of a pool are represented by the same escrow contract.\n    ///\n    /// @param poolId Id of the pool this escrow is deployed for\n    /// @return IPoolEscrow The the newly deployed escrow contract\n    function newEscrow(PoolId poolId) external returns (IPoolEscrow);\n\n    /// @notice Updates contract parameters of type address.\n    function file(bytes32 what, address data) external;\n}\n"
    },
    "src/vaults/interfaces/factories/ITokenFactory.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\ninterface ITokenFactory {\n    /// @notice Used to deploy new share class tokens.\n    /// @dev    In order to have the same address on different EVMs `salt` should be used\n    ///         during creationg process.\n    /// @param name Name of the new token.\n    /// @param symbol Symbol of the new token.\n    /// @param decimals Decimals of the new token.\n    /// @param salt Salt used for deterministic deployments.\n    /// @param tokenWards Address which can call methods behind authorized only.\n    function newToken(\n        string memory name,\n        string memory symbol,\n        uint8 decimals,\n        bytes32 salt,\n        address[] calldata tokenWards\n    ) external returns (IShareToken);\n\n    /// @notice Returns the predicted address (using CREATE2)\n    function getAddress(uint8 decimals, bytes32 salt) external view returns (address);\n}\n"
    },
    "src/vaults/interfaces/factories/IVaultFactory.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IPoolEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface IVaultFactory {\n    error UnsupportedTokenId();\n\n    /// @notice Deploys new vault for `poolId`, `scId` and `asset`.\n    ///\n    /// @param poolId Id of the pool. Id is one of the already supported pools.\n    /// @param scId Id of the share class token. Id is one of the already supported share class tokens.\n    /// @param asset Address of the underlying asset that is getting deposited inside the pool.\n    /// @param asset Token id of the underlying asset that is getting deposited inside the pool. I.e. zero if asset\n    /// corresponds to ERC20 or non-zero if asset corresponds to ERC6909.\n    /// @param token Address of the share class token that is getting issues against the deposited asset.\n    /// @param wards_ Address which can call methods behind authorized only.\n    function newVault(\n        PoolId poolId,\n        ShareClassId scId,\n        address asset,\n        uint256 tokenId,\n        IShareToken token,\n        address[] calldata wards_\n    ) external returns (IBaseVault);\n}\n"
    },
    "src/vaults/interfaces/investments/IAsyncDepositManager.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IDepositManager} from \"src/vaults/interfaces/investments/IDepositManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface IAsyncDepositManager is IDepositManager {\n    /// @notice Requests assets deposit. Vaults have to request investments from Centrifuge before\n    ///         shares can be minted. The deposit requests are added to the order book\n    ///         on the corresponding CP instance. Once the next epoch is executed on the corresponding CP instance,\n    /// vaults can\n    ///         proceed with share payouts in case the order got fulfilled.\n    /// @dev    The assets required to fulfill the deposit request have to be locked and are transferred from the\n    ///         owner to the escrow, even though the share payout can only happen after epoch execution.\n    ///         The receiver becomes the owner of deposit request fulfillment.\n    /// @param  source Deprecated\n    function requestDeposit(IBaseVault vault, uint256 assets, address receiver, address owner, address source)\n        external\n        returns (bool);\n\n    /// @notice Requests the cancellation of a pending deposit request. Vaults have to request the\n    ///         cancellation of outstanding requests from Centrifuge before actual assets can be unlocked and\n    /// transferred\n    ///         to the owner.\n    ///         While users have outstanding cancellation requests no new deposit requests can be submitted.\n    ///         Once the next epoch is executed on the corresponding CP instance, vaults can proceed with asset payouts\n    ///         if orders could be cancelled successfully.\n    /// @dev    The cancellation request might fail in case the pending deposit order already got fulfilled on\n    ///         Centrifuge.\n    /// @param  source Deprecated\n    function cancelDepositRequest(IBaseVault vault, address owner, address source) external;\n\n    /// @notice Processes owner's deposit request cancellation after the epoch has been executed on the corresponding CP\n    /// instance and the\n    ///         deposit order cancellation has been successfully processed (partial fulfillment possible).\n    ///         Assets are transferred from the escrow to the receiver.\n    /// @dev    The assets required to fulfill the claim have already been reserved for the owner in escrow on\n    ///         fulfillCancelDepositRequest.\n    function claimCancelDepositRequest(IBaseVault vault, address receiver, address owner)\n        external\n        returns (uint256 assets);\n\n    /// @notice Indicates whether a user has pending deposit requests and returns the total deposit request asset\n    /// request value.\n    function pendingDepositRequest(IBaseVault vault, address user) external view returns (uint256 assets);\n\n    /// @notice Indicates whether a user has pending deposit request cancellations.\n    function pendingCancelDepositRequest(IBaseVault vault, address user) external view returns (bool isPending);\n\n    /// @notice Indicates whether a user has claimable deposit request cancellation and returns the total claim\n    ///         value in assets.\n    function claimableCancelDepositRequest(IBaseVault vault, address user) external view returns (uint256 assets);\n}\n"
    },
    "src/vaults/interfaces/investments/IAsyncRedeemManager.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IRedeemManager} from \"src/vaults/interfaces/investments/IRedeemManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface IAsyncRedeemManager is IRedeemManager {\n    /// @notice Requests share redemption. Vaults have to request redemptions\n    ///         from Centrifuge before actual asset payouts can be done. The redemption\n    ///         requests are added to the order book on the corresponding CP instance. Once the next epoch is\n    ///         executed on the corresponding CP instance, vaults can proceed with asset payouts\n    ///         in case the order got fulfilled.\n    /// @dev    The shares required to fulfill the redemption request have to be locked and are transferred from the\n    ///         owner to the escrow, even though the asset payout can only happen after epoch execution.\n    ///         The receiver becomes the owner of redeem request fulfillment.\n    /// @param  source Deprecated\n    function requestRedeem(IBaseVault vault, uint256 shares, address receiver, address owner, address source)\n        external\n        returns (bool);\n\n    /// @notice Requests the cancellation of an pending redeem request. Vaults have to request the\n    ///         cancellation of outstanding requests from Centrifuge before actual shares can be unlocked and\n    ///         transferred to the owner.\n    ///         While users have outstanding cancellation requests no new redeem requests can be submitted (exception:\n    ///         trigger through governance).\n    ///         Once the next epoch is executed on the corresponding CP instance, vaults can proceed with share payouts\n    ///         if the orders could be cancelled successfully.\n    /// @dev    The cancellation request might fail in case the pending redeem order already got fulfilled on\n    ///         Centrifuge.\n    function cancelRedeemRequest(IBaseVault vault, address owner, address source) external;\n\n    /// @notice Processes owner's redeem request cancellation after the epoch has been executed on the corresponding CP\n    /// instance and the\n    ///         redeem order cancellation has been successfully processed (partial fulfillment possible).\n    ///         Shares are transferred from the escrow to the receiver.\n    /// @dev    The shares required to fulfill the claim have already been reserved for the owner in escrow on\n    ///         fulfillCancelRedeemRequest.\n    ///         Receiver has to pass all the share token restrictions in order to receive the shares.\n    function claimCancelRedeemRequest(IBaseVault vault, address receiver, address owner)\n        external\n        returns (uint256 shares);\n\n    /// @notice Indicates whether a user has pending redeem requests and returns the total share request value.\n    function pendingRedeemRequest(IBaseVault vault, address user) external view returns (uint256 shares);\n\n    /// @notice Indicates whether a user has pending redeem request cancellations.\n    function pendingCancelRedeemRequest(IBaseVault vault, address user) external view returns (bool isPending);\n\n    /// @notice Indicates whether a user has claimable redeem request cancellation and returns the total claim\n    ///         value in shares.\n    function claimableCancelRedeemRequest(IBaseVault vault, address user) external view returns (uint256 shares);\n}\n"
    },
    "src/vaults/interfaces/investments/IAsyncRequestManager.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IRequestManagerGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\n\nimport {IAsyncDepositManager} from \"src/vaults/interfaces/investments/IAsyncDepositManager.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\n/// @dev Vault requests and deposit/redeem bookkeeping per user\nstruct AsyncInvestmentState {\n    /// @dev Shares that can be claimed using `mint()`\n    uint128 maxMint;\n    /// @dev Assets that can be claimed using `withdraw()`\n    uint128 maxWithdraw;\n    /// @dev Weighted average price of deposits, used to convert maxMint to maxDeposit\n    /// @dev Represents priceAssetPerShare, i.e. ASSET_UNIT/SHARE_UNIT\n    uint256 depositPrice;\n    /// @dev Weighted average price of redemptions, used to convert maxWithdraw to maxRedeem\n    /// @dev Represents priceAssetPerShare, i.e. ASSET_UNIT/SHARE_UNIT\n    uint256 redeemPrice;\n    /// @dev Remaining deposit request in assets\n    uint128 pendingDepositRequest;\n    /// @dev Remaining redeem request in shares\n    uint128 pendingRedeemRequest;\n    /// @dev Assets that can be claimed using `claimCancelDepositRequest()`\n    uint128 claimableCancelDepositRequest;\n    /// @dev Shares that can be claimed using `claimCancelRedeemRequest()`\n    uint128 claimableCancelRedeemRequest;\n    /// @dev Indicates whether the depositRequest was requested to be cancelled\n    bool pendingCancelDepositRequest;\n    /// @dev Indicates whether the redeemRequest was requested to be cancelled\n    bool pendingCancelRedeemRequest;\n}\n\ninterface IAsyncRequestManager is IAsyncDepositManager, IAsyncRedeemManager, IRequestManagerGatewayHandler {\n    error ZeroAmountNotAllowed();\n    error TransferNotAllowed();\n    error CancellationIsPending();\n    error NoPendingRequest();\n    error ShareTokenAmountIsZero();\n    error FailedRedeemRequest();\n    error ExceedsDepositLimits();\n    error ShareTokenTransferFailed();\n    error ExceedsMaxRedeem();\n    error ExceedsRedeemLimits();\n\n    /// @notice Returns the investment state\n    function investments(IBaseVault vaultAddr, address investor)\n        external\n        view\n        returns (\n            uint128 maxMint,\n            uint128 maxWithdraw,\n            uint256 depositPrice,\n            uint256 redeemPrice,\n            uint128 pendingDepositRequest,\n            uint128 pendingRedeemRequest,\n            uint128 claimableCancelDepositRequest,\n            uint128 claimableCancelRedeemRequest,\n            bool pendingCancelDepositRequest,\n            bool pendingCancelRedeemRequest\n        );\n}\n"
    },
    "src/vaults/interfaces/investments/IBaseRequestManager.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\n\nimport {IPoolManager} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IPoolEscrow, IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\n\ninterface IBaseRequestManager {\n    // --- Events ---\n    event File(bytes32 indexed what, address data);\n\n    error FileUnrecognizedParam();\n    error SenderNotVault();\n    error AssetNotAllowed();\n    error ExceedsMaxDeposit();\n    error AssetMismatch();\n    error VaultAlreadyExists();\n    error VaultDoesNotExist();\n\n    /// @notice Updates contract parameters of type address.\n    /// @param what The bytes32 representation of 'gateway' or 'poolManager'.\n    /// @param data The new contract address.\n    function file(bytes32 what, address data) external;\n\n    /// @notice Converts the assets value to share decimals.\n    function convertToShares(IBaseVault vault, uint256 _assets) external view returns (uint256 shares);\n\n    /// @notice Converts the shares value to assets decimals.\n    function convertToAssets(IBaseVault vault, uint256 _shares) external view returns (uint256 assets);\n\n    /// @notice Returns the timestamp of the last share price update for a vaultAddr.\n    function priceLastUpdated(IBaseVault vault) external view returns (uint64 lastUpdated);\n\n    /// @notice Returns the PoolManager contract address.\n    function poolManager() external view returns (IPoolManager poolManager);\n\n    /// @notice The global escrow used for funds that are not yet free to be used for a specific pool\n    function globalEscrow() external view returns (IEscrow escrow);\n\n    /// @notice Escrow per pool. Funds are associated to a specific pool\n    function poolEscrow(PoolId poolId) external view returns (IPoolEscrow);\n\n    /// @notice Adds new vault for `poolId`, `scId` and `asset`.\n    function addVault(PoolId poolId, ShareClassId scId, IBaseVault vault, address asset, AssetId assetId) external;\n\n    /// @notice Removes `vault` from `who`'s authorized callers\n    function removeVault(PoolId poolId, ShareClassId scId, IBaseVault vault, address asset, AssetId assetId) external;\n\n    /// @notice Returns the address of the vault for a given pool, share class and asset\n    function vaultByAssetId(PoolId poolId, ShareClassId scId, AssetId assetId)\n        external\n        view\n        returns (IBaseVault vault);\n}\n"
    },
    "src/vaults/interfaces/investments/IDepositManager.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface IDepositManager is IBaseRequestManager {\n    /// @notice Processes owner's asset deposit after the epoch has been executed on the corresponding CP instance and\n    /// the deposit order\n    ///         has been successfully processed (partial fulfillment possible).\n    ///         Shares are transferred from the escrow to the receiver. Amount of shares is computed based of the amount\n    ///         of assets and the owner's share price.\n    /// @dev    The assets required to fulfill the deposit are already locked in escrow upon calling requestDeposit.\n    ///         The shares required to fulfill the deposit have already been minted and transferred to the escrow on\n    ///         fulfillDepositRequest.\n    ///         Receiver has to pass all the share token restrictions in order to receive the shares.\n    function deposit(IBaseVault vault, uint256 assets, address receiver, address owner)\n        external\n        returns (uint256 shares);\n\n    /// @notice Processes owner's share mint after the epoch has been executed on the corresponding CP instance and the\n    /// deposit order has\n    ///         been successfully processed (partial fulfillment possible).\n    ///         Shares are transferred from the escrow to the receiver. Amount of assets is computed based of the amount\n    ///         of shares and the owner's share price.\n    /// @dev    The assets required to fulfill the mint are already locked in escrow upon calling requestDeposit.\n    ///         The shares required to fulfill the mint have already been minted and transferred to the escrow on\n    ///         fulfillDepositRequest.\n    ///         Receiver has to pass all the share token restrictions in order to receive the shares.\n    function mint(IBaseVault vault, uint256 shares, address receiver, address owner)\n        external\n        returns (uint256 assets);\n\n    /// @notice Returns the max amount of assets based on the unclaimed amount of shares after at least one successful\n    ///         deposit order fulfillment on the corresponding CP instance.\n    function maxDeposit(IBaseVault vault, address user) external view returns (uint256);\n\n    /// @notice Returns the max amount of shares a user can claim after at least one successful deposit order\n    ///         fulfillment on the corresponding CP instance.\n    function maxMint(IBaseVault vault, address user) external view returns (uint256 shares);\n}\n"
    },
    "src/vaults/interfaces/investments/IRedeemManager.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface IRedeemManager is IBaseRequestManager {\n    event TriggerRedeemRequest(\n        uint64 indexed poolId,\n        bytes16 indexed scId,\n        address user,\n        address indexed asset,\n        uint256 tokenId,\n        uint128 shares\n    );\n\n    /// @notice Processes owner's share redemption after the epoch has been executed on the corresponding CP instance\n    /// and the redeem order\n    ///         has been successfully processed (partial fulfillment possible).\n    ///         Assets are transferred from the escrow to the receiver. Amount of assets is computed based of the amount\n    ///         of shares and the owner's share price.\n    /// @dev    The shares required to fulfill the redemption were already locked in escrow on requestRedeem and burned\n    ///         on fulfillRedeemRequest.\n    ///         The assets required to fulfill the redemption have already been reserved in escrow on\n    ///         fulfillRedeemtRequest.\n    function redeem(IBaseVault vault, uint256 shares, address receiver, address owner)\n        external\n        returns (uint256 assets);\n\n    /// @notice Processes owner's asset withdrawal after the epoch has been executed on the corresponding CP instance\n    /// and the redeem order\n    ///         has been successfully processed (partial fulfillment possible).\n    ///         Assets are transferred from the escrow to the receiver. Amount of shares is computed based of the amount\n    ///         of shares and the owner's share price.\n    /// @dev    The shares required to fulfill the withdrawal were already locked in escrow on requestRedeem and burned\n    ///         on fulfillRedeemRequest.\n    ///         The assets required to fulfill the withdrawal have already been reserved in escrow on\n    ///         fulfillRedeemtRequest.\n    function withdraw(IBaseVault vault, uint256 assets, address receiver, address owner)\n        external\n        returns (uint256 shares);\n\n    /// @notice Returns the max amount of shares based on the unclaimed number of assets after at least one successful\n    ///         redeem order fulfillment on the corresponding CP instance.\n    function maxRedeem(IBaseVault vault, address user) external view returns (uint256 shares);\n\n    /// @notice Returns the max amount of assets a user can claim after at least one successful redeem order fulfillment\n    ///         on the corresponding CP instance.\n    function maxWithdraw(IBaseVault vault, address user) external view returns (uint256 assets);\n}\n"
    },
    "src/vaults/interfaces/investments/ISyncDepositManager.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IDepositManager} from \"src/vaults/interfaces/investments/IDepositManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface ISyncDepositManager is IDepositManager {\n    function previewDeposit(IBaseVault vault, address sender, uint256 assets) external view returns (uint256);\n    function previewMint(IBaseVault vault, address sender, uint256 shares) external view returns (uint256);\n}\n"
    },
    "src/vaults/interfaces/investments/ISyncRequestManager.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {D18} from \"src/misc/types/D18.sol\";\n\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IUpdateContract} from \"src/vaults/interfaces/IUpdateContract.sol\";\nimport {ISyncDepositManager} from \"src/vaults/interfaces/investments/ISyncDepositManager.sol\";\n\n/// @dev Solely used locally as protection against stack-too-deep\nstruct Prices {\n    /// @dev Price of 1 asset unit per share unit\n    D18 assetPerShare;\n    /// @dev Price of 1 pool unit per asset unit\n    D18 poolPerAsset;\n    /// @dev Price of 1 pool unit per share unit\n    D18 poolPerShare;\n}\n\ninterface ISyncDepositValuation {\n    /// @notice Returns the pool price per share for a given pool and share class, asset, and asset id.\n    // The provided price is defined as POOL_UNIT/SHARE_UNIT.\n    ///\n    /// @param poolId The pool id\n    /// @param scId The share class id\n    /// @return price The pool price per share\n    function pricePoolPerShare(PoolId poolId, ShareClassId scId) external view returns (D18 price);\n}\n\ninterface ISyncRequestManager is ISyncDepositManager, ISyncDepositValuation, IUpdateContract {\n    event SetValuation(PoolId indexed poolId, ShareClassId indexed scId, address valuation);\n    event SetMaxReserve(\n        PoolId indexed poolId, ShareClassId indexed scId, address asset, uint256 tokenId, uint128 maxReserve\n    );\n\n    error ExceedsMaxMint();\n    error ShareTokenDoesNotExist();\n    error SecondaryManagerDoesNotExist();\n\n    /// @notice Sets the valuation for a specific pool and share class.\n    ///\n    /// @param poolId The id of the pool\n    /// @param scId The id of the share class\n    /// @param valuation The address of the valuation contract\n    function setValuation(PoolId poolId, ShareClassId scId, address valuation) external;\n\n    /// @notice Sets the max reserve for a specific pool, share class and asset.\n    ///\n    /// @param poolId The id of the pool\n    /// @param scId The id of the share class\n    /// @param asset The address of the asset\n    /// @param tokenId The asset token id, i.e. 0 for ERC20, or the token id for ERC6909\n    /// @param maxReserve The amount of maximum reserve\n    function setMaxReserve(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, uint128 maxReserve)\n        external;\n\n    /// @notice Returns the all three prices for a given pool, share class, asset, and asset id.\n    ///\n    /// @param poolId The pool id\n    /// @param scId The share class id\n    /// @param assetId The asset id corresponding to the asset and tokenId\n    /// @return priceData The asset price per share, pool price per asset, and pool price per share\n    function prices(PoolId poolId, ShareClassId scId, AssetId assetId)\n        external\n        view\n        returns (Prices memory priceData);\n}\n"
    },
    "src/vaults/interfaces/token/IShareToken.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC20Metadata} from \"src/misc/interfaces/IERC20.sol\";\nimport {IERC7575Share} from \"src/misc/interfaces/IERC7575.sol\";\n\ninterface IERC1404 {\n    /// @notice Detects if a transfer will be reverted and if so returns an appropriate reference code\n    /// @param from Sending address\n    /// @param to Receiving address\n    /// @param value Amount of tokens being transferred\n    /// @return Code by which to reference message for rejection reasoning\n    /// @dev Overwrite with your custom transfer restriction logic\n    function detectTransferRestriction(address from, address to, uint256 value) external view returns (uint8);\n\n    /// @notice Returns a human-readable message for a given restriction code\n    /// @param restrictionCode Identifier for looking up a message\n    /// @return Text showing the restriction's reasoning\n    /// @dev Overwrite with your custom message and restrictionCode handling\n    function messageForTransferRestriction(uint8 restrictionCode) external view returns (string memory);\n}\n\ninterface IShareToken is IERC20Metadata, IERC7575Share, IERC1404 {\n    // --- Events ---\n    event File(bytes32 indexed what, address data);\n    event SetHookData(address indexed user, bytes16 data);\n\n    // --- Errors ---\n    error NotAuthorizedOrHook();\n    error ExceedsMaxSupply();\n    error RestrictionsFailed();\n\n    struct Balance {\n        /// @dev The user balance is limited to uint128. This is safe because the decimals are limited to 18,\n        ///      thus the max balance is 2^128-1 / 10**18 = 3.40 * 10**20. This is also enforced on mint.\n        uint128 amount;\n        /// @dev There are 16 bytes that are used to store hook data (e.g. restrictions for users).\n        bytes16 hookData;\n    }\n\n    // --- Administration ---\n    /// @notice returns the hook that transfers perform callbacks to\n    /// @dev    MUST comply to `IHook` interface\n    function hook() external view returns (address);\n\n    /// @notice Updates a contract parameter\n    /// @param what Accepts a bytes32 representation of 'name', 'symbol'\n    function file(bytes32 what, string memory data) external;\n\n    /// @notice Updates a contract parameter\n    /// @param what Accepts a bytes32 representation of 'hook'\n    function file(bytes32 what, address data) external;\n\n    /// @notice updates the vault for a given `asset`\n    function updateVault(address asset, address vault_) external;\n\n    // --- ERC20 overrides ---\n    /// @notice returns the 16 byte hook data of the given `user`.\n    /// @dev    Stored in the 128 most significant bits of the user balance\n    function hookDataOf(address user) external view returns (bytes16);\n\n    /// @notice update the 16 byte hook data of the given `user`\n    function setHookData(address user, bytes16 hookData) external;\n\n    /// @notice Function to mint tokens\n    function mint(address user, uint256 value) external;\n\n    /// @notice Function to burn tokens\n    function burn(address user, uint256 value) external;\n\n    /// @notice Checks if the tokens can be transferred given the input values\n    function checkTransferRestriction(address from, address to, uint256 value) external view returns (bool);\n\n    /// @notice Performs an authorized transfer, with `sender` as the given sender.\n    /// @dev    Requires allowance if `sender` != `from`\n    function authTransferFrom(address sender, address from, address to, uint256 amount) external returns (bool);\n}\n"
    },
    "src/vaults/legacy/LegacyVaultAdapter.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {ILegacyVault} from \"src/vaults/legacy/interfaces/ILegacyVault.sol\";\nimport {IInvestmentManager} from \"src/vaults/legacy/interfaces/IInvestmentManager.sol\";\nimport {ILegacyVaultAdapter} from \"src/vaults/legacy/interfaces/ILegacyVaultAdapter.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {AsyncVault} from \"src/vaults/AsyncVault.sol\";\nimport {IAsyncRequestManager} from \"src/vaults/interfaces/investments/IAsyncRequestManager.sol\";\nimport {BaseAsyncRedeemVault, IAsyncRedeemVault} from \"src/vaults/BaseVaults.sol\";\n\n/// @title  LegacyVaultAdapter\n/// @notice An adapter connecting legacy ERC-7540 vaults from Centrifuge V2 to Centrifuge V3.\n///\n/// @dev    This adapter acts as an `IInvestmentManager` for a single legacy `ILegacyVault` vault from Centrifuge V2.\n///         At the same time it acts like a new `IAsyncVault` for the `IAsyncRequestManager` manager of Centrifuge V3.\n///         The adapter needs to be deployed per legacy vault and allows a seamless interaction between Centrifuge V2\n///         vaults and Centrifuge V3 infrastructure. Thereby, allowing to migrate existing vaults to the new system.\ncontract LegacyVaultAdapter is AsyncVault, ILegacyVaultAdapter, IInvestmentManager {\n    uint64 public immutable legacyPoolId;\n    bytes16 public immutable legacyTrancheId;\n    ILegacyVault public immutable legacyVault;\n\n    constructor(\n        ILegacyVault legacyVault_,\n        PoolId poolId,\n        uint64 legacyPoolId_,\n        ShareClassId scId,\n        bytes16 legacyTrancheId_,\n        address asset,\n        IShareToken token,\n        address root,\n        IAsyncRequestManager manager\n    ) AsyncVault(poolId, scId, asset, token, root, manager) {\n        require(legacyVault_.poolId() == legacyPoolId_, NotLegacyPoolId(legacyPoolId_, legacyVault_.poolId()));\n        require(\n            legacyVault_.trancheId() == legacyTrancheId_, NotLegacyTrancheId(legacyTrancheId_, legacyVault_.trancheId())\n        );\n        require(legacyVault_.asset() == asset, NotLegacyAsset(asset, legacyVault_.asset()));\n        require(legacyVault_.share() == address(token), NotLegacyShare(address(token), legacyVault_.share()));\n\n        legacyPoolId = legacyPoolId_;\n        legacyTrancheId = legacyTrancheId_;\n        legacyVault = legacyVault_;\n    }\n\n    /// @dev Check if the msg.sender is the legacy vault\n    modifier legacy() {\n        require(msg.sender == address(legacyVault), NotLegacyVault(msg.sender, address(legacyVault)));\n        _;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // IInvestmentManager handlers\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IInvestmentManager\n    function requestDeposit(address, /* vault */ uint256 assets, address receiver, address owner, address source)\n        public\n        legacy\n        returns (bool)\n    {\n        return asyncManager().requestDeposit(this, assets, receiver, owner, source);\n    }\n\n    /// @inheritdoc IInvestmentManager\n    function requestRedeem(address, /* vault */ uint256 shares, address receiver, address owner, address source)\n        public\n        legacy\n        returns (bool)\n    {\n        return asyncManager().requestRedeem(this, shares, receiver, owner, source);\n    }\n\n    /// @inheritdoc IInvestmentManager\n    function cancelDepositRequest(address, /* vault */ address owner, address source) public legacy {\n        return asyncManager().cancelDepositRequest(this, owner, source);\n    }\n\n    /// @inheritdoc IInvestmentManager\n    function cancelRedeemRequest(address, /* vault */ address owner, address source) public legacy {\n        return asyncManager().cancelRedeemRequest(this, owner, source);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // IInvestmentManager view methods\n    //----------------------------------------------------------------------------------------------\n\n    function escrow() public view returns (address) {\n        return address(manager.globalEscrow());\n    }\n\n    /// @inheritdoc IInvestmentManager\n    function convertToShares(address, /* vault */ uint256 _assets) public view returns (uint256 shares) {\n        shares = asyncManager().convertToShares(this, _assets);\n    }\n\n    /// @inheritdoc IInvestmentManager\n    function convertToAssets(address, /* vault */ uint256 _shares) public view returns (uint256 assets) {\n        assets = asyncManager().convertToAssets(this, _shares);\n    }\n\n    /// @inheritdoc IInvestmentManager\n    function maxDeposit(address, /* vault */ address user) public view returns (uint256 assets) {\n        assets = asyncManager().maxDeposit(this, user);\n    }\n\n    /// @inheritdoc IInvestmentManager\n    function maxMint(address, /* vault */ address user) public view returns (uint256 shares) {\n        shares = asyncManager().maxMint(this, user);\n    }\n\n    /// @inheritdoc IInvestmentManager\n    function maxWithdraw(address, /* vault */ address user) public view returns (uint256 assets) {\n        assets = asyncManager().maxWithdraw(this, user);\n    }\n\n    /// @inheritdoc IInvestmentManager\n    function maxRedeem(address, /* vault */ address user) public view returns (uint256 shares) {\n        shares = asyncManager().maxRedeem(this, user);\n    }\n\n    /// @inheritdoc IInvestmentManager\n    function pendingDepositRequest(address, /* vault */ address user) public view returns (uint256 assets) {\n        assets = asyncManager().pendingDepositRequest(this, user);\n    }\n\n    /// @inheritdoc IInvestmentManager\n    function pendingRedeemRequest(address, /* vault */ address user) public view returns (uint256 shares) {\n        shares = asyncManager().pendingRedeemRequest(this, user);\n    }\n\n    /// @inheritdoc IInvestmentManager\n    function pendingCancelDepositRequest(address, /* vault */ address user) public view returns (bool isPending) {\n        isPending = asyncManager().pendingCancelDepositRequest(this, user);\n    }\n\n    /// @inheritdoc IInvestmentManager\n    function pendingCancelRedeemRequest(address, /* vault */ address user) public view returns (bool isPending) {\n        isPending = asyncManager().pendingCancelRedeemRequest(this, user);\n    }\n\n    /// @inheritdoc IInvestmentManager\n    function claimableCancelDepositRequest(address, /* vault */ address user) public view returns (uint256 assets) {\n        assets = asyncManager().claimableCancelDepositRequest(this, user);\n    }\n\n    /// @inheritdoc IInvestmentManager\n    function claimableCancelRedeemRequest(address, /* vault */ address user) public view returns (uint256 shares) {\n        shares = asyncManager().claimableCancelRedeemRequest(this, user);\n    }\n\n    /// @inheritdoc IInvestmentManager\n    function priceLastUpdated(address /* vault */ ) public view returns (uint64 lastUpdated) {\n        lastUpdated = manager.priceLastUpdated(this);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // IInvestmentManager vault claim methods\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IInvestmentManager\n    function deposit(address, /* vault */ uint256 assets, address receiver, address owner)\n        public\n        legacy\n        returns (uint256 shares)\n    {\n        shares = asyncManager().deposit(this, assets, receiver, owner);\n    }\n\n    /// @inheritdoc IInvestmentManager\n    function mint(address, /* vault */ uint256 shares, address receiver, address owner)\n        public\n        legacy\n        returns (uint256 assets)\n    {\n        assets = asyncManager().mint(this, shares, receiver, owner);\n    }\n\n    /// @inheritdoc IInvestmentManager\n    function redeem(address, /* vault */ uint256 shares, address receiver, address owner)\n        public\n        legacy\n        returns (uint256 assets)\n    {\n        assets = asyncManager().redeem(this, shares, receiver, owner);\n    }\n\n    /// @inheritdoc IInvestmentManager\n    function withdraw(address, /* vault */ uint256 assets, address receiver, address owner)\n        public\n        legacy\n        returns (uint256 shares)\n    {\n        shares = asyncManager().withdraw(this, assets, receiver, owner);\n    }\n\n    /// @inheritdoc IInvestmentManager\n    function claimCancelDepositRequest(address, /* vault */ address receiver, address owner)\n        public\n        legacy\n        returns (uint256 assets)\n    {\n        assets = asyncManager().claimCancelDepositRequest(this, receiver, owner);\n    }\n\n    /// @inheritdoc IInvestmentManager\n    function claimCancelRedeemRequest(address, /* vault */ address receiver, address owner)\n        public\n        legacy\n        returns (uint256 shares)\n    {\n        shares = asyncManager().claimCancelRedeemRequest(this, receiver, owner);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Event emitters\n    //----------------------------------------------------------------------------------------------\n\n    function onDepositClaimable(address controller, uint256 assets, uint256 shares) public override auth {\n        legacyVault.onDepositClaimable(controller, assets, shares);\n    }\n\n    function onCancelDepositClaimable(address controller, uint256 assets) public override auth {\n        legacyVault.onCancelDepositClaimable(controller, assets);\n    }\n\n    function onRedeemRequest(address controller, address owner, uint256 shares)\n        public\n        override(BaseAsyncRedeemVault, IAsyncRedeemVault)\n        auth\n    {\n        legacyVault.onRedeemRequest(controller, owner, shares);\n    }\n\n    function onRedeemClaimable(address controller, uint256 assets, uint256 shares)\n        public\n        override(BaseAsyncRedeemVault, IAsyncRedeemVault)\n        auth\n    {\n        legacyVault.onRedeemClaimable(controller, assets, shares);\n    }\n\n    function onCancelRedeemClaimable(address controller, uint256 shares)\n        public\n        override(BaseAsyncRedeemVault, IAsyncRedeemVault)\n        auth\n    {\n        legacyVault.onCancelRedeemClaimable(controller, shares);\n    }\n}\n"
    },
    "src/vaults/legacy/interfaces/IInvestmentManager.sol": {
      "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.5.0;\n\n/// @notice A stripped down version of the Centrifuge V2 investment manager.\n///\n/// @dev This interface is needed to ensure adapters for legacy vaults are provided with the expected interface.\ninterface IInvestmentManager {\n    /// @notice Documentation see Centrifuge V2 repository.\n    function escrow() external view returns (address);\n\n    // --- Outgoing message handling ---\n    /// @notice Documentation see Centrifuge V2 repository.\n    function requestDeposit(address vault, uint256 assets, address receiver, address owner, address source)\n        external\n        returns (bool);\n\n    /// @notice Documentation see Centrifuge V2 repository.\n    function requestRedeem(address vault, uint256 shares, address receiver, address, /* owner */ address source)\n        external\n        returns (bool);\n\n    /// @notice Documentation see Centrifuge V2 repository.\n    function cancelDepositRequest(address vault, address owner, address source) external;\n\n    /// @notice Documentation see Centrifuge V2 repository.\n    function cancelRedeemRequest(address vault, address owner, address source) external;\n\n    // --- View functions ---\n    /// @notice Documentation see Centrifuge V2 repository.\n    function convertToShares(address vault, uint256 _assets) external view returns (uint256 shares);\n\n    /// @notice Documentation see Centrifuge V2 repository.\n    function convertToAssets(address vault, uint256 _shares) external view returns (uint256 assets);\n\n    /// @notice Documentation see Centrifuge V2 repository.\n    function maxDeposit(address vault, address user) external view returns (uint256);\n\n    /// @notice Documentation see Centrifuge V2 repository.\n    function maxMint(address vault, address user) external view returns (uint256 shares);\n\n    /// @notice Documentation see Centrifuge V2 repository.\n    function maxWithdraw(address vault, address user) external view returns (uint256 assets);\n\n    /// @notice Documentation see Centrifuge V2 repository.\n    function maxRedeem(address vault, address user) external view returns (uint256 shares);\n\n    /// @notice Documentation see Centrifuge V2 repository.\n    function pendingDepositRequest(address vault, address user) external view returns (uint256 assets);\n\n    /// @notice Documentation see Centrifuge V2 repository.\n    function pendingRedeemRequest(address vault, address user) external view returns (uint256 shares);\n\n    /// @notice Documentation see Centrifuge V2 repository.\n    function pendingCancelDepositRequest(address vault, address user) external view returns (bool isPending);\n\n    /// @notice Documentation see Centrifuge V2 repository.\n    function pendingCancelRedeemRequest(address vault, address user) external view returns (bool isPending);\n\n    /// @notice Documentation see Centrifuge V2 repository.\n    function claimableCancelDepositRequest(address vault, address user) external view returns (uint256 assets);\n\n    /// @notice Documentation see Centrifuge V2 repository.\n    function claimableCancelRedeemRequest(address vault, address user) external view returns (uint256 shares);\n\n    /// @notice Documentation see Centrifuge V2 repository.\n    function priceLastUpdated(address vault) external view returns (uint64 lastUpdated);\n\n    // --- Vault claim functions ---\n    /// @notice Documentation see Centrifuge V2 repository.\n    function deposit(address vault, uint256 assets, address receiver, address owner)\n        external\n        returns (uint256 shares);\n\n    /// @notice Documentation see Centrifuge V2 repository.\n    function mint(address vault, uint256 shares, address receiver, address owner) external returns (uint256 assets);\n\n    /// @notice Documentation see Centrifuge V2 repository.\n    function redeem(address vault, uint256 shares, address receiver, address owner) external returns (uint256 assets);\n\n    /// @notice Documentation see Centrifuge V2 repository.\n    function withdraw(address vault, uint256 assets, address receiver, address owner)\n        external\n        returns (uint256 shares);\n\n    /// @notice Documentation see Centrifuge V2 repository.\n    function claimCancelDepositRequest(address vault, address receiver, address owner)\n        external\n        returns (uint256 assets);\n\n    /// @notice Documentation see Centrifuge V2 repository.\n    function claimCancelRedeemRequest(address vault, address receiver, address owner)\n        external\n        returns (uint256 shares);\n}\n"
    },
    "src/vaults/legacy/interfaces/ILegacyVault.sol": {
      "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.5.0;\n\n/// @notice A stripped down version of the Centrifuge V2 ERC-7540 vault.\n///\n/// @dev This interface is needed to ensure adapters for legacy vaults are provided with the expected interface.\ninterface ILegacyVault {\n    /// @notice Documentation see Centrifuge V2 repository.\n    function poolId() external view returns (uint64);\n\n    /// @notice Documentation see Centrifuge V2 repository.\n    function trancheId() external view returns (bytes16);\n\n    /// @notice Documentation see Centrifuge V2 repository.\n    function asset() external view returns (address);\n\n    /// @notice Documentation see Centrifuge V2 repository.\n    function share() external view returns (address);\n\n    /// @notice Callback when a redeem Request is triggered externally;\n    function onRedeemRequest(address controller, address owner, uint256 shares) external;\n\n    /// @notice Callback when a deposit Request becomes claimable\n    function onDepositClaimable(address owner, uint256 assets, uint256 shares) external;\n\n    /// @notice Callback when a redeem Request becomes claimable\n    function onRedeemClaimable(address owner, uint256 assets, uint256 shares) external;\n\n    /// @notice Callback when a claim deposit Request becomes claimable\n    function onCancelDepositClaimable(address owner, uint256 assets) external;\n\n    /// @notice Callback when a claim redeem Request becomes claimable\n    function onCancelRedeemClaimable(address owner, uint256 shares) external;\n}\n"
    },
    "src/vaults/legacy/interfaces/ILegacyVaultAdapter.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\ninterface ILegacyVaultAdapter {\n    error NotLegacyVault(address sender, address legacyVault);\n    error NotLegacyPoolId(uint64 providedPoolId, uint64 legacyPoolId);\n    error NotLegacyTrancheId(bytes16 providedTrancheId, bytes16 legacyTrancheId);\n    error NotLegacyAsset(address providedAsset, address legacyAsset);\n    error NotLegacyShare(address providedShare, address legacyShare);\n}\n"
    },
    "src/vaults/token/ShareToken.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {ERC20} from \"src/misc/ERC20.sol\";\nimport {IERC20, IERC20Metadata} from \"src/misc/interfaces/IERC20.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IERC7575Share, IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nimport {\n    IHook,\n    HookData,\n    SUCCESS_CODE_ID,\n    SUCCESS_MESSAGE,\n    ERROR_CODE_ID,\n    ERROR_MESSAGE\n} from \"src/common/interfaces/IHook.sol\";\nimport {IShareToken, IERC1404} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\n/// @title  Share Token\n/// @notice Extension of ERC20 + ERC1404,\n///         integrating an external hook optionally for ERC20 callbacks and ERC1404 checks.\ncontract ShareToken is ERC20, IShareToken {\n    using MathLib for uint256;\n\n    mapping(address => Balance) private balances;\n\n    /// @inheritdoc IShareToken\n    address public hook;\n\n    /// @inheritdoc IERC7575Share\n    mapping(address asset => address) public vault;\n\n    constructor(uint8 decimals_) ERC20(decimals_) {}\n\n    modifier authOrHook() {\n        require(wards[msg.sender] == 1 || msg.sender == hook, NotAuthorizedOrHook());\n        _;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Administration\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IShareToken\n    function file(bytes32 what, address data) external authOrHook {\n        if (what == \"hook\") hook = data;\n        else revert FileUnrecognizedParam();\n        emit File(what, data);\n    }\n\n    /// @inheritdoc IShareToken\n    function file(bytes32 what, string memory data) public override(ERC20, IShareToken) auth {\n        super.file(what, data);\n    }\n\n    /// @inheritdoc IShareToken\n    function updateVault(address asset, address vault_) external auth {\n        vault[asset] = vault_;\n        emit VaultUpdate(asset, vault_);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // ERC-20 overrides\n    //----------------------------------------------------------------------------------------------\n\n    function _balanceOf(address user) internal view override returns (uint256) {\n        return balances[user].amount;\n    }\n\n    function _setBalance(address user, uint256 value) internal override {\n        balances[user].amount = value.toUint128();\n    }\n\n    /// @inheritdoc IShareToken\n    function hookDataOf(address user) public view returns (bytes16) {\n        return balances[user].hookData;\n    }\n\n    /// @inheritdoc IShareToken\n    function setHookData(address user, bytes16 hookData) public authOrHook {\n        balances[user].hookData = hookData;\n        emit SetHookData(user, hookData);\n    }\n\n    /// @inheritdoc IERC20\n    function transfer(address to, uint256 value) public override(ERC20, IERC20) returns (bool success) {\n        success = super.transfer(to, value);\n        _onTransfer(msg.sender, to, value);\n    }\n\n    /// @inheritdoc IERC20\n    function transferFrom(address from, address to, uint256 value)\n        public\n        override(ERC20, IERC20)\n        returns (bool success)\n    {\n        success = super.transferFrom(from, to, value);\n        _onTransfer(from, to, value);\n    }\n\n    /// @inheritdoc IShareToken\n    function mint(address to, uint256 value) public override(ERC20, IShareToken) {\n        super.mint(to, value);\n        require(totalSupply <= type(uint128).max, ExceedsMaxSupply());\n        _onTransfer(address(0), to, value);\n    }\n\n    /// @inheritdoc IShareToken\n    function burn(address from, uint256 value) public override(ERC20, IShareToken) {\n        super.burn(from, value);\n        _onTransfer(from, address(0), value);\n    }\n\n    function _onTransfer(address from, address to, uint256 value) internal {\n        address hook_ = hook;\n        require(\n            hook_ == address(0)\n                || IHook(hook_).onERC20Transfer(from, to, value, HookData(hookDataOf(from), hookDataOf(to)))\n                    == IHook.onERC20Transfer.selector,\n            RestrictionsFailed()\n        );\n    }\n\n    /// @inheritdoc IShareToken\n    function authTransferFrom(address sender, address from, address to, uint256 value)\n        public\n        auth\n        returns (bool success)\n    {\n        success = _transferFrom(sender, from, to, value);\n        address hook_ = hook;\n        if (hook_ != address(0)) {\n            IHook(hook_).onERC20AuthTransfer(sender, from, to, value, HookData(hookDataOf(from), hookDataOf(to)));\n        }\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // ERC-1404\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IShareToken\n    function checkTransferRestriction(address from, address to, uint256 value) public view returns (bool) {\n        return detectTransferRestriction(from, to, value) == SUCCESS_CODE_ID;\n    }\n\n    /// @inheritdoc IERC1404\n    function detectTransferRestriction(address from, address to, uint256 value) public view returns (uint8) {\n        address hook_ = hook;\n        if (hook_ == address(0)) return SUCCESS_CODE_ID;\n        return IHook(hook_).checkERC20Transfer(from, to, value, HookData(hookDataOf(from), hookDataOf(to)))\n            ? SUCCESS_CODE_ID\n            : ERROR_CODE_ID;\n    }\n\n    /// @inheritdoc IERC1404\n    function messageForTransferRestriction(uint8 restrictionCode) external pure returns (string memory) {\n        return restrictionCode == SUCCESS_CODE_ID ? SUCCESS_MESSAGE : ERROR_MESSAGE;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // ERC-165\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc IERC165\n    function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {\n        return interfaceId == type(IERC7575Share).interfaceId || interfaceId == type(IERC165).interfaceId;\n    }\n}\n"
    }
  },
  "settings": {
    "remappings": [
      "forge-std/=lib/forge-std/src/",
      "@chimera/=lib/chimera/src/",
      "chimera/=lib/chimera/src/",
      "ds-test/=lib/chimera/lib/forge-std/lib/ds-test/src/"
    ],
    "optimizer": { "enabled": true, "runs": 1 },
    "metadata": {
      "useLiteralContent": false,
      "bytecodeHash": "none",
      "appendCBOR": true
    },
    "outputSelection": {
      "lib/forge-std/src/interfaces/IERC165.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/GasService.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/Gateway.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/Guardian.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/MessageDispatcher.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/MessageProcessor.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/Root.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/TokenRecoverer.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/adapters/AxelarAdapter.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/adapters/WormholeAdapter.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/interfaces/IAdapter.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/interfaces/IAxelarAdapter.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/interfaces/IGasService.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/interfaces/IGateway.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/interfaces/IGatewayHandlers.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/interfaces/IGatewaySenders.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/interfaces/IGuardian.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/interfaces/IGuardianActions.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/interfaces/IHook.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/interfaces/IMessageDispatcher.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/interfaces/IMessageHandler.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/interfaces/IMessageProcessor.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/interfaces/IMessageProperties.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/interfaces/IMessageSender.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/interfaces/IRoot.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/interfaces/ITokenRecoverer.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/interfaces/IWormholeAdapter.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/libraries/MessageLib.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/libraries/MessageProofLib.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/libraries/PricingLib.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/types/AccountId.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/types/AssetId.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/types/PoolId.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/common/types/ShareClassId.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/hooks/FreezeOnly.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/hooks/FullRestrictions.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/hooks/RedemptionRestrictions.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/hooks/interfaces/IFreezable.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/hooks/interfaces/IMemberlist.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/hub/Accounting.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/hub/Holdings.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/hub/Hub.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/hub/HubRegistry.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/hub/ShareClassManager.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/hub/interfaces/IAccounting.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/hub/interfaces/IHoldings.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/hub/interfaces/IHub.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/hub/interfaces/IHubRegistry.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/hub/interfaces/IShareClassManager.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/Auth.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/BaseValuation.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/ERC20.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/IdentityValuation.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/Multicall.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/Recoverable.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/ReentrancyProtection.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/interfaces/IAuth.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/interfaces/IBaseValuation.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/interfaces/IERC20.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/interfaces/IERC6909.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/interfaces/IERC7540.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/interfaces/IERC7575.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/interfaces/IERC7726.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/interfaces/IIdentityValuation.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/interfaces/IMulticall.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/interfaces/IRecoverable.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/libraries/ArrayLib.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/libraries/BitmapLib.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/libraries/BytesLib.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/libraries/CastLib.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/libraries/EIP712Lib.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/libraries/MathLib.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/libraries/SafeTransferLib.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/libraries/SignatureLib.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/libraries/StringLib.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/libraries/TransientArrayLib.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/libraries/TransientBytesLib.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/libraries/TransientStorageLib.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/misc/types/D18.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/AsyncRequestManager.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/AsyncVault.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/BalanceSheet.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/BaseRequestManager.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/BaseVaults.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/Escrow.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/PoolManager.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/SyncDepositVault.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/SyncRequestManager.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/VaultRouter.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/factories/AsyncVaultFactory.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/factories/PoolEscrowFactory.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/factories/SyncDepositVaultFactory.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/factories/TokenFactory.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/interfaces/IBalanceSheet.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/interfaces/IBaseVaults.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/interfaces/IEscrow.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/interfaces/IPoolManager.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/interfaces/IUpdateContract.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/interfaces/IVaultRouter.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/interfaces/factories/IPoolEscrowFactory.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/interfaces/factories/ITokenFactory.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/interfaces/factories/IVaultFactory.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/interfaces/investments/IAsyncDepositManager.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/interfaces/investments/IAsyncRedeemManager.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/interfaces/investments/IAsyncRequestManager.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/interfaces/investments/IBaseRequestManager.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/interfaces/investments/IDepositManager.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/interfaces/investments/IRedeemManager.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/interfaces/investments/ISyncDepositManager.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/interfaces/investments/ISyncRequestManager.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/interfaces/token/IShareToken.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/legacy/LegacyVaultAdapter.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/legacy/interfaces/IInvestmentManager.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/legacy/interfaces/ILegacyVault.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/legacy/interfaces/ILegacyVaultAdapter.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      },
      "src/vaults/token/ShareToken.sol": {
        "*": ["abi", "evm.methodIdentifiers", "metadata"]
      }
    },
    "evmVersion": "cancun",
    "viaIR": true,
    "libraries": {}
  }
}