creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "@openzeppelin/contracts/utils/introspection/ERC165.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./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 *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        return interfaceId == type(IERC165).interfaceId;\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/introspection/IERC165.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({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/SafeMath.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n    /**\n     * @dev Returns the addition of two unsigned integers, with an overflow flag.\n     *\n     * _Available since v3.4._\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     * _Available since v3.4._\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     * _Available since v3.4._\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     * _Available since v3.4._\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     * _Available since v3.4._\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 addition of two unsigned integers, reverting on\n     * overflow.\n     *\n     * Counterpart to Solidity's `+` operator.\n     *\n     * Requirements:\n     *\n     * - Addition cannot overflow.\n     */\n    function add(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a + b;\n    }\n\n    /**\n     * @dev Returns the subtraction of two unsigned integers, reverting on\n     * overflow (when the result is negative).\n     *\n     * Counterpart to Solidity's `-` operator.\n     *\n     * Requirements:\n     *\n     * - Subtraction cannot overflow.\n     */\n    function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a - b;\n    }\n\n    /**\n     * @dev Returns the multiplication of two unsigned integers, reverting on\n     * overflow.\n     *\n     * Counterpart to Solidity's `*` operator.\n     *\n     * Requirements:\n     *\n     * - Multiplication cannot overflow.\n     */\n    function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a * b;\n    }\n\n    /**\n     * @dev Returns the integer division of two unsigned integers, reverting on\n     * division by zero. The result is rounded towards zero.\n     *\n     * Counterpart to Solidity's `/` operator.\n     *\n     * Requirements:\n     *\n     * - The divisor cannot be zero.\n     */\n    function div(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a / b;\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n     * reverting when dividing by zero.\n     *\n     * Counterpart to Solidity's `%` operator. This function uses a `revert`\n     * opcode (which leaves remaining gas untouched) while Solidity uses an\n     * invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     *\n     * - The divisor cannot be zero.\n     */\n    function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a % b;\n    }\n\n    /**\n     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n     * overflow (when the result is negative).\n     *\n     * CAUTION: This function is deprecated because it requires allocating memory for the error\n     * message unnecessarily. For custom revert reasons use {trySub}.\n     *\n     * Counterpart to Solidity's `-` operator.\n     *\n     * Requirements:\n     *\n     * - Subtraction cannot overflow.\n     */\n    function sub(\n        uint256 a,\n        uint256 b,\n        string memory errorMessage\n    ) internal pure returns (uint256) {\n        unchecked {\n            require(b <= a, errorMessage);\n            return a - b;\n        }\n    }\n\n    /**\n     * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n     * division by zero. The result is rounded towards zero.\n     *\n     * Counterpart to Solidity's `/` operator. Note: this function uses a\n     * `revert` opcode (which leaves remaining gas untouched) while Solidity\n     * uses an invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     *\n     * - The divisor cannot be zero.\n     */\n    function div(\n        uint256 a,\n        uint256 b,\n        string memory errorMessage\n    ) internal pure returns (uint256) {\n        unchecked {\n            require(b > 0, errorMessage);\n            return a / b;\n        }\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n     * reverting with custom message when dividing by zero.\n     *\n     * CAUTION: This function is deprecated because it requires allocating memory for the error\n     * message unnecessarily. For custom revert reasons use {tryMod}.\n     *\n     * Counterpart to Solidity's `%` operator. This function uses a `revert`\n     * opcode (which leaves remaining gas untouched) while Solidity uses an\n     * invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     *\n     * - The divisor cannot be zero.\n     */\n    function mod(\n        uint256 a,\n        uint256 b,\n        string memory errorMessage\n    ) internal pure returns (uint256) {\n        unchecked {\n            require(b > 0, errorMessage);\n            return a % b;\n        }\n    }\n}\n"
      },
      "contracts/product/interfaces/IERC20Adapter.sol": {
        "content": "pragma solidity 0.8.17;\n\n/**\n * @dev IERC20Adapter is an interface allowing to (mostly) comply with the ERC20 standard while remaining compliant with \n * the financial regulations(mostly KYC and due dilligence obligations).\n * Each call to transfer()/transferFrom() or approve() has to be reviewed by *some* validator authority before either proceeding (by calling validateTransfer()\n * /validateApprove()) or cancelling (by calling rejectTransfer()/rejectApprove())\n * see TransferAdapterLibrary and ApproveAdapteLibrary for implementation.\n */\ninterface IERC20Adapter {\n    /**\n     * @dev Initiate a transfer request. Same semantic as ERC20's transfer function although the transfer\n     * will only actually occur once reviewed by validator(who will call validateTransfer)\n     */\n    function transfer(address _to, uint256 _value) external returns (bool);\n\n    /**\n     * @dev Actually performs the transfer request corresponding to the given `transferHash`\n     * Called by the validator authority\n     */\n    function validateTransfer(bytes32 transferHash) external returns (bool);\n\n    /**\n     * @dev Rejects(and thus, actually cancels) the transfer request corresponding to the given `transferHash`\n     * Called by the validator authority\n     */\n    function rejectTransfer(bytes32 transferHash) external returns (bool);\n\n    /**\n     * @dev Initiate an approve request. Same semantic as ERC20's approve function although the approve\n     * will only actually occur once reviewed by validator(who will call validateApprove)\n     */\n    function approve(address _spender, uint256 _value) external returns (bool);\n\n    /**\n     * @dev Same semantic as ERC20's allowance function\n     */\n    function allowance(address owner, address spender)\n        external\n        view\n        returns (uint256);\n\n    /**\n     * @dev Initiate a transferFrom request. Same semantic as ERC20's transferFrom function although the transferFrom\n     * will only actually occur once reviewed by validator(who will call validateTransfer)\n     */\n    function transferFrom(\n        address from,\n        address to,\n        uint256 amount\n    ) external returns (bool);\n\n    /**\n     * @dev Actually performs the approve request corresponding to the given `transferHash`\n     * Called by the validator authority\n     */\n    function validateApprove(bytes32 approveHash) external returns (bool);\n\n    /**\n     * @dev Rejects(and thus, actually cancels) the approve request corresponding to the given `transferHash`\n     * Called by the validator authority\n     */\n    function rejectApprove(bytes32 approveHash) external returns (bool);\n\n    /**\n     * @dev Emitted when a transfer actuelly occurs(that is, when validateTransfer() is called by the validator authority\n     */\n    event Transfer(address indexed _from, address indexed _to, uint256 _value);\n    /**\n     * @dev Emitted when an approve request is initiated\n     */\n    event ApproveRequest(\n        bytes32 approveHash,\n        address indexed owner,\n        address indexed spender,\n        uint256 value\n    );\n    /**\n     * @dev Emitted when an approve request is rejected\n     */\n    event ApproveRejected(bytes32 approveHash);\n    /**\n     * @dev Emitted when an approve request is validated\n     */\n    event ApproveValidated(bytes32 approveHash);\n    /**\n     * @dev Emitted when an approve actually occurs(that is, when validateApprove() is called by the validator authority\n     */\n    event Approval(\n        address indexed owner,\n        address indexed spender,\n        uint256 value\n    );\n    /**\n     * @dev Emitted when a transfer request is initiated\n     */\n    event TransferRequest(\n        bytes32 transferHash,\n        address indexed from,\n        address indexed to,\n        uint256 value\n    );\n    /**\n     * @dev Emitted when a transfer request is rejected\n     */\n    event TransferRejected(bytes32 transferHash);\n    /**\n     * @dev Emitted when a transfer request is validated\n     */\n    event TransferValidated(bytes32 transferHash);\n}\n"
      },
      "contracts/product/interfaces/IProduct.sol": {
        "content": "pragma solidity 0.8.17;\n\n/**\n * @dev This interface mostly lists all structures used by the Product contract\n */\n\n// Maybe add common functions for products\ninterface IProduct {\n    /**\n     * @dev Details of a legal entity\n     */\n    struct LegalEntity {\n        /**\n         * @dev Legal Entity Identifier of the legal entity\n        */\n        string lei;\n        /**\n         * @dev Account address of the legal entity\n         */\n        address account;\n    }\n\n    /**\n     * @dev Describes an issuance tranche\n    */\n    struct Tranche {\n        uint256 nominalAmountCent;\n        uint256 issueDate;\n    }\n\n    /**\n     * @dev Represents a simple balance with value `balance` for address `account`\n     */\n    struct InitBalance {\n        address account;\n        uint256 balance;\n    }\n    // pourquoi pas dans ISettlement ?\n    event TransferExecuted(uint256 settlementTransactionId);\n\n    /**\n     * @dev This structure describes the parameters of the product to create/issue\n     * Most parameters are financial characteristics of the product\n     */\n    struct BasicProductInput {\n        /**\n         * @dev The balances to setup at the contract's creation\n         * Used when migrating from an existing contract with existing balances\n         */\n        InitBalance[] initialBalances;\n        /**\n         * @dev The details of the initial issuance tranches\n         */\n        Tranche[] initialTranches;\n        /**\n         * @dev The address of a previous contract that is replaced with this one (allows to keep track of successive contract migrations)\n         */\n        address previousContract;\n        /**\n         * @dev FIGI code of the product(optional)\n         */\n        string figi;\n        /**\n         * @dev JSON string of extended information about the product. Can be roughly anything.\n         * Will be used to hold financial information specific to a some products.\n         */\n        string extendedDataJson;\n        /**\n         * @dev String holding ESG information about the product (JSON format)\n         */\n        string esg;\n        /**\n         * @dev This product's note status\n         */\n        string noteStatus;\n        /**\n         * @dev This product's form of the node (e.g. Registered)\n         */\n        string formOfNote;\n        /**\n         * @dev Name of the issuance series (a group of tranches)\n         */\n        string series;\n        /**\n         * @dev The issuer's issuance program this product is part of\n         */\n        string program;\n        /**\n         * @dev The URL of the Settlement Transaction Repository that gives access to confidential information in the Settlement Transactions\n         */\n        string strUrl;\n        /**\n         * @dev The type of the financial product\n         */\n        string productType;\n        /**\n         * @dev Details of the product's guarantor legal entity\n         */\n        LegalEntity guarantor;\n        /**\n         * @dev Details of the product's issuer legal entity\n         */\n        LegalEntity issuer;\n        /**\n         * @dev Details of the product's paying agent legal entity\n         */\n        LegalEntity payingAgent;\n        /**\n         * @dev Details of the product's settlement agent legal entity\n         */\n        LegalEntity settlementAgent;\n        /**\n         * @dev Details of the product's registrar legal entity\n         */\n        LegalEntity registrar;\n        /**\n         * @dev The product's currency\n         */\n        string currency;\n        /**\n         * @dev The address of the IProductRegistry where the product should be listed\n         */\n        address registryAddress;\n        /**\n         * @dev String describing the market places where the product is listed\n         */\n        string listing;\n        /**\n         * @dev The governing law of the product\n         */\n        string governingLaw;\n        /**\n         * @dev The product's maturity date\n         */\n        uint256 maturityDate;\n        /**\n         * @dev The product's denomination in cents\n         */\n        uint256 denominationCent;\n        /**\n         * @dev The product's symbol\n         */\n        string symbol;\n        /**\n         * @dev The product's name\n         */\n        string name;\n        /**\n         * @dev The product's ISIN code\n         */\n        string isinCode;\n    }\n}\n"
      },
      "contracts/product/interfaces/ISettlement.sol": {
        "content": "pragma solidity 0.8.17;\n\nimport \"../libraries/SettlementRepositoryLibrary.sol\";\n\n/**\n * @dev This interface lists the methods allowing to initiate and settle so-called Settlement Transaction.\n * Please refer to CAST framework's whitepaper for details about what Settlement Transactions are\n */\ninterface ISettlement {\n    /**\n     * @dev Initiate a Subscription Settlement Transaction (counterparty buys product on primary market from the product's issuer)\n     * The tokens are locked waiting for the cash leg to settle (see functions confirmPaymentReceived/confirmPaymentTransferred)\n     */\n    function initiateSubscription(\n        SettlementRepositoryLibrary.PartialSettlementTransaction\n            calldata partialSettlementTransaction\n    ) external;\n\n    /**\n     * @dev Initiate a Trade Settlement Transaction (one counterparty buys, the other sells)\n     * The tokens are locked waiting for the cash leg to settle (see functions confirmPaymentReceived/confirmPaymentTransferred)\n     */\n    function initiateTrade(\n        SettlementRepositoryLibrary.PartialSettlementTransaction\n            calldata partialSettlementTransaction\n    ) external;\n\n    /**\n     * @dev Initiate a Redemption Settlement Transactions (issuer redeems product to all holders and gets the tokens back)\n     * The tokens are locked waiting for the cash leg to settle (see functions confirmPaymentReceived/confirmPaymentTransferred)\n     */\n    function initiateRedemption(\n        SettlementRepositoryLibrary.PartialSettlementTransaction[]\n            calldata settlementTransaction,\n        string calldata extendedData\n    ) external;\n\n    /**\n     * @dev Execute unilateral Transfer Settlement Transactions \n     * As there is no cash leg to settle, the tokens are transfered right away and the Settlement Transaction is marked as Settled\n     */\n    function executeTransfer(\n        SettlementRepositoryLibrary.PartialSettlementTransaction\n            memory partialSettlementTransaction\n    ) external;\n\n    /**\n     * @dev Initiate a Coupon Settlement Transactions (issuer pays coupon to all holders)\n     * NB: the tokens are not locked for this kind of transaction\n     */\n    function initiateCoupon(\n        SettlementRepositoryLibrary.PartialSettlementTransaction[]\n            calldata settlementTransaction,\n        string calldata extendedData\n    ) external;\n\n    /**\n     * @dev Cancels ongoing settlement transaction with id `settlementTransactionId`\n     */\n    function cancelSettlementTransaction(uint256 settlementTransactionId)\n        external;\n\n    /**\n     * @dev Confirms that the payment for Settlement Transaction with id `settlementTransactionId` was correctly received\n     * (by the settlement agent). The tokens are unlocked and transferred to the buyer. Settlement Transaction's status moves to Processed\n     */\n    function confirmPaymentReceived(uint256 settlementTransactionId) external;\n\n    /**\n     * @dev Confirms that the payment for Settlement Transaction with id `settlementTransactionId` was correctly transferred to the seller\n     * (by the settlement agent). Settlement Transaction's status moves to Settled\n     */\n    function confirmPaymentTransferred(uint256 settlementTransactionId)\n        external;\n\n    /**\n     * @dev Emitted when Subscription Settlement Transaction with id `settlementTransactionId` was initiated.\n     */\n    event SubscriptionInitiated(uint256 settlementTransactionId);\n    /**\n     * @dev Emitted when Trade Settlement Transaction with id `settlementTransactionId` was initiated.\n     */\n    event TradeInitiated(uint256 settlementTransactionId);\n    /**\n     * @dev Emitted when Redemption Settlement Transactions with ids `settlementTransactionIds` were initiated.\n     */\n    event RedemptionInitiated(uint256[] settlementTransactionIds);\n    /**\n     * @dev Emitted when Coupon Settlement Transactions with ids `settlementTransactionId`s were initiated.\n     */\n    event CouponInitiated(uint256[] settlementTransactionIds);\n    /**\n     * @dev Emitted when payment for Settlement Transaction with id `settlementTransactionId` was reported as received\n     */\n    event PaymentReceived(\n        uint256 settlementTransactionId,\n        SettlementRepositoryLibrary.OperationType settlementTransactionOperationType\n    );\n    /**\n     * @dev Emitted when payment for Settlement Transaction with id `settlementTransactionId` was reported as transferred\n     */\n    event PaymentTransferred(\n        uint256 settlementTransactionId,\n        SettlementRepositoryLibrary.OperationType settlementTransactionOperationType\n    );\n    /**\n     * @dev Emitted when Settlement Transaction with id `settlementTransactionId` was cancelled\n     */\n    event SettlementTransactionCancelled(uint256 settlementTransactionId);\n}\n"
      },
      "contracts/product/libraries/ApproveAdapterLibrary.sol": {
        "content": "pragma solidity 0.8.17;\n\nimport \"./EncodingUtils.sol\";\nimport \"./SecurityTokenBalancesLibrary.sol\";\nimport \"./TransferAdapterLibrary.sol\";\n\nimport { ZeroAddressCheck, InvalidApproveStatus, OwnerHasOngoingApprove, ApproveDoesNotExists, InsufficientAllowance } from \"../../utils/ProductErrorReporter.sol\";\n\n/**\n * @dev This library allows to handle two-step approves as described in IERC20Adapter\n */\nlibrary ApproveAdapterLibrary {\n    using SecurityTokenBalancesLibrary for SecurityTokenBalancesLibrary.SecurityTokenBalances;\n    using TransferAdapterLibrary for TransferAdapterLibrary.OngoingTransfers;\n\n    /**\n     * @dev The different status an approve request can have\n     * Approve requests are initially in the `Created` state\n     * If validated by the validator authority they move to the `Validated` state, which is a final state\n     * If rejected by the validator authority they move to the `Rejected` state, which is a final state\n     * \n     */\n    enum ApproveStatus {\n        Undefined,\n        Created,\n        Validated,\n        Rejected\n    }\n\n    /**\n     * @dev The details of an approve request\n     */\n    struct Approve {\n        /**\n        * @dev The address of the owner \n        */\n        address owner;\n        /**\n        * @dev The address of the spender \n        */\n        address spender;\n        /**\n        * @dev The number of tokens that the spender is allowed to spend\n        */\n        uint256 value;\n        /**\n        * @dev The status of the approve request\n        */\n        ApproveStatus status;\n    }\n\n    /**\n     * @dev Structure containing all ongoing approve requests\n     * Requests are indexed by the hash of their content\n    */\n    struct OngoingApproves {\n        mapping(bytes32 => Approve) approves;\n        /**\n        * @dev Counter of requests, allowing all request to be unique\n        */\n        uint256 counter;\n        /**\n        * @dev Current allowances indexed by owner address, then by spender address\n        */\n        mapping(address => mapping(address => uint256)) allowances;\n        /**\n        * @dev Boolean indicating for a couple (owner,spender) whether there is an ongoing approve request\n        * This enables to reject approve request really if there is already an ongoing approve request for the same (owner, spender), thus\n        * avoiding complex issues\n        */\n        mapping(address => mapping(address => bool)) hasOngoingApprove;\n    }\n\n    /**\n     * @dev Initiates an approve request\n     * If the requested allowance is less than current allowance, the excess tokens are unlocked\n     * If the requested allowance is more than current allowance, the excess tokens are locked\n     * NB : as the allowance is first reset to 0, the allowance will stay 0 is the request is rejected.\n     * This is by design and not a bug.\n    */\n    function addApprove(\n        OngoingApproves storage self,\n        SecurityTokenBalancesLibrary.SecurityTokenBalances\n            storage securityTokenBalances,\n        address owner,\n        address spender,\n        uint256 value\n    ) public returns (bytes32) {\n        if (owner == address(0)) revert ZeroAddressCheck();\n        if (spender == address(0)) revert ZeroAddressCheck();\n        uint256 currentAllowedAmount = self.allowances[owner][spender];\n        if (currentAllowedAmount > value) {\n            securityTokenBalances.unlock(owner, (currentAllowedAmount - value));\n        } else if (currentAllowedAmount < value) {\n            securityTokenBalances.lock(owner, (value - currentAllowedAmount));\n        }\n        self.allowances[owner][spender] = 0; // reset allowance\n        bytes32 approveHash = EncodingUtils.encodeRequest(\n            owner,\n            spender,\n            value,\n            self.counter\n        );\n        self.approves[approveHash] = Approve(\n            owner,\n            spender,\n            value,\n            ApproveStatus.Created\n        );\n        self.hasOngoingApprove[owner][spender] = true;\n        self.counter += 1;\n\n        return approveHash;\n    }\n\n    /**\n     * @dev Validates an approve request\n     * Provided there is a matching approve request in state Created, the approve is performed (that is, the allowance is set to the target\n     * value, and the approve request status moves to Validated)\n    */\n    function validateApprove(OngoingApproves storage self, bytes32 approveHash)\n        public\n    {\n        Approve storage approve = self.approves[approveHash];\n        if (approve.status == ApproveStatus.Undefined)\n            revert ApproveDoesNotExists();\n        if (approve.status != ApproveStatus.Created)\n            revert InvalidApproveStatus();\n        self.allowances[approve.owner][approve.spender] = approve.value;\n        self.hasOngoingApprove[approve.owner][approve.spender] = false;\n        self.approves[approveHash].status = ApproveStatus.Validated;\n    }\n\n    /**\n     * @dev Rejects an approve request\n     * Provided there is a matching approve request in state Created, the approve is cancelled (that is, the tokens are unlocked\n     * , and the approve request status moves to Validated)\n     * NB: after the request has be rejected, the allowance is 0 (and not the allowance that existed before the request was sent), this\n     * is by design and not a bug\n    */\n    function rejectApprove(\n        OngoingApproves storage self,\n        SecurityTokenBalancesLibrary.SecurityTokenBalances\n            storage securityTokenBalances,\n        bytes32 approveHash\n    ) public {\n        Approve memory approve = self.approves[approveHash];\n        if (approve.status == ApproveStatus.Undefined)\n            revert ApproveDoesNotExists();\n        if (approve.status != ApproveStatus.Created)\n            revert InvalidApproveStatus();\n        securityTokenBalances.unlock(approve.owner, approve.value);\n        self.hasOngoingApprove[approve.owner][approve.spender] = false;\n        self.approves[approveHash].status = ApproveStatus.Rejected;\n    }\n\n    /**\n     * @dev Initiates a transferFrom request\n     * This code is here to enable checking the allowance before accepting request\n    */\n    function transferFrom(\n        OngoingApproves storage self,\n        SecurityTokenBalancesLibrary.SecurityTokenBalances\n            storage securityTokenBalances,\n        TransferAdapterLibrary.OngoingTransfers storage ongoingTransfers,\n        address spender,\n        address from,\n        address to,\n        uint256 value\n    ) public returns (bytes32) {\n        uint256 currentAmount = self.allowances[from][spender];\n        if (currentAmount < value) revert InsufficientAllowance();\n        self.allowances[from][spender] -= value;\n        bytes32 transferHash = ongoingTransfers.addTransfer(\n            securityTokenBalances,\n            from,\n            to,\n            value,\n            true, // isTransferFrom\n            spender\n        );\n        return transferHash;\n    }\n\n    /**\n     * @dev Returns current allowance for `owner` and `spender`\n    */\n    function allowance(\n        OngoingApproves storage self,\n        address owner,\n        address spender\n    ) public view returns (uint256) {\n        return self.allowances[owner][spender];\n    }\n}\n"
      },
      "contracts/product/libraries/EncodingUtils.sol": {
        "content": "pragma solidity 0.8.17;\n\nlibrary EncodingUtils {\n    /**\n     * @dev Computes the hash of a tranfer or approve request\n     * Enables to index requests in mappings\n     */\n    function encodeRequest(\n        address _from,\n        address _to,\n        uint256 _value,\n        uint256 counter\n    ) internal view returns (bytes32) {\n        return\n            keccak256(abi.encode(block.timestamp, _from, _to, _value, counter));\n    }\n}\n"
      },
      "contracts/product/libraries/IterableBalances.sol": {
        "content": "pragma solidity 0.8.17;\n\nerror KeyNotInBalances();\n\n/**\n * @dev An iterable mapping of security token balances.\n * Handles total and locked balances (locked balance corresponds to tokens that are reserved for an ongoing Settlement Transaction)\n */\nlibrary IterableBalances {\n    struct iterableBalances {\n        mapping(address => Balance) balances;\n        KeyFlag[] keys;\n        uint256 size;\n    }\n\n    struct Balance {\n        uint256 keyIndex;\n        uint256 total;\n        uint256 locked;\n    }\n    struct KeyFlag {\n        address key;\n        bool deleted;\n    }\n\n    function insert(\n        iterableBalances storage self,\n        address key,\n        uint256 total\n    ) public {\n        uint256 keyIndex = self.balances[key].keyIndex;\n        self.balances[key].total = total;\n\n        if (keyIndex == 0) {\n            keyIndex = self.keys.length;\n            self.keys.push();\n            self.balances[key].keyIndex = keyIndex + 1;\n            self.keys[keyIndex].key = key;\n            self.size++;\n        }\n    }\n\n    function remove(iterableBalances storage self, address key) public {\n        uint256 keyIndex = self.balances[key].keyIndex;\n\n        if (keyIndex == 0) revert KeyNotInBalances();\n\n        delete self.balances[key];\n        self.keys[keyIndex - 1].deleted = true;\n        self.size--;\n    }\n\n    function contains(iterableBalances storage self, address key)\n        public\n        view\n        returns (bool)\n    {\n        return self.balances[key].keyIndex > 0;\n    }\n\n    function iterate_start(iterableBalances storage self)\n        public\n        view\n        returns (uint256 keyIndex)\n    {\n        return iterate_next(self, type(uint256).max);\n    }\n\n    function iterate_valid(iterableBalances storage self, uint256 keyIndex)\n        public\n        view\n        returns (bool)\n    {\n        return keyIndex < self.keys.length;\n    }\n\n    function iterate_next(iterableBalances storage self, uint256 keyIndex)\n        public\n        view\n        returns (uint256 r_keyIndex)\n    {\n        unchecked {\n            keyIndex++;\n        }\n\n        while (keyIndex < self.keys.length && self.keys[keyIndex].deleted) {\n            keyIndex++;\n        }\n\n        return keyIndex;\n    }\n\n    function iterate_get(iterableBalances storage self, uint256 keyIndex)\n        public\n        view\n        returns (\n            address key,\n            uint256 total,\n            uint256 locked\n        )\n    {\n        key = self.keys[keyIndex].key;\n        total = self.balances[key].total;\n        locked = self.balances[key].locked;\n    }\n\n}\n"
      },
      "contracts/product/libraries/SecurityTokenBalancesLibrary.sol": {
        "content": "pragma solidity 0.8.17;\nimport \"./IterableBalances.sol\";\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\n\nimport { InsufficientDisposableBalance, InsufficientBalance, InsufficientLockedBalance } from \"../../utils/ProductErrorReporter.sol\";\n\n/// @dev Models a address -> uint mapping where it is possible to iterate over all keys.\nlibrary SecurityTokenBalancesLibrary {\n    using IterableBalances for IterableBalances.iterableBalances;\n    using SafeMath for uint256;\n\n    struct SecurityTokenBalances {\n        address issuer;\n        IterableBalances.iterableBalances iterableBalances;\n    }\n    modifier onlyWhenBalanceDisposable(\n        SecurityTokenBalances storage self,\n        address _from,\n        uint256 _value\n    ) {\n        if (\n            self.iterableBalances.balances[_from].total -\n                self.iterableBalances.balances[_from].locked <\n            _value\n        ) revert InsufficientDisposableBalance();\n        _;\n    }\n    struct Balance {\n        address account;\n        uint256 total;\n        uint256 locked;\n    }\n\n    event Transfer(address indexed _from, address indexed _to, uint256 _value); // Only for erc20 explorer\n\n    function setIssuer(SecurityTokenBalances storage self, address key) public {\n        self.issuer = key;\n    }\n\n    function mint(\n        SecurityTokenBalances storage self,\n        address key,\n        uint256 balance\n    ) public {\n        self.iterableBalances.insert(key, balance);\n        emit Transfer(0x0000000000000000000000000000000000000000, key, balance);\n    }\n\n    function lock(\n        SecurityTokenBalances storage self,\n        address key,\n        uint256 valueToLock\n    ) public onlyWhenBalanceDisposable(self, key, valueToLock) {\n        self.iterableBalances.balances[key].locked += valueToLock;\n    }\n\n    function unlock(\n        SecurityTokenBalances storage self,\n        address key,\n        uint256 valueToUnlock\n    ) public {\n        if (self.iterableBalances.balances[key].total < valueToUnlock)\n            revert InsufficientBalance();\n        if (self.iterableBalances.balances[key].locked < valueToUnlock)\n            revert InsufficientLockedBalance();\n\n        self.iterableBalances.balances[key].locked -= valueToUnlock;\n    }\n\n    function burn(\n        SecurityTokenBalances storage self,\n        address _from,\n        uint256 _value\n    ) public onlyWhenBalanceDisposable(self, _from, _value) {\n        self.iterableBalances.balances[_from].total -= _value;\n\n        emit Transfer(_from, address(0), _value);\n    }\n\n    function transferLocked(\n        SecurityTokenBalances storage self,\n        address _from,\n        address _to,\n        uint256 _value\n    ) external {\n        unlock(self, _from, _value);\n\n        self.iterableBalances.balances[_from].total -= _value;\n\n        self.iterableBalances.insert(\n            _to,\n            self.iterableBalances.balances[_to].total + _value\n        );\n\n        emit Transfer(_from, _to, _value);\n    }\n\n    // should check this of any security issue?\n    function transfer(\n        SecurityTokenBalances storage self,\n        address _from,\n        address _to,\n        uint256 _value\n    ) external onlyWhenBalanceDisposable(self, _from, _value) {\n        self.iterableBalances.balances[_from].total -= _value;\n\n        self.iterableBalances.insert(\n            _to,\n            self.iterableBalances.balances[_to].total + _value\n        );\n\n        emit Transfer(_from, _to, _value);\n    }\n\n    // rename to getTotalBalance()\n    function getBalance(SecurityTokenBalances storage self, address _address)\n        external\n        view\n        returns (uint256 balance)\n    {\n        return self.iterableBalances.balances[_address].total;\n    }\n\n    function getAvailableBalance(\n        SecurityTokenBalances storage self,\n        address _address\n    ) external view returns (uint256 balance) {\n        return\n            self.iterableBalances.balances[_address].total -\n            self.iterableBalances.balances[_address].locked;\n    }\n\n    function getFullBalance(\n        SecurityTokenBalances storage self,\n        address _address\n    ) external view returns (Balance memory value) {\n        return\n            Balance(\n                _address,\n                self.iterableBalances.balances[_address].total,\n                self.iterableBalances.balances[_address].locked\n            );\n    }\n\n    function getFullBalances(SecurityTokenBalances storage self)\n        public\n        view\n        returns (Balance[] memory value)\n    {\n        address tokenHolder = address(0);\n        uint256 balance;\n        uint256 locked;\n        uint256 balancesSize = self.iterableBalances.size;\n        Balance[] memory addressBalanceArray = new Balance[](balancesSize);\n        for (\n            uint256 index = self.iterableBalances.iterate_start();\n            self.iterableBalances.iterate_valid(index);\n            index = self.iterableBalances.iterate_next(index)\n        ) {\n            (tokenHolder, balance, locked) = self.iterableBalances.iterate_get(\n                index\n            );\n            addressBalanceArray[index] = Balance(tokenHolder, balance, locked);\n        }\n\n        return addressBalanceArray;\n    }\n}\n"
      },
      "contracts/product/libraries/SettlementRepositoryLibrary.sol": {
        "content": "pragma solidity 0.8.17;\n\nimport \"./SecurityTokenBalancesLibrary.sol\";\n\nimport { NotSupportedTrustedToken, InvalidSettlementTransactionStatus, SettlementTransactionAlreadyExists } from \"../../utils/ProductErrorReporter.sol\";\n\n\n/**\n * @dev This library handles the Settlement Transaction Repository which is the container for all\n * Settlement Transactions for a given product\n */\nlibrary SettlementRepositoryLibrary {\n    using SecurityTokenBalancesLibrary for SecurityTokenBalancesLibrary.SecurityTokenBalances;\n    using SettlementRepositoryLibrary for SettlementRepositoryLibrary.SettlementTransactionRepository;\n\n    /**\n     * @dev The different status a Settlement Transaction can have\n     * Settlement Transactions are initially in the `Created` state.\n     * Once correctly initiated they move to the Acknowledged state.\n     * When the payment of the cash leg (if any) is received by the settlement agent, they move to the Processed state\n     * When the payment of the cash leg is transferred to the receiving end, they move to the Settled state, which is a final state.\n     * Whenever a Settlement Transaction is cancelled, it moves to the Cancelled state, which is a final state\n     */\n    enum SettlementTransactionStatus {\n        Undefined,\n        Created,\n        Acknowledged,\n        Processed,\n        Settled,\n        Cancelled\n    }\n\n    /**\n     * @dev The different operation types\n     * Operation types is used to keep track of the type of business operation that a Settlement Transaction is part of.\n     * Some business operations(e.g. Redemption) lead to several Settlement Transactions\n     */\n    enum OperationType {\n        Undefined,\n        Subscription,\n        Redemption,\n        Trade,\n        Coupon,\n        ExecuteTransfer\n    }\n\n    /**\n     * @dev The actual Settlement Transaction Repository, which maps Settlement Transaction ids to Settlement Transaction details\n     */\n    struct SettlementTransactionRepository {\n        mapping(uint256 => SettlementTransaction) settlementTransactionById; // mapping ( settlementtransactionId => settlementtransaction)\n    }\n\n    /**\n     * @dev The details of a Settlement Transaction\n     * NB: actually these are only the details that can be publicly disclosed on the blockchain\n     * The confidential details are available on a public server called the STR, which URL is available in the strUrl field of the products\n     */\n    struct SettlementTransaction {\n        /**\n         * @dev The UUID of the Settlement Transaction(as an integer)\n        */\n        uint256 txId;\n        /**\n         * @dev Optional id of the business operation this Settlement Transaction is part of.\n        */\n        uint256 operationId;\n        /**\n         * @dev The address of counterparty that delivers the security tokens(a.k.a product)\n        */\n        address deliverySenderAccountNumber;\n        /**\n         * @dev The address of counterparty that receives the security tokens(a.k.a product)\n        */\n        address deliveryReceiverAccountNumber;\n        /**\n         * @dev The quantity of security tokens(a.k.a product) that should be delivered\n        */\n        uint256 deliveryQuantity;\n        /**\n         * @dev Hash of the Settlement Transaction details\n        */\n        string txHash;\n        /**\n         * @dev Current status of the Settlement Transaction\n        */\n        SettlementTransactionStatus status;\n        /**\n         * @dev The type of the business operation this Settlement Transaction is part of.\n        */\n        OperationType operationType;\n    }\n\n    /**\n     * @dev Partial details of a Settlement Transaction that are passed when initiating the transaction\n     */\n    struct PartialSettlementTransaction {\n        /**\n         * @dev The UUID of the Settlement Transaction(as an integer)\n        */\n        uint256 txId;\n        /**\n         * @dev Optional id of the business operation this Settlement Transaction is part of.\n        */\n        uint256 operationId;\n        /**\n         * @dev The address of counterparty that delivers the security tokens(a.k.a product)\n         * e.g the issuer for a Subscription operation, the investor for a Redemption operation, the seller for a Trade operation\n        */\n        address deliverySenderAccountNumber;\n        /**\n         * @dev The address of counterparty that receives the security tokens(a.k.a product)\n         *  e.g the investor for a Subscription operation, the issuer for a Redemption operation, the buyer for a Trade operation\n        */\n        address deliveryReceiverAccountNumber;\n        /**\n         * @dev The quantity of security tokens(a.k.a product) that should be delivered\n        */\n        uint256 deliveryQuantity;\n        /**\n         * @dev Hash of the Settlement Transaction details\n        */\n        string txHash;\n    }\n\n    /**\n     * @dev Returns the details of the Settlement Transaction with id `id`\n     */\n    function getSettlementTransactionById(\n        SettlementTransactionRepository storage settlementTransactionRepository,\n        uint256 id\n    ) public view returns (SettlementTransaction memory) {\n        SettlementTransaction\n            memory settlementTransaction = settlementTransactionRepository\n                .settlementTransactionById[id];\n\n        return settlementTransaction;\n    }\n\n    /**\n     * @dev Updates the status of Settlement Transaction with id `txId`\n     */\n    function setSettlementTransactionStatus(\n        SettlementTransactionRepository storage settlementTransactionRepository,\n        uint256 txId,\n        SettlementTransactionStatus status\n    ) internal {\n        if (status == SettlementTransactionStatus.Undefined)\n            revert InvalidSettlementTransactionStatus();\n\n        SettlementTransaction\n            storage settlementTransaction = settlementTransactionRepository\n                .settlementTransactionById[txId];\n        settlementTransaction.status = status;\n    }\n\n    /**\n     * @dev Adds Settlement Transaction with given details to the repository.\n     * NB : status is initialized to `Created`\n     */\n    function createSettlementTransaction(\n        SettlementTransactionRepository storage settlementTransactionRepository,\n        PartialSettlementTransaction memory partialSettlementTransaction,\n        OperationType operationType\n    )\n        internal\n    {\n        if (\n            settlementTransactionRepository\n                .settlementTransactionById[partialSettlementTransaction.txId]\n                .txId == partialSettlementTransaction.txId\n        ) revert SettlementTransactionAlreadyExists();\n\n        SettlementTransaction\n            memory newSettlementTransaction = SettlementTransaction({\n                txId: partialSettlementTransaction.txId,\n                operationId: partialSettlementTransaction.operationId,\n                deliverySenderAccountNumber: partialSettlementTransaction\n                    .deliverySenderAccountNumber,\n                deliveryReceiverAccountNumber: partialSettlementTransaction\n                    .deliveryReceiverAccountNumber,\n                deliveryQuantity: partialSettlementTransaction.deliveryQuantity,\n                txHash: partialSettlementTransaction.txHash,\n                status: SettlementTransactionStatus.Created,\n                operationType: operationType\n            });\n        settlementTransactionRepository.settlementTransactionById[\n            partialSettlementTransaction.txId\n        ] = newSettlementTransaction;\n    }\n}\n"
      },
      "contracts/product/libraries/SettlementWorkflowLibrary.sol": {
        "content": "pragma solidity 0.8.17;\n\nimport \"./SettlementRepositoryLibrary.sol\";\nimport \"./SecurityTokenBalancesLibrary.sol\";\n\nimport { SettlementTransactionNotInAcknowledgedState, DeliveryReceiverAccountNumberNotMatchTokenIssuer, InvalidSettlementTransactionStatus } from \"../../utils/ProductErrorReporter.sol\";\n\n/**\n * @dev This library handles the details of the different Settlement Transaction workflows\n */\nlibrary SettlementWorkflowLibrary {\n    using SettlementRepositoryLibrary for SettlementRepositoryLibrary.SettlementTransactionRepository;\n    using SecurityTokenBalancesLibrary for SecurityTokenBalancesLibrary.SecurityTokenBalances;\n\n    /**\n     * @dev Mutualizes code for initializing DVP-type Settlement Transactions.\n     * DVP means Delivery Versus Payment, meaning that there are both a token leg and a cash leg\n     * In this case the tokens have to be locked while awaiting payment confirmation by the settlement agent\n     */\n    function initiateDVP(\n        SettlementRepositoryLibrary.SettlementTransactionRepository\n            storage settlementTransactionRepository,\n        SecurityTokenBalancesLibrary.SecurityTokenBalances\n            storage securityTokenBalances,\n        uint256 settlementTransactionId\n    ) public {\n        SettlementRepositoryLibrary.SettlementTransaction\n            memory st = settlementTransactionRepository\n                .getSettlementTransactionById(settlementTransactionId);\n\n        securityTokenBalances.lock(\n            st.deliverySenderAccountNumber,\n            st.deliveryQuantity\n        );\n\n        settlementTransactionRepository.setSettlementTransactionStatus(\n            settlementTransactionId,\n            SettlementRepositoryLibrary.SettlementTransactionStatus.Acknowledged\n        );\n    }\n\n    /**\n     * @dev Initiate a Subscription Settlement Transaction (counterparty buys product on primary market from the product's issuer)\n     * The tokens are locked waiting for the cash leg to settle (see functions confirmPaymentReceived/confirmPaymentTransferred)\n     */\n    function initiateSubscription(\n        SettlementRepositoryLibrary.SettlementTransactionRepository\n            storage settlementTransactionRepository,\n        SecurityTokenBalancesLibrary.SecurityTokenBalances\n            storage securityTokenBalances,\n        SettlementRepositoryLibrary.PartialSettlementTransaction\n            memory partialSettlementTransaction\n    ) public {\n        settlementTransactionRepository.createSettlementTransaction(\n            partialSettlementTransaction,\n            SettlementRepositoryLibrary.OperationType.Subscription\n        );\n\n        initiateDVP(\n            settlementTransactionRepository,\n            securityTokenBalances,\n            partialSettlementTransaction.txId\n        );\n    }\n\n    /**\n     * @dev Execute unilateral Transfer Settlement Transactions \n     * As there is no cash leg to settle, the tokens are transfered right away and the Settlement Transaction is marked as Settled\n     */\n    function executeTransfer(\n        SettlementRepositoryLibrary.SettlementTransactionRepository\n            storage settlementTransactionRepository,\n        SecurityTokenBalancesLibrary.SecurityTokenBalances\n            storage securityTokenBalances,\n        SettlementRepositoryLibrary.PartialSettlementTransaction\n            memory partialSettlementTransaction\n    ) public {\n        settlementTransactionRepository.createSettlementTransaction(\n            partialSettlementTransaction,\n            SettlementRepositoryLibrary.OperationType.ExecuteTransfer\n        );\n        securityTokenBalances.transfer(\n            partialSettlementTransaction.deliverySenderAccountNumber,\n            partialSettlementTransaction.deliveryReceiverAccountNumber,\n            partialSettlementTransaction.deliveryQuantity\n        );\n    }\n\n    /**\n     * @dev Initiate a Trade Settlement Transaction (one counterparty buys, the other sells)\n     * The tokens are locked waiting for the cash leg to settle (see functions confirmPaymentReceived/confirmPaymentTransferred)\n     */\n    function initiateTrade(\n        SettlementRepositoryLibrary.SettlementTransactionRepository\n            storage settlementTransactionRepository,\n        SecurityTokenBalancesLibrary.SecurityTokenBalances\n            storage securityTokenBalances,\n        SettlementRepositoryLibrary.PartialSettlementTransaction\n            memory partialSettlementTransaction\n    ) public {\n        settlementTransactionRepository.createSettlementTransaction(\n            partialSettlementTransaction,\n            SettlementRepositoryLibrary.OperationType.Trade\n        );\n\n        initiateDVP(\n            settlementTransactionRepository,\n            securityTokenBalances,\n            partialSettlementTransaction.txId\n        );\n    }\n\n    /**\n     * @dev Initiate a Redemption Settlement Transactions (issuer redeems product to all holders and gets the tokens back)\n     * The tokens are locked waiting for the cash leg to settle (see functions confirmPaymentReceived/confirmPaymentTransferred)\n     */\n    function initiateRedemption(\n        SettlementRepositoryLibrary.SettlementTransactionRepository\n            storage settlementTransactionRepository,\n        SecurityTokenBalancesLibrary.SecurityTokenBalances\n            storage securityTokenBalances,\n        SettlementRepositoryLibrary.PartialSettlementTransaction[]\n            memory partialSettlementTransactions\n    ) public {\n        for (uint256 i = 0; i < partialSettlementTransactions.length; i++) {\n            if (\n                securityTokenBalances.issuer !=\n                partialSettlementTransactions[i].deliveryReceiverAccountNumber\n            ) revert DeliveryReceiverAccountNumberNotMatchTokenIssuer();\n\n            settlementTransactionRepository.createSettlementTransaction(\n                partialSettlementTransactions[i],\n                SettlementRepositoryLibrary.OperationType.Redemption\n            );\n\n            initiateDVP(\n                settlementTransactionRepository,\n                securityTokenBalances,\n                partialSettlementTransactions[i].txId\n            );\n        }\n    }\n\n    /**\n     * @dev Initiate a Coupon Settlement Transactions (issuer pays coupon to all holders)\n     * NB: the tokens are not locked for this kind of transaction\n     */\n    function initiateCoupon(\n        SettlementRepositoryLibrary.SettlementTransactionRepository\n            storage settlementTransactionRepository,\n        SettlementRepositoryLibrary.PartialSettlementTransaction[]\n            memory partialSettlementTransactions\n    ) public {\n        for (uint256 i = 0; i < partialSettlementTransactions.length; i++) {\n            settlementTransactionRepository.createSettlementTransaction(\n                partialSettlementTransactions[i],\n                SettlementRepositoryLibrary.OperationType.Coupon\n            );\n            settlementTransactionRepository.setSettlementTransactionStatus(\n                partialSettlementTransactions[i].txId,\n                SettlementRepositoryLibrary\n                    .SettlementTransactionStatus\n                    .Acknowledged\n            );\n        }\n    }\n\n    /**\n     * @dev Cancels ongoing settlement transaction with id `settlementTransactionId`\n     * Unlocks tokens\n     * Fails if the settlement transaction is not in the Acknowledged state.\n     */\n    function cancelSettlementTransaction(\n        SettlementRepositoryLibrary.SettlementTransactionRepository\n            storage settlementTransactionRepository,\n        SecurityTokenBalancesLibrary.SecurityTokenBalances\n            storage securityTokenBalances,\n        uint256 settlementTransactionId\n    ) public {\n        SettlementRepositoryLibrary.SettlementTransaction\n            memory settlementTransaction = settlementTransactionRepository\n                .settlementTransactionById[settlementTransactionId];\n\n        if (\n            settlementTransaction.status !=\n            SettlementRepositoryLibrary.SettlementTransactionStatus.Acknowledged\n        ) revert SettlementTransactionNotInAcknowledgedState();\n\n        securityTokenBalances.unlock(\n            settlementTransaction.deliverySenderAccountNumber,\n            settlementTransaction.deliveryQuantity\n        );\n        settlementTransactionRepository.setSettlementTransactionStatus(\n            settlementTransactionId,\n            SettlementRepositoryLibrary.SettlementTransactionStatus.Cancelled\n        );\n    }\n}\n"
      },
      "contracts/product/libraries/TransferAdapterLibrary.sol": {
        "content": "pragma solidity 0.8.17;\n\nimport \"./EncodingUtils.sol\";\nimport \"./SecurityTokenBalancesLibrary.sol\";\n\nimport { ZeroAddressCheck, TransferRequestNotFound, InvalidTransferRequestStatus } from \"../../utils/ProductErrorReporter.sol\";\n\n/**\n * @dev This library allows to handle two-step transfers as described in IERC20Adapter\n */\nlibrary TransferAdapterLibrary {\n    using SecurityTokenBalancesLibrary for SecurityTokenBalancesLibrary.SecurityTokenBalances;\n\n    /**\n     * @dev The different status a transfer request can have\n     * Transfer requests are initially in the `Created` state\n     * If validated by the validator authority they move to the `Validated` state, which is a final state\n     * If rejected by the validator authority they move to the `Rejected` state, which is a final state\n     * \n     */\n    enum TransferStatus {\n        Undefined,\n        Created,\n        Validated,\n        Rejected\n    }\n\n    /**\n     * @dev The details of a transfer request\n     */\n    struct Transfer {\n        /**\n        * @dev The source address of the transfer \n        */\n        address from;\n        /**\n        * @dev The destination address of the transfer \n        */\n        address to;\n        /**\n        * @dev The number of tokens to transfer\n        */\n        uint256 value;\n        /**\n        * @dev The status of the transfer request\n        */\n        TransferStatus status;\n        /**\n        * @dev Whether this is a transferFrom request (i.e. allowance will be consumed)\n        */\n        bool isTransferFrom;\n        /**\n        * @dev Address of the spender address, in case of transferFrom request\n        */\n        address spender;\n    }\n\n    /**\n     * @dev Structure containing all ongoing transfer requests\n     * Requests are indexed by the hash of their content\n    */\n    struct OngoingTransfers {\n        mapping(bytes32 => Transfer) transfers;\n        uint256 counter;\n    }\n\n    /**\n     * @dev Initiates a transfer request\n     * If simple transfer request, the tokens are locked, awaiting either validation or rejection by the validator authority\n     * If transferFrom, the tockens where already locked when the approve request was done\n    */\n    function addTransfer(\n        OngoingTransfers storage self,\n        SecurityTokenBalancesLibrary.SecurityTokenBalances\n            storage securityTokenBalances,\n        address from,\n        address to,\n        uint256 value,\n        bool isTransferFrom,\n        address spender\n    ) public returns (bytes32) {\n        if (from == address(0)) revert ZeroAddressCheck();\n        if (to == address(0)) revert ZeroAddressCheck();\n        if (!isTransferFrom) {\n            securityTokenBalances.lock(from, value);\n        }\n        bytes32 transferHash = EncodingUtils.encodeRequest(\n            from,\n            to,\n            value,\n            self.counter\n        );\n        self.transfers[transferHash] = Transfer(\n            from,\n            to,\n            value,\n            TransferStatus.Created,\n            isTransferFrom,\n            spender\n        );\n        self.counter += 1;\n        return transferHash;\n    }\n\n    /**\n     * @dev Validates a transfer request\n     * Provided there is a matching transfer request in state Created, the transfer is performed (that is, the tokens are\n     * transferred to the destination address, and unlocked, and the transfer request status moves to Validated)\n    */\n    function validateTransfer(\n        OngoingTransfers storage self,\n        SecurityTokenBalancesLibrary.SecurityTokenBalances\n            storage securityTokenBalances,\n        bytes32 transferHash\n    ) public {\n        Transfer storage transfer = self.transfers[transferHash];\n        if (transfer.status == TransferStatus.Undefined)\n            revert TransferRequestNotFound();\n        if (transfer.status != TransferStatus.Created)\n            revert InvalidTransferRequestStatus();\n        securityTokenBalances.transferLocked(\n            transfer.from,\n            transfer.to,\n            transfer.value\n        );\n        transfer.status = TransferStatus.Validated;\n    }\n\n    /**\n     * @dev Rejects a transfer request\n     * Provided there is a matching transfer request in state Created, the transfer is cancelled (that is, the transfer request staus moves \n     * to Rejected)\n     * NB : due to the complexity of the token unlocking logic (depending on whether the transfer request was a transferFrom or not, either\n     * the tokens should be unlocked (simple transfer) or the previous allowance should be restored (transferFrom)) and to avoid complex \n     * inter-dependency between ApproveAdapterLibrary and TransferAdapterLibrary, this logic is perform directly in Product.rejectTransfer\n    */\n    function rejectTransfer(OngoingTransfers storage self, bytes32 transferHash)\n        public\n    {\n        Transfer storage transfer = self.transfers[transferHash];\n        if (transfer.status == TransferStatus.Undefined)\n            revert TransferRequestNotFound();\n        if (transfer.status != TransferStatus.Created)\n            revert InvalidTransferRequestStatus();\n        transfer.status = TransferStatus.Rejected;\n    }\n}\n"
      },
      "contracts/product/Product.sol": {
        "content": "pragma solidity 0.8.17;\n\nimport \"./libraries/SecurityTokenBalancesLibrary.sol\";\nimport \"./libraries/IterableBalances.sol\";\nimport \"./libraries/SettlementRepositoryLibrary.sol\";\nimport \"./libraries/SettlementWorkflowLibrary.sol\";\nimport \"./libraries/TransferAdapterLibrary.sol\";\nimport \"./libraries/ApproveAdapterLibrary.sol\";\nimport \"./interfaces/IProduct.sol\";\nimport \"./interfaces/ISettlement.sol\";\nimport \"./interfaces/IERC20Adapter.sol\";\nimport \"../registry/interfaces/IProductRegistry.sol\";\nimport \"../utils/Ownable.sol\";\nimport \"@openzeppelin/contracts/utils/introspection/ERC165.sol\";\nimport \"../utils/ProductErrorReporter.sol\";\n\nerror InvalidRegistryAddress();\n\n\n/**\n * @dev This contract represents a CAST-compatible financial product\n * It includes a number of basic financial information about the product (common to all products)\n * It also contains extended information specific to this product, as a JSON string in field extendedDataJson\n * It also includes the methods needed to handle Settlement Transactions on this instrument(subscriptions on primary market, secondary\n * market trades as well as coupons and redemption) -> see ISettlement interface\n * It also includes the methods needed to interact (almost) as an ERC20 token, enable to interact with DeFi protocols. -> see IERC20Adapter \n * interface\n * Supports ERC165\n */\ncontract Product is\n    ISettlement,\n    IProduct,\n    IERC20Adapter,\n    ERC165,\n    Ownable\n{\n    using SecurityTokenBalancesLibrary for SecurityTokenBalancesLibrary.SecurityTokenBalances;\n    using SettlementRepositoryLibrary for SettlementRepositoryLibrary.SettlementTransactionRepository;\n    using TransferAdapterLibrary for TransferAdapterLibrary.OngoingTransfers;\n    using ApproveAdapterLibrary for ApproveAdapterLibrary.OngoingApproves;\n    // Basic Informations\n    /**\n     * @dev The product's currency\n     */\n    string public currency;\n    /**\n     * @dev The product's denomination in cents\n     */\n    uint256 public denominationCent;\n    /**\n     * @dev The product's maturity date (unix timestamp)\n     */\n    uint256 public maturityDate;\n    /**\n     * @dev The product's governing law\n     */\n    string public governingLaw;\n    /**\n     * @dev The product's guarantor legal entity\n     */\n    LegalEntity public guarantor;\n    /**\n     * @dev The product's isin code\n     */\n    string public isinCode;\n    /**\n     * @dev The product's issuer legal entity\n     */\n    LegalEntity public issuer;\n    /**\n     * @dev The product's quotation market\n     */\n    string public listing;\n    /**\n     * @dev The product's name\n     */\n    string public name;\n    /**\n     * @dev The product's paying agent legal entity\n     */\n    LegalEntity public payingAgent;\n    /**\n     * @dev The product's type code (e.g. sgforge.com/bond/V1)\n     */\n    string public productType;\n    /**\n     * @dev The product's registrar legal entity\n     */\n    LegalEntity public registrar;\n    /**\n     * @dev The product's settlement agent legal entity\n     */\n    LegalEntity public settlementAgent;\n    /**\n     * @dev The product's symbol\n     */\n    string public symbol;\n    /**\n     * @dev The product's state\n     */\n    ProductState public state;\n    /**\n     * @dev This URL where the Settlement Transaction Repository can be reached\n     * The STR can provided the confidential part of the Settlement Transactions to the counterparts (authentication with ethereum private key)\n     */\n    string public strUrl;\n    /**\n     * @dev The issuer's issuance program this product is part of\n     */\n    string public program;\n    /**\n     * @dev This product's series number\n     */\n    string public series;\n    /**\n     * @dev This product's note status\n     */\n    string public noteStatus;\n    /**\n     * @dev JSON string of extended information about the product. Can be roughly anything.\n     * Will be used to hold financial information specific to a some products.\n     */\n    string public extendedDataJson;\n    /**\n     * @dev String holding ESG information about the product (JSON format)\n     */\n    string public esg;\n    /**\n     * @dev This product's form of the node (e.g. Registered)\n     */\n    string public formOfNote;\n    /**\n     * @dev This product's FIGI code\n     */\n    string public figi;\n    /**\n     * @dev The address of a previous contract that is replaced with this one (allows to keep track of successive contract migrations)\n     */\n    address public previousContract;\n\n    /**\n     * @dev Extended data(JSON string) associated with specific business operations\n     */\n    mapping(uint256 => string) public operationExtendedDataJson;\n\n    /**\n     * @dev The product's balances. Handles total and locked balance.\n     */\n    SecurityTokenBalancesLibrary.SecurityTokenBalances\n        private securityTokenBalances;\n\n    /**\n     * @dev The product's settlement transaction repository\n     * Contains all Settlement Transactions involving this product.\n     */\n    SettlementRepositoryLibrary.SettlementTransactionRepository\n        private settlementTransactionRepository;\n\n    /**\n     * @dev Ongoing two-steps transfers.\n     * See IERC20Adapter\n     */\n    TransferAdapterLibrary.OngoingTransfers private ongoingTransfers;\n    /**\n     * @dev Ongoing two-steps approves\n     * See IERC20Adapter\n     */\n    ApproveAdapterLibrary.OngoingApproves private ongoingApproves;\n\n    /**\n     * @dev The version number of this smart contract.\n     */\n    string public constant version = \"1.1\";\n\n    // Tranches related informations\n    Tranche[] public tranches;\n    /**\n     * @dev The product total issued nominal amount(includes all tranches)\n     */\n    uint256 public seriesNominalAmountCent;\n    /**\n     * @dev The product outstanding nominal amount(includes all not-burnt tokens)\n     */\n    uint256 public seriesOutstandingNominalAmountCent;\n    /**\n     * @dev The product redeemed amount(i.e. burnt tokens)\n     */\n    uint256 public seriesRedeemedAmountCent;\n    /**\n     * @dev The total number of (not burnt) tokens\n     */\n    uint256 public totalSupply;\n\n    /**\n     * @dev The different states a product can have\n     * Product are initially in the `Created` state.\n     * Once at list one subscription operation has been initiated, they move to the `Running` state.\n     * Once a redemption operation has been initiated, they move to the `Redeemed` state, which is the product's final state.\n     * Once a product is in the `Redeemed` state, no more Settlement Transaction may be initiated on this product.\n     * \n     */\n    enum ProductState {\n        Undefined,\n        Created,\n        Running,\n        Redeemed\n    }\n\n    constructor(BasicProductInput memory basicProductInput) Ownable(basicProductInput.registrar.account){\n        \n        isinCode = basicProductInput.isinCode;\n        name = basicProductInput.name;\n        symbol = basicProductInput.symbol;\n        denominationCent = basicProductInput.denominationCent;\n        maturityDate = basicProductInput.maturityDate;\n        governingLaw = basicProductInput.governingLaw;\n        listing = basicProductInput.listing;\n        state = ProductState.Created;\n        currency = basicProductInput.currency;\n        registrar = LegalEntity(\n            basicProductInput.registrar.lei,\n            basicProductInput.registrar.account\n        );\n        if(basicProductInput.settlementAgent.account == address(0))\n            revert ZeroAddressCheck();\n        settlementAgent = LegalEntity(\n            basicProductInput.settlementAgent.lei,\n            basicProductInput.settlementAgent.account\n        );\n        payingAgent = LegalEntity(\n            basicProductInput.payingAgent.lei,\n            basicProductInput.payingAgent.account\n        );\n        issuer = LegalEntity(\n            basicProductInput.issuer.lei,\n            basicProductInput.issuer.account\n        );\n        securityTokenBalances.setIssuer(issuer.account);\n        guarantor = LegalEntity(\n            basicProductInput.guarantor.lei,\n            basicProductInput.guarantor.account\n        );\n        strUrl = basicProductInput.strUrl;\n        productType = basicProductInput.productType;\n        program = basicProductInput.program;\n        series = basicProductInput.series;\n        noteStatus = basicProductInput.noteStatus;\n        formOfNote = basicProductInput.formOfNote;\n        extendedDataJson = basicProductInput.extendedDataJson;\n        esg = basicProductInput.esg;\n        figi = basicProductInput.figi;\n        previousContract = basicProductInput.previousContract;\n\n        for (uint256 i = 0; i < basicProductInput.initialTranches.length; i++) {\n            internalCreateTranche(basicProductInput.initialTranches[i]);\n        }\n\n        if (basicProductInput.initialBalances.length > 0) {\n            uint256 balanceSupply = 0;\n            for (\n                uint256 i = 0;\n                i < basicProductInput.initialBalances.length;\n                i++\n            ) {\n                uint256 value = basicProductInput.initialBalances[i].balance;\n                address to = basicProductInput.initialBalances[i].account;\n\n                securityTokenBalances.mint(to, value);\n                balanceSupply += value;\n            }\n            if (balanceSupply != totalSupply)\n                revert TotalSupplyNotMatchTotalInitialSupply();\n        } else {\n            securityTokenBalances.mint(issuer.account, totalSupply);\n        }\n    }\n\n    /**\n     * @dev ERC165. Indicates that the product implements the ISettlement,IERC20Adapter and IProduct interfaces.\n     */\n    function supportsInterface(bytes4 interfaceId)\n        override\n        public\n        view\n        returns (bool)\n    {\n        return\n            interfaceId == type(ISettlement).interfaceId ||\n            interfaceId == type(IERC20Adapter).interfaceId ||\n            interfaceId == type(IProduct).interfaceId ||\n            super.supportsInterface(interfaceId);\n    }\n\n    // Basic Token\n    /**\n     * @dev Shortcut to the account of the issuer legal entity\n     */\n    function issuerAccount() external view returns (address) {\n        return issuer.account;\n    }\n\n    /**\n     * @dev Shortcut to the Legal Entity ID of the issuer legal entity\n     */\n    function issuerLEI() external view returns (string memory) {\n        return issuer.lei;\n    }\n\n    /**\n     * @dev Shortcut to the account of the settlement agent legal entity\n     */\n    function settlementAgentAccount() external view returns (address) {\n        return settlementAgent.account;\n    }\n\n    /**\n     * @dev Shortcut to the Legal Entity ID of the settlement agent legal entity\n     */\n    function settlementAgentLEI() external view returns (string memory) {\n        return settlementAgent.lei;\n    }\n\n    /**\n     * @dev Shortcut to the account of the paying agent legal entity\n     */\n    function payingAgentAccount() external view returns (address) {\n        if (payingAgent.account == address(0)) revert PayingAgentNotSet();\n        return payingAgent.account;\n    }\n\n    /**\n     * @dev Shortcut to the Legal Entity ID of the paying agent legal entity\n     */\n    function payingAgentLEI() external view returns (string memory) {\n        if (bytes(payingAgent.lei).length == 0) revert PayingAgentNotSet();\n        return payingAgent.lei;\n    }\n\n    /**\n     * @dev Shortcut to the account of the registrar legal entity\n     */\n    function registrarAccount() external view returns (address) {\n        return registrar.account;\n    }\n\n    /**\n     * @dev Shortcut to the Legal Entity ID of the registrar legal entity\n     */\n    function registrarLEI() external view returns (string memory) {\n        return registrar.lei;\n    }\n\n    /**\n     * @dev Shortcut to the account of the guarantor legal entity\n     */\n    function guarantorAccount() external view returns (address) {\n        if (guarantor.account == address(0)) revert GuarantorNotSet();\n        return guarantor.account;\n    }\n\n    /**\n     * @dev Shortcut to the Legal Entity ID of the guarantor legal entity\n     */\n    function guarantorLEI() external view returns (string memory) {\n        if (bytes(guarantor.lei).length == 0) revert GuarantorNotSet();\n        return guarantor.lei;\n    }\n\n    /**\n     * @dev Return details of all tranches\n     */\n    function getTranches() external view returns (Tranche[] memory) {\n        return tranches;\n    }\n\n    // Modifiers\n    /**\n     * @dev Checks the product is not redeemed yet\n     */\n    modifier onlyNotRedeemedProduct() {\n        if (state >= ProductState.Redeemed) revert ProductIsFullyRedeemed();\n        _;\n    }\n    /**\n     * @dev Checks there is no ongoing approve request for the same spender\n     */\n    modifier onlyOnAvailableSpender(address spender) {\n        if (ongoingApproves.hasOngoingApprove[msg.sender][spender])\n            revert OwnerHasOngoingApprove();\n        _;\n    }\n\n    /**\n     * @dev Used to protect methods that only the product's settlement agent can call\n     */\n    modifier settlerOnly() {\n        if (msg.sender != settlementAgent.account) revert UnauthorizedSettler();\n        _;\n    }\n\n    /**\n     * @dev Allows to change the product's extended data descriptor\n     * NB: Only the registrar can call this method\n     */\n    function setExtendeDataJson(string memory _extendedDataJson)\n        external\n        onlyRegistrar\n    {\n        extendedDataJson = _extendedDataJson;\n    }\n\n    /**\n     * @dev Allows to change the product's ESG data descriptor\n     * NB: Only the registrar can call this method\n     */\n    function setEsg(string memory _esg) external onlyRegistrar {\n        esg = _esg;\n    }\n\n    // [ERC-20] Only\n    function balanceOf(address _owner) public view returns (uint256 balance) {\n        return securityTokenBalances.getBalance(_owner);\n    }\n\n    /**\n     * @dev Initiates two-step simple transfer(cf IERC20Adapter) and sends corresponding `TransferRequest` event\n     */\n    function transfer(address _to, uint256 _value)\n        external\n        virtual\n        override\n        returns (bool)\n    {\n        if (_value == 0) revert ZeroValueCheck();\n        if (_to == msg.sender) revert InvalidReceiver();\n        bytes32 transferHash = ongoingTransfers.addTransfer(\n            securityTokenBalances,\n            msg.sender,\n            _to,\n            _value,\n            false,\n            address(0)\n        );\n        emit Transfer(msg.sender, _to, 0); // Required by https://eips.ethereum.org/EIPS/eip-20#transfer\n        emit TransferRequest(transferHash, msg.sender, _to, _value);\n        return true;\n    }\n\n    /**\n     * @dev Initiates two-step approve(cf IERC20Adapter) and sends corresponding `ApproveRequest` event\n     */\n    function approve(address _spender, uint256 _value)\n        external\n        virtual\n        override\n        onlyOnAvailableSpender(_spender)\n        returns (bool)\n    {\n        bytes32 approveHash = ongoingApproves.addApprove(\n            securityTokenBalances,\n            msg.sender,\n            _spender,\n            _value\n        );\n        emit ApproveRequest(approveHash, msg.sender, _spender, _value);\n        return true;\n    }\n\n    /**\n     * @dev Validates two-step transfer(cf IERC20Adapter) and sends corresponding `TransferValidated` event\n     * NB: Only the registrar can call this method\n     */\n    function validateTransfer(bytes32 transferHash)\n        external\n        override\n        onlyRegistrar\n        returns (bool)\n    {\n        ongoingTransfers.validateTransfer(securityTokenBalances, transferHash);\n        emit TransferValidated(transferHash);\n        return true;\n    }\n\n    /**\n     * @dev Rejects two-step transfer(cf IERC20Adapter) and sends corresponding `TransferRejected` event\n     * Unlocks token if simple transfer\n     * Restore allowance if tranferFrom\n     * NB: Only the registrar can call this method\n     */\n    function rejectTransfer(bytes32 transferHash)\n        external\n        override\n        onlyRegistrar\n        returns (bool)\n    {\n        ongoingTransfers.rejectTransfer(transferHash);\n        TransferAdapterLibrary.Transfer\n            memory transferRequest = ongoingTransfers.transfers[transferHash];\n        if (transferRequest.isTransferFrom) {\n            ongoingApproves.allowances[transferRequest.from][\n                transferRequest.spender\n            ] += transferRequest.value;\n        } else {\n            securityTokenBalances.unlock(\n                transferRequest.from,\n                transferRequest.value\n            );\n        }\n        emit TransferRejected(transferHash);\n        return true;\n    }\n\n    /**\n     * @dev Validates two-step approve(cf IERC20Adapter) and sends corresponding `ApproveValidated` event\n     * NB: Only the registrar can call this method\n     */\n    function validateApprove(bytes32 approveHash)\n        external\n        override\n        onlyRegistrar\n        returns (bool)\n    {\n        ongoingApproves.validateApprove(approveHash);\n        ApproveAdapterLibrary.Approve memory approveRequest = ongoingApproves\n            .approves[approveHash];\n        emit Approval(\n            approveRequest.owner,\n            approveRequest.spender,\n            approveRequest.value\n        );\n        emit ApproveValidated(approveHash);\n        return true;\n    }\n\n\n    /**\n     * @dev Rejects two-step transfer(cf IERC20Adapter) and sends corresponding `ApproveRejected` event\n     * NB: Only the registrar can call this method\n     */\n    function rejectApprove(bytes32 approveHash)\n        external\n        override\n        onlyRegistrar\n        returns (bool)\n    {\n        ongoingApproves.rejectApprove(securityTokenBalances, approveHash);\n        emit ApproveRejected(approveHash);\n        return true;\n    }\n\n    /**\n     * @dev Returns current allowance for provided `owner` and `spender`\n     */\n    function allowance(address owner, address spender)\n        external\n        view\n        override\n        returns (uint256)\n    {\n        return ongoingApproves.allowance(owner, spender);\n    }\n\n    /**\n     * @dev Initiates two-step transferFrom(cf IERC20Adapter) and sends corresponding `TransferRequest` event\n     */\n    function transferFrom(\n        address from,\n        address to,\n        uint256 amount\n    ) public virtual override returns (bool) {\n        bytes32 transferHash = ongoingApproves.transferFrom(\n            securityTokenBalances,\n            ongoingTransfers,\n            msg.sender,\n            from,\n            to,\n            amount\n        );\n        emit TransferRequest(transferHash, msg.sender, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev Security tokens are not divisible.\n     * Only an integer number of tokens can be manipulated\n     */\n    function decimals() public pure returns (uint8) {\n        return 0;\n    }\n\n    /**\n     * @dev Burn the given `quantity` of tokens\n     * The product's totalSupply is updated accordingly.\n     * NB : only the product's registrar can call this method\n     */\n    function burn(uint256 quantity) public onlyRegistrar {\n        internalBurn(issuer.account, quantity);        \n    }\n\n    function internalBurn(address account, uint256 quantity) internal {\n        securityTokenBalances.burn(account, quantity);\n        seriesRedeemedAmountCent += quantity * denominationCent;\n        recomputeTotalSupply();\n    }\n\n    // IBasicToken\n    /**\n     * @dev Returns all balances as an array of Balance structures(including total and locked balance)\n     */\n    function getFullBalances()\n        public\n        view\n        returns (SecurityTokenBalancesLibrary.Balance[] memory value)\n    {\n        return securityTokenBalances.getFullBalances();\n    }\n\n    /**\n     * @dev Returns balance of `owner` as a Balance structures(including total and locked balance)\n     */\n    function getFullBalance(address owner)\n        public\n        view\n        returns (SecurityTokenBalancesLibrary.Balance memory value)\n    {\n        return securityTokenBalances.getFullBalance(owner);\n    }\n\n    /**\n     * @dev Returns balance of `owner` (this is the total balance, which includes locked tokens)\n     */\n    function getBalance(address _address) public view returns (uint256 value) {\n        return securityTokenBalances.getBalance(_address);\n    }\n\n    /**\n     * @dev Allows to update the STR's URL\n     * NB : only the product's registrar can call this method\n     */\n    function setStrUrl(string memory _strUrl) public onlyRegistrar {\n        strUrl = _strUrl;\n    }\n\n    // ISettlement\n    /**\n     * @dev Initiate a Subscription Settlement Transaction (counterparty buys product on primary market from the product's issuer)\n     * and sends the corresponding `SubscriptionInitiated` event\n     * The tokens are locked waiting for the cash leg to settle (see functions confirmPaymentReceived/confirmPaymentTransferred)\n     * NB : only the product's registrar can call this method\n     * NB : the call fails if the product has previously been redeemed\n     */\n    function initiateSubscription(\n        SettlementRepositoryLibrary.PartialSettlementTransaction\n            memory partialSettlementTransaction\n    ) public override onlyRegistrar onlyNotRedeemedProduct {\n        SettlementWorkflowLibrary.initiateSubscription(\n            settlementTransactionRepository,\n            securityTokenBalances,\n            partialSettlementTransaction\n        );\n        state = ProductState.Running;\n        emit SubscriptionInitiated(partialSettlementTransaction.txId);\n    }\n\n    /**\n     * @dev Initiate a Trade Settlement Transaction (one counterparty buys, the other sells)\n     * and sends the corresponding `TradeInitiated` event\n     * The tokens are locked waiting for the cash leg to settle (see functions confirmPaymentReceived/confirmPaymentTransferred)\n     * NB : only the product's registrar can call this method\n     * NB : the call fails if the product has previously been redeemed\n     */\n    function initiateTrade(\n        SettlementRepositoryLibrary.PartialSettlementTransaction\n            memory partialSettlementTransaction\n    ) public override onlyRegistrar onlyNotRedeemedProduct {\n        SettlementWorkflowLibrary.initiateTrade(\n            settlementTransactionRepository,\n            securityTokenBalances,\n            partialSettlementTransaction\n        );\n        state = ProductState.Running;\n        emit TradeInitiated(partialSettlementTransaction.txId);\n    }\n\n    /**\n     * @dev Execute unilateral Transfer Settlement Transactions \n     * and sends the corresponding `TransferExecuted` event\n     * As there is no cash leg to settle, the tokens are transfered right away and the Settlement Transaction is marked as Settled\n     * NB : only the product's registrar can call this method\n     */\n    function executeTransfer(\n        SettlementRepositoryLibrary.PartialSettlementTransaction\n            memory partialSettlementTransaction\n    ) external override onlyRegistrar onlyNotRedeemedProduct{\n        SettlementWorkflowLibrary.executeTransfer(\n            settlementTransactionRepository,\n            securityTokenBalances,\n            partialSettlementTransaction\n        );\n        settlementTransactionRepository.setSettlementTransactionStatus(\n            partialSettlementTransaction.txId,\n            SettlementRepositoryLibrary.SettlementTransactionStatus.Settled\n        );\n        emit TransferExecuted(partialSettlementTransaction.txId);\n    }\n\n    /**\n     * @dev Initiate a Redemption Settlement Transactions (issuer redeems product to all holders and gets the tokens back)\n     * and sends the corresponding `RedemptionInitiated` event\n     * The tokens are locked waiting for the cash leg to settle (see functions confirmPaymentReceived/confirmPaymentTransferred)\n     * NB : only the product's registrar can call this method\n     * NB : the call fails if the product has previously been redeemed\n     * NB : extended data in the form of JSON string can be associated with this operation\n     */\n    function initiateRedemption(\n        SettlementRepositoryLibrary.PartialSettlementTransaction[]\n            memory partialSettlementTransactions,\n        string memory extendedData\n    ) public override onlyRegistrar onlyNotRedeemedProduct {\n        uint256[] memory ids = new uint256[](\n            partialSettlementTransactions.length\n        );\n\n        SettlementWorkflowLibrary.initiateRedemption(\n            settlementTransactionRepository,\n            securityTokenBalances,\n            partialSettlementTransactions\n        );\n\n        uint256 operationId = partialSettlementTransactions[0].operationId;\n        operationExtendedDataJson[operationId] = extendedData;\n\n        for (uint256 i = 0; i < partialSettlementTransactions.length; i++) {\n            ids[i] = partialSettlementTransactions[i].txId;\n        }\n        state = ProductState.Redeemed;\n        emit RedemptionInitiated(ids);\n    }\n\n    /**\n     * @dev Initiate a Coupon Settlement Transactions (issuer pays coupon to all holders)\n     * and sends the corresponding `CouponInitiated` event\n     * NB: the tokens are not locked for this kind of transaction\n     * NB : only the product's registrar can call this method\n     * NB : the call fails if the product has previously been redeemed\n     * NB : extended data in the form of JSON string can be associated with this operation\n     */\n    function initiateCoupon(\n        SettlementRepositoryLibrary.PartialSettlementTransaction[]\n            memory partialSettlementTransactions,\n        string memory extendedData\n    ) public override onlyRegistrar onlyNotRedeemedProduct {\n        uint256[] memory ids = new uint256[](\n            partialSettlementTransactions.length\n        );\n\n        SettlementWorkflowLibrary.initiateCoupon(\n            settlementTransactionRepository,\n            partialSettlementTransactions\n        );\n\n        uint256 operationId = partialSettlementTransactions[0].operationId;\n        operationExtendedDataJson[operationId] = extendedData;\n\n        for (uint256 i = 0; i < partialSettlementTransactions.length; i++) {\n            ids[i] = partialSettlementTransactions[i].txId;\n        }\n        emit CouponInitiated(ids);\n    }\n\n    /**\n     * @dev Confirms that the payment for Settlement Transaction with id `_settlementTransactionId` was received\n     * and sends the corresponding `PaymentReceived` event\n     * The tokens are actually transferred to the recipient (except for Coupon where no token is exchanged)\n     * If the Settlement Transaction is part of a Redemption operation, the tokens are burnt right after being transferred back to the issuer.\n     * The Settlement Transaction state moves to Processed\n     * The call fails if the Settlement Transaction with id `_settlementTransactionId` is not found in the repository\n     * The call fails if the Settlement Transaction is not in the Acknowledged state.\n     * NB : only the product's settlement agent can call this method\n     */\n    function confirmPaymentReceived(uint256 _settlementTransactionId)\n        external\n        override\n        settlerOnly\n    {\n        SettlementRepositoryLibrary.SettlementTransaction\n            memory settlementTransaction = settlementTransactionRepository\n                .getSettlementTransactionById(_settlementTransactionId);\n        if (\n            settlementTransaction.operationType ==\n            SettlementRepositoryLibrary.OperationType.Undefined\n        ) revert InvalidOperationType();\n        _handleConfirmPaymentReceived(_settlementTransactionId);\n    }\n\n    /**\n     * @dev Internal method that does the actual job of `confirmPaymentReceived`\n     */\n    function _handleConfirmPaymentReceived(uint256 settlementTransactionId)\n        internal\n    {\n        SettlementRepositoryLibrary.SettlementTransaction\n            memory st = settlementTransactionRepository\n                .getSettlementTransactionById(settlementTransactionId);\n\n        if (\n            st.status !=\n            SettlementRepositoryLibrary.SettlementTransactionStatus.Acknowledged\n        ) revert SettlementTransactionNotInAcknowledgedState();\n\n        if (\n            st.operationType != SettlementRepositoryLibrary.OperationType.Coupon\n        ) {\n            securityTokenBalances.transferLocked(\n                st.deliverySenderAccountNumber,\n                st.deliveryReceiverAccountNumber,\n                st.deliveryQuantity\n            );\n        }\n\n        if (\n            st.operationType ==\n            SettlementRepositoryLibrary.OperationType.Redemption\n        ) {\n            internalBurn(\n                st.deliveryReceiverAccountNumber,\n                st.deliveryQuantity\n            );\n        }\n\n        settlementTransactionRepository.setSettlementTransactionStatus(\n            settlementTransactionId,\n            SettlementRepositoryLibrary.SettlementTransactionStatus.Processed\n        );\n        emit PaymentReceived(settlementTransactionId, st.operationType);\n    }\n\n    /**\n     * @dev Confirms that the payment for Settlement Transaction with id `_settlementTransactionId` was transferred to the recipient\n     * and sends the corresponding `PaymentTransferred` event\n     * The Settlement Transaction state moves to Settled\n     * The call fails if the Settlement Transaction with id `_settlementTransactionId` is not found in the repository\n     * The call fails if the Settlement Transaction is not in the Processed state.\n     * NB : only the product's settlement agent can call this method\n     */\n    function confirmPaymentTransferred(uint256 _settlementTransactionId)\n        external\n        override\n        settlerOnly\n    {\n        _handleConfirmPaymentTransferred(_settlementTransactionId);\n    }\n\n    /**\n     * @dev Internal method that does the actual job of `confirmPaymentTransferred`\n     */\n    function _handleConfirmPaymentTransferred(uint256 _settlementTransactionId)\n        internal\n    {\n        SettlementRepositoryLibrary.SettlementTransaction\n            memory st = settlementTransactionRepository\n                .getSettlementTransactionById(_settlementTransactionId);\n        if (\n            st.operationType ==\n            SettlementRepositoryLibrary.OperationType.Undefined\n        ) revert InvalidOperationType();\n        if (\n            st.status !=\n            SettlementRepositoryLibrary.SettlementTransactionStatus.Processed\n        ) revert SettlementTransactionNotInProcessedState();\n\n        settlementTransactionRepository.setSettlementTransactionStatus(\n            _settlementTransactionId,\n            SettlementRepositoryLibrary.SettlementTransactionStatus.Settled\n        );\n\n        emit PaymentTransferred(_settlementTransactionId, st.operationType);\n    }\n\n    \n    /**\n     * @dev Returns the details of Settlement Transaction with id `_settlementTransactionId`\n     */\n    function getSettlementTransaction(uint256 _settlementTransactionId)\n        external\n        view\n        returns (SettlementRepositoryLibrary.SettlementTransaction memory)\n    {\n        return\n            settlementTransactionRepository.getSettlementTransactionById(\n                _settlementTransactionId\n            );\n    }\n\n    /**\n     * @dev Cancels ongoing settlement transaction with id `settlementTransactionId`\n     * and sends the corresponding `SettlementTransactionCancelled` event\n     * Unlocks tokens\n     * Fails if the settlement transaction is not in the Acknowledged state.\n     * NB : only the product's registrar can call this method     *  \n     */\n    function cancelSettlementTransaction(uint256 settlementTransactionId)\n        public\n        override\n        onlyRegistrar\n    {\n        SettlementWorkflowLibrary.cancelSettlementTransaction(\n            settlementTransactionRepository,\n            securityTokenBalances,\n            settlementTransactionId\n        );\n\n        emit SettlementTransactionCancelled(settlementTransactionId);\n    }\n\n    /**\n     * @dev Internal function that recomputes the totalSupply when it changes (mint/burn)\n     * \n     */\n    function recomputeTotalSupply() internal {\n        seriesOutstandingNominalAmountCent =\n            seriesNominalAmountCent -\n            seriesRedeemedAmountCent;\n        totalSupply = seriesOutstandingNominalAmountCent / denominationCent;\n    }\n\n    /**\n     * @dev Internal function that adds a new tranche and updates aggregated amounts accordingly.\n     * \n     */\n    function internalCreateTranche(Tranche memory newTranche) internal {\n        tranches.push(newTranche);\n        seriesNominalAmountCent += newTranche.nominalAmountCent;\n        recomputeTotalSupply();\n    }\n\n    /**\n     * @dev Issue a new tranche of tokens for the same product\n     * Mints the corresponding number of tokens\n     * The product's totalSupply is updated accordingly.\n     * NB : only the product's registrar can call this method\n     */\n    function createTranche(Tranche memory newTranche) public onlyRegistrar {\n        securityTokenBalances.mint(issuer.account, newTranche.nominalAmountCent / denominationCent);\n        internalCreateTranche(newTranche);\n    }\n}\n"
      },
      "contracts/registry/interfaces/IProductRegistry.sol": {
        "content": "pragma solidity 0.8.17;\n\n/**\n * @title The product registry\n * @dev The registry listing all financial products handled by a given registrar(the owner of the registry).\n */\ninterface IProductRegistry {\n    /** \n     * @dev Add a new product to the registry\n     * @param name The name of the product\n     * @param isinCode The ISIN code of the product\n     * @param productAddress The adress of the product's contract\n     */\n    function listProduct(\n        string calldata name,\n        string calldata isinCode,\n        address productAddress\n    ) external;\n\n    /** \n     * @dev Get the address of a product by providing its name\n     * @param name The name of the product\n     * @return product The found product's contract address\n     */\n    function getProductByName(string calldata name)\n        external\n        view\n        returns (address product);\n\n    /**\n     * @dev Get the address of a product by providing its ISIN code\n     * @param isin The ISIN code of the product\n     * @return product The found product's contract address\n     */\n    function getProductByIsinCode(string calldata isin)\n        external\n        view\n        returns (address product);\n\n    /**\n     * @dev Get all products' addresses at once\n     * @return product An array of all producs' addresses\n     */\n    function getAllProducts() external view returns (address[] memory product);\n\n    /// @dev Remove a product from the registry\n    /// @param isin The ISIN code of the product\n    function unListProduct(string calldata isin) external;\n}\n"
      },
      "contracts/utils/Ownable.sol": {
        "content": "pragma solidity 0.8.17;\n\n/**\n * @dev Used when a function reserved to the registrar is called by some other account\n */\nimport { UnauthorizedRegistrar, ZeroAddressCheck } from \"./ProductErrorReporter.sol\";\n\n/**\n * @dev The Ownable contract handles an owner, called the registrar, and a modifier used to protect methods reserved to the registrar.\n */\nabstract contract Ownable {\n    address private registrarAgent;\n\n    /**\n     * @dev `_registrar` will be the owner of the contract\n     */\n    constructor(address _registrar) {\n        if(_registrar == address(0))\n            revert ZeroAddressCheck();\n        registrarAgent = _registrar;\n    }\n    /**\n     * @dev Throws an error if the caller is not the contract's owner(a.k.a. registrar)\n     */\n    modifier onlyRegistrar() {\n        if (msg.sender != registrarAgent) revert UnauthorizedRegistrar();\n        _;\n    }\n}\n"
      },
      "contracts/utils/ProductErrorReporter.sol": {
        "content": "pragma solidity 0.8.17;\n\nerror TotalSupplyNotMatchTotalInitialSupply();\n\nerror PayingAgentNotSet();\nerror GuarantorNotSet();\n\nerror UnauthorizedIssuer();\nerror UnauthorizedSettler();\n\nerror ProductIsFullyRedeemed();\n\nerror SettlementTransactionNotInProcessedState();\nerror SettlementTransactionNotInAcknowledgedState();\nerror SettlementTransactionAlreadyExists();\nerror InvalidSettlementTransactionStatus();\nerror DeliveryReceiverAccountNumberNotMatchTokenIssuer();\n\nerror InvalidOperationType();\n\nerror InvalidTrustedToken();\nerror NotSupportedTrustedToken();\n\nerror InsufficientDisposableBalance();\nerror InsufficientBalance();\nerror InsufficientLockedBalance();\n\nerror TransferRequestNotFound();\nerror InvalidTransferRequestStatus();\n\nerror ZeroAddressCheck();\nerror OwnerHasOngoingApprove();\nerror ApproveDoesNotExists();\nerror InvalidApproveStatus();\nerror InsufficientAllowance();\nerror UnauthorizedRegistrar();\n\nerror ZeroValueCheck();\nerror InvalidReceiver();\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 1000
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "metadata": {
        "useLiteralContent": true
      },
      "libraries": {
        "contracts/product/libraries/ApproveAdapterLibrary.sol": {
          "ApproveAdapterLibrary": "0x783c952feeb792aa63908c9b85c83ab46b0bf2fd"
        },
        "contracts/product/libraries/SecurityTokenBalancesLibrary.sol": {
          "SecurityTokenBalancesLibrary": "0xe320252f58d744a09584c79ac4f3629fca3798cb"
        },
        "contracts/product/libraries/SettlementRepositoryLibrary.sol": {
          "SettlementRepositoryLibrary": "0xc21b38fffc1bbe9cd95e7d9be962ad0dc5593e16"
        },
        "contracts/product/libraries/SettlementWorkflowLibrary.sol": {
          "SettlementWorkflowLibrary": "0x7dac013c0caa344f7086ae3f06419be9208d6e89"
        },
        "contracts/product/libraries/TransferAdapterLibrary.sol": {
          "TransferAdapterLibrary": "0x128d1485f8feb919100fcddd0571df2975010acd"
        }
      }
    }
  }}