{"file_path":"src/hooks/FreelyTransferable.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.28;\n\nimport {BaseTransferHook} from \"./BaseTransferHook.sol\";\n\nimport {ITransferHook, HookData} from \"../core/spoke/interfaces/ITransferHook.sol\";\n\n/// @title  Freely Transferable\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 deposit or redemption request\n///         * Supports freezing accounts which blocks transfers both to and from them\ncontract FreelyTransferable is BaseTransferHook {\n    constructor(\n        address root_,\n        address spoke_,\n        address balanceSheet_,\n        address crosschainSource_,\n        address deployer,\n        address poolEscrowProvider_,\n        address poolEscrow_\n    ) BaseTransferHook(root_, spoke_, balanceSheet_, crosschainSource_, deployer, poolEscrowProvider_, poolEscrow_) {}\n\n    /// @inheritdoc ITransferHook\n    function checkERC20Transfer(\n        address from,\n        address to,\n        uint256,\n        /* value */\n        HookData calldata hookData\n    )\n        public\n        view\n        override\n        returns (bool)\n    {\n        if (isSourceOrTargetFrozen(from, to, hookData)) return false;\n        if (isDepositRequestOrIssuance(from, to)) return isTargetMember(to, hookData);\n        if (isDepositClaim(from, to)) return isTargetMember(to, hookData);\n        if (isRedeemRequest(from, to)) return isSourceMember(from, hookData);\n        if (isRedeemClaimOrRevocation(from, to)) return isSourceMember(from, hookData);\n\n        // Else, it's a fulfillment, redemption, or transfer\n        return true;\n    }\n}\n","deployed_bytecode":"0x608060405234801561000f575f5ffd5b5060043610610194575f3560e01c806301ffc9a71461019857806303678eeb146101c0578063078d18cd146101d35780630e046af61461020b578063157482501461021e5780631fa4ef721461023357806322285cf61461026057806339ac7a08146102945780633f71910e146102c657806346de0fb1146102d957806347bfbcc6146102ec5780635156eb17146103135780635adb6ddb146103265780635ffc3d69146103395780636499415d1461034c57806365fae35e1461035f5780637017d09d1461037257806372070cb21461039957806378fe85a8146103ac5780637aeba8d5146103bf5780637f5ca5a3146103d25780638833cf0c146103eb578063929565dc146103fe5780639c52a7f1146104255780639e6cb9b914610438578063a37256601461044b578063a95512141461045e578063abd0e1eb14610471578063bf353dbb14610484578063ebf0c717146104b1578063ed6aac73146104d8578063ef59bc92146104eb578063f83e7828146104fe578063faff5bf714610511575b5f5ffd5b6101ab6101a63660046118e0565b610538565b60405190151581526020015b60405180910390f35b6101ab6101ce36600461191e565b61056e565b6101f26101e136600461194f565b63078d18cd60e01b95945050505050565b6040516001600160e01b031990911681526020016101b7565b6101ab6102193660046119b0565b610752565b61023161022c3660046119f5565b6107c4565b005b6101ab6102413660046119f5565b600160209081525f928352604080842090915290825290205460ff1681565b6102877f00000000000000000000000012a110ce5f0fc871cc72bc7ecaf35cf39dd0f43e81565b6040516101b79190611a2c565b6102a76102a23660046119f5565b610a1c565b6040805192151583526001600160401b039091166020830152016101b7565b6101f26102d4366004611a40565b610ad1565b6101ab6102e73660046119f5565b610b0d565b6102877f000000000000000000000000ec3582fcdc34078a4b7a8c75a5a3ae46f48525ab81565b610231610321366004611aa3565b610b80565b6102316103343660046119f5565b610da5565b6101ab6103473660046119f5565b610f1a565b6101ab61035a3660046119f5565b610fa6565b61023161036d36600461191e565b610fc2565b6102877f0000000000000000000000005187a505c485e22f0b8a5fbdf69ef1c29c478ce381565b6101ab6103a73660046119f5565b611035565b6101ab6103ba3660046119f5565b611083565b6102316103cd366004611b88565b6110e6565b6103d95f81565b60405160ff90911681526020016101b7565b6102316103f9366004611be9565b6111e9565b6102877f000000000000000000000000798712d8fea603e007a43f4705af98dc6b76258a81565b61023161043336600461191e565b61140c565b6101ab6104463660046119f5565b61147e565b6101ab610459366004611c46565b6114a0565b6101ab61046c3660046119f5565b6114d0565b6101ab61047f366004611c46565b6114e5565b6104a361049236600461191e565b5f6020819052908152604090205481565b6040519081526020016101b7565b6102877f0000000000000000000000007ed48c31f2fdc40d37407cbabf0870b2b688368f81565b6101ab6104e63660046119f5565b6115a8565b6101ab6104f9366004611a40565b6115f5565b6101ab61050c3660046119f5565b611683565b6102877f000000000000000000000000ec3582fcdc34078a4b7a8c75a5a3ae46f48525ab81565b5f6001600160e01b03198216632b53a76160e21b148061056857506001600160e01b031982166301ffc9a760e01b145b92915050565b5f7f000000000000000000000000798712d8fea603e007a43f4705af98dc6b76258a6001600160a01b0316156105da577f000000000000000000000000798712d8fea603e007a43f4705af98dc6b76258a6001600160a01b0316826001600160a01b0316149050919050565b816001600160a01b03163b5f036105f257505f919050565b60408051600481526024810182526020810180516001600160e01b0316631f06e1a760e11b17905290515f9182916001600160a01b0386169161063491611c7a565b5f60405180830381855afa9150503d805f811461066c576040519150601f19603f3d011682016040523d82523d5f602084013e610671565b606091505b509150915081158061068557508051602014155b1561069357505f9392505050565b5f818060200190518101906106a89190611c90565b9050846001600160a01b03167f0000000000000000000000005187a505c485e22f0b8a5fbdf69ef1c29c478ce36001600160a01b0316638b96ad12836040518263ffffffff1660e01b81526004016107009190611cab565b602060405180830381865afa15801561071b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061073f9190611cbf565b6001600160a01b03161495945050505050565b5f610772816107646020850185611cda565b60801c906001901b16151590565b1515600114801561078957506107878461056e565b155b806107ba57506107a35f6107646040850160208601611cda565b151560011480156107ba57506107b88361056e565b155b90505b9392505050565b335f9081526020819052604090205482906001148061080557506001600160a01b0381165f90815260016020908152604080832033845290915290205460ff165b6108225760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b03821661084957604051631e778ac960e21b815260040160405180910390fd5b60405163854b89d560e01b81526001600160a01b037f0000000000000000000000007ed48c31f2fdc40d37407cbabf0870b2b688368f169063854b89d590610895908590600401611a2c565b602060405180830381865afa1580156108b0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108d49190611d09565b1580156108e757506108e58261056e565b155b610904576040516307bd5aa160e51b815260040160405180910390fd5b60405163e8e6dc7560e01b81525f906001600160a01b0385169063e8e6dc7590610932908690600401611a2c565b602060405180830381865afa15801561094d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109719190611d22565b60801c90506001600160a01b038416636a9154aa84610992845f60016116d0565b60801b6040518363ffffffff1660e01b81526004016109b2929190611d3d565b5f604051808303815f87803b1580156109c9575f5ffd5b505af11580156109db573d5f5f3e3d5ffd5b50506040516001600160a01b038087169350871691507f51d18786e9cb144f87d46e7b796309ea84c7c687d91e09c97f051eacf59bc528905f90a350505050565b5f5f610aba5f856001600160a01b031663e8e6dc75866040518263ffffffff1660e01b8152600401610a4e9190611a2c565b602060405180830381865afa158015610a69573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a8d9190611d22565b6040516001600160801b0319909116602082015260300160408051601f19818403018152919052906116ee565b426001600160401b03821610159590945092505050565b5f610ade858585856115f5565b610afb57604051637c8733a560e11b815260040160405180910390fd5b50631fb8c88760e11b5b949350505050565b60405163e8e6dc7560e01b81525f906107bd9082906001600160a01b0386169063e8e6dc7590610b41908790600401611a2c565b602060405180830381865afa158015610b5c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107649190611d22565b335f90815260208190526040902054839060011480610bc157506001600160a01b0381165f90815260016020908152604080832033845290915290205460ff165b610bde5760405163ea8e4eb560e01b815260040160405180910390fd5b816001600160401b0316421115610c085760405163488b16b760e01b815260040160405180910390fd5b60405163854b89d560e01b81526001600160a01b037f0000000000000000000000007ed48c31f2fdc40d37407cbabf0870b2b688368f169063854b89d590610c54908690600401611a2c565b602060405180830381865afa158015610c6f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c939190611d09565b158015610ca65750610ca48361056e565b155b610cc35760405163da427dd160e01b815260040160405180910390fd5b600160401b600160801b03604083901b16610cf35f610ce28787610b0d565b6001600160801b03841691906116d0565b9050846001600160a01b0316636a9154aa858360801b6040518363ffffffff1660e01b8152600401610d26929190611d3d565b5f604051808303815f87803b158015610d3d575f5ffd5b505af1158015610d4f573d5f5f3e3d5ffd5b50505050836001600160a01b0316856001600160a01b03167f2cb446aa76cf148ccee709c872ab53d7064340c84a66351f6a16ec660434c8cc85604051610d969190611cab565b60405180910390a35050505050565b335f90815260208190526040902054829060011480610de657506001600160a01b0381165f90815260016020908152604080832033845290915290205460ff165b610e035760405163ea8e4eb560e01b815260040160405180910390fd5b60405163e8e6dc7560e01b81525f906001600160a01b0385169063e8e6dc7590610e31908690600401611a2c565b602060405180830381865afa158015610e4c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e709190611d22565b60801c90506001600160a01b038416636a9154aa84610e90845f806116d0565b60801b6040518363ffffffff1660e01b8152600401610eb0929190611d3d565b5f604051808303815f87803b158015610ec7575f5ffd5b505af1158015610ed9573d5f5f3e3d5ffd5b50506040516001600160a01b038087169350871691507f4f3ab9ff0cc4f039268532098e01239544b0420171876e36889d01c62c784c79905f90a350505050565b5f7f00000000000000000000000012a110ce5f0fc871cc72bc7ecaf35cf39dd0f43e6001600160a01b0316836001600160a01b031614158015610f8f57507f000000000000000000000000ec3582fcdc34078a4b7a8c75a5a3ae46f48525ab6001600160a01b0316836001600160a01b031614155b80156107bd5750506001600160a01b031615919050565b5f6001600160a01b0383161580156107bd57506107bd8261056e565b335f90815260208190526040902054600114610ff15760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f8181526020819052604080822060019055517fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a609190a250565b5f7f000000000000000000000000ec3582fcdc34078a4b7a8c75a5a3ae46f48525ab6001600160a01b0316836001600160a01b03161480156107bd5750506001600160a01b03161515919050565b5f6001600160a01b0383161580156110a1575061109f8261056e565b155b80156107bd57507f000000000000000000000000ec3582fcdc34078a4b7a8c75a5a3ae46f48525ab6001600160a01b0316826001600160a01b03161415905092915050565b335f908152602081905260409020546001146111155760405163ea8e4eb560e01b815260040160405180910390fd5b5f61111f82611724565b9050600181600381111561113557611135611d60565b03611166575f61114483611743565b905061116084611156835f01516117c7565b8360200151610b80565b50505050565b600281600381111561117a5761117a611d60565b0361119b575f611189836117f7565b90506111608461022c835f01516117c7565b60038160038111156111af576111af611d60565b036111d0575f6111be8361185f565b905061116084610334835f01516117c7565b604051637d5ba07f60e01b815260040160405180910390fd5b335f908152602081905260409020546001146112185760405163ea8e4eb560e01b815260040160405180910390fd5b5f8180602001905181019061122d9190611d84565b905060ff8116156112515760405163e85b9b3d60e01b815260040160405180910390fd5b5f60ff8216801561126457611264611d60565b90505f81801561127657611276611d60565b03611405575f5f848060200190518101906112919190611d9d565b60405163602ff8a960e11b81526001600160401b038b1660048201526001600160801b03198a16602482015291945092505f91506001600160a01b037f000000000000000000000000ec3582fcdc34078a4b7a8c75a5a3ae46f48525ab169063c05ff15290604401602060405180830381865afa158015611314573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113389190611cbf565b90506001600160a01b03811661136157604051630344039160e61b815260040160405180910390fd5b6001600160a01b0381165f9081526001602052604081208391611383866117c7565b6001600160a01b0316815260208101919091526040015f20805460ff19169115159190911790556113b3836117c7565b6001600160a01b0316816001600160a01b03167fd05acace02290394837284bf7e4a4cca4a12d0afbf678bb87f586f449f455491846040516113f9911515815260200190565b60405180910390a35050505b5050505050565b335f9081526020819052604090205460011461143b5760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f81815260208190526040808220829055517f184450df2e323acec0ed3b5c7531b81f9b4cdef7914dfd4c0a4317416bb5251b9190a250565b5f6114888361056e565b80156107bd5750506001600160a01b03161515919050565b5f4260406114b16020850185611cda565b60801c901c6001600160801b03161015806107bd57506107bd8361056e565b6001600160a01b0381166201cf601492915050565b5f4260406114f884820160208601611cda565b60801c901c6001600160801b0316101580611599575060405163854b89d560e01b81526001600160a01b037f0000000000000000000000007ed48c31f2fdc40d37407cbabf0870b2b688368f169063854b89d59061155a908690600401611a2c565b602060405180830381865afa158015611575573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115999190611d09565b806107bd57506107bd8361056e565b5f7f000000000000000000000000ec3582fcdc34078a4b7a8c75a5a3ae46f48525ab6001600160a01b0316836001600160a01b03161480156107bd5750506001600160a01b031615919050565b5f611601858584610752565b1561160d57505f610b05565b6116178585611083565b1561162d5761162684836114e5565b9050610b05565b611637858561147e565b156116465761162684836114e5565b61165085856114d0565b1561165f5761162685836114a0565b6116698585610f1a565b156116785761162685836114a0565b506001949350505050565b5f7f00000000000000000000000012a110ce5f0fc871cc72bc7ecaf35cf39dd0f43e6001600160a01b0316836001600160a01b03161480156107bd5750506001600160a01b031615919050565b5f81156116e357506001821b83176107bd565b50506001901b191690565b5f6116fa826008611dcd565b8351101561171b57604051633b99b53d60e01b815260040160405180910390fd5b50016008015190565b5f61172f8282611874565b60ff16600381111561056857610568611d60565b604080518082019091525f8082526020820152600161176183611724565b600381111561177257611772611d60565b14611790576040516304c735eb60e11b815260040160405180910390fd5b60408051808201909152806117a68460016118aa565b81526020016117b68460216116ee565b6001600160401b0316905292915050565b5f6001600160601b038216156117f05760405163e8bd165960e01b815260040160405180910390fd5b5060601c90565b60408051602081019091525f815260025b61181183611724565b600381111561182257611822611d60565b14611840576040516304c735eb60e11b815260040160405180910390fd5b6040805160208101909152806118578460016118aa565b905292915050565b60408051602081019091525f81526003611808565b5f611880826001611dcd565b835110156118a157604051633b99b53d60e01b815260040160405180910390fd5b50016001015190565b5f6118b6826020611dcd565b835110156118d757604051633b99b53d60e01b815260040160405180910390fd5b50016020015190565b5f602082840312156118f0575f5ffd5b81356001600160e01b0319811681146107bd575f5ffd5b6001600160a01b038116811461191b575f5ffd5b50565b5f6020828403121561192e575f5ffd5b81356107bd81611907565b5f60408284031215611949575f5ffd5b50919050565b5f5f5f5f5f60c08688031215611963575f5ffd5b853561196e81611907565b9450602086013561197e81611907565b9350604086013561198e81611907565b9250606086013591506119a48760808801611939565b90509295509295909350565b5f5f5f608084860312156119c2575f5ffd5b83356119cd81611907565b925060208401356119dd81611907565b91506119ec8560408601611939565b90509250925092565b5f5f60408385031215611a06575f5ffd5b8235611a1181611907565b91506020830135611a2181611907565b809150509250929050565b6001600160a01b0391909116815260200190565b5f5f5f5f60a08587031215611a53575f5ffd5b8435611a5e81611907565b93506020850135611a6e81611907565b925060408501359150611a848660608701611939565b905092959194509250565b6001600160401b038116811461191b575f5ffd5b5f5f5f60608486031215611ab5575f5ffd5b8335611ac081611907565b92506020840135611ad081611907565b91506040840135611ae081611a8f565b809150509250925092565b634e487b7160e01b5f52604160045260245ffd5b5f82601f830112611b0e575f5ffd5b81356001600160401b03811115611b2757611b27611aeb565b604051601f8201601f19908116603f011681016001600160401b0381118282101715611b5557611b55611aeb565b604052818152838201602001851015611b6c575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f5f60408385031215611b99575f5ffd5b8235611ba481611907565b915060208301356001600160401b03811115611bbe575f5ffd5b611bca85828601611aff565b9150509250929050565b6001600160801b03198116811461191b575f5ffd5b5f5f5f60608486031215611bfb575f5ffd5b8335611c0681611a8f565b92506020840135611c1681611bd4565b915060408401356001600160401b03811115611c30575f5ffd5b611c3c86828701611aff565b9150509250925092565b5f5f60608385031215611c57575f5ffd5b8235611c6281611907565b9150611c718460208501611939565b90509250929050565b5f82518060208501845e5f920191825250919050565b5f60208284031215611ca0575f5ffd5b81516107bd81611a8f565b6001600160401b0391909116815260200190565b5f60208284031215611ccf575f5ffd5b81516107bd81611907565b5f60208284031215611cea575f5ffd5b81356107bd81611bd4565b80518015158114611d04575f5ffd5b919050565b5f60208284031215611d19575f5ffd5b6107bd82611cf5565b5f60208284031215611d32575f5ffd5b81516107bd81611bd4565b6001600160a01b039290921682526001600160801b031916602082015260400190565b634e487b7160e01b5f52602160045260245ffd5b805160ff81168114611d04575f5ffd5b5f60208284031215611d94575f5ffd5b6107bd82611d74565b5f5f5f60608486031215611daf575f5ffd5b611db884611d74565b9250602084015191506119ec60408501611cf5565b8082018082111561056857634e487b7160e01b5f52601160045260245ffd","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"cancun","libraries":{},"metadata":{"appendCBOR":false,"bytecodeHash":"none","useLiteralContent":true},"optimizer":{"enabled":true,"runs":1},"outputSelection":{"*":{"":["*"],"*":["*"]}},"remappings":["forge-std/=lib/forge-std/src/","@chimera/=lib/chimera/src/"],"viaIR":false},"optimization_runs":1,"sourcify_repo_url":null,"decoded_constructor_args":[["0x7Ed48C31f2fdC40d37407cBaBf0870B2b688368f",{"internalType":"address","name":"root_","type":"address"}],["0xEC3582fcDc34078a4B7a8c75a5a3AE46f48525aB",{"internalType":"address","name":"spoke_","type":"address"}],["0x12a110cE5f0FC871cC72Bc7ECaF35cf39DD0f43e",{"internalType":"address","name":"balanceSheet_","type":"address"}],["0xEC3582fcDc34078a4B7a8c75a5a3AE46f48525aB",{"internalType":"address","name":"crosschainSource_","type":"address"}],["0x8D566ADACe57ee5DD2BF98953B804991D634211A",{"internalType":"address","name":"deployer","type":"address"}],["0x5187A505c485E22f0b8a5FBdF69eF1c29C478CE3",{"internalType":"address","name":"poolEscrowProvider_","type":"address"}],["0x798712d8FeA603E007A43f4705AF98DC6B76258a",{"internalType":"address","name":"poolEscrow_","type":"address"}]],"compiler_version":"v0.8.28+commit.7893614a","is_verified_via_verifier_alliance":false,"verified_at":"2026-06-11T20:59:10.268589Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x610140604052348015610010575f5ffd5b5060405161201738038061201783398101604081905261002f91610108565b6001600160a01b0383165f8181526020819052604080822060019055518992899289928992899289928992859290917fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a609190a250836001600160a01b0316856001600160a01b0316036100b5576040516379a67d5b60e11b815260040160405180910390fd5b6001600160a01b0396871660805294861660a0529285166101005250831660e0528216610120521660c0525061018995505050505050565b80516001600160a01b0381168114610103575f5ffd5b919050565b5f5f5f5f5f5f5f60e0888a03121561011e575f5ffd5b610127886100ed565b9650610135602089016100ed565b9550610143604089016100ed565b9450610151606089016100ed565b935061015f608089016100ed565b925061016d60a089016100ed565b915061017b60c089016100ed565b905092959891949750929550565b60805160a05160c05160e0516101005161012051611dec61022b5f395f818161037701526106b601525f818161026501528181610f1d015261168601525f818161051601528181610f5a01528181611038015281816110aa01526115ab01525f81816104030152818161057101526105a001525f81816102f101526112cf01525f81816104b60152818161086001528181610c1f01526115250152611dec5ff3fe608060405234801561000f575f5ffd5b5060043610610194575f3560e01c806301ffc9a71461019857806303678eeb146101c0578063078d18cd146101d35780630e046af61461020b578063157482501461021e5780631fa4ef721461023357806322285cf61461026057806339ac7a08146102945780633f71910e146102c657806346de0fb1146102d957806347bfbcc6146102ec5780635156eb17146103135780635adb6ddb146103265780635ffc3d69146103395780636499415d1461034c57806365fae35e1461035f5780637017d09d1461037257806372070cb21461039957806378fe85a8146103ac5780637aeba8d5146103bf5780637f5ca5a3146103d25780638833cf0c146103eb578063929565dc146103fe5780639c52a7f1146104255780639e6cb9b914610438578063a37256601461044b578063a95512141461045e578063abd0e1eb14610471578063bf353dbb14610484578063ebf0c717146104b1578063ed6aac73146104d8578063ef59bc92146104eb578063f83e7828146104fe578063faff5bf714610511575b5f5ffd5b6101ab6101a63660046118e0565b610538565b60405190151581526020015b60405180910390f35b6101ab6101ce36600461191e565b61056e565b6101f26101e136600461194f565b63078d18cd60e01b95945050505050565b6040516001600160e01b031990911681526020016101b7565b6101ab6102193660046119b0565b610752565b61023161022c3660046119f5565b6107c4565b005b6101ab6102413660046119f5565b600160209081525f928352604080842090915290825290205460ff1681565b6102877f000000000000000000000000000000000000000000000000000000000000000081565b6040516101b79190611a2c565b6102a76102a23660046119f5565b610a1c565b6040805192151583526001600160401b039091166020830152016101b7565b6101f26102d4366004611a40565b610ad1565b6101ab6102e73660046119f5565b610b0d565b6102877f000000000000000000000000000000000000000000000000000000000000000081565b610231610321366004611aa3565b610b80565b6102316103343660046119f5565b610da5565b6101ab6103473660046119f5565b610f1a565b6101ab61035a3660046119f5565b610fa6565b61023161036d36600461191e565b610fc2565b6102877f000000000000000000000000000000000000000000000000000000000000000081565b6101ab6103a73660046119f5565b611035565b6101ab6103ba3660046119f5565b611083565b6102316103cd366004611b88565b6110e6565b6103d95f81565b60405160ff90911681526020016101b7565b6102316103f9366004611be9565b6111e9565b6102877f000000000000000000000000000000000000000000000000000000000000000081565b61023161043336600461191e565b61140c565b6101ab6104463660046119f5565b61147e565b6101ab610459366004611c46565b6114a0565b6101ab61046c3660046119f5565b6114d0565b6101ab61047f366004611c46565b6114e5565b6104a361049236600461191e565b5f6020819052908152604090205481565b6040519081526020016101b7565b6102877f000000000000000000000000000000000000000000000000000000000000000081565b6101ab6104e63660046119f5565b6115a8565b6101ab6104f9366004611a40565b6115f5565b6101ab61050c3660046119f5565b611683565b6102877f000000000000000000000000000000000000000000000000000000000000000081565b5f6001600160e01b03198216632b53a76160e21b148061056857506001600160e01b031982166301ffc9a760e01b145b92915050565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316156105da577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316149050919050565b816001600160a01b03163b5f036105f257505f919050565b60408051600481526024810182526020810180516001600160e01b0316631f06e1a760e11b17905290515f9182916001600160a01b0386169161063491611c7a565b5f60405180830381855afa9150503d805f811461066c576040519150601f19603f3d011682016040523d82523d5f602084013e610671565b606091505b509150915081158061068557508051602014155b1561069357505f9392505050565b5f818060200190518101906106a89190611c90565b9050846001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638b96ad12836040518263ffffffff1660e01b81526004016107009190611cab565b602060405180830381865afa15801561071b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061073f9190611cbf565b6001600160a01b03161495945050505050565b5f610772816107646020850185611cda565b60801c906001901b16151590565b1515600114801561078957506107878461056e565b155b806107ba57506107a35f6107646040850160208601611cda565b151560011480156107ba57506107b88361056e565b155b90505b9392505050565b335f9081526020819052604090205482906001148061080557506001600160a01b0381165f90815260016020908152604080832033845290915290205460ff165b6108225760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b03821661084957604051631e778ac960e21b815260040160405180910390fd5b60405163854b89d560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063854b89d590610895908590600401611a2c565b602060405180830381865afa1580156108b0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108d49190611d09565b1580156108e757506108e58261056e565b155b610904576040516307bd5aa160e51b815260040160405180910390fd5b60405163e8e6dc7560e01b81525f906001600160a01b0385169063e8e6dc7590610932908690600401611a2c565b602060405180830381865afa15801561094d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109719190611d22565b60801c90506001600160a01b038416636a9154aa84610992845f60016116d0565b60801b6040518363ffffffff1660e01b81526004016109b2929190611d3d565b5f604051808303815f87803b1580156109c9575f5ffd5b505af11580156109db573d5f5f3e3d5ffd5b50506040516001600160a01b038087169350871691507f51d18786e9cb144f87d46e7b796309ea84c7c687d91e09c97f051eacf59bc528905f90a350505050565b5f5f610aba5f856001600160a01b031663e8e6dc75866040518263ffffffff1660e01b8152600401610a4e9190611a2c565b602060405180830381865afa158015610a69573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a8d9190611d22565b6040516001600160801b0319909116602082015260300160408051601f19818403018152919052906116ee565b426001600160401b03821610159590945092505050565b5f610ade858585856115f5565b610afb57604051637c8733a560e11b815260040160405180910390fd5b50631fb8c88760e11b5b949350505050565b60405163e8e6dc7560e01b81525f906107bd9082906001600160a01b0386169063e8e6dc7590610b41908790600401611a2c565b602060405180830381865afa158015610b5c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107649190611d22565b335f90815260208190526040902054839060011480610bc157506001600160a01b0381165f90815260016020908152604080832033845290915290205460ff165b610bde5760405163ea8e4eb560e01b815260040160405180910390fd5b816001600160401b0316421115610c085760405163488b16b760e01b815260040160405180910390fd5b60405163854b89d560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063854b89d590610c54908690600401611a2c565b602060405180830381865afa158015610c6f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c939190611d09565b158015610ca65750610ca48361056e565b155b610cc35760405163da427dd160e01b815260040160405180910390fd5b600160401b600160801b03604083901b16610cf35f610ce28787610b0d565b6001600160801b03841691906116d0565b9050846001600160a01b0316636a9154aa858360801b6040518363ffffffff1660e01b8152600401610d26929190611d3d565b5f604051808303815f87803b158015610d3d575f5ffd5b505af1158015610d4f573d5f5f3e3d5ffd5b50505050836001600160a01b0316856001600160a01b03167f2cb446aa76cf148ccee709c872ab53d7064340c84a66351f6a16ec660434c8cc85604051610d969190611cab565b60405180910390a35050505050565b335f90815260208190526040902054829060011480610de657506001600160a01b0381165f90815260016020908152604080832033845290915290205460ff165b610e035760405163ea8e4eb560e01b815260040160405180910390fd5b60405163e8e6dc7560e01b81525f906001600160a01b0385169063e8e6dc7590610e31908690600401611a2c565b602060405180830381865afa158015610e4c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e709190611d22565b60801c90506001600160a01b038416636a9154aa84610e90845f806116d0565b60801b6040518363ffffffff1660e01b8152600401610eb0929190611d3d565b5f604051808303815f87803b158015610ec7575f5ffd5b505af1158015610ed9573d5f5f3e3d5ffd5b50506040516001600160a01b038087169350871691507f4f3ab9ff0cc4f039268532098e01239544b0420171876e36889d01c62c784c79905f90a350505050565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b031614158015610f8f57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b031614155b80156107bd5750506001600160a01b031615919050565b5f6001600160a01b0383161580156107bd57506107bd8261056e565b335f90815260208190526040902054600114610ff15760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f8181526020819052604080822060019055517fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a609190a250565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b03161480156107bd5750506001600160a01b03161515919050565b5f6001600160a01b0383161580156110a1575061109f8261056e565b155b80156107bd57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415905092915050565b335f908152602081905260409020546001146111155760405163ea8e4eb560e01b815260040160405180910390fd5b5f61111f82611724565b9050600181600381111561113557611135611d60565b03611166575f61114483611743565b905061116084611156835f01516117c7565b8360200151610b80565b50505050565b600281600381111561117a5761117a611d60565b0361119b575f611189836117f7565b90506111608461022c835f01516117c7565b60038160038111156111af576111af611d60565b036111d0575f6111be8361185f565b905061116084610334835f01516117c7565b604051637d5ba07f60e01b815260040160405180910390fd5b335f908152602081905260409020546001146112185760405163ea8e4eb560e01b815260040160405180910390fd5b5f8180602001905181019061122d9190611d84565b905060ff8116156112515760405163e85b9b3d60e01b815260040160405180910390fd5b5f60ff8216801561126457611264611d60565b90505f81801561127657611276611d60565b03611405575f5f848060200190518101906112919190611d9d565b60405163602ff8a960e11b81526001600160401b038b1660048201526001600160801b03198a16602482015291945092505f91506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c05ff15290604401602060405180830381865afa158015611314573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113389190611cbf565b90506001600160a01b03811661136157604051630344039160e61b815260040160405180910390fd5b6001600160a01b0381165f9081526001602052604081208391611383866117c7565b6001600160a01b0316815260208101919091526040015f20805460ff19169115159190911790556113b3836117c7565b6001600160a01b0316816001600160a01b03167fd05acace02290394837284bf7e4a4cca4a12d0afbf678bb87f586f449f455491846040516113f9911515815260200190565b60405180910390a35050505b5050505050565b335f9081526020819052604090205460011461143b5760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f81815260208190526040808220829055517f184450df2e323acec0ed3b5c7531b81f9b4cdef7914dfd4c0a4317416bb5251b9190a250565b5f6114888361056e565b80156107bd5750506001600160a01b03161515919050565b5f4260406114b16020850185611cda565b60801c901c6001600160801b03161015806107bd57506107bd8361056e565b6001600160a01b0381166201cf601492915050565b5f4260406114f884820160208601611cda565b60801c901c6001600160801b0316101580611599575060405163854b89d560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063854b89d59061155a908690600401611a2c565b602060405180830381865afa158015611575573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115999190611d09565b806107bd57506107bd8361056e565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b03161480156107bd5750506001600160a01b031615919050565b5f611601858584610752565b1561160d57505f610b05565b6116178585611083565b1561162d5761162684836114e5565b9050610b05565b611637858561147e565b156116465761162684836114e5565b61165085856114d0565b1561165f5761162685836114a0565b6116698585610f1a565b156116785761162685836114a0565b506001949350505050565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b03161480156107bd5750506001600160a01b031615919050565b5f81156116e357506001821b83176107bd565b50506001901b191690565b5f6116fa826008611dcd565b8351101561171b57604051633b99b53d60e01b815260040160405180910390fd5b50016008015190565b5f61172f8282611874565b60ff16600381111561056857610568611d60565b604080518082019091525f8082526020820152600161176183611724565b600381111561177257611772611d60565b14611790576040516304c735eb60e11b815260040160405180910390fd5b60408051808201909152806117a68460016118aa565b81526020016117b68460216116ee565b6001600160401b0316905292915050565b5f6001600160601b038216156117f05760405163e8bd165960e01b815260040160405180910390fd5b5060601c90565b60408051602081019091525f815260025b61181183611724565b600381111561182257611822611d60565b14611840576040516304c735eb60e11b815260040160405180910390fd5b6040805160208101909152806118578460016118aa565b905292915050565b60408051602081019091525f81526003611808565b5f611880826001611dcd565b835110156118a157604051633b99b53d60e01b815260040160405180910390fd5b50016001015190565b5f6118b6826020611dcd565b835110156118d757604051633b99b53d60e01b815260040160405180910390fd5b50016020015190565b5f602082840312156118f0575f5ffd5b81356001600160e01b0319811681146107bd575f5ffd5b6001600160a01b038116811461191b575f5ffd5b50565b5f6020828403121561192e575f5ffd5b81356107bd81611907565b5f60408284031215611949575f5ffd5b50919050565b5f5f5f5f5f60c08688031215611963575f5ffd5b853561196e81611907565b9450602086013561197e81611907565b9350604086013561198e81611907565b9250606086013591506119a48760808801611939565b90509295509295909350565b5f5f5f608084860312156119c2575f5ffd5b83356119cd81611907565b925060208401356119dd81611907565b91506119ec8560408601611939565b90509250925092565b5f5f60408385031215611a06575f5ffd5b8235611a1181611907565b91506020830135611a2181611907565b809150509250929050565b6001600160a01b0391909116815260200190565b5f5f5f5f60a08587031215611a53575f5ffd5b8435611a5e81611907565b93506020850135611a6e81611907565b925060408501359150611a848660608701611939565b905092959194509250565b6001600160401b038116811461191b575f5ffd5b5f5f5f60608486031215611ab5575f5ffd5b8335611ac081611907565b92506020840135611ad081611907565b91506040840135611ae081611a8f565b809150509250925092565b634e487b7160e01b5f52604160045260245ffd5b5f82601f830112611b0e575f5ffd5b81356001600160401b03811115611b2757611b27611aeb565b604051601f8201601f19908116603f011681016001600160401b0381118282101715611b5557611b55611aeb565b604052818152838201602001851015611b6c575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f5f60408385031215611b99575f5ffd5b8235611ba481611907565b915060208301356001600160401b03811115611bbe575f5ffd5b611bca85828601611aff565b9150509250929050565b6001600160801b03198116811461191b575f5ffd5b5f5f5f60608486031215611bfb575f5ffd5b8335611c0681611a8f565b92506020840135611c1681611bd4565b915060408401356001600160401b03811115611c30575f5ffd5b611c3c86828701611aff565b9150509250925092565b5f5f60608385031215611c57575f5ffd5b8235611c6281611907565b9150611c718460208501611939565b90509250929050565b5f82518060208501845e5f920191825250919050565b5f60208284031215611ca0575f5ffd5b81516107bd81611a8f565b6001600160401b0391909116815260200190565b5f60208284031215611ccf575f5ffd5b81516107bd81611907565b5f60208284031215611cea575f5ffd5b81356107bd81611bd4565b80518015158114611d04575f5ffd5b919050565b5f60208284031215611d19575f5ffd5b6107bd82611cf5565b5f60208284031215611d32575f5ffd5b81516107bd81611bd4565b6001600160a01b039290921682526001600160801b031916602082015260400190565b634e487b7160e01b5f52602160045260245ffd5b805160ff81168114611d04575f5ffd5b5f60208284031215611d94575f5ffd5b6107bd82611d74565b5f5f5f60608486031215611daf575f5ffd5b611db884611d74565b9250602084015191506119ec60408501611cf5565b8082018082111561056857634e487b7160e01b5f52601160045260245ffd0000000000000000000000007ed48c31f2fdc40d37407cbabf0870b2b688368f000000000000000000000000ec3582fcdc34078a4b7a8c75a5a3ae46f48525ab00000000000000000000000012a110ce5f0fc871cc72bc7ecaf35cf39dd0f43e000000000000000000000000ec3582fcdc34078a4b7a8c75a5a3ae46f48525ab0000000000000000000000008d566adace57ee5dd2bf98953b804991d634211a0000000000000000000000005187a505c485e22f0b8a5fbdf69ef1c29c478ce3000000000000000000000000798712d8fea603e007a43f4705af98dc6b76258a","name":"FreelyTransferable","is_blueprint":false,"license_type":"none","is_fully_verified":false,"is_verified_via_eth_bytecode_db":true,"language":"solidity","evm_version":"cancun","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":false,"additional_sources":[{"file_path":"src/core/messaging/interfaces/IProtocolPauser.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\n\ninterface IProtocolPauser {\n    event Pause();\n    event Unpause();\n\n    /// @notice Returns whether the root is paused\n    /// @return True if the protocol is paused, false otherwise\n    function paused() external view returns (bool);\n}\n"},{"file_path":"src/hooks/libraries/UpdateRestrictionMessageLib.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.28;\n\nimport {CastLib} from \"../../misc/libraries/CastLib.sol\";\nimport {BytesLib} from \"../../misc/libraries/BytesLib.sol\";\n\nenum UpdateRestrictionType {\n    /// @dev Placeholder for null update restriction type\n    Invalid,\n    Member,\n    Freeze,\n    Unfreeze\n}\n\nlibrary UpdateRestrictionMessageLib {\n    using UpdateRestrictionMessageLib for bytes;\n    using BytesLib for bytes;\n    using CastLib for *;\n\n    error UnknownMessageType();\n\n    function updateRestrictionType(bytes memory message) internal pure returns (UpdateRestrictionType) {\n        return UpdateRestrictionType(message.toUint8(0));\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        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        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        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"},{"file_path":"src/misc/libraries/BytesLib.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\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 slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) {\n        unchecked {\n            require(_length + 31 >= _length, SliceOverflow());\n        }\n        require(_bytes.length >= _start + _length, SliceOutOfBounds());\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 sliceZeroPadded(bytes memory _bytes, uint256 _start, uint256 _length)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        bool needsPad = _bytes.length < _start + _length;\n        if (!needsPad) return slice(_bytes, _start, _length);\n\n        bytes memory slice_ = slice(_bytes, _start, _bytes.length - _start);\n        bytes memory padding = new bytes(_length + _start - _bytes.length);\n        return bytes.concat(slice_, padding);\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"},{"file_path":"src/hooks/interfaces/IBaseTransferHook.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\n\nimport {ITransferHook} from \"../../core/spoke/interfaces/ITransferHook.sol\";\n\n/// @title  IBaseTransferHook\n/// @notice Interface for base transfer hook with trusted call functionality\ninterface IBaseTransferHook is ITransferHook {\n    //----------------------------------------------------------------------------------------------\n    // Enums\n    //----------------------------------------------------------------------------------------------\n\n    enum TrustedCall {\n        UpdateHookManager\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Events\n    //----------------------------------------------------------------------------------------------\n\n    event UpdateHookManager(address indexed token, address indexed manager, bool canManage);\n\n    //----------------------------------------------------------------------------------------------\n    // Errors\n    //----------------------------------------------------------------------------------------------\n\n    error UnknownTrustedCall();\n}\n"},{"file_path":"src/misc/libraries/SafeTransferLib.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity 0.8.28;\n\nimport {IERC20} from \"../interfaces/IERC20.sol\";\nimport {IERC7751} from \"../interfaces/IERC7751.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 returnData) = token.call(abi.encodeCall(IERC20.transferFrom, (from, to, value)));\n        require(\n            success && (returnData.length == 0 || abi.decode(returnData, (bool))),\n            IERC7751.WrappedError(\n                token, IERC20.transferFrom.selector, returnData, abi.encodeWithSelector(SafeTransferFromFailed.selector)\n            )\n        );\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 returnData) = token.call(abi.encodeCall(IERC20.transfer, (to, value)));\n        require(\n            success && (returnData.length == 0 || abi.decode(returnData, (bool))),\n            IERC7751.WrappedError(\n                token, IERC20.transfer.selector, returnData, abi.encodeWithSelector(SafeTransferFailed.selector)\n            )\n        );\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 returnData) = token.call(abi.encodeCall(IERC20.approve, (to, value)));\n        require(\n            success && (returnData.length == 0 || abi.decode(returnData, (bool))),\n            IERC7751.WrappedError(\n                token, IERC20.approve.selector, returnData, abi.encodeWithSelector(SafeApproveFailed.selector)\n            )\n        );\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"},{"file_path":"src/core/spoke/interfaces/IBalanceSheet.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\n\nimport {ISpoke} from \"./ISpoke.sol\";\nimport {IPoolEscrow} from \"./IPoolEscrow.sol\";\nimport {IEndorsements} from \"./IEndorsements.sol\";\n\nimport {D18} from \"../../../misc/types/D18.sol\";\n\nimport {ISpokeMessageSender} from \"../../messaging/interfaces/IGatewaySenders.sol\";\n\nimport {PoolId} from \"../../types/PoolId.sol\";\nimport {AssetId} from \"../../types/AssetId.sol\";\nimport {ShareClassId} from \"../../types/ShareClassId.sol\";\nimport {IBatchedMulticall} from \"../../utils/interfaces/IBatchedMulticall.sol\";\nimport {IPoolEscrowProvider} from \"../factories/interfaces/IPoolEscrowFactory.sol\";\n\nstruct ShareQueueAmount {\n    // Net queued shares\n    uint128 delta;\n    // Whether the net queued shares lead to an issuance or revocation\n    bool isPositive;\n    // Number of queued asset IDs for this share class\n    uint32 queuedAssetCounter;\n    // Nonce for share + asset messages to the hub\n    uint64 nonce;\n}\n\nstruct AssetQueueAmount {\n    uint128 deposits;\n    uint128 withdrawals;\n}\n\n/// @notice Withdrawal operation modes for BalanceSheet.withdraw()\nenum WithdrawMode {\n    /// @dev No escrow accounting, no Hub queue (ARM cancel flows)\n    TransferOnly,\n    /// @dev Escrow accounting + transfer, skip Hub queue (ARM after noteWithdraw)\n    EscrowAndTransfer,\n    /// @dev Full accounting (Default): escrow + Hub queue + transfer (OnOfframpManager)\n    Full\n}\n\ninterface IBalanceSheet is IBatchedMulticall {\n    //----------------------------------------------------------------------------------------------\n    // Events\n    //----------------------------------------------------------------------------------------------\n\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 NoteWithdraw(\n        PoolId indexed poolId,\n        ShareClassId indexed scId,\n        address asset,\n        uint256 tokenId,\n        uint128 amount,\n        D18 pricePoolPerAsset\n    );\n    event Deposit(\n        PoolId indexed poolId, ShareClassId indexed scId, address sender, address asset, uint256 tokenId, uint128 amount\n    );\n    event NoteDeposit(\n        PoolId indexed poolId,\n        ShareClassId indexed scId,\n        address sender,\n        address asset,\n        uint256 tokenId,\n        uint128 amount,\n        D18 pricePoolPerAsset\n    );\n    event Issue(\n        PoolId indexed poolId,\n        ShareClassId indexed scId,\n        address sender,\n        address to,\n        D18 pricePoolPerShare,\n        uint128 shares\n    );\n    event Revoke(\n        PoolId indexed poolId,\n        ShareClassId indexed scId,\n        address sender,\n        address from,\n        D18 pricePoolPerShare,\n        uint128 shares\n    );\n\n    event TransferSharesFrom(\n        PoolId indexed poolId,\n        ShareClassId indexed scId,\n        address sender,\n        address indexed from,\n        address to,\n        uint256 amount\n    );\n    event SubmitQueuedShares(PoolId indexed poolId, ShareClassId indexed scId, ISpokeMessageSender.UpdateData data);\n    event SubmitQueuedAssets(\n        PoolId indexed poolId,\n        ShareClassId indexed scId,\n        AssetId indexed assetId,\n        ISpokeMessageSender.UpdateData data,\n        D18 pricePoolPerAsset\n    );\n\n    //----------------------------------------------------------------------------------------------\n    // Errors\n    //----------------------------------------------------------------------------------------------\n\n    error FileUnrecognizedParam();\n    error CannotTransferFromEndorsedContract();\n\n    //----------------------------------------------------------------------------------------------\n    // Administration\n    //----------------------------------------------------------------------------------------------\n\n    /// @notice Updates a contract parameter\n    /// @param what Accepts a bytes32 representation of 'spoke', 'sender', 'gateway', 'poolEscrowProvider'\n    /// @param data The new address\n    function file(bytes32 what, address data) external;\n\n    //----------------------------------------------------------------------------------------------\n    // Management functions (standard operations)\n    //----------------------------------------------------------------------------------------------\n\n    /// @notice Deposit assets into the escrow of the pool\n    /// @param poolId The pool identifier\n    /// @param scId The share class identifier\n    /// @param asset The asset address\n    /// @param tokenId The token ID (SHOULD be 0 if depositing ERC20 assets. ERC6909 assets with tokenId=0 are not supported)\n    /// @param amount The amount to deposit\n    function deposit(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, uint128 amount) external payable;\n\n    /// @notice Withdraw assets from the escrow of the pool (standard operation)\n    /// @dev    Full withdrawal with escrow accounting, Hub queue, and transfer.\n    ///         Delegates to withdraw(7-param) with WithdrawMode.Full.\n    /// @param poolId The pool identifier\n    /// @param scId The share class identifier\n    /// @param asset The asset address\n    /// @param tokenId The token ID (SHOULD be 0 if depositing ERC20 assets. ERC6909 assets with tokenId=0 are not supported)\n    /// @param receiver The address to receive the withdrawn assets\n    /// @param amount The amount to withdraw\n    function withdraw(\n        PoolId poolId,\n        ShareClassId scId,\n        address asset,\n        uint256 tokenId,\n        address receiver,\n        uint128 amount\n    ) external payable;\n\n    /// @notice Increase the reserved balance of the pool\n    /// @dev These assets are removed from the available balance and cannot be withdrawn before they are unreserved.\n    ///      It is possible to reserve more than the current balance, to lock future expected assets.\n    ///      Any manager can reserve on behalf of any address, enabling recovery of stuck funds.\n    /// @param poolId The pool identifier\n    /// @param scId The share class identifier\n    /// @param asset The asset address\n    /// @param tokenId The token ID\n    /// @param amount The amount to reserve\n    /// @param reserver The address that will own the reservation (tracked in PoolEscrow)\n    /// @param reason The reason code (1=DEPOSIT, 2=REDEEM)\n    function reserve(\n        PoolId poolId,\n        ShareClassId scId,\n        address asset,\n        uint256 tokenId,\n        uint128 amount,\n        address reserver,\n        uint32 reason\n    ) external payable;\n\n    /// @notice Decrease the reserved balance of the pool\n    /// @dev These assets are re-added to the available balance.\n    ///      Any manager can unreserve any reserver's funds, enabling recovery of stuck funds.\n    /// @param poolId The pool identifier\n    /// @param scId The share class identifier\n    /// @param asset The asset address\n    /// @param tokenId The token ID\n    /// @param amount The amount to unreserve\n    /// @param reserver The address that owns the reservation to be unreserved\n    /// @param reason The reason code that was used when reserving\n    function unreserve(\n        PoolId poolId,\n        ShareClassId scId,\n        address asset,\n        uint256 tokenId,\n        uint128 amount,\n        address reserver,\n        uint32 reason\n    ) external payable;\n\n    /// @notice Issue new share tokens\n    /// @dev Increases the total issuance\n    /// @param poolId The pool identifier\n    /// @param scId The share class identifier\n    /// @param to The address to issue shares to\n    /// @param shares The number of shares to issue\n    function issue(PoolId poolId, ShareClassId scId, address to, uint128 shares) external payable;\n\n    /// @notice Revoke share tokens\n    /// @dev Decreases the total issuance\n    /// @param poolId The pool identifier\n    /// @param scId The share class identifier\n    /// @param shares The number of shares to revoke\n    function revoke(PoolId poolId, ShareClassId scId, uint128 shares) external payable;\n\n    /// @notice Sends the queued updated holding amount to the Hub\n    /// @param poolId The pool identifier\n    /// @param scId The share class identifier\n    /// @param assetId The asset identifier\n    /// @param extraGasLimit Extra gas limit for cross-chain execution\n    /// @param refund Address to receive excess gas refund\n    function submitQueuedAssets(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        uint128 extraGasLimit,\n        address refund\n    ) external payable;\n\n    /// @notice Sends the queued updated shares changed to the Hub\n    /// @param poolId The pool identifier\n    /// @param scId The share class identifier\n    /// @param extraGasLimit Extra gas limit for cross-chain execution\n    /// @param refund Address to receive excess gas refund\n    function submitQueuedShares(PoolId poolId, ShareClassId scId, uint128 extraGasLimit, address refund)\n        external\n        payable;\n\n    /// @notice Force-transfers share tokens\n    /// @param poolId The pool identifier\n    /// @param scId The share class identifier\n    /// @param sender The address initiating the transfer\n    /// @param from The address to transfer from\n    /// @param to The address to transfer to\n    /// @param amount The amount to transfer\n    function transferSharesFrom(\n        PoolId poolId,\n        ShareClassId scId,\n        address sender,\n        address from,\n        address to,\n        uint256 amount\n    ) external payable;\n\n    /// @notice Override the price pool per asset, to be used for any other balance sheet interactions.\n    /// @dev    This can be used to note an interaction at a lower/higher price than the current one.\n    ///         resetPricePoolPerAsset MUST be called after the balance sheet interactions using this price.\n    /// @param poolId The pool identifier\n    /// @param scId The share class identifier\n    /// @param assetId The asset identifier\n    /// @param value The price to override with\n    function overridePricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, D18 value) external payable;\n\n    /// @notice Reset the price pool per asset.\n    /// @param poolId The pool identifier\n    /// @param scId The share class identifier\n    /// @param assetId The asset identifier\n    function resetPricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId) external payable;\n\n    /// @notice Override the price pool per share, to be used for any other balance sheet interactions.\n    /// @dev    This can be used to note an interaction at a lower/higher price than the current one.\n    ///         resetPricePoolPerShare MUST be called after the balance sheet interactions using this price.\n    /// @param poolId The pool identifier\n    /// @param scId The share class identifier\n    /// @param value The price to override with\n    function overridePricePoolPerShare(PoolId poolId, ShareClassId scId, D18 value) external payable;\n\n    /// @notice Reset the price pool per share.\n    /// @param poolId The pool identifier\n    /// @param scId The share class identifier\n    function resetPricePoolPerShare(PoolId poolId, ShareClassId scId) external payable;\n\n    //----------------------------------------------------------------------------------------------\n    // Management functions (manual operations)\n    //----------------------------------------------------------------------------------------------\n\n    /// @notice Note a deposit of assets into the escrow of the pool.\n    /// @dev    Must be followed by a transfer of the equivalent amount of assets to `IBalanceSheet.escrow(poolId)`\n    ///         Delegates to noteDeposit(6-param) with updateEscrow=true.\n    /// @param poolId The pool identifier\n    /// @param scId The share class identifier\n    /// @param asset The asset address\n    /// @param  tokenId SHOULD be 0 if depositing ERC20 assets. ERC6909 assets with tokenId=0 are not supported.\n    /// @param amount The amount to deposit\n    /// @return pricePoolPerAsset The price used for queueing the asset increase\n    function noteDeposit(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, uint128 amount)\n        external\n        payable\n        returns (D18 pricePoolPerAsset);\n\n    /// @notice Note a deposit with configurable escrow update (manual operation)\n    /// @dev    When updateEscrow=true, calls escrow.deposit() to increase holding.total.\n    ///         When updateEscrow=false, only queues asset increase for Hub notification.\n    /// @param poolId The pool identifier\n    /// @param scId The share class identifier\n    /// @param asset The asset address\n    /// @param tokenId SHOULD be 0 if depositing ERC20 assets. ERC6909 assets with tokenId=0 are not supported.\n    /// @param amount The amount to deposit\n    /// @param updateEscrow If true, calls escrow.deposit() to increase holding.total\n    /// @return pricePoolPerAsset The price used for queueing the asset increase\n    function noteDeposit(\n        PoolId poolId,\n        ShareClassId scId,\n        address asset,\n        uint256 tokenId,\n        uint128 amount,\n        bool updateEscrow\n    ) external payable returns (D18 pricePoolPerAsset);\n\n    /// @notice Withdraw assets from the escrow of the pool (manual operation)\n    /// @dev Behavior depends on WithdrawMode:\n    ///      - TransferOnly: Transfer only, no escrow accounting, no Hub queue (ARM cancel flows)\n    ///      - EscrowAndTransfer: Escrow accounting + transfer, skip Hub queue (ARM after noteWithdraw)\n    ///      - Full: Full accounting - escrow + Hub queue + transfer (OnOfframpManager)\n    /// @param poolId The pool identifier\n    /// @param scId The share class identifier\n    /// @param asset The asset address\n    /// @param tokenId The token ID (SHOULD be 0 if depositing ERC20 assets. ERC6909 assets with tokenId=0 are not supported)\n    /// @param receiver The address to receive the withdrawn assets\n    /// @param amount The amount to withdraw\n    /// @param mode The withdrawal operation mode\n    function withdraw(\n        PoolId poolId,\n        ShareClassId scId,\n        address asset,\n        uint256 tokenId,\n        address receiver,\n        uint128 amount,\n        WithdrawMode mode\n    ) external payable;\n\n    /// @notice Note a withdrawal of assets from the escrow of the pool without performing the actual transfer.\n    /// @dev    Queues asset decrease for Hub without escrow accounting update.\n    ///         Delegates to noteWithdraw(7-param) with receiver=address(0), updateEscrow=false.\n    ///         Must be followed by withdraw(..., EscrowAndTransfer) to perform the escrow\n    ///         accounting update and actual transfer when user claims.\n    ///         Used in revokedShares() to atomically queue asset and share updates to prevent share price\n    ///         inflation during the async window.\n    /// @param poolId The pool identifier\n    /// @param scId The share class identifier\n    /// @param asset The asset address\n    /// @param tokenId SHOULD be 0 if depositing ERC20 assets. ERC6909 assets with tokenId=0 are not supported.\n    /// @param amount The amount to note as withdrawn\n    /// @return pricePoolPerAsset The price used for queueing the asset decrease\n    function noteWithdraw(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, uint128 amount)\n        external\n        payable\n        returns (D18 pricePoolPerAsset);\n\n    /// @notice Note a withdrawal with configurable escrow update (manual operation)\n    /// @dev    When updateEscrow=true, calls escrow.withdraw() to decrease holding.total.\n    ///         When updateEscrow=false, only queues asset decrease for Hub notification.\n    /// @param poolId The pool identifier\n    /// @param scId The share class identifier\n    /// @param asset The asset address\n    /// @param tokenId SHOULD be 0 if depositing ERC20 assets. ERC6909 assets with tokenId=0 are not supported.\n    /// @param receiver The address to receive the withdrawn assets (for escrow.withdraw event)\n    /// @param amount The amount to note as withdrawn\n    /// @param updateEscrow If true, calls escrow.withdraw() to decrease holding.total\n    /// @return pricePoolPerAsset The price used for queueing the asset decrease\n    function noteWithdraw(\n        PoolId poolId,\n        ShareClassId scId,\n        address asset,\n        uint256 tokenId,\n        address receiver,\n        uint128 amount,\n        bool updateEscrow\n    ) external payable returns (D18 pricePoolPerAsset);\n\n    //----------------------------------------------------------------------------------------------\n    // View methods\n    //----------------------------------------------------------------------------------------------\n\n    /// @notice Returns the spoke contract\n    /// @return The spoke contract instance\n    function spoke() external view returns (ISpoke);\n\n    /// @notice Returns the message sender contract\n    /// @return The message sender contract instance\n    function sender() external view returns (ISpokeMessageSender);\n\n    /// @notice Returns the endorsements contract\n    /// @return The endorsements contract instance\n    function endorsements() external view returns (IEndorsements);\n\n    /// @notice Returns the pool escrow provider\n    /// @return The pool escrow provider instance\n    function poolEscrowProvider() external view returns (IPoolEscrowProvider);\n\n    /// @notice Checks if an address is a manager for a pool\n    /// @param poolId The pool identifier\n    /// @param manager The address to check\n    /// @return Whether the address is a manager\n    function manager(PoolId poolId, address manager) external view returns (bool);\n\n    /// @notice Returns the queued shares for a share class\n    /// @param poolId The pool identifier\n    /// @param scId The share class identifier\n    /// @return delta Net queued shares\n    /// @return isPositive Whether the net queued shares lead to an issuance or revocation\n    /// @return queuedAssetCounter Number of queued asset IDs for this share class\n    /// @return nonce Nonce for share + asset messages to the hub\n    function queuedShares(PoolId poolId, ShareClassId scId)\n        external\n        view\n        returns (uint128 delta, bool isPositive, uint32 queuedAssetCounter, uint64 nonce);\n\n    /// @notice Returns the queued assets for a share class and asset\n    /// @param poolId The pool identifier\n    /// @param scId The share class identifier\n    /// @param assetId The asset identifier\n    /// @return increase Queued deposits\n    /// @return decrease Queued withdrawals\n    function queuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId)\n        external\n        view\n        returns (uint128 increase, uint128 decrease);\n\n    /// @notice Returns the pool escrow.\n    /// @dev    Assets for pending deposit requests are not held by the pool escrow.\n    /// @param poolId The pool identifier\n    /// @return The pool escrow instance\n    function escrow(PoolId poolId) external view returns (IPoolEscrow);\n\n    /// @notice Returns the amount of assets that can be withdrawn from the balance sheet.\n    /// @dev    Assets that are locked for redemption requests are reserved and not available for withdrawals.\n    /// @param  poolId The pool identifier\n    /// @param scId The share class identifier\n    /// @param asset The asset address\n    /// @param  tokenId SHOULD be 0 if depositing ERC20 assets. ERC6909 assets with tokenId=0 are not supported.\n    /// @return The available balance\n    function availableBalanceOf(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId)\n        external\n        view\n        returns (uint128);\n}\n"},{"file_path":"src/admin/interfaces/IRoot.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\n\nimport {IEndorsements} from \"../../core/spoke/interfaces/IEndorsements.sol\";\nimport {IScheduleAuth} from \"../../core/messaging/interfaces/IScheduleAuth.sol\";\nimport {IProtocolPauser} from \"../../core/messaging/interfaces/IProtocolPauser.sol\";\n\ninterface IRoot is IEndorsements, IProtocolPauser, IScheduleAuth {\n    //----------------------------------------------------------------------------------------------\n    // Events\n    //----------------------------------------------------------------------------------------------\n\n    event File(bytes32 indexed what, uint256 data);\n    event RelyContract(address indexed target, address indexed user);\n    event DenyContract(address indexed target, address indexed user);\n\n    //----------------------------------------------------------------------------------------------\n    // Errors\n    //----------------------------------------------------------------------------------------------\n\n    error DelayTooLong();\n    error FileUnrecognizedParam();\n    error TargetNotScheduled();\n    error TargetNotReady();\n\n    //----------------------------------------------------------------------------------------------\n    // View methods\n    //----------------------------------------------------------------------------------------------\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    //----------------------------------------------------------------------------------------------\n    // Administration\n    //----------------------------------------------------------------------------------------------\n\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    //----------------------------------------------------------------------------------------------\n    // Endorsements\n    //----------------------------------------------------------------------------------------------\n\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    //----------------------------------------------------------------------------------------------\n    // Pause management\n    //----------------------------------------------------------------------------------------------\n\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    //----------------------------------------------------------------------------------------------\n    // Timelocked ward management\n    //----------------------------------------------------------------------------------------------\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    //----------------------------------------------------------------------------------------------\n    // External contract ward management\n    //----------------------------------------------------------------------------------------------\n\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"},{"file_path":"src/core/spoke/interfaces/IVault.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\n\nimport {PoolId} from \"../../types/PoolId.sol\";\nimport {ShareClassId} from \"../../types/ShareClassId.sol\";\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\n/// @notice Interface for the all vault contracts\n/// @dev Must be implemented by all vaults\ninterface IVault {\n    /// @notice Identifier of the Centrifuge pool\n    /// @return The pool identifier\n    function poolId() external view returns (PoolId);\n\n    /// @notice Identifier of the share class of the Centrifuge pool\n    /// @return The share class identifier\n    function scId() external view returns (ShareClassId);\n\n    /// @notice Checks whether the vault is partially (a)synchronous\n    /// @return vaultKind_ The kind of the vault\n    function vaultKind() external view returns (VaultKind vaultKind_);\n}\n"},{"file_path":"src/misc/interfaces/IERC20.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\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"},{"file_path":"src/core/messaging/interfaces/IMessageHandler.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\n\n/// @notice Generic interface for entities that handle incoming messages\ninterface IMessageHandler {\n    //----------------------------------------------------------------------------------------------\n    // Incoming\n    //----------------------------------------------------------------------------------------------\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"},{"file_path":"src/misc/Auth.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity 0.8.28;\n\nimport {IAuth} from \"./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"},{"file_path":"src/misc/interfaces/IEscrow.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\n\n/// @title  Escrow for holding assets\ninterface IEscrow {\n    //----------------------------------------------------------------------------------------------\n    // Events\n    //----------------------------------------------------------------------------------------------\n\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 receiver, 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 Transfers assets from the escrow to a receiver address\n    /// @param asset The address of the asset to transfer\n    /// @param tokenId The token ID of the asset (0 for ERC20, non-zero for ERC6909)\n    /// @param receiver The address receiving the transferred assets\n    /// @param value The amount of assets to transfer\n    function authTransferTo(address asset, uint256 tokenId, address receiver, uint256 value) external;\n}\n"},{"file_path":"src/misc/interfaces/IERC7751.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\n\n/// [ERC-7751](https://eips.ethereum.org/EIPS/eip-7751): Wrapping of bubbled up reverts\n/// Handling bubbled up reverts using custom errors with additional context.\ninterface IERC7751 {\n    error WrappedError(address target, bytes4 selector, bytes reason, bytes details);\n}\n"},{"file_path":"src/core/spoke/interfaces/ITransferHook.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\n\nimport {IERC165} from \"../../../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\n/// @dev Equals 118_624 such that there is no collision with any uint16 Centrifuge ID\naddress constant ESCROW_HOOK_ID = address(uint160(0x1CF60));\n\n/// @notice Hook interface to customize share token behaviour\n/// @dev    To detect specific system actions:\n///           Deposit request/issuance:         address(0)       -> address(user)\n///           Deposit fulfillment:              address(0)       -> poolEscrow\n///           Deposit claim:                    poolEscrow       -> address(user)\n///           Redeem request:                   address(user)    -> ESCROW_HOOK_ID\n///           Redeem fulfillment:               balanceSheet     -> address(0)\n///           Redeem claim/revocation:          address(user)    -> address(0)\n///           Cross-chain transfer:             address(user)    -> address(uint160(chainId))\n///           Cross-chain execution:            crosschainSource -> address(user)\n///\n///         Endorsed refers to core protocol contracts, which can be retrieved using root.endorsed(addr)\n///         poolEscrow: Pool-specific escrow contract identified via balanceSheet.escrow(poolId)\n///         balanceSheet: Contract that fulfills redemptions and provides pool escrow lookups\n///         crosschainSource: Contract handling cross-chain message execution (spoke)\ninterface ITransferHook is IERC165 {\n    //----------------------------------------------------------------------------------------------\n    // Errors\n    //----------------------------------------------------------------------------------------------\n\n    error TransferBlocked();\n    error InvalidUpdate();\n\n    //----------------------------------------------------------------------------------------------\n    // Callbacks\n    //----------------------------------------------------------------------------------------------\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    //----------------------------------------------------------------------------------------------\n    // View methods\n    //----------------------------------------------------------------------------------------------\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    //----------------------------------------------------------------------------------------------\n    // Administration\n    //----------------------------------------------------------------------------------------------\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"},{"file_path":"src/misc/libraries/CastLib.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity 0.8.28;\n\n/// @title  CastLib\nlibrary CastLib {\n    error PrefixNotZero();\n    error SizeNot128();\n\n    function toAddressLeftPadded(bytes32 addr) internal pure returns (address) {\n        require(bytes12(addr) == 0, PrefixNotZero());\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, PrefixNotZero());\n        return address(bytes20(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, SizeNot128());\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"},{"file_path":"src/core/utils/interfaces/IContractUpdate.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\n\nimport {PoolId} from \"../../types/PoolId.sol\";\nimport {ShareClassId} from \"../../types/ShareClassId.sol\";\n\ninterface ITrustedContractUpdate {\n    /// @notice Triggers an update on the target contract.\n    /// @dev    Sent from the trusted hub manager role.\n    function trustedCall(PoolId poolId, ShareClassId scId, bytes calldata payload) external;\n}\n\ninterface IUntrustedContractUpdate {\n    /// @notice Triggers an update on the target contract.\n    /// @dev    Sender MUST be validated. Sent by anyone on the spoke side.\n    function untrustedCall(\n        PoolId poolId,\n        ShareClassId scId,\n        bytes calldata payload,\n        uint16 centrifugeId,\n        bytes32 sender\n    ) external;\n}\n"},{"file_path":"src/misc/libraries/BitmapLib.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity 0.8.28;\n\n/// @title  BitmapLib\nlibrary BitmapLib {\n    function withBit(uint256 bitmap, uint256 index, bool isTrue) internal pure returns (uint256) {\n        if (isTrue) {\n            return bitmap | (uint256(1) << index);\n        }\n\n        return bitmap & ~(uint256(1) << index);\n    }\n\n    function getBit(uint256 bitmap, uint256 index) internal pure returns (bool) {\n        uint256 bitAtIndex = uint256(bitmap & (1 << index));\n        return bitAtIndex != 0;\n    }\n}\n"},{"file_path":"src/hooks/BaseTransferHook.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.28;\n\nimport {IFreezable} from \"./interfaces/IFreezable.sol\";\nimport {IMemberlist} from \"./interfaces/IMemberlist.sol\";\nimport {IBaseTransferHook} from \"./interfaces/IBaseTransferHook.sol\";\nimport {UpdateRestrictionType, UpdateRestrictionMessageLib} from \"./libraries/UpdateRestrictionMessageLib.sol\";\n\nimport {Auth} from \"../misc/Auth.sol\";\nimport {IAuth} from \"../misc/interfaces/IAuth.sol\";\nimport {CastLib} from \"../misc/libraries/CastLib.sol\";\nimport {BytesLib} from \"../misc/libraries/BytesLib.sol\";\nimport {IERC165} from \"../misc/interfaces/IERC7575.sol\";\nimport {BitmapLib} from \"../misc/libraries/BitmapLib.sol\";\n\nimport {PoolId} from \"../core/types/PoolId.sol\";\nimport {ISpoke} from \"../core/spoke/interfaces/ISpoke.sol\";\nimport {ShareClassId} from \"../core/types/ShareClassId.sol\";\nimport {IShareToken} from \"../core/spoke/interfaces/IShareToken.sol\";\nimport {IBalanceSheet} from \"../core/spoke/interfaces/IBalanceSheet.sol\";\nimport {ITrustedContractUpdate} from \"../core/utils/interfaces/IContractUpdate.sol\";\nimport {IPoolEscrowProvider} from \"../core/spoke/factories/interfaces/IPoolEscrowFactory.sol\";\nimport {ITransferHook, HookData, ESCROW_HOOK_ID} from \"../core/spoke/interfaces/ITransferHook.sol\";\n\nimport {IRoot} from \"../admin/interfaces/IRoot.sol\";\n\n/// @title  BaseTransferHook\n/// @notice Abstract base contract for share token transfer restrictions that provides memberlist management,\n///         account freezing capabilities, and cross-chain message handling, while encoding member validity\n///         and freeze status in the hookData structure for efficient on-chain verification.\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.\nabstract contract BaseTransferHook is Auth, IMemberlist, IFreezable, ITrustedContractUpdate, IBaseTransferHook {\n    using BitmapLib for *;\n    using UpdateRestrictionMessageLib for *;\n    using BytesLib for bytes;\n    using CastLib for bytes32;\n\n    error InvalidInputs();\n    error ShareTokenDoesNotExist();\n\n    /// @dev Least significant bit\n    uint8 public constant FREEZE_BIT = 0;\n\n    IRoot public immutable root;\n    ISpoke public immutable spoke;\n    address public immutable poolEscrow;\n    address public immutable crosschainSource;\n    IBalanceSheet public immutable balanceSheet;\n    IPoolEscrowProvider public immutable poolEscrowProvider;\n\n    mapping(address token => mapping(address => bool)) public manager;\n\n    constructor(\n        address root_,\n        address spoke_,\n        address balanceSheet_,\n        address crosschainSource_,\n        address deployer,\n        address poolEscrowProvider_,\n        address poolEscrow_\n    ) Auth(deployer) {\n        require(balanceSheet_ != crosschainSource_, InvalidInputs());\n\n        root = IRoot(root_);\n        spoke = ISpoke(spoke_);\n        balanceSheet = IBalanceSheet(balanceSheet_);\n        crosschainSource = crosschainSource_;\n        poolEscrowProvider = IPoolEscrowProvider(poolEscrowProvider_);\n        poolEscrow = poolEscrow_;\n    }\n\n    /// @dev Check if the msg.sender is ward or a manager\n    modifier authOrManager(address token) {\n        require(wards[msg.sender] == 1 || manager[token][msg.sender], IAuth.NotAuthorized());\n        _;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Callback from share token\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc ITransferHook\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 ITransferHook.onERC20Transfer.selector;\n    }\n\n    /// @inheritdoc ITransferHook\n    function onERC20AuthTransfer(\n        address, /* sender */\n        address, /* from */\n        address, /* to */\n        uint256, /* value */\n        HookData calldata /* hookData */\n    )\n        external\n        pure\n        virtual\n        returns (bytes4)\n    {\n        return ITransferHook.onERC20AuthTransfer.selector;\n    }\n\n    function checkERC20Transfer(\n        address from,\n        address to,\n        uint256,\n        /* value */\n        HookData calldata hookData\n    )\n        public\n        view\n        virtual\n        returns (bool);\n\n    function isPoolEscrow(address addr) public view returns (bool) {\n        // Fast path: single-pool optimization\n        if (poolEscrow != address(0)) return addr == poolEscrow;\n\n        // Multi-pool path: dynamic verification\n        if (addr.code.length == 0) return false;\n\n        (bool success, bytes memory data) = addr.staticcall(abi.encodeWithSignature(\"poolId()\"));\n        if (!success || data.length != 32) return false;\n\n        PoolId poolId = abi.decode(data, (PoolId));\n        return address(poolEscrowProvider.escrow(poolId)) == addr;\n    }\n\n    function isDepositRequestOrIssuance(address from, address to) public view returns (bool) {\n        return from == address(0) && !isPoolEscrow(to) && to != crosschainSource;\n    }\n\n    function isDepositFulfillment(address from, address to) public view returns (bool) {\n        return from == address(0) && isPoolEscrow(to);\n    }\n\n    function isDepositClaim(address from, address to) public view returns (bool) {\n        return isPoolEscrow(from) && to != address(0);\n    }\n\n    function isRedeemRequest(address, address to) public pure returns (bool) {\n        return to == ESCROW_HOOK_ID;\n    }\n\n    function isRedeemFulfillment(address from, address to) public view returns (bool) {\n        return from == address(balanceSheet) && to == address(0);\n    }\n\n    function isRedeemClaimOrRevocation(address from, address to) public view returns (bool) {\n        return (from != address(balanceSheet) && from != crosschainSource) && to == address(0);\n    }\n\n    function isCrosschainTransfer(address from, address to) public view returns (bool) {\n        return from == crosschainSource && to == address(0);\n    }\n\n    function isCrosschainTransferExecution(address from, address to) public view returns (bool) {\n        return from == crosschainSource && to != address(0);\n    }\n\n    function isSourceOrTargetFrozen(address from, address to, HookData calldata hookData) public view returns (bool) {\n        return (uint128(hookData.from).getBit(FREEZE_BIT) == true && !isPoolEscrow(from))\n            || (uint128(hookData.to).getBit(FREEZE_BIT) == true && !isPoolEscrow(to));\n    }\n\n    function isSourceMember(address from, HookData calldata hookData) public view returns (bool) {\n        return uint128(hookData.from) >> 64 >= block.timestamp || isPoolEscrow(from);\n    }\n\n    function isTargetMember(address to, HookData calldata hookData) public view returns (bool) {\n        return uint128(hookData.to) >> 64 >= block.timestamp || root.endorsed(to) || isPoolEscrow(to);\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Administration\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc ITrustedContractUpdate\n    function trustedCall(PoolId poolId, ShareClassId scId, bytes memory payload) external virtual auth {\n        uint8 kindValue = abi.decode(payload, (uint8));\n        require(kindValue <= uint8(type(TrustedCall).max), UnknownTrustedCall());\n\n        TrustedCall kind = TrustedCall(kindValue);\n        if (kind == TrustedCall.UpdateHookManager) {\n            (, bytes32 manager_, bool canManage) = abi.decode(payload, (uint8, bytes32, bool));\n            address token = address(spoke.shareToken(poolId, scId));\n            require(token != address(0), ShareTokenDoesNotExist());\n\n            manager[token][manager_.toAddress()] = canManage;\n            emit UpdateHookManager(token, manager_.toAddress(), canManage);\n        }\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Restriction updates\n    //----------------------------------------------------------------------------------------------\n\n    /// @inheritdoc ITransferHook\n    function updateRestriction(address token, bytes memory payload) external auth {\n        UpdateRestrictionType updateId = payload.updateRestrictionType();\n\n        if (updateId == UpdateRestrictionType.Member) {\n            UpdateRestrictionMessageLib.UpdateRestrictionMember memory m = payload.deserializeUpdateRestrictionMember();\n            updateMember(token, m.user.toAddress(), m.validUntil);\n        } else if (updateId == UpdateRestrictionType.Freeze) {\n            UpdateRestrictionMessageLib.UpdateRestrictionFreeze memory m = payload.deserializeUpdateRestrictionFreeze();\n            freeze(token, m.user.toAddress());\n        } else if (updateId == UpdateRestrictionType.Unfreeze) {\n            UpdateRestrictionMessageLib.UpdateRestrictionUnfreeze memory m =\n                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 authOrManager(token) {\n        require(user != address(0), CannotFreezeZeroAddress());\n        require(!root.endorsed(user) && !isPoolEscrow(user), EndorsedUserCannotBeFrozen());\n\n        uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n        IShareToken(token).setHookData(user, bytes16(uint128(hookData.withBit(FREEZE_BIT, true))));\n\n        emit Freeze(token, user);\n    }\n\n    /// @inheritdoc IFreezable\n    function unfreeze(address token, address user) public authOrManager(token) {\n        uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n        IShareToken(token).setHookData(user, bytes16(uint128(hookData.withBit(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 authOrManager(token) {\n        require(block.timestamp <= validUntil, InvalidValidUntil());\n        require(!root.endorsed(user) && !isPoolEscrow(user), EndorsedUserCannotBeUpdated());\n\n        uint128 hookData = uint128(validUntil) << 64;\n        hookData = uint128(uint256(hookData).withBit(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(ITransferHook).interfaceId || interfaceId == type(IERC165).interfaceId;\n    }\n}\n"},{"file_path":"src/misc/types/D18.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\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 \"../libraries/MathLib.sol\";\n\ntype D18 is uint128;\n\nerror D18_DivisionByZero();\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 subtract 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 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_DivisionByZero());\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.raw(), 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.raw(), 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 isZero(D18 a) pure returns (bool) {\n    return D18.unwrap(a) == 0;\n}\n\nfunction isNotZero(D18 a) pure returns (bool) {\n    return D18.unwrap(a) != 0;\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    eq,\n    mulD18 as *,\n    mulUint128,\n    mulUint256,\n    reciprocalMulUint128,\n    reciprocalMulUint256,\n    reciprocal,\n    raw,\n    isZero,\n    isNotZero\n} for D18 global;\n"},{"file_path":"src/core/interfaces/IRequestManager.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\n\nimport {PoolId} from \"../types/PoolId.sol\";\nimport {AssetId} from \"../types/AssetId.sol\";\nimport {ShareClassId} from \"../types/ShareClassId.sol\";\n\ninterface IRequestManager {\n    //----------------------------------------------------------------------------------------------\n    // Errors\n    //----------------------------------------------------------------------------------------------\n\n    error UnknownRequestCallbackType();\n\n    //----------------------------------------------------------------------------------------------\n    // Request handling\n    //----------------------------------------------------------------------------------------------\n\n    /// @notice Handles a request callback originating from the Hub side\n    /// @param poolId The pool id\n    /// @param scId The share class id\n    /// @param assetId The asset id\n    /// @param payload The payload to be processed by the request callback\n    function callback(PoolId poolId, ShareClassId scId, AssetId assetId, bytes calldata payload) external;\n}\n"},{"file_path":"src/core/messaging/interfaces/IGatewaySenders.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\n\nimport {D18} from \"../../../misc/types/D18.sol\";\n\nimport {PoolId} from \"../../types/PoolId.sol\";\nimport {AssetId} from \"../../types/AssetId.sol\";\nimport {ShareClassId} from \"../../types/ShareClassId.sol\";\nimport {VaultUpdateKind} from \"../libraries/MessageLib.sol\";\n\ninterface ILocalCentrifugeId {\n    error CannotBeSentLocally();\n\n    function localCentrifugeId() external view returns (uint16);\n}\n\n/// @notice Interface for dispatch-only gateway\ninterface IScheduleAuthMessageSender {\n    /// @notice Creates and send the message\n    function sendScheduleUpgrade(uint16 centrifugeId, bytes32 target, address refund) external payable;\n\n    /// @notice Creates and send the message\n    function sendCancelUpgrade(uint16 centrifugeId, bytes32 target, address refund) external payable;\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        address refund\n    ) external payable;\n}\n\n/// @notice Interface for dispatch-only gateway\ninterface IHubMessageSender is ILocalCentrifugeId {\n    /// @notice Creates and send the message\n    function sendNotifyPool(uint16 centrifugeId, PoolId poolId, address refund) external payable;\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        address refund\n    ) external payable;\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        address refund\n    ) external payable;\n\n    /// @notice Creates and send the message\n    function sendUpdateShareHook(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 hook, address refund)\n        external\n        payable;\n\n    /// @notice Creates and send the message\n    function sendNotifyPricePoolPerShare(\n        uint16 chainId,\n        PoolId poolId,\n        ShareClassId scId,\n        D18 pricePoolPerShare,\n        uint64 computedAt,\n        address refund\n    ) external payable;\n\n    /// @notice Creates and send the message\n    function sendNotifyPricePoolPerAsset(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        D18 pricePoolPerAsset,\n        address refund\n    ) external payable;\n\n    /// @notice Creates and send the message\n    function sendUpdateRestriction(\n        uint16 centrifugeId,\n        PoolId poolId,\n        ShareClassId scId,\n        bytes calldata payload,\n        uint128 extraGasLimit,\n        address refund\n    ) external payable;\n\n    /// @notice Creates and send the message\n    function sendTrustedContractUpdate(\n        uint16 centrifugeId,\n        PoolId poolId,\n        ShareClassId scId,\n        bytes32 target,\n        bytes calldata payload,\n        uint128 extraGasLimit,\n        address refund\n    ) external payable;\n\n    /// @notice Creates and send the message\n    function sendUpdateVault(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        bytes32 vaultOrFactory,\n        VaultUpdateKind kind,\n        uint128 extraGasLimit,\n        address refund\n    ) external payable;\n\n    /// @notice Creates and send the message\n    function sendSetRequestManager(uint16 centrifugeId, PoolId poolId, bytes32 manager, address refund) external payable;\n\n    /// @notice Creates and send the message\n    function sendUpdateBalanceSheetManager(\n        uint16 centrifugeId,\n        PoolId poolId,\n        bytes32 who,\n        bool canManage,\n        address refund\n    ) external payable;\n\n    /// @notice Creates and send the message\n    function sendExecuteTransferShares(\n        uint16 originCentrifugeId,\n        uint16 targetCentrifugeId,\n        PoolId poolId,\n        ShareClassId scId,\n        bytes32 receiver,\n        uint128 amount,\n        uint128 extraGasLimit,\n        address refund\n    ) external payable;\n\n    /// @notice Creates and send the message\n    function sendSetMaxAssetPriceAge(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        uint64 maxPriceAge,\n        address refund\n    ) external payable;\n\n    /// @notice Creates and send the message\n    function sendSetMaxSharePriceAge(\n        uint16 centrifugeId,\n        PoolId poolId,\n        ShareClassId scId,\n        uint64 maxPriceAge,\n        address refund\n    ) external payable;\n\n    /// @notice Creates and send the message\n    function sendRequestCallback(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        bytes calldata payload,\n        uint128 extraGasLimit,\n        bool unpaidMode,\n        address refund\n    ) external payable;\n\n    /// @notice Creates and send the message\n    function sendSetPoolAdapters(\n        uint16 centrifugeId,\n        PoolId poolId,\n        bytes32[] memory adapters,\n        uint8 threshold,\n        uint8 recoveryIndex,\n        address refund\n    ) external payable;\n\n    /// @notice Creates and send the message\n    function sendUpdateGatewayManager(uint16 centrifugeId, PoolId poolId, bytes32 who, bool canManage, address refund)\n        external\n        payable;\n}\n\n/// @notice Interface for dispatch-only gateway\ninterface ISpokeMessageSender is ILocalCentrifugeId {\n    struct UpdateData {\n        uint128 netAmount;\n        bool isIncrease;\n        bool isSnapshot;\n        uint64 nonce;\n    }\n\n    /// @notice Creates and send the message\n    function sendInitiateTransferShares(\n        uint16 centrifugeId,\n        PoolId poolId,\n        ShareClassId scId,\n        bytes32 receiver,\n        uint128 amount,\n        uint128 extraGasLimit,\n        uint128 remoteExtraGasLimit,\n        address refund\n    ) external payable;\n\n    /// @notice Creates and send the message\n    function sendRegisterAsset(uint16 centrifugeId, AssetId assetId, uint8 decimals, address refund) external payable;\n\n    /// @notice Creates and send the message\n    function sendUpdateHoldingAmount(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        UpdateData calldata data,\n        D18 pricePoolPerAsset,\n        uint128 extraGasLimit,\n        address refund\n    ) external payable;\n\n    /// @notice Creates and send the message\n    function sendUpdateShares(\n        PoolId poolId,\n        ShareClassId scId,\n        UpdateData calldata data,\n        uint128 extraGasLimit,\n        address refund\n    ) external payable;\n\n    /// @notice Creates and send the message\n    function sendRequest(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        bytes calldata payload,\n        uint128 extraGasLimit,\n        bool unpaidMode,\n        address refund\n    ) external payable;\n\n    /// @notice Creates and sends an UntrustedContractUpdate message\n    /// @param poolId The pool identifier\n    /// @param scId The share class identifier\n    /// @param target The hub-side target contract (as bytes32)\n    /// @param sender The spoke-side initiator (as bytes32)\n    /// @param payload The update payload\n    /// @param extraGasLimit Additional gas for cross-chain execution\n    /// @param refund Address to refund excess payment\n    function sendUntrustedContractUpdate(\n        PoolId poolId,\n        ShareClassId scId,\n        bytes32 target,\n        bytes calldata payload,\n        bytes32 sender,\n        uint128 extraGasLimit,\n        address refund\n    ) external payable;\n}\n"},{"file_path":"src/core/utils/interfaces/IBatchedMulticall.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\n\nimport {IGateway} from \"../../messaging/interfaces/IGateway.sol\";\n\n/// @notice A multicall that batches the messages using the gateway\ninterface IBatchedMulticall {\n    error AlreadyBatching();\n\n    /// @notice Returns the gateway contract used for batching messages\n    /// @return The gateway contract instance\n    function gateway() external view returns (IGateway);\n}\n"},{"file_path":"src/core/types/ShareClassId.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.28;\n\nimport {PoolId} from \"./PoolId.sol\";\n\ntype ShareClassId is bytes16;\n\nfunction isNull(ShareClassId scId) pure returns (bool) {\n    return ShareClassId.unwrap(scId) == 0;\n}\n\nfunction index(ShareClassId scId) pure returns (uint32) {\n    return uint32(uint128(ShareClassId.unwrap(scId)));\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, index, raw, equals as ==} for ShareClassId global;\n"},{"file_path":"src/misc/libraries/MathLib.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\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    error MulDiv_Overflow();\n    error Uint8_Overflow();\n    error Uint16_Overflow();\n    error Uint32_Overflow();\n    error Uint64_Overflow();\n    error Uint96_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\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    /// @notice Safe type conversion from uint256 to uint16.\n    function toUint16(uint256 value) internal pure returns (uint16) {\n        require(value <= type(uint16).max, Uint16_Overflow());\n        return uint16(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    function toUint96(uint256 value) internal pure returns (uint96) {\n        require(value <= type(uint96).max, Uint96_Overflow());\n        return uint96(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"},{"file_path":"src/misc/interfaces/IRecoverable.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\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"},{"file_path":"src/hooks/interfaces/IMemberlist.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\n\ninterface IMemberlist {\n    //----------------------------------------------------------------------------------------------\n    // Events\n    //----------------------------------------------------------------------------------------------\n\n    event UpdateMember(address indexed token, address indexed user, uint64 validUntil);\n\n    //----------------------------------------------------------------------------------------------\n    // Errors\n    //----------------------------------------------------------------------------------------------\n\n    error InvalidValidUntil();\n    error EndorsedUserCannotBeUpdated();\n\n    //----------------------------------------------------------------------------------------------\n    // Managing members\n    //----------------------------------------------------------------------------------------------\n\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"},{"file_path":"src/misc/Recoverable.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity 0.8.28;\n\nimport {Auth} from \"./Auth.sol\";\nimport {IERC6909} from \"./interfaces/IERC6909.sol\";\nimport {SafeTransferLib} from \"./libraries/SafeTransferLib.sol\";\nimport {IRecoverable, ETH_ADDRESS} from \"./interfaces/IRecoverable.sol\";\n\n/// @title  Recoverable\n/// @notice Abstract contract that provides emergency token recovery functionality, allowing authorized parties\n///         to retrieve accidentally sent ETH, ERC20, or ERC6909 tokens from the contract to a specified\n///         receiver address.\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"},{"file_path":"src/hooks/interfaces/IFreezable.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\n\ninterface IFreezable {\n    //----------------------------------------------------------------------------------------------\n    // Events\n    //----------------------------------------------------------------------------------------------\n\n    event Freeze(address indexed token, address indexed user);\n    event Unfreeze(address indexed token, address indexed user);\n\n    //----------------------------------------------------------------------------------------------\n    // Errors\n    //----------------------------------------------------------------------------------------------\n\n    error CannotFreezeZeroAddress();\n    error EndorsedUserCannotBeFrozen();\n\n    //----------------------------------------------------------------------------------------------\n    // Handling freezes\n    //----------------------------------------------------------------------------------------------\n\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"},{"file_path":"src/core/messaging/interfaces/IScheduleAuth.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\n\ninterface IScheduleAuth {\n    event ScheduleRely(address indexed target, uint256 indexed scheduledTime);\n    event CancelRely(address indexed target);\n\n    /// @notice Schedule relying a new ward after the delay has passed\n    /// @param target The address to schedule as a ward\n    function scheduleRely(address target) external;\n\n    /// @notice Cancel a pending scheduled rely\n    /// @param target The address to cancel the scheduled rely for\n    function cancelRely(address target) external;\n}\n"},{"file_path":"src/core/spoke/interfaces/IShareToken.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\n\nimport {IERC20Metadata} from \"../../../misc/interfaces/IERC20.sol\";\nimport {IERC7575Share} from \"../../../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    //----------------------------------------------------------------------------------------------\n    // Events\n    //----------------------------------------------------------------------------------------------\n\n    event File(bytes32 indexed what, address data);\n    event SetHookData(address indexed user, bytes16 data);\n\n    //----------------------------------------------------------------------------------------------\n    // Errors\n    //----------------------------------------------------------------------------------------------\n\n    error NotAuthorizedOrHook();\n    error ExceedsMaxSupply();\n    error RestrictionsFailed();\n\n    //----------------------------------------------------------------------------------------------\n    // Structs\n    //----------------------------------------------------------------------------------------------\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    //----------------------------------------------------------------------------------------------\n    // Administration\n    //----------------------------------------------------------------------------------------------\n\n    /// @notice Returns the hook that transfers perform callbacks to\n    /// @dev MUST comply to `ITransferHook` interface\n    /// @return The hook contract address\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    /// @param data The new string value\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    /// @param data The new address value\n    function file(bytes32 what, address data) external;\n\n    /// @notice Updates the vault for a given `asset`\n    /// @param asset The asset address\n    /// @param vault_ The vault address\n    function updateVault(address asset, address vault_) external;\n\n    //----------------------------------------------------------------------------------------------\n    // ERC20 overrides\n    //----------------------------------------------------------------------------------------------\n\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    /// @param user The user address\n    /// @return The 16 byte hook data\n    function hookDataOf(address user) external view returns (bytes16);\n\n    /// @notice Update the 16 byte hook data of the given `user`\n    /// @param user The user address\n    /// @param hookData The new hook data\n    function setHookData(address user, bytes16 hookData) external;\n\n    /// @notice Function to mint tokens\n    /// @param user The address to mint tokens to\n    /// @param value The amount of tokens to mint\n    function mint(address user, uint256 value) external;\n\n    /// @notice Function to burn tokens\n    /// @param user The address to burn tokens from\n    /// @param value The amount of tokens to burn\n    function burn(address user, uint256 value) external;\n\n    /// @notice Checks if the tokens can be transferred given the input values\n    /// @param from The sender address\n    /// @param to The recipient address\n    /// @param value The amount to transfer\n    /// @return Whether the transfer is allowed\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    /// @param sender The address initiating the transfer\n    /// @param from The address to transfer from\n    /// @param to The address to transfer to\n    /// @param amount The amount to transfer\n    /// @return Whether the transfer succeeded\n    function authTransferFrom(address sender, address from, address to, uint256 amount) external returns (bool);\n}\n"},{"file_path":"src/core/types/PoolId.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.28;\n\nimport {MathLib} from \"../../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 isEqual(PoolId a, PoolId b) pure returns (bool) {\n    return PoolId.unwrap(a) == PoolId.unwrap(b);\n}\n\nfunction raw(PoolId poolId) pure returns (uint64) {\n    return PoolId.unwrap(poolId);\n}\n\nusing {centrifugeId, isNull, raw, isEqual as ==} for PoolId global;\n"},{"file_path":"src/core/spoke/factories/interfaces/IPoolEscrowFactory.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\n\nimport {PoolId} from \"../../../types/PoolId.sol\";\nimport {IPoolEscrow} from \"../../interfaces/IPoolEscrow.sol\";\n\n/// @title  IPoolEscrowProvider\n/// @notice Interface for deterministic pool escrow address resolution\ninterface IPoolEscrowProvider {\n    /// @notice Returns the deterministic address of an escrow contract based on a given pool id\n    ///         wrapped into the 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\n/// @title  IPoolEscrowFactory\n/// @notice Factory for deploying deterministic pool escrow contracts\n/// @dev    Each pool has a unique escrow contract shared across all its share classes\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"},{"file_path":"src/core/spoke/types/Price.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.28;\n\nimport {D18} from \"../../../misc/types/D18.sol\";\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    D18 price;\n    uint64 computedAt;\n    uint64 maxAge;\n}\n\n/// @dev Checks if a price is valid. Returns false if computedAt is 0. Otherwise checks for block\n/// timestamp <= computedAt + maxAge\nfunction isValid(Price memory price) view returns (bool) {\n    if (price.computedAt != 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\nusing {isValid, validUntil} for Price global;\n"},{"file_path":"src/core/spoke/interfaces/IPoolEscrow.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\n\nimport {IRecoverable} from \"../../../misc/Recoverable.sol\";\nimport {IEscrow} from \"../../../misc/interfaces/IEscrow.sol\";\n\nimport {PoolId} from \"../../types/PoolId.sol\";\nimport {ShareClassId} from \"../../types/ShareClassId.sol\";\n\nstruct Holding {\n    uint128 total;\n    uint128 reserved;\n}\n\n/// @title Per-Pool Escrow separating funds by pool and share class\ninterface IPoolEscrow is IEscrow, IRecoverable {\n    //----------------------------------------------------------------------------------------------\n    // Events\n    //----------------------------------------------------------------------------------------------\n\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 caller The address of the manager creating the reservation\n    /// @param reason The reason code for the reservation\n    /// @param delta 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        address caller,\n        uint32 reason,\n        uint128 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 caller The address of the manager that created the reservation\n    /// @param reason The reason code that was used when reserving\n    /// @param delta 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        address caller,\n        uint32 reason,\n        uint128 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 receiver The address receiving the withdrawn assets\n    /// @param value The amount withdrawn\n    event Withdraw(\n        address indexed asset,\n        uint256 indexed tokenId,\n        PoolId indexed poolId,\n        ShareClassId scId,\n        address receiver,\n        uint128 value\n    );\n\n    /// @notice Emitted when ETH is transferred to the escrow\n    /// @param who The address that sent the ETH\n    /// @param amount The amount transferred\n    event ReceiveNativeTokens(address who, uint256 amount);\n\n    //----------------------------------------------------------------------------------------------\n    // Errors\n    //----------------------------------------------------------------------------------------------\n\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 InsufficientReserve();\n\n    //----------------------------------------------------------------------------------------------\n    // Functions\n    //----------------------------------------------------------------------------------------------\n\n    /// @notice Deposits `value` of `asset` in underlying `poolId` and given `scId`\n    /// @dev NOTE: Must ensure balance sufficiency, i.e. that the depositing amount does not exceed the balance of escrow\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 If wasNoted is true, funds were already added to 'total' (decrements total and emits event)\n    ///      If wasNoted is false, funds are in 'reserved' only (just transfers, no accounting change)\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 receiver The address receiving the withdrawn assets\n    /// @param value The amount to withdraw\n    function withdraw(ShareClassId scId, address asset, uint256 tokenId, address receiver, uint128 value) external;\n\n    /// @notice Increases the reserved amount of `value` for `asset` in underlying `poolId` and given `scId`\n    /// @dev Reserves funds in a specific bucket identified by caller and reason\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    /// @param caller The address of the manager creating the reservation (passed by BalanceSheet)\n    /// @param reason The reason code (1=DEPOSIT, 2=REDEEM)\n    function reserve(ShareClassId scId, address asset, uint256 tokenId, uint128 value, address caller, uint32 reason)\n        external;\n\n    /// @notice Decreases the reserved amount of `value` for `asset` in underlying `poolId` and given `scId`\n    /// @dev Unreserves funds from a specific bucket. MUST fail if bucket has insufficient funds.\n    /// @param scId The id of the share class\n    /// @param asset The address of the asset to be unreserved\n    /// @param tokenId The id of the asset - 0 for ERC20\n    /// @param value The amount to decrease\n    /// @param caller The address of the manager that created the reservation\n    /// @param reason The reason code that was used when reserving\n    function unreserve(ShareClassId scId, address asset, uint256 tokenId, uint128 value, address caller, uint32 reason)\n        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"},{"file_path":"src/core/messaging/interfaces/IGateway.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\n\nimport {IMessageHandler} from \"./IMessageHandler.sol\";\n\nimport {IRecoverable} from \"../../../misc/interfaces/IRecoverable.sol\";\n\nimport {PoolId} from \"../../types/PoolId.sol\";\n\n// Reserved gas amount for processing a message failure (assuming the worst case)\nuint256 constant PROCESS_FAIL_MESSAGE_GAS = 35_000;\n\n// Max length for a supported message. Note that a batch can use several messages with this length.\nuint256 constant MESSAGE_MAX_LENGTH = 1_000;\n\n// Max length of an error that happens when processing a message.\nuint16 constant ERR_MAX_LENGTH = 32 * 4; // enough for most errors\n\n/// @notice Interface for dispatch-only gateway\ninterface IGateway is IMessageHandler, IRecoverable {\n    //----------------------------------------------------------------------------------------------\n    // Structs\n    //----------------------------------------------------------------------------------------------\n\n    struct Underpaid {\n        uint128 gasLimit;\n        uint64 counter;\n    }\n\n    //----------------------------------------------------------------------------------------------\n    // Events\n    //----------------------------------------------------------------------------------------------\n\n    event File(bytes32 indexed what, address addr);\n    event UpdateManager(PoolId poolId, address who, bool canManage);\n    event BlockOutgoing(uint16 centrifugeId, PoolId poolId, bool isBlocked);\n    event PrepareMessage(uint16 indexed centrifugeId, PoolId poolId, bytes message);\n    event UnderpaidBatch(uint16 indexed centrifugeId, bytes batch, bytes32 batchHash);\n    event RepayBatch(uint16 indexed centrifugeId, bytes batch);\n    event ExecuteMessage(uint16 indexed centrifugeId, bytes32 messageHash);\n    event FailMessage(uint16 indexed centrifugeId, bytes32 messageHash, bytes error);\n    event SetRefundAddress(PoolId poolId, IRecoverable refund);\n    event DepositSubsidy(PoolId indexed poolId, address indexed sender, uint256 amount);\n    event WithdrawSubsidy(PoolId indexed poolId, address indexed sender, uint256 amount);\n\n    //----------------------------------------------------------------------------------------------\n    // Errors\n    //----------------------------------------------------------------------------------------------\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 tries to send an empty message.\n    error EmptyMessage();\n\n    /// @notice Dispatched when the message exceeds MESSAGE_MAX_LENGTH.\n    error TooLongMessage();\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 the content of a batch doesn't belong to the same pool\n    error MalformedBatch();\n\n    /// @notice Dispatched when a message is sent but the gateway is blocked for sending messages\n    error OutgoingBlocked();\n\n    /// @notice Dispatched when an account is not valid to withdraw subsidized pool funds\n    error CannotRefund();\n\n    /// @notice Dispatched when there is not enough gas to send the message\n    error NotEnoughGas();\n\n    /// @notice Dispatched when the batch requires more gas than the destination chain can execute in a single transaction\n    error BatchTooExpensive();\n\n    /// @notice Dispatched when a message was batched but there was a payment for it\n    error NotPayable();\n\n    /// @notice Dispatched when the callback fails with no error\n    error CallFailedWithEmptyRevert();\n\n    /// @notice Dispatched when the callback is called inside the callback\n    error CallbackIsLocked();\n\n    /// @notice Dispatched when the user doesn't call lockCallback()\n    error CallbackWasNotLocked();\n\n    /// @notice Dispatched when the callback was not from the sender\n    error CallbackWasNotFromSender();\n\n    /// @notice Dispatched when there is not enough msg.value to send to the callback\n    error NotEnoughValueForCallback();\n\n    /// @notice Dispatched when trying to create a batch during the send loop\n    error ReentrantBatchCreation();\n\n    //----------------------------------------------------------------------------------------------\n    // Administration\n    //----------------------------------------------------------------------------------------------\n\n    /// @notice Used to update an address (state variable) on very rare occasions\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 Configures a manager address for a pool\n    /// @param poolId PoolId associated to the adapters\n    /// @param who Manager address\n    /// @param canManage If enabled as manager\n    function updateManager(PoolId poolId, address who, bool canManage) external;\n\n    /// @notice Indicates if the gateway for a determined pool can send messages or not\n    /// @param centrifugeId Centrifuge ID associated to this block\n    /// @param poolId PoolId associated to this block\n    /// @param canSend If can send messages or not\n    function blockOutgoing(uint16 centrifugeId, PoolId poolId, bool canSend) external;\n\n    //----------------------------------------------------------------------------------------------\n    // Message handling\n    //----------------------------------------------------------------------------------------------\n\n    /// @notice Repay an underpaid batch\n    /// @param centrifugeId The destination chain\n    /// @param batch The batch to repay\n    /// @param refund Address to refund excess payment\n    function repay(uint16 centrifugeId, bytes memory batch, address refund) external payable;\n\n    /// @notice Retry a failed message\n    /// @param centrifugeId The destination chain\n    /// @param message The message to retry\n    function retry(uint16 centrifugeId, bytes memory message) external;\n\n    /// @notice Handling outgoing messages\n    /// @param centrifugeId Destination chain\n    /// @param message The message to send\n    /// @param unpaidMode Tells if storing the message as unpaid if not enough funds\n    /// @param refund Address to refund excess payment\n    function send(uint16 centrifugeId, bytes calldata message, bool unpaidMode, address refund) external payable;\n\n    //----------------------------------------------------------------------------------------------\n    // Batching\n    //----------------------------------------------------------------------------------------------\n\n    /// @notice Automatic batching of cross-chain transactions through a callback.\n    ///         Any cross-chain transactions triggered in this callback will automatically be batched.\n    /// @dev    Should be used like:\n    ///         ```\n    ///         contract Integration {\n    ///             IGateway gateway;\n    ///\n    ///             function doSomething(PoolId poolId) external {\n    ///                 gateway.withBatch(abi.encodeWithSelector(Integration.callback.selector, poolId));\n    ///             }\n    ///\n    ///             function callback(PoolId poolId) external {\n    ///                 // Avoid reentrancy to the callback and ensure it's called from withBatch in the same contract:\n    ///                 gateway.lockCallback();\n    ///\n    ///                 // Call several hub, balance sheet, or spoke methods that trigger cross-chain transactions\n    ///             }\n    ///         }\n    ///         ```\n    ///\n    ///         NOTE: inside callback, `msgSender` should be used instead of msg.sender\n    /// @param  callbackData encoding data for the callback method\n    /// @param  callbackValue msg.value to send to the callback\n    /// @param  refund Address to refund excess payment\n    function withBatch(bytes memory callbackData, uint256 callbackValue, address refund) external payable;\n\n    /// @notice Same as withBatch(..), but without sending any msg.value to the callback\n    function withBatch(bytes memory callbackData, address refund) external payable;\n\n    /// @notice Ensures the callback is called by withBatch in the same contract.\n    /// @dev calling this at the very beginning inside the multicall means:\n    ///         - The callback is called from the gateway under `withBatch`.\n    ///         - The callback is called from the same contract, because withBatch uses `msg.sender` as target for the callback\n    ///         - The callback that uses this can only be called once inside withBatch scope. No reentrancy.\n    function lockCallback() external;\n\n    //----------------------------------------------------------------------------------------------\n    // View methods\n    //----------------------------------------------------------------------------------------------\n\n    /// @notice Returns the current gateway batching level\n    /// @return Whether the gateway is currently batching\n    function isBatching() external view returns (bool);\n}\n"},{"file_path":"src/core/types/AssetId.sol","source_code":"// 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 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, raw, centrifugeId, eq as ==} for AssetId global;\n"},{"file_path":"src/misc/interfaces/IERC6909.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\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) external 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"},{"file_path":"src/misc/interfaces/IERC165.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\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"},{"file_path":"src/core/spoke/interfaces/IEndorsements.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\n\ninterface IEndorsements {\n    event Endorse(address indexed user);\n    event Veto(address indexed user);\n\n    /// @notice Returns whether the user is endorsed\n    /// @param user The address to check for endorsement status\n    /// @return True if the user is endorsed, false otherwise\n    function endorsed(address user) external view returns (bool);\n}\n"},{"file_path":"src/core/spoke/factories/interfaces/IVaultFactory.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\n\nimport {PoolId} from \"../../../types/PoolId.sol\";\nimport {IVault} from \"../../interfaces/IVault.sol\";\nimport {IShareToken} from \"../../interfaces/IShareToken.sol\";\nimport {ShareClassId} from \"../../../types/ShareClassId.sol\";\n\n/// @title  IVaultFactory\n/// @notice Factory for deploying vault contracts for pool share classes\n/// @dev    Creates vaults linking pool IDs, share class IDs, assets, and tokens\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.\n    ///              I.e. zero if asset 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    function newVault(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, IShareToken token)\n        external\n        returns (IVault);\n}\n"},{"file_path":"src/misc/interfaces/IAuth.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\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    /// @param target The address to check for ward status\n    /// @return The ward status (1 if ward, 0 if not)\n    function wards(address target) external view returns (uint256);\n\n    /// @notice Make user a ward (give them admin access)\n    /// @param user The address to grant ward status to\n    function rely(address user) external;\n\n    /// @notice Remove user as a ward (remove admin access)\n    /// @param user The address to remove ward status from\n    function deny(address user) external;\n}\n"},{"file_path":"src/core/messaging/libraries/MessageLib.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.28;\n\nimport {CastLib} from \"../../../misc/libraries/CastLib.sol\";\nimport {MathLib} from \"../../../misc/libraries/MathLib.sol\";\nimport {BytesLib} from \"../../../misc/libraries/BytesLib.sol\";\n\nimport {PoolId} from \"../../types/PoolId.sol\";\n\nenum MessageType {\n    /// @dev Placeholder for null message type\n    _Invalid,\n    // -- Pool independent messages\n    ScheduleUpgrade,\n    CancelUpgrade,\n    RecoverTokens,\n    RegisterAsset,\n    SetPoolAdapters,\n    // -- Pool dependent messages\n    NotifyPool,\n    NotifyShareClass,\n    NotifyPricePoolPerShare,\n    NotifyPricePoolPerAsset,\n    NotifyShareMetadata,\n    UpdateShareHook,\n    InitiateTransferShares,\n    ExecuteTransferShares,\n    UpdateRestriction,\n    UpdateVault,\n    UpdateBalanceSheetManager,\n    UpdateGatewayManager,\n    UpdateHoldingAmount,\n    UpdateShares,\n    SetMaxAssetPriceAge,\n    SetMaxSharePriceAge,\n    Request,\n    RequestCallback,\n    SetRequestManager,\n    TrustedContractUpdate,\n    UntrustedContractUpdate\n}\n\n/// @dev Used internally in the UpdateVault message (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    using MathLib 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        (33  << uint8(MessageType.ScheduleUpgrade) * 8) +\n        (33  << uint8(MessageType.CancelUpgrade) * 8) +\n        (161 << uint8(MessageType.RecoverTokens) * 8) +\n        (18  << uint8(MessageType.RegisterAsset) * 8) +\n        (13  << uint8(MessageType.SetPoolAdapters) * 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        (107  << uint8(MessageType.InitiateTransferShares) * 8) +\n        (89  << uint8(MessageType.ExecuteTransferShares) * 8) +\n        (41  << uint8(MessageType.UpdateRestriction) * 8) +\n        (90  << uint8(MessageType.UpdateVault) * 8) +\n        (42  << uint8(MessageType.UpdateBalanceSheetManager) * 8) +\n        (42  << uint8(MessageType.UpdateGatewayManager) * 8) +\n        (107  << uint8(MessageType.UpdateHoldingAmount) * 8) +\n        (75  << uint8(MessageType.UpdateShares) * 8) +\n        (49  << uint8(MessageType.SetMaxAssetPriceAge) * 8) +\n        (33  << uint8(MessageType.SetMaxSharePriceAge) * 8) +\n        (57  << uint8(MessageType.Request) * 8) +\n        (57  << uint8(MessageType.RequestCallback) * 8) +\n        (41  << uint8(MessageType.SetRequestManager) * 8) +\n        (73  << uint8(MessageType.TrustedContractUpdate) * 8) +\n        (105  << uint8(MessageType.UntrustedContractUpdate) * 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 = uint16(uint8(bytes32(MESSAGE_LENGTHS_1)[31 - kind]));\n\n        // Special 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.TrustedContractUpdate)) {\n            length += 2 + message.toUint16(length); //payloadLength\n        } else if (kind == uint8(MessageType.UntrustedContractUpdate)) {\n            length += 2 + message.toUint16(length); //payloadLength\n        } else if (kind == uint8(MessageType.Request)) {\n            length += 2 + message.toUint16(length); //payloadLength\n        } else if (kind == uint8(MessageType.RequestCallback)) {\n            length += 2 + message.toUint16(length); //payloadLength\n        } else if (kind == uint8(MessageType.SetPoolAdapters)) {\n            length += message.toUint16(11) * 32; // message with variable length\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 the end contains a PoolId in position 1.\n        if (kind >= uint8(MessageType.NotifyPool)) {\n            return PoolId.wrap(message.toUint64(1));\n        }\n\n        return PoolId.wrap(0);\n    }\n\n    function messageExtraGasLimit(bytes memory message) internal pure returns (uint128) {\n        uint8 kind = message.toUint8(0);\n\n        if (kind == uint8(MessageType.InitiateTransferShares)) {\n            return message.toUint128(91);\n        } else if (kind == uint8(MessageType.ExecuteTransferShares)) {\n            return message.toUint128(73);\n        } else if (kind == uint8(MessageType.UpdateRestriction)) {\n            return message.toUint128(25);\n        } else if (kind == uint8(MessageType.TrustedContractUpdate)) {\n            return message.toUint128(57);\n        } else if (kind == uint8(MessageType.UntrustedContractUpdate)) {\n            return message.toUint128(89);\n        } else if (kind == uint8(MessageType.Request)) {\n            return message.toUint128(41);\n        } else if (kind == uint8(MessageType.RequestCallback)) {\n            return message.toUint128(41);\n        } else if (kind == uint8(MessageType.UpdateVault)) {\n            return message.toUint128(74);\n        } else if (kind == uint8(MessageType.UpdateHoldingAmount)) {\n            return message.toUint128(91);\n        } else if (kind == uint8(MessageType.UpdateShares)) {\n            return message.toUint128(59);\n        }\n\n        return 0;\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    //   SetPoolAdapters\n    //---------------------------------------\n\n    struct SetPoolAdapters {\n        uint64 poolId;\n        uint8 threshold;\n        uint8 recoveryIndex;\n        bytes32[] adapterList;\n    }\n\n    function deserializeSetPoolAdapters(bytes memory data) internal pure returns (SetPoolAdapters memory) {\n        require(messageType(data) == MessageType.SetPoolAdapters, UnknownMessageType());\n\n        uint16 length = data.toUint16(11);\n        bytes32[] memory adapterList = new bytes32[](length);\n        for (uint256 i; i < length; i++) {\n            adapterList[i] = data.toBytes32(13 + i * 32);\n        }\n\n        return SetPoolAdapters({\n            poolId: data.toUint64(1),\n            threshold: data.toUint8(9),\n            recoveryIndex: data.toUint8(10),\n            adapterList: adapterList\n        });\n    }\n\n    function serialize(SetPoolAdapters memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(\n            MessageType.SetPoolAdapters,\n            t.poolId,\n            t.threshold,\n            t.recoveryIndex,\n            t.adapterList.length.toUint16(),\n            t.adapterList\n        );\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), scId: data.toBytes16(9), price: data.toUint128(25), 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    //    InitiateTransferShares\n    //---------------------------------------\n\n    struct InitiateTransferShares {\n        uint64 poolId;\n        bytes16 scId;\n        uint16 centrifugeId;\n        bytes32 receiver;\n        uint128 amount;\n        uint128 remoteExtraGasLimit;\n        uint128 extraGasLimit;\n    }\n\n    function deserializeInitiateTransferShares(bytes memory data)\n        internal\n        pure\n        returns (InitiateTransferShares memory)\n    {\n        require(messageType(data) == MessageType.InitiateTransferShares, UnknownMessageType());\n        return InitiateTransferShares({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            centrifugeId: data.toUint16(25),\n            receiver: data.toBytes32(27),\n            amount: data.toUint128(59),\n            remoteExtraGasLimit: data.toUint128(75),\n            extraGasLimit: data.toUint128(91)\n        });\n    }\n\n    function serialize(InitiateTransferShares memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(\n            MessageType.InitiateTransferShares,\n            t.poolId,\n            t.scId,\n            t.centrifugeId,\n            t.receiver,\n            t.amount,\n            t.remoteExtraGasLimit,\n            t.extraGasLimit\n        );\n    }\n\n    //---------------------------------------\n    //    ExecuteTransferShares\n    //---------------------------------------\n\n    struct ExecuteTransferShares {\n        uint64 poolId;\n        bytes16 scId;\n        bytes32 receiver;\n        uint128 amount;\n        uint128 extraGasLimit;\n    }\n\n    function deserializeExecuteTransferShares(bytes memory data) internal pure returns (ExecuteTransferShares memory) {\n        require(messageType(data) == MessageType.ExecuteTransferShares, UnknownMessageType());\n        return ExecuteTransferShares({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            receiver: data.toBytes32(25),\n            amount: data.toUint128(57),\n            extraGasLimit: data.toUint128(73)\n        });\n    }\n\n    function serialize(ExecuteTransferShares memory t) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(MessageType.ExecuteTransferShares, t.poolId, t.scId, t.receiver, t.amount, t.extraGasLimit);\n    }\n\n    //---------------------------------------\n    //    UpdateRestriction\n    //---------------------------------------\n\n    struct UpdateRestriction {\n        uint64 poolId;\n        bytes16 scId;\n        uint128 extraGasLimit;\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(41);\n        return UpdateRestriction({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            extraGasLimit: data.toUint128(25),\n            payload: data.slice(43, payloadLength)\n        });\n    }\n\n    function serialize(UpdateRestriction memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(\n            MessageType.UpdateRestriction, t.poolId, t.scId, t.extraGasLimit, t.payload.length.toUint16(), t.payload\n        );\n    }\n\n    //---------------------------------------\n    //    TrustedContractUpdate\n    //---------------------------------------\n\n    struct TrustedContractUpdate {\n        uint64 poolId;\n        bytes16 scId;\n        bytes32 target;\n        uint128 extraGasLimit;\n        bytes payload; // As sequence of bytes\n    }\n\n    function deserializeTrustedContractUpdate(bytes memory data) internal pure returns (TrustedContractUpdate memory) {\n        require(messageType(data) == MessageType.TrustedContractUpdate, UnknownMessageType());\n        uint16 payloadLength = data.toUint16(73);\n        return TrustedContractUpdate({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            target: data.toBytes32(25),\n            extraGasLimit: data.toUint128(57),\n            payload: data.slice(75, payloadLength)\n        });\n    }\n\n    function serialize(TrustedContractUpdate memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(\n            MessageType.TrustedContractUpdate,\n            t.poolId,\n            t.scId,\n            t.target,\n            t.extraGasLimit,\n            t.payload.length.toUint16(),\n            t.payload\n        );\n    }\n\n    //---------------------------------------\n    //    UntrustedContractUpdate\n    //---------------------------------------\n\n    struct UntrustedContractUpdate {\n        uint64 poolId;\n        bytes16 scId;\n        bytes32 target;\n        bytes32 sender;\n        uint128 extraGasLimit;\n        bytes payload; // As sequence of bytes\n    }\n\n    function deserializeUntrustedContractUpdate(bytes memory data)\n        internal\n        pure\n        returns (UntrustedContractUpdate memory)\n    {\n        require(messageType(data) == MessageType.UntrustedContractUpdate, UnknownMessageType());\n        uint16 payloadLength = data.toUint16(105);\n        return UntrustedContractUpdate({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            target: data.toBytes32(25),\n            sender: data.toBytes32(57),\n            extraGasLimit: data.toUint128(89),\n            payload: data.slice(107, payloadLength)\n        });\n    }\n\n    function serialize(UntrustedContractUpdate memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(\n            MessageType.UntrustedContractUpdate,\n            t.poolId,\n            t.scId,\n            t.target,\n            t.sender,\n            t.extraGasLimit,\n            t.payload.length.toUint16(),\n            t.payload\n        );\n    }\n\n    //---------------------------------------\n    //    Request\n    //---------------------------------------\n\n    struct Request {\n        uint64 poolId;\n        bytes16 scId;\n        uint128 assetId;\n        uint128 extraGasLimit;\n        bytes payload; // As sequence of bytes\n    }\n\n    function deserializeRequest(bytes memory data) internal pure returns (Request memory) {\n        require(messageType(data) == MessageType.Request, UnknownMessageType());\n        uint16 payloadLength = data.toUint16(57);\n        return Request({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            assetId: data.toUint128(25),\n            extraGasLimit: data.toUint128(41),\n            payload: data.slice(59, payloadLength)\n        });\n    }\n\n    function serialize(Request memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(\n            MessageType.Request, t.poolId, t.scId, t.assetId, t.extraGasLimit, t.payload.length.toUint16(), t.payload\n        );\n    }\n\n    //---------------------------------------\n    //    RequestCallback\n    //---------------------------------------\n\n    struct RequestCallback {\n        uint64 poolId;\n        bytes16 scId;\n        uint128 assetId;\n        uint128 extraGasLimit;\n        bytes payload; // As sequence of bytes\n    }\n\n    function deserializeRequestCallback(bytes memory data) internal pure returns (RequestCallback memory) {\n        require(messageType(data) == MessageType.RequestCallback, UnknownMessageType());\n        uint16 payloadLength = data.toUint16(57);\n        return RequestCallback({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            assetId: data.toUint128(25),\n            extraGasLimit: data.toUint128(41),\n            payload: data.slice(59, payloadLength)\n        });\n    }\n\n    function serialize(RequestCallback memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(\n            MessageType.RequestCallback,\n            t.poolId,\n            t.scId,\n            t.assetId,\n            t.extraGasLimit,\n            t.payload.length.toUint16(),\n            t.payload\n        );\n    }\n\n    //---------------------------------------\n    //   VaultUpdate\n    //---------------------------------------\n\n    struct UpdateVault {\n        uint64 poolId;\n        bytes16 scId;\n        uint128 assetId;\n        bytes32 vaultOrFactory;\n        uint8 kind; // VaultUpdateKind\n        uint128 extraGasLimit;\n    }\n\n    function deserializeUpdateVault(bytes memory data) internal pure returns (UpdateVault memory) {\n        require(messageType(data) == MessageType.UpdateVault, UnknownMessageType());\n        return UpdateVault({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            assetId: data.toUint128(25),\n            vaultOrFactory: data.toBytes32(41),\n            kind: data.toUint8(73),\n            extraGasLimit: data.toUint128(74)\n        });\n    }\n\n    function serialize(UpdateVault memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(\n            MessageType.UpdateVault, t.poolId, t.scId, t.assetId, t.vaultOrFactory, t.kind, t.extraGasLimit\n        );\n    }\n\n    //---------------------------------------\n    //   SetRequestManager\n    //---------------------------------------\n\n    struct SetRequestManager {\n        uint64 poolId;\n        bytes32 manager;\n    }\n\n    function deserializeSetRequestManager(bytes memory data) internal pure returns (SetRequestManager memory) {\n        require(messageType(data) == MessageType.SetRequestManager, UnknownMessageType());\n        return SetRequestManager({poolId: data.toUint64(1), manager: data.toBytes32(9)});\n    }\n\n    function serialize(SetRequestManager memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(MessageType.SetRequestManager, t.poolId, t.manager);\n    }\n\n    //---------------------------------------\n    //   UpdateBalanceSheetManager\n    //---------------------------------------\n\n    struct UpdateBalanceSheetManager {\n        uint64 poolId;\n        bytes32 who;\n        bool canManage;\n    }\n\n    function deserializeUpdateBalanceSheetManager(bytes memory data)\n        internal\n        pure\n        returns (UpdateBalanceSheetManager memory)\n    {\n        require(messageType(data) == MessageType.UpdateBalanceSheetManager, UnknownMessageType());\n        return UpdateBalanceSheetManager({poolId: data.toUint64(1), who: data.toBytes32(9), canManage: data.toBool(41)});\n    }\n\n    function serialize(UpdateBalanceSheetManager memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(MessageType.UpdateBalanceSheetManager, t.poolId, t.who, t.canManage);\n    }\n\n    //---------------------------------------\n    //    UpdateHoldingAmount\n    //---------------------------------------\n\n    struct UpdateHoldingAmount {\n        uint64 poolId;\n        bytes16 scId;\n        uint128 assetId;\n        uint128 amount;\n        uint128 pricePoolPerAsset;\n        uint64 timestamp;\n        bool isIncrease;\n        bool isSnapshot;\n        uint64 nonce;\n        uint128 extraGasLimit;\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            amount: data.toUint128(41),\n            pricePoolPerAsset: data.toUint128(57),\n            timestamp: data.toUint64(73),\n            isIncrease: data.toBool(81),\n            isSnapshot: data.toBool(82),\n            nonce: data.toUint64(83),\n            extraGasLimit: data.toUint128(91)\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.amount,\n            t.pricePoolPerAsset,\n            t.timestamp,\n            t.isIncrease,\n            t.isSnapshot,\n            t.nonce,\n            t.extraGasLimit\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        bool isSnapshot;\n        uint64 nonce;\n        uint128 extraGasLimit;\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            isSnapshot: data.toBool(50),\n            nonce: data.toUint64(51),\n            extraGasLimit: data.toUint128(59)\n        });\n    }\n\n    function serialize(UpdateShares memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(\n            MessageType.UpdateShares,\n            t.poolId,\n            t.scId,\n            t.shares,\n            t.timestamp,\n            t.isIssuance,\n            t.isSnapshot,\n            t.nonce,\n            t.extraGasLimit\n        );\n    }\n\n    //---------------------------------------\n    //   SetMaxAssetPriceAge\n    //---------------------------------------\n\n    struct SetMaxAssetPriceAge {\n        uint64 poolId;\n        bytes16 scId;\n        uint128 assetId;\n        uint64 maxPriceAge;\n    }\n\n    function deserializeSetMaxAssetPriceAge(bytes memory data) internal pure returns (SetMaxAssetPriceAge memory) {\n        require(messageType(data) == MessageType.SetMaxAssetPriceAge, UnknownMessageType());\n        return SetMaxAssetPriceAge({\n            poolId: data.toUint64(1),\n            scId: data.toBytes16(9),\n            assetId: data.toUint128(25),\n            maxPriceAge: data.toUint64(41)\n        });\n    }\n\n    function serialize(SetMaxAssetPriceAge memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(MessageType.SetMaxAssetPriceAge, t.poolId, t.scId, t.assetId, t.maxPriceAge);\n    }\n\n    //---------------------------------------\n    //   SetMaxSharePriceAge\n    //---------------------------------------\n\n    struct SetMaxSharePriceAge {\n        uint64 poolId;\n        bytes16 scId;\n        uint64 maxPriceAge;\n    }\n\n    function deserializeSetMaxSharePriceAge(bytes memory data) internal pure returns (SetMaxSharePriceAge memory) {\n        require(messageType(data) == MessageType.SetMaxSharePriceAge, UnknownMessageType());\n        return SetMaxSharePriceAge({poolId: data.toUint64(1), scId: data.toBytes16(9), maxPriceAge: data.toUint64(25)});\n    }\n\n    function serialize(SetMaxSharePriceAge memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(MessageType.SetMaxSharePriceAge, t.poolId, t.scId, t.maxPriceAge);\n    }\n\n    //---------------------------------------\n    //   UpdateGatewayManager\n    //---------------------------------------\n\n    struct UpdateGatewayManager {\n        uint64 poolId;\n        bytes32 who;\n        bool canManage;\n    }\n\n    function deserializeUpdateGatewayManager(bytes memory data) internal pure returns (UpdateGatewayManager memory) {\n        require(messageType(data) == MessageType.UpdateGatewayManager, UnknownMessageType());\n        return UpdateGatewayManager({poolId: data.toUint64(1), who: data.toBytes32(9), canManage: data.toBool(41)});\n    }\n\n    function serialize(UpdateGatewayManager memory t) internal pure returns (bytes memory) {\n        return abi.encodePacked(MessageType.UpdateGatewayManager, t.poolId, t.who, t.canManage);\n    }\n}\n"},{"file_path":"src/misc/interfaces/IERC7575.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\n\nimport {IERC165} from \"./IERC165.sol\";\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"},{"file_path":"src/core/spoke/interfaces/ISpoke.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\n\nimport {IShareToken} from \"./IShareToken.sol\";\nimport {IVault, VaultKind} from \"./IVault.sol\";\n\nimport {D18} from \"../../../misc/types/D18.sol\";\n\nimport {Price} from \"../types/Price.sol\";\nimport {PoolId} from \"../../types/PoolId.sol\";\nimport {AssetId} from \"../../types/AssetId.sol\";\nimport {ShareClassId} from \"../../types/ShareClassId.sol\";\nimport {IRequestManager} from \"../../interfaces/IRequestManager.sol\";\nimport {IVaultFactory} from \"../factories/interfaces/IVaultFactory.sol\";\n\n/// @dev Centrifuge pools\nstruct Pool {\n    /// @dev Timestamp of pool creation\n    uint64 createdAt;\n}\n\n/// @dev Each Centrifuge pool is associated to 1 or more share 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}\n\n/// @dev Eech share token maps to a pool and share class\nstruct TokenDetails {\n    PoolId poolId;\n    ShareClassId scId;\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 ISpoke {\n    //----------------------------------------------------------------------------------------------\n    // Events\n    //----------------------------------------------------------------------------------------------\n\n    event File(bytes32 indexed what, address data);\n    event RegisterAsset(\n        uint16 centrifugeId,\n        AssetId indexed assetId,\n        address indexed asset,\n        uint256 indexed tokenId,\n        string name,\n        string symbol,\n        uint8 decimals,\n        bool isInitialization\n    );\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        IVault vault,\n        VaultKind kind\n    );\n    event SetRequestManager(PoolId indexed poolId, IRequestManager manager);\n    event UpdateAssetPrice(\n        PoolId indexed poolId,\n        ShareClassId indexed scId,\n        address indexed asset,\n        uint256 tokenId,\n        D18 price,\n        uint64 computedAt\n    );\n    event UpdateSharePrice(PoolId indexed poolId, ShareClassId indexed scId, D18 price, uint64 computedAt);\n    event InitiateTransferShares(\n        uint16 centrifugeId,\n        PoolId indexed poolId,\n        ShareClassId indexed scId,\n        address indexed sender,\n        bytes32 destinationAddress,\n        uint128 amount\n    );\n    event ExecuteTransferShares(\n        PoolId indexed poolId, ShareClassId indexed scId, address indexed receiver, uint128 amount\n    );\n    event LinkVault(\n        PoolId indexed poolId, ShareClassId indexed scId, address indexed asset, uint256 tokenId, IVault vault\n    );\n    event UnlinkVault(\n        PoolId indexed poolId, ShareClassId indexed scId, address indexed asset, uint256 tokenId, IVault 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    event UntrustedContractUpdate(\n        uint16 indexed centrifugeId,\n        PoolId indexed poolId,\n        ShareClassId scId,\n        bytes32 target,\n        bytes payload,\n        address indexed sender\n    );\n\n    //----------------------------------------------------------------------------------------------\n    // Errors\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 InvalidFactory();\n    error InvalidPrice();\n    error AssetMissingDecimals();\n    error ShareTokenDoesNotExist();\n    error LocalTransferNotAllowed();\n    error CrossChainTransferNotAllowed();\n    error ShareTokenTransferFailed();\n    error TransferFromFailed();\n    error InvalidRequestManager();\n    error RequestManagerNotSet();\n    error InvalidManager();\n    error InvalidVault();\n    error AlreadyLinkedVault();\n    error AlreadyUnlinkedVault();\n\n    //----------------------------------------------------------------------------------------------\n    // Administration\n    //----------------------------------------------------------------------------------------------\n\n    /// @notice Updates a contract parameter\n    /// @param what Accepts a bytes32 representation of 'gateway', 'investmentManager', 'tokenFactory', or 'gasService'\n    /// @param data The new address\n    function file(bytes32 what, address data) external;\n\n    /// @notice Links a share token to a pool and share class\n    /// @param poolId The pool identifier\n    /// @param scId The share class identifier\n    /// @param shareToken The share token contract\n    function linkToken(PoolId poolId, ShareClassId scId, IShareToken shareToken) external;\n\n    /// @notice Updates a share token's vault reference for a specific asset\n    /// @param poolId The pool ID\n    /// @param scId The share class ID\n    /// @param asset The asset address\n    /// @param vault The vault address to set (or address(0) to unset)\n    function setShareTokenVault(PoolId poolId, ShareClassId scId, address asset, address vault) external;\n\n    //----------------------------------------------------------------------------------------------\n    // Outgoing methods\n    //----------------------------------------------------------------------------------------------\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    /// @param extraGasLimit Extra gas limit used for computation on the intermediary hub\n    /// @param remoteExtraGasLimit Extra gas limit used for computation in the destination chain\n    /// @param refund Address to refund the excess of the payment\n    function crosschainTransferShares(\n        uint16 centrifugeId,\n        PoolId poolId,\n        ShareClassId scId,\n        bytes32 receiver,\n        uint128 amount,\n        uint128 extraGasLimit,\n        uint128 remoteExtraGasLimit,\n        address refund\n    ) external payable;\n\n    /// @notice Transfers share class tokens to a cross-chain recipient address (legacy)\n    /// @dev Maintained for retrocompatibility. New implementers should use the above\n    /// @param centrifugeId The centrifuge id of chain to where the shares are transferred\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    /// @param remoteExtraGasLimit Extra gas limit used for computation in the destination chain\n    function crosschainTransferShares(\n        uint16 centrifugeId,\n        PoolId poolId,\n        ShareClassId scId,\n        bytes32 receiver,\n        uint128 amount,\n        uint128 remoteExtraGasLimit\n    ) external 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    /// @param refund Address to refund the excess of the payment\n    /// @return assetId The underlying internal uint128 assetId.\n    function registerAsset(uint16 centrifugeId, address asset, uint256 tokenId, address refund)\n        external\n        payable\n        returns (AssetId assetId);\n\n    /// @notice Initiates an update to a hub-side contract from spoke\n    /// @param poolId The pool identifier\n    /// @param scId The share class identifier\n    /// @param target The hub-side target contract (as bytes32 for cross-chain compatibility)\n    /// @param payload The update payload\n    /// @param extraGasLimit Additional gas for cross-chain execution\n    /// @param refund Address to refund excess payment\n    /// @dev Permissionless by choice, forwards caller's address to recipient for permission validation\n    function updateContract(\n        PoolId poolId,\n        ShareClassId scId,\n        bytes32 target,\n        bytes calldata payload,\n        uint128 extraGasLimit,\n        address refund\n    ) external payable;\n\n    /// @notice Handles a request originating from the Spoke side\n    /// @param poolId The pool id\n    /// @param scId The share class id\n    /// @param assetId The asset id\n    /// @param payload The request payload to be processed\n    /// @param extraGasLimit Additional gas stipend for cross-chain execution\n    /// @param unpaid Whether to allow unpaid mode\n    /// @param refund Address to refund excess payment\n    function request(\n        PoolId poolId,\n        ShareClassId scId,\n        AssetId assetId,\n        bytes memory payload,\n        uint128 extraGasLimit,\n        bool unpaid,\n        address refund\n    ) external payable;\n\n    //----------------------------------------------------------------------------------------------\n    // View methods\n    //----------------------------------------------------------------------------------------------\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 Returns poolId and shareClassId given a share token address\n    /// @dev Reverts if share token does not exist\n    ///\n    /// @param shareToken_ The address of the share token\n    /// @return poolId The pool id associated with the share token\n    /// @return scId The share class id associated with the share token\n    function shareTokenDetails(address shareToken_) external view returns (PoolId poolId, ShareClassId scId);\n\n    /// @notice Returns whether the given pool id is active\n    /// @param poolId The pool id\n    /// @return Whether the pool 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    /// @param poolId The pool id\n    /// @param scId The share class id\n    /// @return The address of the share token\n    function shareToken(PoolId poolId, ShareClassId scId) external view returns (IShareToken);\n\n    /// @notice Returns the price per share for a given pool and share class\n    /// @dev The provided price is defined as POOL_UNIT/SHARE_UNIT\n    /// @dev Conditionally checks if price is valid\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) external view returns (D18 price);\n\n    /// @notice Returns the price per asset for a given pool, share class and the underlying asset id\n    /// @dev The provided price is defined as POOL_UNIT/ASSET_UNIT\n    /// @dev Conditionally checks if price is valid\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 both prices per pool for a given pool, share class and the underlying asset id\n    /// @dev The provided prices are defined as POOL_UNIT/ASSET_UNIT and POOL_UNIT/SHARE_UNIT\n    /// @dev Conditionally checks if prices are valid\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    /// @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    /// @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    /// @notice Returns the request manager for a given pool\n    /// @param poolId The pool id\n    /// @return manager The request manager for the pool\n    function requestManager(PoolId poolId) external view returns (IRequestManager manager);\n}\n"},{"file_path":"lib/forge-std/src/interfaces/IERC165.sol","source_code":"// 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"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[{"internalType":"address","name":"root_","type":"address"},{"internalType":"address","name":"spoke_","type":"address"},{"internalType":"address","name":"balanceSheet_","type":"address"},{"internalType":"address","name":"crosschainSource_","type":"address"},{"internalType":"address","name":"deployer","type":"address"},{"internalType":"address","name":"poolEscrowProvider_","type":"address"},{"internalType":"address","name":"poolEscrow_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CannotFreezeZeroAddress","type":"error"},{"inputs":[],"name":"EndorsedUserCannotBeFrozen","type":"error"},{"inputs":[],"name":"EndorsedUserCannotBeUpdated","type":"error"},{"inputs":[],"name":"InvalidInputs","type":"error"},{"inputs":[],"name":"InvalidUpdate","type":"error"},{"inputs":[],"name":"InvalidValidUntil","type":"error"},{"inputs":[],"name":"NotAuthorized","type":"error"},{"inputs":[],"name":"PrefixNotZero","type":"error"},{"inputs":[],"name":"ShareTokenDoesNotExist","type":"error"},{"inputs":[],"name":"SliceOutOfBounds","type":"error"},{"inputs":[],"name":"TransferBlocked","type":"error"},{"inputs":[],"name":"UnknownMessageType","type":"error"},{"inputs":[],"name":"UnknownTrustedCall","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"Deny","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"Freeze","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"Rely","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"Unfreeze","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"manager","type":"address"},{"indexed":false,"internalType":"bool","name":"canManage","type":"bool"}],"name":"UpdateHookManager","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint64","name":"validUntil","type":"uint64"}],"name":"UpdateMember","type":"event"},{"inputs":[],"name":"FREEZE_BIT","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"balanceSheet","outputs":[{"internalType":"contract IBalanceSheet","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"components":[{"internalType":"bytes16","name":"from","type":"bytes16"},{"internalType":"bytes16","name":"to","type":"bytes16"}],"internalType":"struct HookData","name":"hookData","type":"tuple"}],"name":"checkERC20Transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"crosschainSource","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"deny","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"user","type":"address"}],"name":"freeze","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"isCrosschainTransfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"isCrosschainTransferExecution","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"isDepositClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"isDepositFulfillment","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"isDepositRequestOrIssuance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"user","type":"address"}],"name":"isFrozen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"user","type":"address"}],"name":"isMember","outputs":[{"internalType":"bool","name":"isValid","type":"bool"},{"internalType":"uint64","name":"validUntil","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"isPoolEscrow","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"isRedeemClaimOrRevocation","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"isRedeemFulfillment","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"isRedeemRequest","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"components":[{"internalType":"bytes16","name":"from","type":"bytes16"},{"internalType":"bytes16","name":"to","type":"bytes16"}],"internalType":"struct HookData","name":"hookData","type":"tuple"}],"name":"isSourceMember","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"components":[{"internalType":"bytes16","name":"from","type":"bytes16"},{"internalType":"bytes16","name":"to","type":"bytes16"}],"internalType":"struct HookData","name":"hookData","type":"tuple"}],"name":"isSourceOrTargetFrozen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"components":[{"internalType":"bytes16","name":"from","type":"bytes16"},{"internalType":"bytes16","name":"to","type":"bytes16"}],"internalType":"struct HookData","name":"hookData","type":"tuple"}],"name":"isTargetMember","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"manager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"components":[{"internalType":"bytes16","name":"from","type":"bytes16"},{"internalType":"bytes16","name":"to","type":"bytes16"}],"internalType":"struct HookData","name":"","type":"tuple"}],"name":"onERC20AuthTransfer","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"components":[{"internalType":"bytes16","name":"from","type":"bytes16"},{"internalType":"bytes16","name":"to","type":"bytes16"}],"internalType":"struct HookData","name":"hookData","type":"tuple"}],"name":"onERC20Transfer","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"poolEscrow","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolEscrowProvider","outputs":[{"internalType":"contract IPoolEscrowProvider","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"rely","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"root","outputs":[{"internalType":"contract IRoot","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"spoke","outputs":[{"internalType":"contract ISpoke","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId","type":"bytes16"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"trustedCall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"user","type":"address"}],"name":"unfreeze","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint64","name":"validUntil","type":"uint64"}],"name":"updateMember","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"updateRestriction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"wards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":true,"constructor_args":"0000000000000000000000007ed48c31f2fdc40d37407cbabf0870b2b688368f000000000000000000000000ec3582fcdc34078a4b7a8c75a5a3ae46f48525ab00000000000000000000000012a110ce5f0fc871cc72bc7ecaf35cf39dd0f43e000000000000000000000000ec3582fcdc34078a4b7a8c75a5a3ae46f48525ab0000000000000000000000008d566adace57ee5dd2bf98953b804991d634211a0000000000000000000000005187a505c485e22f0b8a5fbdf69ef1c29c478ce3000000000000000000000000798712d8fea603e007a43f4705af98dc6b76258a"}