diff --git a/.changeset/short-chefs-sing.md b/.changeset/short-chefs-sing.md new file mode 100644 index 0000000..0df75ee --- /dev/null +++ b/.changeset/short-chefs-sing.md @@ -0,0 +1,5 @@ +--- +"@peeramid-labs/eds": minor +--- + +added devnet deployment arfifacts diff --git a/deployments/anvil/.chainId b/deployments/anvil/.chainId new file mode 100644 index 0000000..b6fffa9 --- /dev/null +++ b/deployments/anvil/.chainId @@ -0,0 +1 @@ +97113 \ No newline at end of file diff --git a/deployments/anvil/CodeIndex.json b/deployments/anvil/CodeIndex.json new file mode 100644 index 0000000..bec13db --- /dev/null +++ b/deployments/anvil/CodeIndex.json @@ -0,0 +1,146 @@ +{ + "address": "0xc0D31d398c5ee86C5f8a23FA253ee8a586dA03Ce", + "abi": [ + { + "inputs": [ + { + "internalType": "bytes32", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "source", + "type": "address" + } + ], + "name": "alreadyExists", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "container", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "codeHash", + "type": "bytes32" + } + ], + "name": "Indexed", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "id", + "type": "bytes32" + } + ], + "name": "get", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "container", + "type": "address" + } + ], + "name": "register", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "args": [], + "numDeployments": 1, + "solcInputHash": "e1061d92e8448c3a923ed0fb03e88250", + "metadata": "{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"source\",\"type\":\"address\"}],\"name\":\"alreadyExists\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"container\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"codeHash\",\"type\":\"bytes32\"}],\"name\":\"Indexed\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"get\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"container\",\"type\":\"address\"}],\"name\":\"register\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Tim Pechersky (@Peersky)\",\"details\":\"This allows to query contracts by their bytecode instead of addresses.\",\"kind\":\"dev\",\"methods\":{\"get(bytes32)\":{\"details\":\"returns zero if the contract is not indexed\",\"params\":{\"id\":\"The bytecode hash\"},\"returns\":{\"_0\":\"The contract address\"}},\"register(address)\":{\"details\":\"`msg.codeHash` will be usedIt will revert if the contract is already indexed\",\"params\":{\"container\":\"The contract to register\"}}},\"title\":\"Byte Code Indexer Contract\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"get(bytes32)\":{\"notice\":\"Returns the contract address by its bytecode hash\"},\"register(address)\":{\"notice\":\"Registers a contract in the index by its bytecode hash\"}},\"notice\":\"You can use this contract to index contracts by their bytecode.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/CodeIndex.sol\":\"CodeIndex\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200000},\"remappings\":[]},\"sources\":{\"src/CodeIndex.sol\":{\"content\":\"// SPDX-License-Identifier: CC0-1.0\\npragma solidity 0.8.20;\\nimport \\\"./ICodeIndex.sol\\\";\\n\\n/**\\n * @title Byte Code Indexer Contract\\n * @notice You can use this contract to index contracts by their bytecode.\\n * @dev This allows to query contracts by their bytecode instead of addresses.\\n * @author Tim Pechersky (@Peersky)\\n */\\ncontract CodeIndex is ICodeIndex {\\n mapping(bytes32 => address) private index;\\n\\n /**\\n * @notice Registers a contract in the index by its bytecode hash\\n * @param container The contract to register\\n * @dev `msg.codeHash` will be used\\n * @dev It will revert if the contract is already indexed\\n */\\n function register(address container) external {\\n address etalon = index[container.codehash];\\n if (etalon != address(0)) {\\n revert alreadyExists(container.codehash, etalon);\\n }\\n index[container.codehash] = container;\\n emit Indexed(container, container.codehash);\\n }\\n\\n /**\\n * @notice Returns the contract address by its bytecode hash\\n * @dev returns zero if the contract is not indexed\\n * @param id The bytecode hash\\n * @return The contract address\\n */\\n function get(bytes32 id) external view returns (address) {\\n return index[id];\\n }\\n}\",\"keccak256\":\"0x549e9093d5417b748ec9b46a61e09d2aece8783efe3fff2d085e35be057a5699\",\"license\":\"CC0-1.0\"},\"src/ICodeIndex.sol\":{\"content\":\"// SPDX-License-Identifier: CC0-1.0\\npragma solidity 0.8.20;\\n\\ninterface ICodeIndex {\\n event Indexed(address indexed container, bytes32 indexed codeHash);\\n error alreadyExists(bytes32 id, address source);\\n\\n function register(address container) external;\\n\\n function get(bytes32 id) external view returns (address);\\n}\",\"keccak256\":\"0x46ba8ab4127e5d6f2171d84c15cea75e530d48fb8997766002a45fe1014766dd\",\"license\":\"CC0-1.0\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b5061023d806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80634420e4861461003b5780638eaa6ac014610050575b600080fd5b61004e6100493660046101b1565b6100af565b005b61008661005e3660046101ee565b60009081526020819052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b73ffffffffffffffffffffffffffffffffffffffff8082163f600090815260208190526040902054168015610135576040517f1a88fd5200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8084163f60048301528216602482015260440160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216803f60009081526020819052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000168417905551823f92917f7eac48f4f5b19bc4a3e15fd574676fc0f406678447f0ca444ed4830d0a4b521f91a35050565b6000602082840312156101c357600080fd5b813573ffffffffffffffffffffffffffffffffffffffff811681146101e757600080fd5b9392505050565b60006020828403121561020057600080fd5b503591905056fea2646970667358221220751ad8c3c74fe055c4d0b5590925ad6f2b9a03b3b3972786607cfe5084c2783e64736f6c63430008140033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c80634420e4861461003b5780638eaa6ac014610050575b600080fd5b61004e6100493660046101b1565b6100af565b005b61008661005e3660046101ee565b60009081526020819052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b73ffffffffffffffffffffffffffffffffffffffff8082163f600090815260208190526040902054168015610135576040517f1a88fd5200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8084163f60048301528216602482015260440160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216803f60009081526020819052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000168417905551823f92917f7eac48f4f5b19bc4a3e15fd574676fc0f406678447f0ca444ed4830d0a4b521f91a35050565b6000602082840312156101c357600080fd5b813573ffffffffffffffffffffffffffffffffffffffff811681146101e757600080fd5b9392505050565b60006020828403121561020057600080fd5b503591905056fea2646970667358221220751ad8c3c74fe055c4d0b5590925ad6f2b9a03b3b3972786607cfe5084c2783e64736f6c63430008140033", + "devdoc": { + "author": "Tim Pechersky (@Peersky)", + "details": "This allows to query contracts by their bytecode instead of addresses.", + "kind": "dev", + "methods": { + "get(bytes32)": { + "details": "returns zero if the contract is not indexed", + "params": { + "id": "The bytecode hash" + }, + "returns": { + "_0": "The contract address" + } + }, + "register(address)": { + "details": "`msg.codeHash` will be usedIt will revert if the contract is already indexed", + "params": { + "container": "The contract to register" + } + } + }, + "title": "Byte Code Indexer Contract", + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "get(bytes32)": { + "notice": "Returns the contract address by its bytecode hash" + }, + "register(address)": { + "notice": "Registers a contract in the index by its bytecode hash" + } + }, + "notice": "You can use this contract to index contracts by their bytecode.", + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 2784, + "contract": "src/CodeIndex.sol:CodeIndex", + "label": "index", + "offset": 0, + "slot": "0", + "type": "t_mapping(t_bytes32,t_address)" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_bytes32": { + "encoding": "inplace", + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_address)": { + "encoding": "mapping", + "key": "t_bytes32", + "label": "mapping(bytes32 => address)", + "numberOfBytes": "32", + "value": "t_address" + } + } + } +} \ No newline at end of file diff --git a/deployments/anvil/solcInputs/e1061d92e8448c3a923ed0fb03e88250.json b/deployments/anvil/solcInputs/e1061d92e8448c3a923ed0fb03e88250.json new file mode 100644 index 0000000..2e62b7c --- /dev/null +++ b/deployments/anvil/solcInputs/e1061d92e8448c3a923ed0fb03e88250.json @@ -0,0 +1,153 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```solidity\n * contract MyToken is ERC20Upgradeable {\n * function initialize() initializer public {\n * __ERC20_init(\"MyToken\", \"MTK\");\n * }\n * }\n *\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n * function initializeV2() reinitializer(2) public {\n * __ERC20Permit_init(\"MyToken\");\n * }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n * _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n /**\n * @dev Storage of the initializable contract.\n *\n * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions\n * when using with upgradeable contracts.\n *\n * @custom:storage-location erc7201:openzeppelin.storage.Initializable\n */\n struct InitializableStorage {\n /**\n * @dev Indicates that the contract has been initialized.\n */\n uint64 _initialized;\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool _initializing;\n }\n\n // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Initializable\")) - 1)) & ~bytes32(uint256(0xff))\n bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;\n\n /**\n * @dev The contract is already initialized.\n */\n error InvalidInitialization();\n\n /**\n * @dev The contract is not initializing.\n */\n error NotInitializing();\n\n /**\n * @dev Triggered when the contract has been initialized or reinitialized.\n */\n event Initialized(uint64 version);\n\n /**\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n * `onlyInitializing` functions can be used to initialize parent contracts.\n *\n * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any\n * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in\n * production.\n *\n * Emits an {Initialized} event.\n */\n modifier initializer() {\n // solhint-disable-next-line var-name-mixedcase\n InitializableStorage storage $ = _getInitializableStorage();\n\n // Cache values to avoid duplicated sloads\n bool isTopLevelCall = !$._initializing;\n uint64 initialized = $._initialized;\n\n // Allowed calls:\n // - initialSetup: the contract is not in the initializing state and no previous version was\n // initialized\n // - construction: the contract is initialized at version 1 (no reininitialization) and the\n // current contract is just being deployed\n bool initialSetup = initialized == 0 && isTopLevelCall;\n bool construction = initialized == 1 && address(this).code.length == 0;\n\n if (!initialSetup && !construction) {\n revert InvalidInitialization();\n }\n $._initialized = 1;\n if (isTopLevelCall) {\n $._initializing = true;\n }\n _;\n if (isTopLevelCall) {\n $._initializing = false;\n emit Initialized(1);\n }\n }\n\n /**\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n * used to initialize parent contracts.\n *\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n * are added through upgrades and that require initialization.\n *\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n * cannot be nested. If one is invoked in the context of another, execution will revert.\n *\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n * a contract, executing them in the right order is up to the developer or operator.\n *\n * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.\n *\n * Emits an {Initialized} event.\n */\n modifier reinitializer(uint64 version) {\n // solhint-disable-next-line var-name-mixedcase\n InitializableStorage storage $ = _getInitializableStorage();\n\n if ($._initializing || $._initialized >= version) {\n revert InvalidInitialization();\n }\n $._initialized = version;\n $._initializing = true;\n _;\n $._initializing = false;\n emit Initialized(version);\n }\n\n /**\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\n */\n modifier onlyInitializing() {\n _checkInitializing();\n _;\n }\n\n /**\n * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.\n */\n function _checkInitializing() internal view virtual {\n if (!_isInitializing()) {\n revert NotInitializing();\n }\n }\n\n /**\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n * through proxies.\n *\n * Emits an {Initialized} event the first time it is successfully executed.\n */\n function _disableInitializers() internal virtual {\n // solhint-disable-next-line var-name-mixedcase\n InitializableStorage storage $ = _getInitializableStorage();\n\n if ($._initializing) {\n revert InvalidInitialization();\n }\n if ($._initialized != type(uint64).max) {\n $._initialized = type(uint64).max;\n emit Initialized(type(uint64).max);\n }\n }\n\n /**\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\n */\n function _getInitializedVersion() internal view returns (uint64) {\n return _getInitializableStorage()._initialized;\n }\n\n /**\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n */\n function _isInitializing() internal view returns (bool) {\n return _getInitializableStorage()._initializing;\n }\n\n /**\n * @dev Returns a pointer to the storage namespace.\n */\n // solhint-disable-next-line var-name-mixedcase\n function _getInitializableStorage() private pure returns (InitializableStorage storage $) {\n assembly {\n $.slot := INITIALIZABLE_STORAGE\n }\n }\n}\n" + }, + "@openzeppelin/contracts/access/Ownable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\n\npragma solidity ^0.8.20;\n\nimport {Context} from \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * The initial owner is set to the address provided by the deployer. This can\n * later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n /**\n * @dev The caller account is not authorized to perform an operation.\n */\n error OwnableUnauthorizedAccount(address account);\n\n /**\n * @dev The owner is not a valid owner account. (eg. `address(0)`)\n */\n error OwnableInvalidOwner(address owner);\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the address provided by the deployer as the initial owner.\n */\n constructor(address initialOwner) {\n if (initialOwner == address(0)) {\n revert OwnableInvalidOwner(address(0));\n }\n _transferOwnership(initialOwner);\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n if (owner() != _msgSender()) {\n revert OwnableUnauthorizedAccount(_msgSender());\n }\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby disabling any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n if (newOwner == address(0)) {\n revert OwnableInvalidOwner(address(0));\n }\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" + }, + "@openzeppelin/contracts/proxy/Clones.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (proxy/Clones.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for\n * deploying minimal proxy contracts, also known as \"clones\".\n *\n * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies\n * > a minimal bytecode implementation that delegates all calls to a known, fixed address.\n *\n * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`\n * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the\n * deterministic method.\n */\nlibrary Clones {\n /**\n * @dev A clone instance deployment failed.\n */\n error ERC1167FailedCreateClone();\n\n /**\n * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.\n *\n * This function uses the create opcode, which should never revert.\n */\n function clone(address implementation) internal returns (address instance) {\n /// @solidity memory-safe-assembly\n assembly {\n // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes\n // of the `implementation` address with the bytecode before the address.\n mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))\n // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.\n mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))\n instance := create(0, 0x09, 0x37)\n }\n if (instance == address(0)) {\n revert ERC1167FailedCreateClone();\n }\n }\n\n /**\n * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.\n *\n * This function uses the create2 opcode and a `salt` to deterministically deploy\n * the clone. Using the same `implementation` and `salt` multiple time will revert, since\n * the clones cannot be deployed twice at the same address.\n */\n function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {\n /// @solidity memory-safe-assembly\n assembly {\n // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes\n // of the `implementation` address with the bytecode before the address.\n mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))\n // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.\n mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))\n instance := create2(0, 0x09, 0x37, salt)\n }\n if (instance == address(0)) {\n revert ERC1167FailedCreateClone();\n }\n }\n\n /**\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\n */\n function predictDeterministicAddress(\n address implementation,\n bytes32 salt,\n address deployer\n ) internal pure returns (address predicted) {\n /// @solidity memory-safe-assembly\n assembly {\n let ptr := mload(0x40)\n mstore(add(ptr, 0x38), deployer)\n mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)\n mstore(add(ptr, 0x14), implementation)\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)\n mstore(add(ptr, 0x58), salt)\n mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))\n predicted := keccak256(add(ptr, 0x43), 0x55)\n }\n }\n\n /**\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\n */\n function predictDeterministicAddress(\n address implementation,\n bytes32 salt\n ) internal view returns (address predicted) {\n return predictDeterministicAddress(implementation, salt, address(this));\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Context.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/ERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165Checker.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @dev Library used to query support of an interface declared via {IERC165}.\n *\n * Note that these functions return the actual result of the query: they do not\n * `revert` if an interface is not supported. It is up to the caller to decide\n * what to do in these cases.\n */\nlibrary ERC165Checker {\n // As per the EIP-165 spec, no interface should ever match 0xffffffff\n bytes4 private constant INTERFACE_ID_INVALID = 0xffffffff;\n\n /**\n * @dev Returns true if `account` supports the {IERC165} interface.\n */\n function supportsERC165(address account) internal view returns (bool) {\n // Any contract that implements ERC165 must explicitly indicate support of\n // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid\n return\n supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) &&\n !supportsERC165InterfaceUnchecked(account, INTERFACE_ID_INVALID);\n }\n\n /**\n * @dev Returns true if `account` supports the interface defined by\n * `interfaceId`. Support for {IERC165} itself is queried automatically.\n *\n * See {IERC165-supportsInterface}.\n */\n function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {\n // query support of both ERC165 as per the spec and support of _interfaceId\n return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId);\n }\n\n /**\n * @dev Returns a boolean array where each value corresponds to the\n * interfaces passed in and whether they're supported or not. This allows\n * you to batch check interfaces for a contract where your expectation\n * is that some interfaces may not be supported.\n *\n * See {IERC165-supportsInterface}.\n */\n function getSupportedInterfaces(\n address account,\n bytes4[] memory interfaceIds\n ) internal view returns (bool[] memory) {\n // an array of booleans corresponding to interfaceIds and whether they're supported or not\n bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);\n\n // query support of ERC165 itself\n if (supportsERC165(account)) {\n // query support of each interface in interfaceIds\n for (uint256 i = 0; i < interfaceIds.length; i++) {\n interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]);\n }\n }\n\n return interfaceIdsSupported;\n }\n\n /**\n * @dev Returns true if `account` supports all the interfaces defined in\n * `interfaceIds`. Support for {IERC165} itself is queried automatically.\n *\n * Batch-querying can lead to gas savings by skipping repeated checks for\n * {IERC165} support.\n *\n * See {IERC165-supportsInterface}.\n */\n function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {\n // query support of ERC165 itself\n if (!supportsERC165(account)) {\n return false;\n }\n\n // query support of each interface in interfaceIds\n for (uint256 i = 0; i < interfaceIds.length; i++) {\n if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) {\n return false;\n }\n }\n\n // all interfaces supported\n return true;\n }\n\n /**\n * @notice Query if a contract implements an interface, does not check ERC165 support\n * @param account The address of the contract to query for support of an interface\n * @param interfaceId The interface identifier, as specified in ERC-165\n * @return true if the contract at account indicates support of the interface with\n * identifier interfaceId, false otherwise\n * @dev Assumes that account contains a contract that supports ERC165, otherwise\n * the behavior of this method is undefined. This precondition can be checked\n * with {supportsERC165}.\n *\n * Some precompiled contracts will falsely indicate support for a given interface, so caution\n * should be exercised when using this function.\n *\n * Interface identification is specified in ERC-165.\n */\n function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) {\n // prepare call\n bytes memory encodedParams = abi.encodeCall(IERC165.supportsInterface, (interfaceId));\n\n // perform static call\n bool success;\n uint256 returnSize;\n uint256 returnValue;\n assembly {\n success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)\n returnSize := returndatasize()\n returnValue := mload(0x00)\n }\n\n return success && returnSize >= 0x20 && returnValue > 0;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.20;\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 ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\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" + }, + "@openzeppelin/contracts/utils/math/Math.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n /**\n * @dev Muldiv operation overflow.\n */\n error MathOverflowedMulDiv();\n\n enum Rounding {\n Floor, // Toward negative infinity\n Ceil, // Toward positive infinity\n Trunc, // Toward zero\n Expand // Away from zero\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a > b ? a : b;\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds towards infinity instead\n * of rounding towards zero.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n if (b == 0) {\n // Guarantee the same behavior as in a regular Solidity division.\n return a / b;\n }\n\n // (a + b - 1) / b can overflow on addition, so we distribute.\n return a == 0 ? 0 : (a - 1) / b + 1;\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) with further edits by\n * Uniswap Labs also under MIT license.\n */\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 = x * y; // 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 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 if (denominator <= prod1) {\n revert MathOverflowedMulDiv();\n }\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. See https://cs.stackexchange.com/q/138556/92363.\n\n uint256 twos = denominator & (0 - denominator);\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 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 /**\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n uint256 result = mulDiv(x, y, denominator);\n if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {\n result += 1;\n }\n return result;\n }\n\n /**\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded\n * towards zero.\n *\n * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n */\n function sqrt(uint256 a) internal pure returns (uint256) {\n if (a == 0) {\n return 0;\n }\n\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n //\n // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n //\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n //\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n uint256 result = 1 << (log2(a) >> 1);\n\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n // into the expected uint128 result.\n unchecked {\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n return min(result, a / result);\n }\n }\n\n /**\n * @notice Calculates sqrt(a), following the selected rounding direction.\n */\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = sqrt(a);\n return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 2 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n */\n function log2(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >> 128 > 0) {\n value >>= 128;\n result += 128;\n }\n if (value >> 64 > 0) {\n value >>= 64;\n result += 64;\n }\n if (value >> 32 > 0) {\n value >>= 32;\n result += 32;\n }\n if (value >> 16 > 0) {\n value >>= 16;\n result += 16;\n }\n if (value >> 8 > 0) {\n value >>= 8;\n result += 8;\n }\n if (value >> 4 > 0) {\n value >>= 4;\n result += 4;\n }\n if (value >> 2 > 0) {\n value >>= 2;\n result += 2;\n }\n if (value >> 1 > 0) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log2(value);\n return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 10 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n */\n function log10(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >= 10 ** 64) {\n value /= 10 ** 64;\n result += 64;\n }\n if (value >= 10 ** 32) {\n value /= 10 ** 32;\n result += 32;\n }\n if (value >= 10 ** 16) {\n value /= 10 ** 16;\n result += 16;\n }\n if (value >= 10 ** 8) {\n value /= 10 ** 8;\n result += 8;\n }\n if (value >= 10 ** 4) {\n value /= 10 ** 4;\n result += 4;\n }\n if (value >= 10 ** 2) {\n value /= 10 ** 2;\n result += 2;\n }\n if (value >= 10 ** 1) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log10(value);\n return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 256 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n *\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n */\n function log256(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >> 128 > 0) {\n value >>= 128;\n result += 16;\n }\n if (value >> 64 > 0) {\n value >>= 64;\n result += 8;\n }\n if (value >> 32 > 0) {\n value >>= 32;\n result += 4;\n }\n if (value >> 16 > 0) {\n value >>= 16;\n result += 2;\n }\n if (value >> 8 > 0) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log256(value);\n return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);\n }\n }\n\n /**\n * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.\n */\n function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {\n return uint8(rounding) % 2 == 1;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/math/SignedMath.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Standard signed math utilities missing in the Solidity language.\n */\nlibrary SignedMath {\n /**\n * @dev Returns the largest of two signed numbers.\n */\n function max(int256 a, int256 b) internal pure returns (int256) {\n return a > b ? a : b;\n }\n\n /**\n * @dev Returns the smallest of two signed numbers.\n */\n function min(int256 a, int256 b) internal pure returns (int256) {\n return a < b ? a : b;\n }\n\n /**\n * @dev Returns the average of two signed numbers without overflow.\n * The result is rounded towards zero.\n */\n function average(int256 a, int256 b) internal pure returns (int256) {\n // Formula from the book \"Hacker's Delight\"\n int256 x = (a & b) + ((a ^ b) >> 1);\n return x + (int256(uint256(x) >> 255) & (a ^ b));\n }\n\n /**\n * @dev Returns the absolute unsigned value of a signed value.\n */\n function abs(int256 n) internal pure returns (uint256) {\n unchecked {\n // must be unchecked in order to support `n = type(int256).min`\n return uint256(n >= 0 ? n : -n);\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Strings.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)\n\npragma solidity ^0.8.20;\n\nimport {Math} from \"./math/Math.sol\";\nimport {SignedMath} from \"./math/SignedMath.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant HEX_DIGITS = \"0123456789abcdef\";\n uint8 private constant ADDRESS_LENGTH = 20;\n\n /**\n * @dev The `value` string doesn't fit in the specified `length`.\n */\n error StringsInsufficientHexLength(uint256 value, uint256 length);\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n unchecked {\n uint256 length = Math.log10(value) + 1;\n string memory buffer = new string(length);\n uint256 ptr;\n /// @solidity memory-safe-assembly\n assembly {\n ptr := add(buffer, add(32, length))\n }\n while (true) {\n ptr--;\n /// @solidity memory-safe-assembly\n assembly {\n mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))\n }\n value /= 10;\n if (value == 0) break;\n }\n return buffer;\n }\n }\n\n /**\n * @dev Converts a `int256` to its ASCII `string` decimal representation.\n */\n function toStringSigned(int256 value) internal pure returns (string memory) {\n return string.concat(value < 0 ? \"-\" : \"\", toString(SignedMath.abs(value)));\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n unchecked {\n return toHexString(value, Math.log256(value) + 1);\n }\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n uint256 localValue = value;\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = HEX_DIGITS[localValue & 0xf];\n localValue >>= 4;\n }\n if (localValue != 0) {\n revert StringsInsufficientHexLength(value, length);\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal\n * representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);\n }\n\n /**\n * @dev Returns true if the two strings are equal.\n */\n function equal(string memory a, string memory b) internal pure returns (bool) {\n return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));\n }\n}\n" + }, + "@openzeppelin/contracts/utils/structs/EnumerableSet.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value => uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n" + }, + "src/abstracts/CloneDistribution.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\n\nimport \"@openzeppelin/contracts/proxy/Clones.sol\";\nimport \"../interfaces/IDistribution.sol\";\nimport \"./CodeIndexer.sol\";\n\nabstract contract CloneDistribution is IDistribution, CodeIndexer {\n error CodeNotFoundInIndex(bytes32 codeId);\n\n function sources() internal view virtual returns (address[] memory, bytes32 name, uint256 version);\n\n // @inheritdoc IDistribution\n function _instantiate()\n internal\n virtual\n returns (address[] memory instances, bytes32 distributionName, uint256 distributionVersion)\n {\n (address[] memory _sources, bytes32 _distributionName, uint256 _distributionVersion) = sources();\n uint256 srcsLength = _sources.length;\n instances = new address[](srcsLength);\n for (uint256 i; i < srcsLength; ++i) {\n address clone = Clones.clone(_sources[i]);\n instances[i] = clone;\n }\n emit Distributed(msg.sender, instances);\n return (instances, _distributionName, _distributionVersion);\n }\n // @inheritdoc IDistribution\n function get() external view virtual returns (address[] memory src, bytes32 name, uint256 version) {\n return sources();\n }\n // @inheritdoc IDistribution\n function contractURI() external view virtual returns (string memory);\n}\n" + }, + "src/abstracts/CodeIndexer.sol": { + "content": "// SPDX-License-Identifier: CC0-1.0\npragma solidity >=0.8.0 <0.9.0;\n\nimport \"../ICodeIndex.sol\";\n\nabstract contract CodeIndexer {\n //Create2 contract\n ICodeIndex private constant INDEX_CONTRACT = ICodeIndex(0xc0D31d398c5ee86C5f8a23FA253ee8a586dA03Ce);\n constructor() {}\n // @inheritdoc ICodeIndex\n function getContractsIndex() internal pure returns (ICodeIndex) {\n return INDEX_CONTRACT;\n }\n // @inheritdoc ICodeIndex\n function index(address source) internal {\n INDEX_CONTRACT.register(source);\n }\n}\n" + }, + "src/abstracts/Distributor.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0 <0.9.0;\nimport \"../interfaces/IDistribution.sol\";\nimport \"../interfaces/IDistributor.sol\";\nimport \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\nimport \"../interfaces/IInitializer.sol\";\nimport \"../abstracts/CodeIndexer.sol\";\nimport \"@openzeppelin/contracts/utils/introspection/ERC165.sol\";\nimport \"@openzeppelin/contracts/utils/introspection/ERC165Checker.sol\";\nimport {IContractURI} from \"../interfaces/IContractURI.sol\";\n/**\n * @title Distributor\n * @notice Abstract contract that implements the IDistributor interface, CodeIndexer, and ERC165.\n * This contract serves as a base for creating distributor contracts with specific functionalities.\n * It provides the necessary structure and functions to be extended by other contracts.\n * @author Peeramid Labs, 2024\n */\nabstract contract Distributor is IDistributor, CodeIndexer, ERC165 {\n using LibSemver for LibSemver.Version;\n struct DistributionComponent {\n address distributionLocation;\n address initializer;\n }\n\n struct VersionedDistribution {\n LibSemver.VersionRequirement requirement;\n }\n\n using EnumerableSet for EnumerableSet.Bytes32Set;\n EnumerableSet.Bytes32Set private distirbutionsSet;\n mapping(address instance => uint256 instanceId) private instanceIds;\n mapping(uint256 instance => bytes32 distributorsId) public distributionOf;\n mapping(bytes32 distributorsId => DistributionComponent distirbution) public distributionComponents;\n mapping(bytes32 distributorsId => LibSemver.VersionRequirement VersionRequirement) public versionRequirements;\n mapping(uint256 instanceId => LibSemver.Version instanceVersion) public instanceVersions;\n\n uint256 public numInstances;\n // @inheritdoc IDistributor\n function getDistributions() external view returns (bytes32[] memory) {\n return distirbutionsSet.values();\n }\n // @inheritdoc IDistributor\n function getDistributionId(address instance) external view virtual returns (bytes32) {\n return distributionOf[getInstanceId(instance)];\n }\n // @inheritdoc IDistributor\n function getInstanceId(address instance) public view virtual returns (uint256) {\n return instanceIds[instance];\n }\n // @inheritdoc IDistributor\n function getDistributionURI(bytes32 distributorsId) external view returns (string memory) {\n DistributionComponent memory distributionComponent = distributionComponents[distributorsId];\n return IContractURI(distributionComponent.distributionLocation).contractURI();\n }\n\n function _addDistribution(\n address repository,\n address initializer,\n LibSemver.VersionRequirement memory requirement\n ) internal {\n if (!ERC165Checker.supportsInterface(address(repository), type(IRepository).interfaceId)) {\n revert InvalidRepository(repository);\n }\n bytes32 distributorId = keccak256(abi.encode(repository, initializer));\n if (LibSemver.toUint256(requirement.version) == 0) {\n revert InvalidVersionRequested(distributorId, LibSemver.toString(requirement.version));\n }\n _newDistriubutionRecord(distributorId, repository, initializer);\n versionRequirements[distributorId] = requirement;\n emit VersionChanged(distributorId, requirement, requirement);\n }\n\n function _newDistriubutionRecord(bytes32 distributorId, address source, address initializer) private {\n if (distirbutionsSet.contains(distributorId)) revert DistributionExists(distributorId);\n distirbutionsSet.add(distributorId);\n distributionComponents[distributorId] = DistributionComponent(source, initializer);\n emit DistributionAdded(distributorId, source, initializer);\n }\n function _addDistribution(bytes32 id, address initializerAddress) internal {\n ICodeIndex codeIndex = getContractsIndex();\n address distributionLocation = codeIndex.get(id);\n if (distributionLocation == address(0)) revert DistributionNotFound(id);\n bytes32 distributorsId = keccak256(abi.encode(id, initializerAddress));\n _newDistriubutionRecord(distributorsId, distributionLocation, initializerAddress);\n }\n\n function _removeDistribution(bytes32 distributorsId) internal virtual {\n if (!distirbutionsSet.contains(distributorsId)) revert DistributionNotFound(distributorsId);\n distirbutionsSet.remove(distributorsId);\n delete distributionComponents[distributorsId];\n delete versionRequirements[distributorsId];\n emit DistributionRemoved(distributorsId);\n }\n\n /**\n * @notice Internal function to instantiate a new instance.\n * @dev WARNING: This function will DELEGATECALL to initializer if such is provided. Initializer contract MUST be trusted by distributor.\n */\n function _instantiate(\n bytes32 distributorsId,\n bytes memory args\n ) internal virtual returns (address[] memory instances, bytes32 distributionName, uint256 distributionVersion) {\n if (!distirbutionsSet.contains(distributorsId)) revert DistributionNotFound(distributorsId);\n DistributionComponent memory distributionComponent = distributionComponents[distributorsId];\n LibSemver.VersionRequirement memory versionRequirement = versionRequirements[distributorsId];\n\n // External initializer is provided, delegatecall to it\n // Countrary, if no initializer is provided, the distribution is expected to be self-initializing\n bool externallyInitialized = distributionComponent.initializer == address(0);\n bytes4 selector = IInitializer.initialize.selector;\n bytes memory instantiationArgs = externallyInitialized ? args : bytes(\"\");\n address distributionLocation;\n numInstances++;\n uint256 instanceId = numInstances;\n\n if (LibSemver.toUint256(versionRequirement.version) == 0) {\n // Unversioned distribution, expect IDistribution\n distributionLocation = distributionComponent.distributionLocation;\n // Name and version are inferred from what the distribution provides\n (instances, distributionName, distributionVersion) = IDistribution(distributionLocation).instantiate(\n instantiationArgs\n );\n // Unversioned distributions are considered to be at version 0, and are not expected to change\n // This might change in the future, as it could make sence to inherit `distributionVersion` from the distribution\n // Yet for ease of runtime validation and to avoid potential issues, we keep it at 0\n instanceVersions[numInstances] = LibSemver.parse(0);\n } else {\n // Versioned distribution, expect IRepository\n IRepository repository = IRepository(distributionComponent.distributionLocation);\n IRepository.Source memory repoSource = repository.get(versionRequirement);\n ICodeIndex codeIndex = getContractsIndex();\n distributionLocation = codeIndex.get(repoSource.sourceId);\n if (distributionLocation == address(0)) revert DistributionNotFound(repoSource.sourceId);\n (instances, , ) = IDistribution(distributionLocation).instantiate(instantiationArgs);\n distributionName = repository.repositoryName();\n distributionVersion = LibSemver.toUint256(repoSource.version);\n instanceVersions[numInstances] = repoSource.version;\n }\n\n if (externallyInitialized) {\n (bool success, bytes memory result) = address(distributionComponent.initializer).delegatecall(\n abi.encodeWithSelector(selector, instances, args)\n );\n if (!success) {\n if (result.length > 0) {\n assembly {\n let returndata_size := mload(result)\n revert(add(32, result), returndata_size)\n }\n } else {\n revert(\"initializer delegatecall failed without revert reason\");\n }\n }\n }\n\n {\n uint256 instancesLength = instances.length;\n for (uint256 i; i < instancesLength; ++i) {\n instanceIds[instances[i]] = instanceId;\n distributionOf[instanceId] = distributorsId;\n }\n }\n emit Instantiated(distributorsId, instanceId, distributionVersion, instances, args);\n }\n\n /**\n * @inheritdoc IERC7746\n * @notice This is ERC7746 hook must be called by instance methods that access scope is limited to the same instance or distribution\n * @dev it will revert if: (1) `msg.sender` is not a valid instance; (2) `maybeInstance` is not a valid instance (3) `instanceId` belongs to disactivated distribution\n */\n function beforeCall(\n bytes memory config,\n bytes4,\n address maybeInstance,\n uint256,\n bytes memory\n ) external view virtual returns (bytes memory) {\n address target = config.length > 0 ? abi.decode(config, (address)) : msg.sender;\n bytes32 distributorsId = distributionOf[getInstanceId(maybeInstance)];\n uint256 instanceId = getInstanceId(maybeInstance);\n if (\n distributorsId != bytes32(0) &&\n getInstanceId(target) == instanceId &&\n distirbutionsSet.contains(distributorsId)\n ) {\n // ToDo: This check could be based on DistributionOf, hence allowing cross-instance calls\n // Use layerConfig to allow client to configure requirement for the call\n if (!LibSemver.compare(instanceVersions[instanceId], versionRequirements[distributorsId])) {\n revert VersionOutdated(distributorsId, LibSemver.toString(instanceVersions[instanceId]));\n }\n return abi.encode(distributorsId, \"\");\n }\n revert InvalidInstance(maybeInstance);\n }\n /**\n * @inheritdoc IERC7746\n * @notice This is ERC7746 hook must be called by instance methods that access scope is limited to the same instance or distribution\n * @dev it will revert if: (1) `msg.sender` is not a valid instance; (2) `maybeInstance` is not a valid instance (3) `instanceId` belongs to disactivated distribution\n */\n function afterCall(\n bytes memory config,\n bytes4,\n address maybeInstance,\n uint256,\n bytes memory,\n bytes memory\n ) external virtual {\n address target = config.length > 0 ? abi.decode(config, (address)) : msg.sender;\n bytes32 distributorsId = distributionOf[getInstanceId(maybeInstance)];\n uint256 instanceId = getInstanceId(maybeInstance);\n if ((getInstanceId(target) != getInstanceId(maybeInstance)) && distirbutionsSet.contains(distributorsId)) {\n revert InvalidInstance(maybeInstance);\n }\n if (!LibSemver.compare(instanceVersions[instanceId], versionRequirements[distributorsId])) {\n revert VersionOutdated(distributorsId, LibSemver.toString(instanceVersions[instanceId]));\n }\n }\n\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\n return interfaceId == type(IDistributor).interfaceId || super.supportsInterface(interfaceId);\n }\n\n function _changeVersion(bytes32 distributionId, LibSemver.VersionRequirement memory newRequirement) internal {\n if (!distirbutionsSet.contains(distributionId)) revert DistributionNotFound(distributionId);\n LibSemver.VersionRequirement memory oldRequirement = versionRequirements[distributionId];\n if (LibSemver.toUint256(oldRequirement.version) == 0) {\n revert UniversionedDistribution(distributionId);\n }\n if (LibSemver.toUint256(newRequirement.version) == 0) {\n revert InvalidVersionRequested(distributionId, LibSemver.toString(newRequirement.version));\n }\n if (LibSemver.areEqual(oldRequirement.version, newRequirement.version)) {\n revert InvalidVersionRequested(distributionId, LibSemver.toString(newRequirement.version));\n }\n versionRequirements[distributionId] = newRequirement;\n }\n}\n" + }, + "src/abstracts/ERC7746Middleware.sol": { + "content": "// SPDX-License-Identifier: Apache-2.0\n\npragma solidity >=0.8.0 <0.9.0;\nimport \"../libraries/LibMiddleware.sol\";\n\n/**\n * @title ERC7746Middleware\n * @notice Abstract contract that serves as a middleware for ERC7746 standard.\n * This contract is intended to be inherited by other contracts that implement\n * the ERC7746 functionality. It provides base functionality and structure\n * that can be extended and customized by derived contracts.\n * @author Peeramid Labs, 2024\n */\nabstract contract ERC7746Middleware {\n /**\n * @notice Modifier to apply custom logic for ERC7746 compliance.\n * @param _selector The function selector to be checked.\n * @param sender The address of the sender.\n * @param data The calldata being passed to the function.\n * @param value The value being transferred.\n */\n modifier ERC7746C(bytes4 _selector, address sender, bytes calldata data, uint256 value) {\n bytes[] memory layerReturns = LibMiddleware.beforeCall(_selector, sender, data, value);\n _;\n LibMiddleware.afterCall(_selector, sender, data, value, layerReturns);\n }\n\n /**\n * @notice Modifier to apply ERC7746 specific logic.\n * This modifier can be used to enforce certain conditions or\n * execute specific code before or after the function it modifies.\n */\n modifier ERC7746() {\n bytes[] memory layerReturns = LibMiddleware.beforeCall(msg.sig, msg.sender, msg.data, msg.value);\n _;\n LibMiddleware.afterCall(msg.sig, msg.sender, msg.data, msg.value, layerReturns);\n }\n}\n" + }, + "src/abstracts/Installer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\nimport \"../interfaces/IDistributor.sol\";\nimport \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\nimport \"../interfaces/IInstaller.sol\";\n/**\n * @title Installer\n * @notice Abstract contract that implements the IInstaller interface.\n * This contract serves as a base for other contracts that require installation functionality.\n * @author Peeramid Labs, 2024\n */\nabstract contract Installer is IInstaller {\n using EnumerableSet for EnumerableSet.AddressSet;\n using EnumerableSet for EnumerableSet.Bytes32Set;\n address private immutable _target;\n EnumerableSet.AddressSet private whitelistedDistributors;\n mapping(address => EnumerableSet.Bytes32Set) private _permittedDistributions;\n mapping(address => address) private _distributorOf;\n mapping(uint256 => address[]) private _instanceEnum;\n uint256 private instancesNum;\n\n constructor(address targetAddress) {\n _target = targetAddress;\n }\n\n function isDistributor(IDistributor distributor) public view returns (bool) {\n return whitelistedDistributors.contains(address(distributor));\n }\n\n function getWhitelistedDistributors() public view returns (address[] memory) {\n return whitelistedDistributors.values();\n }\n\n function whitelistedDistributions(IDistributor distributor) public view returns (bytes32[] memory) {\n if (whitelistedDistributors.contains(address(distributor))) {\n return distributor.getDistributions();\n } else {\n return _permittedDistributions[address(distributor)].values();\n }\n }\n\n function _allowAllDistributions(IDistributor distributor) internal virtual {\n whitelistedDistributors.add(address(distributor));\n }\n\n function _disallowAllDistributions(IDistributor distributor) internal virtual {\n whitelistedDistributors.remove(address(distributor));\n }\n\n function _allowDistribution(IDistributor distributor, bytes32 distributionId) internal virtual {\n if (whitelistedDistributors.contains(address(distributor))) {\n revert alreadyAllowed(distributor);\n }\n _permittedDistributions[address(distributor)].add(distributionId);\n }\n\n function _disallowDistribution(IDistributor distributor, bytes32 distributionId) internal virtual {\n if (whitelistedDistributors.contains(address(distributor))) {\n revert DissalowDistOnWhitelistedDistributor(distributor, distributionId);\n }\n _permittedDistributions[address(distributor)].remove(distributionId);\n }\n\n function enforceActiveDistribution(IDistributor distributor, bytes32 distributionId) internal view {\n if (\n !whitelistedDistributors.contains(address(distributor)) &&\n !_permittedDistributions[address(distributor)].contains(distributionId)\n ) {\n revert DistributionIsNotPermitted(distributor, distributionId);\n }\n }\n\n function _install(\n IDistributor distributor,\n bytes32 distributionId,\n bytes calldata args\n ) internal virtual returns (uint256 instanceId) {\n if (!isDistributor(distributor) && !_permittedDistributions[address(distributor)].contains(distributionId)) {\n revert InvalidDistributor(distributor);\n }\n enforceActiveDistribution(distributor, distributionId);\n (address[] memory installation, , ) = distributor.instantiate(distributionId, args);\n instancesNum++;\n _instanceEnum[instancesNum] = installation;\n uint256 installationLength = installation.length;\n for (uint256 i; i < installationLength; ++i) {\n _distributorOf[installation[i]] = address(distributor);\n emit Installed(installation[0], distributionId, \"0x\", args);\n }\n return instancesNum;\n }\n\n function _uninstall(uint256 instanceId) internal virtual {\n address[] memory instance = _instanceEnum[instanceId];\n uint256 instanceLength = instance.length;\n for (uint256 i; i < instanceLength; ++i) {\n _distributorOf[instance[i]] = address(0);\n emit Uninstalled(instance[i]);\n }\n }\n\n function getInstance(uint256 instanceId) public view returns (address[] memory instaneContracts) {\n return _instanceEnum[instanceId];\n }\n\n function getInstancesNum() public view returns (uint256) {\n return instancesNum;\n }\n\n function isInstance(address instance) public view returns (bool) {\n return _distributorOf[instance] != address(0);\n }\n\n function distributorOf(address instance) public view returns (IDistributor) {\n return IDistributor(_distributorOf[instance]);\n }\n\n function target() public view returns (address) {\n return _target;\n }\n\n function beforeCall(\n bytes memory layerConfig,\n bytes4 selector,\n address requestingInstance,\n uint256 value,\n bytes memory data\n ) external returns (bytes memory) {\n if (msg.sender != _target) {\n revert InvalidTarget(msg.sender);\n }\n address distributor = _distributorOf[requestingInstance];\n if (distributor != address(0)) {\n bytes memory beforeCallValue = IDistributor(distributor).beforeCall(\n layerConfig,\n selector,\n requestingInstance,\n value,\n data\n );\n (bytes32 id, ) = abi.decode(beforeCallValue, (bytes32, bytes));\n enforceActiveDistribution(IDistributor(distributor), id);\n return abi.encode(id, distributor);\n }\n revert NotAnInstance(requestingInstance);\n }\n\n function afterCall(\n bytes memory layerConfig,\n bytes4 selector,\n address sender,\n uint256 value,\n bytes memory data,\n bytes memory beforeCallResult\n ) external {\n if (msg.sender != _target) {\n revert InvalidTarget(msg.sender);\n }\n address distributor = _distributorOf[sender];\n if (distributor != address(0)) {\n IDistributor(distributor).afterCall(layerConfig, selector, sender, value, data, beforeCallResult);\n }\n revert NotAnInstance(sender);\n }\n}\n" + }, + "src/abstracts/InstallerCloneable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\nimport \"../interfaces/IDistributor.sol\";\nimport \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"../interfaces/IInstaller.sol\";\nimport \"../libraries/LibInstaller.sol\";\n/**\n * @title InstallerClonable\n * @notice Abstract contract that implements the IInstaller interface and is Initializable.\n * This contract serves as a base for creating clonable installer contracts.\n */\nabstract contract InstallerClonable is IInstaller, Initializable {\n using EnumerableSet for EnumerableSet.AddressSet;\n using EnumerableSet for EnumerableSet.Bytes32Set;\n\n constructor() {\n _disableInitializers();\n }\n // @inheritdoc IInstaller\n function initialize(address targetAddress) public virtual initializer {\n LibInstaller.getStorage()._target = targetAddress;\n }\n // @inheritdoc IInstaller\n function isDistributor(IDistributor distributor) public view returns (bool) {\n return LibInstaller.getStorage().whitelistedDistributors.contains(address(distributor));\n }\n // @inheritdoc IInstaller\n function getWhitelistedDistributors() public view returns (address[] memory) {\n return LibInstaller.getStorage().whitelistedDistributors.values();\n }\n // @inheritdoc IInstaller\n function whitelistedDistributions(IDistributor distributor) public view returns (bytes32[] memory) {\n if (LibInstaller.getStorage().whitelistedDistributors.contains(address(distributor))) {\n return distributor.getDistributions();\n } else {\n return LibInstaller.getStorage()._permittedDistributions[address(distributor)].values();\n }\n }\n\n function _allowAllDistributions(IDistributor distributor) internal virtual {\n LibInstaller.getStorage().whitelistedDistributors.add(address(distributor));\n }\n\n function _disallowAllDistributions(IDistributor distributor) internal virtual {\n LibInstaller.getStorage().whitelistedDistributors.remove(address(distributor));\n }\n\n function _allowDistribution(IDistributor distributor, bytes32 distributionId) internal virtual {\n if (LibInstaller.getStorage().whitelistedDistributors.contains(address(distributor))) {\n revert alreadyAllowed(distributor);\n }\n LibInstaller.getStorage()._permittedDistributions[address(distributor)].add(distributionId);\n }\n\n function _disallowDistribution(IDistributor distributor, bytes32 distributionId) internal virtual {\n if (LibInstaller.getStorage().whitelistedDistributors.contains(address(distributor))) {\n revert DissalowDistOnWhitelistedDistributor(distributor, distributionId);\n }\n LibInstaller.getStorage()._permittedDistributions[address(distributor)].remove(distributionId);\n }\n\n function enforceActiveDistribution(IDistributor distributor, bytes32 distributionId) internal view {\n LibInstaller.InstallerStruct storage strg = LibInstaller.getStorage();\n if (\n !strg.whitelistedDistributors.contains(address(distributor)) &&\n !strg._permittedDistributions[address(distributor)].contains(distributionId)\n ) {\n revert DistributionIsNotPermitted(distributor, distributionId);\n }\n }\n\n function _install(\n IDistributor distributor,\n bytes32 distributionId,\n bytes calldata args\n ) internal virtual returns (uint256 instanceId) {\n LibInstaller.InstallerStruct storage strg = LibInstaller.getStorage();\n if (\n !isDistributor(distributor) && !strg._permittedDistributions[address(distributor)].contains(distributionId)\n ) {\n revert InvalidDistributor(distributor);\n }\n enforceActiveDistribution(distributor, distributionId);\n (address[] memory installation, , ) = distributor.instantiate(distributionId, args);\n strg.instancesNum++;\n strg._instanceEnum[strg.instancesNum] = installation;\n uint256 installationlength = installation.length;\n for (uint256 i; i < installationlength; ++i) {\n strg._distributorOf[installation[i]] = address(distributor);\n emit Installed(installation[0], distributionId, \"0x\", args);\n }\n return strg.instancesNum;\n }\n\n function _uninstall(uint256 instanceId) internal virtual {\n LibInstaller.InstallerStruct storage strg = LibInstaller.getStorage();\n address[] memory instance = strg._instanceEnum[instanceId];\n uint256 length = instance.length;\n for (uint256 i; i < length; ++i) {\n strg._distributorOf[instance[i]] = address(0);\n emit Uninstalled(instance[i]);\n }\n strg.instancesNum--;\n }\n // @inheritdoc IInstaller\n function getInstance(uint256 instanceId) public view returns (address[] memory instaneContracts) {\n return LibInstaller.getStorage()._instanceEnum[instanceId];\n }\n // @inheritdoc IInstaller\n function getInstancesNum() public view returns (uint256) {\n return LibInstaller.getStorage().instancesNum;\n }\n // @inheritdoc IInstaller\n function isInstance(address instance) public view returns (bool) {\n return LibInstaller.getStorage()._distributorOf[instance] != address(0);\n }\n // @inheritdoc IInstaller\n function distributorOf(address instance) public view returns (IDistributor) {\n return IDistributor(LibInstaller.getStorage()._distributorOf[instance]);\n }\n // @inheritdoc IInstaller\n function target() public view returns (address) {\n return LibInstaller.getStorage()._target;\n }\n // @inheritdoc IERC7746\n // @notice this will revert if the sender is not the target or requesting instance is not a valid instance\n // @dev it will daisy-chain the call to the distributor, if instance is valid and active distribution\n function beforeCall(\n bytes memory layerConfig,\n bytes4 selector,\n address requestingInstance,\n uint256 value,\n bytes memory data\n ) external virtual returns (bytes memory) {\n LibInstaller.InstallerStruct storage installerSettings = LibInstaller.getStorage();\n if (msg.sender != installerSettings._target) {\n revert InvalidTarget(msg.sender);\n }\n address distributor = installerSettings._distributorOf[requestingInstance];\n if (distributor != address(0)) {\n bytes memory beforeCallValue = IDistributor(distributor).beforeCall(\n layerConfig,\n selector,\n requestingInstance,\n value,\n data\n );\n (bytes32 id, ) = abi.decode(beforeCallValue, (bytes32, bytes));\n enforceActiveDistribution(IDistributor(distributor), id);\n return abi.encode(id, distributor);\n }\n revert NotAnInstance(requestingInstance);\n }\n // @inheritdoc IERC7746\n // @notice this will revert if the sender is not the target or requesting instance is not a valid instance\n // @dev it will daisy-chain the call to the distributor, if instance is valid and active distribution\n function afterCall(\n bytes memory layerConfig,\n bytes4 selector,\n address sender,\n uint256 value,\n bytes memory data,\n bytes memory beforeCallResult\n ) external virtual {\n LibInstaller.InstallerStruct storage installerSettings = LibInstaller.getStorage();\n if (msg.sender != installerSettings._target) {\n revert InvalidTarget(msg.sender);\n }\n address distributor = LibInstaller.getStorage()._distributorOf[sender];\n if (distributor != address(0)) {\n IDistributor(distributor).afterCall(layerConfig, selector, sender, value, data, beforeCallResult);\n }\n revert NotAnInstance(sender);\n }\n}\n" + }, + "src/abstracts/MiddlewareProxy.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0 <0.9.0;\nimport \"./ERC7746Middleware.sol\";\nimport \"../libraries/LibMiddleware.sol\";\n\n/**\n * @dev This contract is a modified OpenZeppelin proxy v5.0.0.\n * Modification wraps a fallback function within ERC7746.\n * Rest is similar to Proxy.sol\n */\ncontract MiddlewareProxy is ERC7746Middleware {\n address private immutable implementationAddress;\n\n constructor(LibMiddleware.LayerStruct[] memory layers, address implementation) {\n implementationAddress = implementation;\n LibMiddleware.setLayers(layers);\n }\n\n /**\n * @dev This is a virtual function that should be overridden so it returns the address to which the fallback\n * function and {_fallback} should delegate.\n */\n function _implementation() internal view returns (address) {\n return implementationAddress;\n }\n\n /**\n * @dev Delegates the current call to the address returned by `_implementation()`.\n *\n * This function does not return to its internal call site, it will return directly to the external caller.\n */\n function _fallback() internal virtual {\n (bool success, bytes memory result) = _implementation().delegatecall(msg.data);\n if (!success) {\n // If the call failed, bubble up the revert reason if present\n if (result.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n assembly {\n let returndata_size := mload(result)\n revert(add(32, result), returndata_size)\n }\n } else {\n revert(\"delegatecall failed without revert reason\");\n }\n }\n }\n\n /**\n * @notice Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other\n * function in the contract matches the call data.\n * @dev This function is wrapped in ERC7746 middleware pattern\n */\n fallback() external payable virtual ERC7746 {\n _fallback();\n }\n}\n" + }, + "src/abstracts/Repository.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\n\nimport \"../libraries/LibSemver.sol\";\nimport \"../interfaces/IRepository.sol\";\n\n/**\n * @title Repository\n * @notice Abstract contract that implements the IRepository interface. This contract serves as a base for other contracts that require repository functionalities.\n */\nabstract contract Repository is IRepository {\n bytes32 public immutable repositoryName;\n string private _cURI;\n using LibSemver for LibSemver.Version;\n mapping(uint256 => bytes32) internal versionedSources; // Flat version -> Source\n mapping(uint64 => bytes) internal releaseMetadata; // Major version -> Metadata\n mapping(uint128 => bytes) internal minorReleaseMetadata; // Major + Minor -> Metadata\n mapping(uint256 => bytes) internal patchReleaseMetadata; // Major + Minor + Patch -> Metadata\n mapping(uint64 => uint64) internal minorReleases;\n mapping(uint128 => uint128) internal patchReleases;\n uint64 internal majorReleases;\n uint256 internal latestVersion;\n\n constructor(bytes32 _repositoryName, string memory cURI) {\n repositoryName = _repositoryName;\n _cURI = cURI;\n }\n\n function _updateReleaseMetadata(LibSemver.Version memory version, bytes memory metadata) internal {\n uint256 versionFlat = version.toUint256();\n if (versionFlat == 0) revert VersionDoesNotExist(versionFlat);\n if (version.major > majorReleases) revert VersionDoesNotExist(versionFlat);\n if (version.minor > minorReleases[version.major]) revert VersionDoesNotExist(versionFlat);\n if (version.patch > patchReleases[(uint128(version.major) << 64) | uint128(version.minor)])\n revert VersionDoesNotExist(versionFlat);\n if (version.patch == 0) {\n if (version.minor == 0) {\n if (version.major == 0) revert ReleaseZeroNotAllowed();\n releaseMetadata[version.major] = metadata;\n } else {\n minorReleaseMetadata[(uint128(version.major) << 64) | uint128(version.minor)] = metadata;\n }\n } else {\n patchReleaseMetadata[versionFlat] = metadata;\n }\n emit ReleaseMetadataUpdated(versionFlat, metadata);\n }\n function _newRelease(bytes32 sourceId, bytes memory metadata, LibSemver.Version memory version) internal {\n uint256 versionFlat = version.toUint256();\n if (versionFlat == 0 && version.major == 0) revert ReleaseZeroNotAllowed();\n if (version.major > majorReleases) {\n if (version.major != majorReleases + 1) revert VersionIncrementInvalid(versionFlat);\n majorReleases = version.major;\n minorReleases[version.major] = 0;\n patchReleases[(uint128(version.major) << 64)] = 0;\n releaseMetadata[version.major] = metadata;\n } else if (version.minor > minorReleases[version.major]) {\n if (version.minor != minorReleases[version.major] + 1) revert VersionIncrementInvalid(versionFlat);\n minorReleases[version.major] = version.minor;\n patchReleases[(uint128(version.major) << 64) | uint128(version.minor)] = 0;\n minorReleaseMetadata[(uint128(version.major) << 64) | uint128(version.minor)] = metadata;\n } else if (version.patch > patchReleases[(uint128(version.major) << 64) | uint128(version.minor)]) {\n if (version.patch != patchReleases[(uint128(version.major) << 64) | uint128(version.minor)] + 1)\n revert VersionIncrementInvalid(versionFlat);\n patchReleases[(uint128(version.major) << 64) | uint128(version.minor)] = version.patch;\n patchReleaseMetadata[versionFlat] = metadata;\n } else {\n revert VersionExists(versionFlat);\n }\n versionedSources[versionFlat] = sourceId;\n latestVersion = versionFlat;\n emit VersionAdded(versionFlat, sourceId, metadata);\n }\n // @inheritdoc IRepository\n function getLatest() public view returns (Source memory) {\n Source memory src;\n src.sourceId = versionedSources[latestVersion];\n src.version = LibSemver.parse(latestVersion);\n src.metadata = releaseMetadata[uint64(latestVersion)];\n return src;\n }\n // @inheritdoc IRepository\n function get(LibSemver.VersionRequirement calldata required) public view returns (Source memory) {\n Source memory src;\n uint256 versionFlat = required.version.toUint256();\n uint256 resolvedVersion;\n if (required.version.major == 0) revert VersionDoesNotExist(versionFlat);\n if (required.requirement == LibSemver.requirements.EXACT) resolvedVersion = versionFlat;\n else if (required.requirement == LibSemver.requirements.MAJOR) {\n if (required.version.major > majorReleases) revert VersionDoesNotExist(required.version.toUint256());\n uint128 minorReleaseId = (uint128(required.version.major) << 64) |\n uint128(minorReleases[required.version.major]);\n resolvedVersion = (uint256(minorReleaseId) << 128) | uint256(patchReleases[minorReleaseId]);\n src.sourceId = versionedSources[resolvedVersion];\n src.version = LibSemver.parse(resolvedVersion);\n } else if (required.requirement == LibSemver.requirements.MAJOR_MINOR) {\n if (required.version.major > majorReleases) revert VersionDoesNotExist(required.version.toUint256());\n if (required.version.major == majorReleases) {\n if (required.version.minor > minorReleases[required.version.major])\n revert VersionDoesNotExist(required.version.toUint256());\n }\n uint128 minorReleaseId = (uint128(required.version.major) << 64) | uint128(required.version.minor);\n resolvedVersion = (uint256(minorReleaseId) << 128) | uint256(patchReleases[minorReleaseId]);\n } else if (required.requirement == LibSemver.requirements.GREATER_EQUAL) {\n if (required.version.major > majorReleases) revert VersionDoesNotExist(required.version.toUint256());\n if (required.version.major == majorReleases) {\n if (required.version.minor > minorReleases[required.version.major])\n revert VersionDoesNotExist(required.version.toUint256());\n if (required.version.minor == minorReleases[required.version.major]) {\n if (\n required.version.patch >\n patchReleases[(uint128(required.version.major) << 64) | uint128(required.version.minor)]\n ) revert VersionDoesNotExist(required.version.toUint256());\n }\n }\n uint128 minorReleaseId = (uint128(majorReleases) << 64) | uint128(minorReleases[majorReleases]);\n resolvedVersion = (uint256(minorReleaseId) << 128) | uint256(patchReleases[minorReleaseId]);\n } else if (required.requirement == LibSemver.requirements.GREATER) {\n if (required.version.major > majorReleases) revert VersionDoesNotExist(required.version.toUint256());\n if (required.version.major == majorReleases) {\n if (required.version.minor > minorReleases[required.version.major])\n revert VersionDoesNotExist(required.version.toUint256());\n if (required.version.minor == minorReleases[required.version.major]) {\n if (\n required.version.patch >=\n patchReleases[(uint128(required.version.major) << 64) | uint128(required.version.minor)]\n ) revert VersionDoesNotExist(required.version.toUint256());\n }\n }\n uint128 minorReleaseId = (uint128(majorReleases) << 64) | uint128(minorReleases[majorReleases]);\n resolvedVersion = (uint256(minorReleaseId) << 128) | uint256(patchReleases[minorReleaseId]);\n } else if (required.requirement == LibSemver.requirements.LESSER_EQUAL) {\n revert(\"Not implemented\");\n } else if (required.requirement == LibSemver.requirements.LESSER) {\n revert(\"Not implemented\");\n } else if (required.requirement == LibSemver.requirements.ANY) {\n resolvedVersion = latestVersion;\n } else {\n revert VersionDoesNotExist(required.version.toUint256());\n }\n src.sourceId = versionedSources[resolvedVersion];\n src.version = LibSemver.parse(resolvedVersion);\n src.metadata = combineMetadata(resolvedVersion);\n assert(src.sourceId != bytes32(0));\n return src;\n }\n\n function combineMetadata(uint256 versionFlat) internal view returns (bytes memory) {\n LibSemver.Version memory version = LibSemver.parse(versionFlat);\n bytes memory majorMetadata = releaseMetadata[version.major];\n bytes memory minorMetadata = minorReleaseMetadata[(uint128(version.major) << 64) | uint128(version.minor)];\n bytes memory patchMetadata = patchReleaseMetadata[versionFlat];\n return bytes.concat(majorMetadata, minorMetadata, patchMetadata);\n }\n // @inheritdoc IRepository\n function getMajorReleaseMetadata(uint64 major) public view returns (bytes memory) {\n return releaseMetadata[major];\n }\n // @inheritdoc IRepository\n function getMinorReleaseMetadata(uint64 major, uint64 minor) public view returns (bytes memory) {\n return minorReleaseMetadata[(uint128(major) << 64) | uint128(minor)];\n }\n // @inheritdoc IRepository\n function getPatchReleaseMetadata(uint64 major, uint64 minor, uint64 patch) public view returns (bytes memory) {\n return patchReleaseMetadata[(uint256(major) << 192) | (uint256(minor) << 128) | uint256(patch)];\n }\n // @inheritdoc IRepository\n function getMajorReleases() public view returns (uint64) {\n return majorReleases;\n }\n // @inheritdoc IRepository\n function getMinorReleases(uint64 major) public view returns (uint64) {\n return minorReleases[major];\n }\n // @inheritdoc IRepository\n function getPatchReleases(uint64 major, uint64 minor) public view returns (uint128) {\n return patchReleases[(uint128(major) << 64) | uint128(minor)];\n }\n\n function contractURI() public view returns (string memory) {\n return _cURI;\n }\n}\n" + }, + "src/CodeIndex.sol": { + "content": "// SPDX-License-Identifier: CC0-1.0\npragma solidity 0.8.20;\nimport \"./ICodeIndex.sol\";\n\n/**\n * @title Byte Code Indexer Contract\n * @notice You can use this contract to index contracts by their bytecode.\n * @dev This allows to query contracts by their bytecode instead of addresses.\n * @author Tim Pechersky (@Peersky)\n */\ncontract CodeIndex is ICodeIndex {\n mapping(bytes32 => address) private index;\n\n /**\n * @notice Registers a contract in the index by its bytecode hash\n * @param container The contract to register\n * @dev `msg.codeHash` will be used\n * @dev It will revert if the contract is already indexed\n */\n function register(address container) external {\n address etalon = index[container.codehash];\n if (etalon != address(0)) {\n revert alreadyExists(container.codehash, etalon);\n }\n index[container.codehash] = container;\n emit Indexed(container, container.codehash);\n }\n\n /**\n * @notice Returns the contract address by its bytecode hash\n * @dev returns zero if the contract is not indexed\n * @param id The bytecode hash\n * @return The contract address\n */\n function get(bytes32 id) external view returns (address) {\n return index[id];\n }\n}" + }, + "src/distributions/CodeHashDistribution.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\n\nimport \"../abstracts/CloneDistribution.sol\";\n\n/**\n * @title CodeHashDistribution\n * @notice This contract creates immutable. It allows to add metadata to the distribution as well as specify name and version for EIP712 compatability reasons.\n * @dev This contract is a base for creating distributions that are identified by a deployed functionality (byte code hash).\n */\ncontract CodeHashDistribution is CloneDistribution {\n bytes32 private immutable metadata;\n address private immutable _reference;\n bytes32 public immutable distributionName;\n uint256 public immutable distributionVersion;\n\n /**\n * @notice Constructor for the CodeHashDistribution contract.\n * @param codeHash The hash of the code to be distributed.\n * @param _metadata Metadata associated with the code.\n * @param name The name of the distribution.\n * @param version The version number of the distribution.\n */\n constructor(bytes32 codeHash, bytes32 _metadata, bytes32 name, uint256 version) {\n distributionName = name;\n distributionVersion = version;\n metadata = _metadata;\n ICodeIndex index = getContractsIndex();\n _reference = index.get(codeHash);\n if (_reference == address(0)) {\n revert CodeNotFoundInIndex(codeHash);\n }\n }\n\n function instantiate(bytes memory) external returns (address[] memory instances, bytes32, uint256) {\n return super._instantiate();\n }\n\n // @inheritdoc IDistribution\n function sources() internal view virtual override returns (address[] memory, bytes32 name, uint256 version) {\n address[] memory _sources = new address[](1);\n _sources[0] = _reference;\n return (_sources, distributionName, distributionVersion);\n }\n // @inheritdoc IDistribution\n function contractURI() external view virtual override returns (string memory) {\n return string(abi.encodePacked(metadata)); //ToDo: Add IPFS link with readme!\n }\n}\n" + }, + "src/distributions/LatestVersionDistribution.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\n\nimport \"../abstracts/CloneDistribution.sol\";\nimport \"../interfaces/IRepository.sol\";\nimport \"../libraries/LibSemver.sol\";\n\n/**\n * @title LatestVersionDistribution\n * @notice This contract extends the CloneDistribution contract to manage the distribution of the latest version of a given resource.\n * It provides mechanisms to ensure that the most recent version is distributed to users.\n * @dev it MUST refer to {../interfaces/IRepository}\n */\ncontract LatestVersionDistribution is CloneDistribution {\n bytes32 private immutable metadata;\n IRepository public immutable repository;\n\n /**\n * @notice Constructor for the LatestVersionDistribution contract.\n * @param _repository The address of the IRepository contract.\n * @param _metadata The metadata associated with the distribution.\n */\n constructor(IRepository _repository, bytes32 _metadata) {\n metadata = _metadata;\n repository = _repository;\n }\n\n function instantiate(bytes memory) external returns (address[] memory instances, bytes32, uint256) {\n return super._instantiate();\n }\n\n function sources() internal view virtual override returns (address[] memory srcs, bytes32 name, uint256 version) {\n address[] memory _sources = new address[](1);\n IRepository.Source memory latest = repository.getLatest();\n _sources[0] = getContractsIndex().get(latest.sourceId);\n return (_sources, repository.repositoryName(), LibSemver.toUint256(latest.version));\n }\n\n function contractURI() external view virtual override returns (string memory) {\n return string(abi.encodePacked(metadata)); //ToDo: Add IPFS link with readme!\n }\n}\n" + }, + "src/distributors/OwnableDistributor.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"../abstracts/Distributor.sol\";\n\ncontract OwnableDistributor is Distributor, Ownable {\n constructor(address _owner) Ownable(_owner) {}\n\n function instantiate(bytes32 id, bytes calldata args) external returns (address[] memory, bytes32, uint256) {\n return super._instantiate(id, args);\n }\n\n function addDistribution(bytes32 id, address initializer) external onlyOwner {\n super._addDistribution(id, initializer);\n }\n function addDistribution(\n IRepository repository,\n address initializer,\n LibSemver.VersionRequirement memory requirement\n ) external onlyOwner {\n super._addDistribution(address(repository), initializer, requirement);\n }\n\n function changeVersion(\n bytes32 distributionId,\n LibSemver.VersionRequirement memory newRequirement\n ) public onlyOwner {\n super._changeVersion(distributionId, newRequirement);\n }\n\n function removeDistribution(bytes32 id) public onlyOwner {\n super._removeDistribution(id);\n }\n}\n" + }, + "src/ICodeIndex.sol": { + "content": "// SPDX-License-Identifier: CC0-1.0\npragma solidity 0.8.20;\n\ninterface ICodeIndex {\n event Indexed(address indexed container, bytes32 indexed codeHash);\n error alreadyExists(bytes32 id, address source);\n\n function register(address container) external;\n\n function get(bytes32 id) external view returns (address);\n}" + }, + "src/interfaces/IContractURI.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\n\ninterface IContractURI {\n function contractURI() external view returns (string memory);\n}\n" + }, + "src/interfaces/IDistribution.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\nimport {IContractURI} from \"./IContractURI.sol\";\n/**\n * @title IDistribution\n * @notice Interface for distribution-related functionalities. It can get sources and produce a new instances out from them. It also provides metadata about the distribution.\n * @dev It is highly recommended to keep implementation stateless, and use `immutable` variables for any state. This allows your code to be referred in distributor and respositories via ERC7744. It's also easier to reason about, and more gas efficient.\n * @author Peeramid Labs, 2024\n */\ninterface IDistribution is IContractURI {\n /**\n * @notice Emitted when a distribution occurs.\n * @param distributor The address of the entity that performed the distribution.\n * @param instances An array of addresses that were produced.\n */\n event Distributed(address indexed distributor, address[] instances);\n\n /**\n * @notice Instantiates a new instance with the given parameters.\n * @param data The data to be used for instantiation.\n * @return instances An array of addresses that were produced.\n * @return distributionName The name of the distribution.\n * @return distributionVersion The version of the distribution.\n * @dev WARNING: It MUST emit Distributed event.\n */\n function instantiate(\n bytes memory data\n ) external returns (address[] memory instances, bytes32 distributionName, uint256 distributionVersion);\n\n /**\n * @notice Retrieves the current distribution sources.\n * @return sources An array of addresses that are used for instantiation.\n * @return distributionName The name of the distribution.\n * @return distributionVersion The version of the distribution.\n */\n function get()\n external\n view\n returns (address[] memory sources, bytes32 distributionName, uint256 distributionVersion);\n}\n" + }, + "src/interfaces/IDistributor.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\nimport {IERC7746} from \"../interfaces/IERC7746.sol\";\nimport \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\nimport \"../interfaces/IRepository.sol\";\nimport \"../libraries/LibSemver.sol\";\nimport {IERC7746} from \"../interfaces/IERC7746.sol\";\n\n/**\n * @title IDistributor Interface\n * @notice Defines the standard functions for a distributor contract.\n * @dev If you want to use {IRepository} for versioned distributions, use {IVersionDistributor} interface.\n * @author Peeramid Labs, 2024\n */\ninterface IDistributor is IERC7746, IERC165 {\n error InvalidVersionRequested(bytes32 distributionId, string version);\n error InvalidRepository(address repository);\n error RepositoryAlreadyExists(address repository);\n error VersionOutdated(bytes32 distributionId, string version);\n error InvalidInstance(address instance);\n error UniversionedDistribution(bytes32 distributionId);\n\n /**\n * @notice Emitted when the version of the distributor is changed.\n * @param distributionId The unique identifier of the distribution.\n * @param newRequirement The new version requirement (hashed for indexing).\n * @param newRequirementData The new version requirement data.\n */\n event VersionChanged(\n bytes32 indexed distributionId,\n LibSemver.VersionRequirement indexed newRequirement,\n LibSemver.VersionRequirement newRequirementData\n );\n\n /**\n * @notice Error indicating that the distribution with the specified ID was not found.\n * @param id The unique identifier of the distribution that was not found.\n */\n error DistributionNotFound(bytes32 id);\n /**\n * @notice Error indicating that a distribution with the specified ID already exists.\n * @param id The unique identifier of the distribution that already exists.\n */\n error DistributionExists(bytes32 id);\n /**\n * @notice Error indicating that the initializer for the distribution was not found.\n * @param id The unique identifier of the distribution that was not found.\n */\n error InitializerNotFound(bytes32 id);\n\n /**\n * @notice Event emitted when a new distribution is instantiated.\n * @param distributionId The unique identifier of the distribution.\n * @param newInstanceId The unique identifier of the instance.\n * @param version The version of the distribution, taken either from IDsitribution or from IRepository.\n * @param instances The addresses of the instances that were created.\n * @param args The arguments that were used for instantiation.\n * @dev It MUST emit when {IDistributor.instantiate} is called.\n */\n event Instantiated(\n bytes32 indexed distributionId,\n uint256 indexed newInstanceId,\n uint256 indexed version,\n address[] instances,\n bytes args\n );\n /**\n * @notice Event emitted when a distribution is removed.\n * @param id The unique identifier of the distribution that was removed.\n * @dev It MUST emit when {IDistributor.removeDistribution} is called.\n */\n event DistributionRemoved(bytes32 indexed id);\n\n /**\n * @notice Event emitted when a distribution is added.\n * @param id The unique identifier of the distribution that was added.\n * @param distribution The address of the distribution that was added.\n * @param initializer The address of the initializer for the distribution.\n * @dev It MUST emit when {IDistributor.addDistribution} is called.\n */\n event DistributionAdded(bytes32 indexed id, address distribution, address indexed initializer);\n\n /**\n * @notice Retrieves the unique identifiers of all distributions.\n * @return distributorIds An array of unique identifiers of all distributions.\n */\n function getDistributions() external view returns (bytes32[] memory distributorIds);\n\n /**\n * @notice Retrieves the URI of the distribution.\n * @param distributorId The unique identifier of the distribution.\n * @return uri The URI of the distribution.\n */\n function getDistributionURI(bytes32 distributorId) external view returns (string memory);\n\n /**\n * @notice Instantiates a new instance with the given distributor ID and arguments.\n * @param distributorId The unique identifier of the distributor.\n * @param args The arguments to be used for instantiation.\n * @return instances The addresses of the instances that were created.\n * @return distributionName The name of the distribution.\n * @return distributionVersion The version of the distribution.\n * @dev It MUST emit {Instantiated} event.\n */\n function instantiate(\n bytes32 distributorId,\n bytes calldata args\n ) external returns (address[] memory, bytes32 distributionName, uint256 distributionVersion);\n\n /**\n * @notice Adds a new distribution with the specified distributor ID and initializer address.\n * @param distributorId The unique identifier for the distributor.\n * @param initializer The address of the initializer for the distribution.\n * @dev WARNING: If initializer is provided, it will DELEGATECALL to the initializer. Otherwise, instantiation arguments will be passed to the distribution for self-initialization. Initializer contract MUST be trusted by the distributor.\n */\n function addDistribution(bytes32 distributorId, address initializer) external;\n\n /**\n * @notice Removes a distribution identified by the given distributorId.\n * @param distributorId The unique identifier of the distribution to be removed.\n */\n function removeDistribution(bytes32 distributorId) external;\n\n /**\n * @notice Retrieves the distribution ID associated with a given instance address.\n * @param instance The address of the instance for which the distribution ID is being requested.\n * @return The distribution ID as a bytes32 value.\n */\n function getDistributionId(address instance) external view returns (bytes32);\n /**\n * @notice Retrieves the unique identifier for a given instance address.\n * @param instance The address of the instance whose ID is to be retrieved.\n * @return The unique identifier (uint256) associated with the specified instance address.\n */\n function getInstanceId(address instance) external view returns (uint256);\n\n /**\n * @notice Adds a new versioned distribution to the repository.\n * @param repository The repository to which the distribution will be added.\n * @param initializer The address that initializes the distribution.\n * @param requirement The version requirements for the distribution.\n * @dev WARNING: If initializer is provided, it will DELEGATECALL to the initializer. Otherwise, instantiation arguments will be passed to the distribution for self-initialization. Initializer contract MUST be trusted by the distributor.\n */\n function addDistribution(\n IRepository repository,\n address initializer,\n LibSemver.VersionRequirement memory requirement\n ) external;\n\n /**\n * @notice Changes the version requirement for a specific distribution.\n * @param distributionId The unique identifier of the distribution whose version requirement is to be changed.\n * @param newRequirement The new version requirement to be set for the distribution.\n */\n function changeVersion(bytes32 distributionId, LibSemver.VersionRequirement memory newRequirement) external;\n}\n" + }, + "src/interfaces/IERC7746.sol": { + "content": "// SPDX-License-Identifier: CC0-1.0\npragma solidity >=0.8.0 <0.9.0;\n\n/**\n * @title IERC7746 Interface\n * @dev Interface for the ERC7746 standard.\n */\ninterface IERC7746 {\n /// @notice Validates a function call before execution.\n /// @param configuration Middleware-specific configuration data.\n /// @param selector The function selector being called.\n /// @param sender The address initiating the call.\n /// @param value The amount of ETH sent with the call (if any).\n /// @param data The calldata for the function call.\n /// @return beforeCallResult Arbitrary data to be passed to `afterCallValidation`.\n /// @dev MUST revert if validation fails.\n function beforeCall(\n bytes memory configuration,\n bytes4 selector,\n address sender,\n uint256 value,\n bytes memory data\n ) external returns (bytes memory);\n\n /// @notice Validates a function call after execution.\n /// @param configuration Middleware-specific configuration data.\n /// @param selector The function selector being called.\n /// @param sender The address initiating the call.\n /// @param value The amount of ETH sent with the call (if any).\n /// @param data The calldata for the function call.\n /// @param beforeCallResult The data returned by `beforeCallValidation`.\n /// @dev MUST revert if validation fails.\n function afterCall(\n bytes memory configuration,\n bytes4 selector,\n address sender,\n uint256 value,\n bytes memory data,\n bytes memory beforeCallResult\n ) external;\n}\n" + }, + "src/interfaces/IInitializer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\n\n/**\n * @title IInitializer\n * @notice Interface for the Initializer contract. This is intended to be used\n * as distribution initializer within the Distributor contract.\n */\ninterface IInitializer {\n event Initialized(address indexed container, bytes32 indexed codeHash);\n error initializationFailed(bytes32 id, string reason);\n\n /**\n * @notice Initializes the contract with necessary parameters.\n * @dev This function should be delegete-called by the distributor contract.\n * @param distributionId The ID of the distribution being initialized\n * @param instances The addresses of the instances being initialized\n * @param distributionName The name of the distribution\n * @param distributionVersion The version of the distribution\n * @param args The additional arguments to be used for initialization\n */\n function initialize(\n bytes32 distributionId,\n address[] memory instances,\n bytes32 distributionName,\n uint256 distributionVersion,\n bytes calldata args\n ) external;\n}\n" + }, + "src/interfaces/IInstaller.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\n\nimport {IDistributor} from \"./IDistributor.sol\";\nimport {IERC7746} from \"../interfaces/IERC7746.sol\";\n\n/**\n * @title IInstaller Interface\n * @notice Enables target smart account to interact with Distributor contract ecosystem.\n */\ninterface IInstaller is IERC7746 {\n /**\n * @dev Error indicating that the provided address is not a valid instance.\n * @param instance The address that was checked and found not to be an instance.\n */\n error NotAnInstance(address instance);\n\n /**\n * @notice Error indicating that the provided distributor is invalid.\n * @param distributor The distributor that is considered invalid.\n */\n error InvalidDistributor(IDistributor distributor);\n /**\n * @dev Error indicating that the provided target address is not the smart account installer serves.\n * @param target The address that is considered invalid.\n */\n error InvalidTarget(address target);\n /**\n * @notice Error indicating that the specified distributor is already allowed.\n * @param distributor The distributor that is already allowed.\n */\n error alreadyAllowed(IDistributor distributor);\n /**\n * @notice Error indicating that a distribution is not permitted (not installed).\n * @param distributor The address of the distributor containing the distribution.\n * @param distributionId The unique identifier of the distribution.\n */\n error DistributionIsNotPermitted(IDistributor distributor, bytes32 distributionId);\n /**\n * @notice Error indicating that distributor is whitelisted and hence it is not possible to selectively dissalow distriributions.\n * @param distributor The whitelisted distributor.\n * @param distributionId The ID of the distribution that was attempted to dissalow.\n * @dev If getting this error: consider first removing distributor from whitelist, and then dissalowing the distribution.\n */\n error DissalowDistOnWhitelistedDistributor(IDistributor distributor, bytes32 distributionId);\n\n /**\n * @dev Emitted when a distributor is whitelisted.\n * @param distributor The address of the distributor that has been whitelisted.\n * @dev Any distribution of the whitelisted distributor MUST be allowed to be installed.\n */\n event DistributorWhitelisted(IDistributor indexed distributor);\n /**\n * @notice Emitted when a distributor is removed from the whitelist.\n * @param distributor The address of the distributor that was revoked.\n * @dev WARNING: After removal, the distributions that were allowed by id are still allowed.\n */\n event DistributorWhitelistRevoked(IDistributor indexed distributor);\n\n /**\n * @dev Emitted when a distribution is allowed by the installer.\n * @param distributor The address of the distributor that is allowed.\n * @param distributionId The unique identifier of the distribution.\n */\n event DistributionAllowed(IDistributor indexed distributor, bytes32 indexed distributionId);\n /**\n * @dev Emitted when a distribution is disallowed by the installer.\n * @param distributor The address of the distributor that is disallowed.\n * @param distributionId The unique identifier of the distribution that is disallowed.\n */\n event DistributionDisallowed(IDistributor indexed distributor, bytes32 indexed distributionId);\n\n /**\n * @notice Allows a specified distributor to distribute a given distribution ID.\n * @param distributor The address of the distributor hosting a distribution Id.\n * @param distributionId The ID of the distribution to be allowed.\n * @dev MUST emit `DistributionAllowed` event.\n */\n function allowDistribution(IDistributor distributor, bytes32 distributionId) external;\n\n /**\n * @notice Disallows a specific distribution from a given distributor.\n * @param distributor The address of the distributor contract.\n * @param distributionId The unique identifier of the distribution to be disallowed.\n * @dev MUST emit `DistributionDisallowed` event.\n */\n function disallowDistribution(IDistributor distributor, bytes32 distributionId) external;\n\n /**\n * @notice Retrieves the list of whitelisted distributions for a given distributor.\n * @param distributor The address of the distributor to query.\n * @return An array of bytes32 representing the whitelisted distributions.\n * @dev If the distributor is whitelisted, all distributions are allowed.\n */\n function whitelistedDistributions(IDistributor distributor) external view returns (bytes32[] memory);\n\n /**\n * @notice Adds a distributor to the whitelist.\n * @param distributor The address of the distributor to be whitelisted.\n * @dev After whitelisting, all distributions of the distributor are allowed. Must emit `DistributorWhitelisted` event.\n */\n function whitelistDistributor(IDistributor distributor) external;\n\n /**\n * @notice Revokes the whitelisted status of a given distributor.\n * @param distributor The address of the distributor to be revoked.\n * @dev After revoking, the distributions that were allowed by id are still allowed. Must emit `DistributorWhitelistRevoked` event.\n */\n function revokeWhitelistedDistributor(IDistributor distributor) external;\n\n /**\n * @notice Checks if the given address is a valid distributor.\n * @param distributor The address of the distributor to check.\n * @return bool Returns true if the address is a valid distributor, otherwise false.\n */\n function isDistributor(IDistributor distributor) external view returns (bool);\n\n /**\n * @notice Retrieves the list of whitelisted distributor addresses.\n * @return An array of addresses that are whitelisted as distributors.\n */\n function getWhitelistedDistributors() external view returns (address[] memory);\n\n /**\n * @dev Emitted when an instance is installed.\n * @param instance The address of the installed instance.\n * @param distributionId The identifier of the distribution.\n * @param permissions The permissions associated with the installation.\n * @param args Additional arguments related to the installation.\n * @dev MUST be emitted for every new instance installed via `install` function.\n */\n event Installed(address indexed instance, bytes32 indexed distributionId, bytes32 indexed permissions, bytes args);\n event Uninstalled(address indexed instance);\n\n /**\n * @notice Installs a new instance with the given distributor, distribution ID, and arguments.\n * @param distributor The distributor contract to be used for the installation.\n * @param distributionId The unique identifier for the distribution.\n * @param args Additional arguments required for the installation process.\n * @return instanceId The unique identifier of the newly installed instance.\n * @dev MUST emit `Installed` event per installed instance. MUST revert if the distributor is not whitelisted or the distribution is not allowed. MUST revert if the distributor is not a valid distributor.\n * @dev After succesfull installation ERC77446 hooks SHALL NOT revert if called by target, specifying active instance in `sender` field.\n */\n function install(\n IDistributor distributor,\n bytes32 distributionId,\n bytes calldata args\n ) external payable returns (uint256 instanceId);\n\n /**\n * @notice Uninstalls an instance with the given ID.\n * @param instanceId The unique identifier of the instance to be uninstalled.\n * @dev MUST emit `Uninstalled` event per uninstalled instance. MUST revert if the instance is not installed.\n * @dev After succesfull uninstallation ERC77446 hooks SHALL revert if called by target, specifying uninstalled instance in `sender` field.\n */\n function uninstall(uint256 instanceId) external;\n\n /**\n * @notice Retrieves the contracts associated with a specific instance.\n * @param instanceId The unique identifier of the instance.\n * @return instaneContracts An array of addresses representing the contracts of the instance.\n */\n function getInstance(uint256 instanceId) external view returns (address[] memory instaneContracts);\n\n /**\n * @notice Retrieves the number of instances.\n * @return The total number of instances as a uint256.\n * @dev this number SHALL NOT decrease after uninstallation.\n */\n function getInstancesNum() external view returns (uint256);\n\n /**\n * @notice Checks if the given address is an active instance.\n * @param instance The address to check.\n * @return bool True if the address is an instance, false otherwise.\n */\n function isInstance(address instance) external view returns (bool);\n\n /**\n * @notice Returns the distributor associated with a given instance.\n * @param instance The address of the instance for which the distributor is being queried.\n * @return The distributor associated with the specified instance.\n */\n function distributorOf(address instance) external view returns (IDistributor);\n\n /**\n * @notice Retrieves the address of the target contract.\n * @return The address of the target contract.\n */\n function target() external view returns (address);\n}\n" + }, + "src/interfaces/IRepository.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\n\nimport \"../libraries/LibSemver.sol\";\nimport \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\nimport {IContractURI} from \"./IContractURI.sol\";\n/**\n * @title IRepository Interface\n * @notice It is intended to be implemented by contracts that manage a collection of versions of a byte code.\n * @author Peeramid Labs, 2024\n */\ninterface IRepository is IERC165, IContractURI {\n /**\n * @notice Represents a source with version information, a unique identifier, and associated metadata.\n * @param version The version of the source, represented using the LibSemver.Version struct.\n * @param sourceId A unique identifier for the source.\n * @param metadata Additional data associated with the source.\n */\n struct Source {\n LibSemver.Version version;\n bytes32 sourceId;\n bytes metadata;\n }\n\n /**\n * @notice Error indicating that the specified version does not exist.\n * @param version The version number that does not exist.\n */\n error VersionDoesNotExist(uint256 version);\n /**\n * @notice Error indicating that a release with a zero value is not allowed.\n */\n error ReleaseZeroNotAllowed();\n /**\n * @notice Error indicating that the specified version already exists.\n * @param version The version number that already exists.\n */\n error VersionExists(uint256 version);\n /**\n * @notice Error indicating that the version increment is invalid.\n * @param version The version number that caused the error.\n * @dev The version increment must be exactly one for either major, minor, or patch.\n */\n error VersionIncrementInvalid(uint256 version);\n /**\n * @dev Error indicating that the release metadata is empty.\n */\n error EmptyReleaseMetadata();\n\n /**\n * @notice Emitted when a new version is added to the repository.\n * @param version The version number of the added item.\n * @param source The source identifier of the added item.\n * @param buildMetadata Additional metadata related to the build.\n */\n event VersionAdded(uint256 indexed version, bytes32 indexed source, bytes buildMetadata);\n /**\n * @notice Emitted when the metadata of a release is updated.\n * @param version The version number of the release.\n * @param releaseMetadata The metadata associated with the release.\n */\n event ReleaseMetadataUpdated(uint256 indexed version, bytes releaseMetadata);\n\n /**\n * @notice Updates the metadata for a specific release version.\n * @param version The version of the release to update.\n * @param releaseMetadata The new metadata to associate with the release.\n * @dev It MUST emit `ReleaseMetadataUpdated` event.\n */\n function updateReleaseMetadata(LibSemver.Version memory version, bytes calldata releaseMetadata) external;\n /**\n * @notice Retrieves the name of the repository.\n * @return The name of the repository as a bytes32 value.\n */\n function repositoryName() external view returns (bytes32);\n /**\n * @notice Creates a new release for the given source ID.\n * @param sourceId The unique identifier of the source.\n * @param metadata The metadata associated with the release.\n * @param version The semantic version of the new release.\n * @dev It MUST emit `VersionAdded` event.\n */\n function newRelease(bytes32 sourceId, bytes memory metadata, LibSemver.Version memory version) external;\n /**\n * @notice Retrieves the latest source.\n * @return The requested source\n */\n function getLatest() external view returns (Source memory);\n /**\n * @notice Retrieves a specific item from the repository.\n * @param required the required version\n * @return The requested `Source`.\n */\n function get(LibSemver.VersionRequirement calldata required) external view returns (Source memory);\n}\n" + }, + "src/libraries/LibInstaller.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0 <0.9.0;\n\nimport \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\n\nlibrary LibInstaller {\n using EnumerableSet for EnumerableSet.AddressSet;\n using EnumerableSet for EnumerableSet.Bytes32Set;\n\n struct InstallerStruct {\n address _target;\n EnumerableSet.AddressSet whitelistedDistributors;\n mapping(address => EnumerableSet.Bytes32Set) _permittedDistributions;\n mapping(address => address) _distributorOf;\n mapping(uint256 => address[]) _instanceEnum;\n uint256 instancesNum;\n }\n\n bytes32 private constant EDS_INSTALLER_STORAGE_POSITION = keccak256(\"EDS.INSTALLER.STORAGE.POSITION\");\n\n function getStorage() internal pure returns (InstallerStruct storage i) {\n bytes32 position = EDS_INSTALLER_STORAGE_POSITION;\n assembly {\n i.slot := position\n }\n }\n}\n" + }, + "src/libraries/LibMiddleware.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\nimport {IERC7746} from \"../interfaces/IERC7746.sol\";\n\nlibrary LibMiddleware {\n bytes32 private constant ACCESS_LAYERS_STORAGE_POSITION = keccak256(\"lib.access.layer.storage\");\n\n struct LayerStruct {\n address layerAddess;\n bytes layerConfigData;\n }\n\n function accessLayersStorage() internal pure returns (LayerStruct[] storage ls) {\n bytes32 position = ACCESS_LAYERS_STORAGE_POSITION;\n assembly {\n ls.slot := position\n }\n }\n\n function setLayer(address layerAddress, uint256 layerIndex, bytes memory layerConfigData) internal {\n LayerStruct[] storage ls = accessLayersStorage();\n ls[layerIndex].layerAddess = layerAddress;\n ls[layerIndex].layerConfigData = layerConfigData;\n }\n\n function addLayer(LayerStruct memory newLayer) internal {\n LayerStruct[] storage ls = accessLayersStorage();\n ls.push(newLayer);\n }\n\n function setLayers(LayerStruct[] memory newLayers) internal {\n uint256 length = newLayers.length;\n for (uint256 i; i < length; ++i) {\n addLayer(newLayers[i]);\n }\n }\n\n function addLayer(address layerAddress, bytes memory layerConfigData) internal {\n LayerStruct[] storage ls = accessLayersStorage();\n LayerStruct memory newLayer = LayerStruct({layerAddess: layerAddress, layerConfigData: layerConfigData});\n ls.push(newLayer);\n }\n\n function popLayer() internal {\n LayerStruct[] storage ls = accessLayersStorage();\n ls.pop();\n }\n\n function getLayer(uint256 layerIdx) internal view returns (LayerStruct storage) {\n LayerStruct[] storage ls = accessLayersStorage();\n return ls[layerIdx];\n }\n\n function beforeCall(\n bytes4 _selector,\n address sender,\n bytes calldata data,\n uint256 value\n ) internal returns (bytes[] memory) {\n LayerStruct[] storage ls = accessLayersStorage();\n uint256 length = ls.length;\n bytes[] memory layerReturns = new bytes[](length);\n for (uint256 i; i < length; ++i) {\n layerReturns[i] = validateLayerBeforeCall(ls[i], _selector, sender, data, value);\n }\n return layerReturns;\n }\n\n function validateLayerBeforeCall(\n LayerStruct storage layer,\n bytes4 _selector,\n address sender,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n bytes memory retval = IERC7746(layer.layerAddess).beforeCall(\n layer.layerConfigData,\n _selector,\n sender,\n value,\n data\n );\n\n return retval;\n }\n\n function afterCall(\n bytes4 _selector,\n address sender,\n bytes calldata data,\n uint256 value,\n bytes[] memory beforeCallReturns\n ) internal {\n LayerStruct[] storage ls = accessLayersStorage();\n uint256 length = ls.length;\n for (uint256 i; i < length; ++i) {\n validateLayerAfterCall(ls[length - 1 - i], _selector, sender, data, value, beforeCallReturns[i]);\n }\n }\n\n function extractRevertReason(bytes memory revertData) internal pure returns (string memory reason) {\n uint256 l = revertData.length;\n if (l < 68) return \"\";\n uint256 t;\n assembly {\n revertData := add(revertData, 4)\n t := mload(revertData) // Save the content of the length slot\n mstore(revertData, sub(l, 4)) // Set proper length\n }\n reason = abi.decode(revertData, (string));\n assembly {\n mstore(revertData, t) // Restore the content of the length slot\n }\n }\n\n function validateLayerAfterCall(\n LayerStruct storage layer,\n bytes4 _selector,\n address sender,\n bytes calldata data,\n uint256 value,\n bytes memory beforeCallReturnValue\n ) internal {\n IERC7746(layer.layerAddess).afterCall(\n layer.layerConfigData,\n _selector,\n sender,\n value,\n data,\n beforeCallReturnValue\n );\n }\n}\n" + }, + "src/libraries/LibSemver.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\nimport \"@openzeppelin/contracts/utils/Strings.sol\";\nlibrary LibSemver {\n error versionMissmatch(string message);\n struct Version {\n uint64 major;\n uint64 minor;\n uint128 patch;\n }\n\n enum requirements {\n ANY, // *\n EXACT, // =\n MAJOR, // ^\n MAJOR_MINOR, // ~\n GREATER_EQUAL, // >=\n GREATER, // >\n LESSER_EQUAL, // <=\n LESSER // <\n }\n\n struct VersionRequirement {\n Version version;\n requirements requirement;\n }\n\n function toUint256(Version memory _version) internal pure returns (uint256) {\n return (uint256(_version.major) << 192) | (uint256(_version.minor) << 128) | uint256(_version.patch);\n }\n\n function parse(uint256 _version) internal pure returns (Version memory) {\n return Version(uint64(_version >> 192), uint64(_version >> 128), uint128(_version));\n }\n\n function toString(Version memory _version) internal pure returns (string memory) {\n return\n string(\n abi.encodePacked(\n Strings.toString(uint256(_version.major)),\n \".\",\n Strings.toString(uint256(_version.minor)),\n \".\",\n Strings.toString(uint256(_version.patch))\n )\n );\n }\n\n function require_exact(Version memory _version1, Version memory _version2) internal pure {\n if (toUint256(_version1) != toUint256(_version2)) revert versionMissmatch(\"Version mismatch\");\n }\n\n function require_major(Version memory _version1, Version memory _version2) internal pure {\n if (_version1.major != _version2.major) revert versionMissmatch(\"Major version mismatch\");\n }\n\n function require_major_minor(Version memory _version1, Version memory _version2) internal pure {\n if (_version1.major != _version2.major || _version1.minor != _version2.minor)\n revert versionMissmatch(\"Major and minor version mismatch\");\n }\n\n function require_greater_equal(Version memory _version1, Version memory _version2) internal pure {\n if (toUint256(_version1) < toUint256(_version2)) revert versionMissmatch(\"Version is not greater or equal\");\n }\n\n function require_greater(Version memory _version1, Version memory _version2) internal pure {\n if (toUint256(_version1) <= toUint256(_version2)) revert versionMissmatch(\"Version is not greater\");\n }\n\n function require_lesser_equal(Version memory _version1, Version memory _version2) internal pure {\n if (toUint256(_version1) > toUint256(_version2)) revert versionMissmatch(\"Version is not lesser or equal\");\n }\n\n function require_lesser(Version memory _version1, Version memory _version2) internal pure {\n if (toUint256(_version1) >= toUint256(_version2)) revert versionMissmatch(\"Version is not lesser\");\n }\n\n function areEqual(Version memory _version1, Version memory _version2) internal pure returns (bool) {\n return toUint256(_version1) == toUint256(_version2);\n }\n\n function compare(Version memory has, VersionRequirement memory needs) internal pure returns (bool) {\n if (needs.requirement == requirements.ANY) return true;\n if (needs.requirement == requirements.EXACT) return toUint256(has) == toUint256(needs.version);\n if (needs.requirement == requirements.MAJOR) return has.major == needs.version.major;\n if (needs.requirement == requirements.MAJOR_MINOR)\n return has.major == needs.version.major && has.minor == needs.version.minor;\n if (needs.requirement == requirements.GREATER_EQUAL) return toUint256(has) >= toUint256(needs.version);\n if (needs.requirement == requirements.GREATER) return toUint256(has) > toUint256(needs.version);\n if (needs.requirement == requirements.LESSER_EQUAL) return toUint256(has) <= toUint256(needs.version);\n if (needs.requirement == requirements.LESSER) return toUint256(has) < toUint256(needs.version);\n return false;\n }\n\n function getNextMajor(Version memory _version) internal pure returns (Version memory) {\n return Version(_version.major + 1, 0, 0);\n }\n\n function getNextMinor(Version memory _version) internal pure returns (Version memory) {\n return Version(_version.major, _version.minor + 1, 0);\n }\n\n function getNextPatch(Version memory _version) internal pure returns (Version memory) {\n return Version(_version.major, _version.minor, _version.patch + 1);\n }\n}\n" + }, + "src/managers/SimpleAccessManager.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0 <0.9.0;\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport {IERC7746} from \"../interfaces/IERC7746.sol\";\nimport {IDistributor} from \"../interfaces/IDistributor.sol\";\nimport \"@openzeppelin/contracts/utils/introspection/ERC165Checker.sol\";\nimport \"@openzeppelin/contracts/utils/introspection/ERC165.sol\";\ncontract SimpleAccessManager is Initializable, IERC7746, ERC165 {\n struct MethodSettings {\n bool isDistributionOnly;\n mapping(address => bool) dissallowedAddresses;\n }\n\n struct Storage {\n mapping(bytes4 => MethodSettings) methodSettings;\n address target;\n IDistributor distributor;\n }\n\n bytes32 private constant SACM_STORAGE_POSITION = keccak256(\"simple.access.manager.storage.position\");\n\n function getStorage() private pure returns (Storage storage s) {\n bytes32 position = SACM_STORAGE_POSITION;\n assembly {\n s.slot := position\n }\n }\n\n struct SimpleAccessManagerInitializer {\n bytes4 selector;\n address[] dissallowedAddresses;\n bool distributionComponentsOnly;\n }\n\n constructor() {\n _disableInitializers();\n }\n error ERC165CheckFailed(address distributor, bytes4 interfaceId, string interfaceName);\n function initialize(\n SimpleAccessManagerInitializer[] memory methodSettings,\n address target,\n IDistributor distributor\n ) public initializer {\n Storage storage s = getStorage();\n s.distributor = distributor;\n s.target = target;\n if (!ERC165Checker.supportsInterface(address(distributor), type(IDistributor).interfaceId)) {\n revert ERC165CheckFailed(address(distributor), type(IDistributor).interfaceId, \"IDistributor\");\n }\n uint256 length = methodSettings.length;\n for (uint256 i; i < length; ++i) {\n s.methodSettings[methodSettings[i].selector].isDistributionOnly = methodSettings[i]\n .distributionComponentsOnly;\n uint256 dissalowedMethodsLength = methodSettings[i].dissallowedAddresses.length;\n for (uint256 j; j < dissalowedMethodsLength; ++j) {\n s.methodSettings[methodSettings[i].selector].dissallowedAddresses[\n methodSettings[i].dissallowedAddresses[j]\n ] = true;\n }\n }\n }\n\n error OnlyTargetAllowed(address sender, address target);\n error dissallowedAddress(address sender, bytes4 selector);\n\n function beforeCall(\n bytes memory,\n bytes4 selector,\n address sender,\n uint256 value,\n bytes memory data\n ) external returns (bytes memory) {\n Storage storage s = getStorage();\n if (msg.sender != s.target) {\n revert OnlyTargetAllowed(msg.sender, s.target);\n }\n if (s.methodSettings[selector].dissallowedAddresses[sender]) {\n revert dissallowedAddress(sender, selector);\n } else {\n if (s.methodSettings[selector].isDistributionOnly) {\n return s.distributor.beforeCall(abi.encode(msg.sender), selector, sender, value, data);\n }\n return \"\";\n }\n }\n\n function afterCall(\n bytes memory,\n bytes4 selector,\n address sender,\n uint256 value,\n bytes memory data,\n bytes memory beforeCallResult\n ) external {\n Storage storage s = getStorage();\n if (msg.sender != s.target) {\n revert OnlyTargetAllowed(msg.sender, s.target);\n }\n if (s.methodSettings[selector].isDistributionOnly) {\n s.distributor.afterCall(abi.encode(msg.sender), selector, sender, value, data, beforeCallResult);\n }\n }\n\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165) returns (bool) {\n return interfaceId == type(IERC7746).interfaceId || super.supportsInterface(interfaceId);\n }\n}\n" + }, + "src/mocks/MockCloneDistribution.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\n\nimport \"../abstracts/CloneDistribution.sol\";\n\ncontract MockCloneDistribution is CloneDistribution {\n function contractURI() external pure override returns (string memory) {\n return \"MockCloneDistribution\";\n }\n\n function instantiate(bytes memory) external override returns (address[] memory, bytes32, uint256) {\n return super._instantiate();\n }\n\n function sources() internal view virtual override returns (address[] memory, bytes32, uint256) {\n address[] memory source = new address[](1);\n source[0] = address(this);\n return (source, bytes32(abi.encodePacked(\"MockCloneDistribution\")), 1);\n }\n}\n" + }, + "src/mocks/MockDiamondInitialize.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\n\ncontract MockDiamondInitialize {\n event MockInit(string testData);\n\n function init(bytes calldata data) public {\n emit MockInit(string(data));\n }\n}\n" + }, + "src/mocks/MockInstaller.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\n\nimport \"../abstracts/Installer.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\ncontract MockInstaller is Installer, Ownable {\n constructor(address targetAddress, address owner) Ownable(owner) Installer(targetAddress) {}\n\n function install(\n IDistributor distributor,\n bytes32 distributionId,\n bytes calldata args\n ) public payable returns (uint256 instanceId) {\n return super._install(distributor, distributionId, args);\n }\n\n function uninstall(uint256 instanceId) public onlyOwner {\n super._uninstall(instanceId);\n }\n\n function allowDistribution(IDistributor distributor, bytes32 distributionId) public onlyOwner {\n super._allowDistribution(distributor, distributionId);\n }\n\n function disallowDistribution(IDistributor distributor, bytes32 distributionId) public onlyOwner {\n super._disallowDistribution(distributor, distributionId);\n }\n\n function whitelistDistributor(IDistributor distributor) public onlyOwner {\n super._allowAllDistributions(distributor);\n }\n\n function revokeWhitelistedDistributor(IDistributor distributor) public onlyOwner {\n super._disallowAllDistributions(distributor);\n }\n}\n" + }, + "src/mocks/TestFacet.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\n\ncontract TestFacet {\n event Bar();\n\n function foo() public {\n emit Bar();\n }\n\n function ping() public pure returns (string memory) {\n return \"pong\";\n }\n}\n" + }, + "src/repositories/OwnableRepository.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"../abstracts/Repository.sol\";\nimport \"@openzeppelin/contracts/utils/introspection/ERC165.sol\";\nimport \"../interfaces/IRepository.sol\";\ncontract OwnableRepository is Repository, Ownable, ERC165 {\n constructor(address owner, bytes32 name, string memory cURI) Ownable(owner) Repository(name, cURI) {}\n\n function updateReleaseMetadata(LibSemver.Version memory version, bytes calldata releaseMetadata) public onlyOwner {\n super._updateReleaseMetadata(version, releaseMetadata);\n }\n function newRelease(bytes32 sourceId, bytes memory metadata, LibSemver.Version memory version) public onlyOwner {\n super._newRelease(sourceId, metadata, version);\n }\n\n function supportsInterface(bytes4 interfaceId) public view override(ERC165, IERC165) returns (bool) {\n return interfaceId == type(IRepository).interfaceId || super.supportsInterface(interfaceId);\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200000 + }, + "evmVersion": "paris", + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file