POL Price: $0.237698 (+3.39%)
Gas: 30 GWei
 

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Redeem Position ...455230542023-07-26 2:11:06610 days ago1690337466IN
0xFf7d5243...CcA609148
0 POL0.0071506573.02245106
Redeem Position ...455230372023-07-26 2:10:26610 days ago1690337426IN
0xFf7d5243...CcA609148
0 POL0.0074970269.961072
Redeem Position ...452022582023-07-17 21:36:53618 days ago1689629813IN
0xFf7d5243...CcA609148
0 POL0.01091313101.83966429
Redeem Position ...441265572023-06-20 10:45:24645 days ago1687257924IN
0xFf7d5243...CcA609148
0 POL0.01719293213.47603144
Redeem Position ...441265422023-06-20 10:44:40645 days ago1687257880IN
0xFf7d5243...CcA609148
0 POL0.02101489169.12038401
Redeem Position ...440822702023-06-19 7:33:36646 days ago1687160016IN
0xFf7d5243...CcA609148
0 POL0.01593999162.77919702
Redeem Position ...440822272023-06-19 7:32:06646 days ago1687159926IN
0xFf7d5243...CcA609148
0 POL0.0239575192.80142058
Redeem Position ...440465822023-06-18 9:23:59647 days ago1687080239IN
0xFf7d5243...CcA609148
0 POL0.02038245190.1845221
Redeem Position ...440204672023-06-17 16:49:31648 days ago1687020571IN
0xFf7d5243...CcA609148
0 POL0.0194984156.91616588
Redeem Position ...440196402023-06-17 16:17:59648 days ago1687018679IN
0xFf7d5243...CcA609148
0 POL0.0214763172.81689821
Redeem Position ...440144982023-06-17 12:54:29648 days ago1687006469IN
0xFf7d5243...CcA609148
0 POL0.01949334181.88844177
Redeem Position ...440144652023-06-17 12:53:19648 days ago1687006399IN
0xFf7d5243...CcA609148
0 POL0.02145159172.61811188
Redeem Position ...440132182023-06-17 12:04:12648 days ago1687003452IN
0xFf7d5243...CcA609148
0 POL0.02679250
Redeem Position ...440017322023-06-17 4:48:32648 days ago1686977312IN
0xFf7d5243...CcA609148
0 POL0.01583309161.68756395
Redeem Position ...440017152023-06-17 4:47:56648 days ago1686977276IN
0xFf7d5243...CcA609148
0 POL0.01693546158.02138977
Redeem Position ...439998762023-06-17 3:34:01649 days ago1686972841IN
0xFf7d5243...CcA609148
0 POL0.01400056173.83794525
Redeem Position ...439998312023-06-17 3:31:55649 days ago1686972715IN
0xFf7d5243...CcA609148
0 POL0.0160645149.91142348
Redeem Position ...439949612023-06-17 0:15:21649 days ago1686960921IN
0xFf7d5243...CcA609148
0 POL0.01491143152.27559198
Redeem Position ...439949532023-06-17 0:14:59649 days ago1686960899IN
0xFf7d5243...CcA609148
0 POL0.02054727165.3411091
Redeem Position ...439836052023-06-16 16:42:53649 days ago1686933773IN
0xFf7d5243...CcA609148
0 POL0.01753891163.68864209
Redeem Position ...439811172023-06-16 15:05:32649 days ago1686927932IN
0xFf7d5243...CcA609148
0 POL0.03625789338.35287937
Redeem Position ...439794042023-06-16 14:03:02649 days ago1686924182IN
0xFf7d5243...CcA609148
0 POL0.03569461287.28521777
Redeem Position ...439789852023-06-16 13:48:10649 days ago1686923290IN
0xFf7d5243...CcA609148
0 POL0.03251629303.43690364
Redeem Position ...439682052023-06-16 7:08:25649 days ago1686899305IN
0xFf7d5243...CcA609148
0 POL0.02195353170.10329919
Redeem Position ...439680872023-06-16 7:04:15649 days ago1686899055IN
0xFf7d5243...CcA609148
0 POL0.01708195152.58829072
View all transactions

Parent Transaction Hash Block From To
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Diamond

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 40 : Diamond.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.17;

/**
 * @author DIVA protocol team.
 * @title A protocol to create and settle derivative assets.
 * @dev DIVA protocol is implemented using the Diamond Standard
 * (EIP-2535: https://eips.ethereum.org/EIPS/eip-2535).
 * Contract issues directionally reversed long and short positions
 * (represented as ERC20 tokens) upon collateral deposit. Combined those
 * assets represent a claim on the collateral held in the contract. If held
 * in isolation, they expose the user to the up- or downside of the reference
 * asset. Contract holds all the collateral backing all position tokens in
 * existence.
 * Users can withdraw collateral by i) submitting both short and long tokens
 * in equal proportions or by redeeming them separately after the final
 * reference asset value and hence the payout for long and short position
 * tokens has been determined.
 * Contract is the owner of all position tokens and hence the only account
 * authorized to execute the `mint` and `burn` functions inside
 * `PositionToken` contract.
 */

import {LibDiamond} from "./libraries/LibDiamond.sol";
import {LibDiamondStorage} from "./libraries/LibDiamondStorage.sol";
import {LibDIVAStorage} from "./libraries/LibDIVAStorage.sol";
import {LibEIP712} from "./libraries/LibEIP712.sol";
import {LibEIP712Storage} from "./libraries/LibEIP712Storage.sol";
import {IClaim} from "./interfaces/IClaim.sol";
import {IDiamondCut} from "./interfaces/IDiamondCut.sol";
import {IDiamondLoupe} from "./interfaces/IDiamondLoupe.sol";
import {IEIP712Add} from "./interfaces/IEIP712Add.sol";
import {IEIP712Cancel} from "./interfaces/IEIP712Cancel.sol";
import {IEIP712Create} from "./interfaces/IEIP712Create.sol";
import {IEIP712Remove} from "./interfaces/IEIP712Remove.sol";
import {IERC165} from "./interfaces/IERC165.sol";
import {IGetter} from "./interfaces/IGetter.sol";
import {IGovernance} from "./interfaces/IGovernance.sol";
import {ILiquidity} from "./interfaces/ILiquidity.sol";
import {IDIVAOwnershipShared} from "./interfaces/IDIVAOwnershipShared.sol";
import {IPermissionedPositionToken} from "./interfaces/IPermissionedPositionToken.sol";
import {IPool} from "./interfaces/IPool.sol";
import {IPositionToken} from "./interfaces/IPositionToken.sol";
import {IPositionTokenFactory} from "./interfaces/IPositionTokenFactory.sol";
import {ISettlement} from "./interfaces/ISettlement.sol";


// Thrown if no function exists for function called
error FunctionNotFound(bytes4 _functionSelector);
// Thrown if zero address is provided as ownershipContract
error ZeroOwnershipContractAddress();
// Thrown if zero address is provided as fallback data provider
error ZeroFallbackDataProviderAddress();
// Thrown if zero address is provided as treasury
error ZeroTreasuryAddress();
// Thrown if zero address is provided as position token factory contract
error ZeroPositionTokenFactoryAddress();

contract Diamond {
    /**
     * @dev Deploy DiamondCutFacet before deploying the diamond
     */
    constructor(
        address _ownershipContract,
        address _fallbackDataProvider,
        address _diamondCutFacet,
        address _treasury,
        address _positionTokenFactory
    ) payable {
        if (_ownershipContract == address(0)) revert ZeroOwnershipContractAddress();
        if (_fallbackDataProvider == address(0)) revert ZeroFallbackDataProviderAddress();
        if (_treasury == address(0)) revert ZeroTreasuryAddress();
        if (_positionTokenFactory == address(0)) revert ZeroPositionTokenFactoryAddress();

        // Add the diamondCut external function from the diamondCutFacet
        IDiamondCut.FacetCut[] memory cut = new IDiamondCut.FacetCut[](1);
        bytes4[] memory functionSelectors = new bytes4[](1);
        functionSelectors[0] = IDiamondCut.diamondCut.selector;
        cut[0] = IDiamondCut.FacetCut({
            facetAddress: _diamondCutFacet,
            action: IDiamondCut.FacetCutAction.Add,
            functionSelectors: functionSelectors
        });
        LibDiamond._diamondCut(cut, address(0), "");

        // ************************************************************************
        // Initialization of DIVA protocol variables (updateable by contract owner)
        // ************************************************************************
        LibDiamondStorage.DiamondStorage storage ds = LibDiamondStorage
            ._diamondStorage();
        LibDIVAStorage.GovernanceStorage storage gs = LibDIVAStorage
            ._governanceStorage();
        LibDIVAStorage.PoolStorage storage ps = LibDIVAStorage
            ._poolStorage();
        LibEIP712Storage.EIP712Storage storage es = LibEIP712Storage
            ._eip712Storage();        

        // Initialize fee parameters. Ensure that values are 0 or within the
        // bandwidths specified in `_isValidFee`.
        gs.fees.push(LibDIVAStorage.Fees({
            startTime: block.timestamp,
            protocolFee: 2500000000000000,  // 0.25%
            settlementFee: 500000000000000  // 0.05%
        }));

        // Initialize settlement period parameters. Ensure that values are between
        // 3 and 15 days (as specified in `_isValidPeriod`).
        gs.settlementPeriods.push(LibDIVAStorage.SettlementPeriods({
            startTime: block.timestamp,
            submissionPeriod: 7 days,
            challengePeriod: 3 days,
            reviewPeriod: 5 days,
            fallbackSubmissionPeriod: 10 days
        }));

        // Initialize treasury and fallback data provider address.
        // `previousFallbackDataProvider` and `previousTreasury` are initialized to
        // zero address at contract deployment.
        gs.startTimeTreasury = block.timestamp;
        gs.treasury = _treasury;
        gs.startTimeFallbackDataProvider = block.timestamp;
        gs.fallbackDataProvider = _fallbackDataProvider;        

        // Store positionTokenFactory address
        ps.positionTokenFactory = _positionTokenFactory;

        // Initialize EIP712 domain separator and store chain id to protect against replay attacks
        // in case of a fork. This approach is inspired by openzeppelin's EIP712 implementation:
        // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/EIP712.sol
        // Note that the address(this) check was consciously removed as not deemed relevant for our case.
        es.EIP712_DOMAIN_SEPARATOR = LibEIP712._getDomainHash();
        es.CACHED_CHAIN_ID = LibEIP712._chainId();

        // Set owner contract address
        ds.ownershipContract = _ownershipContract;

        // Adding ERC165 data
        ds.supportedInterfaces[type(IClaim).interfaceId] = true;
        ds.supportedInterfaces[type(IDiamondCut).interfaceId] = true;
        ds.supportedInterfaces[type(IDiamondLoupe).interfaceId] = true;
        ds.supportedInterfaces[type(IEIP712Add).interfaceId] = true;
        ds.supportedInterfaces[type(IEIP712Cancel).interfaceId] = true;
        ds.supportedInterfaces[type(IEIP712Create).interfaceId] = true;
        ds.supportedInterfaces[type(IEIP712Remove).interfaceId] = true;
        ds.supportedInterfaces[type(IERC165).interfaceId] = true;
        ds.supportedInterfaces[type(IGetter).interfaceId] = true;
        ds.supportedInterfaces[type(IGovernance).interfaceId] = true;
        ds.supportedInterfaces[type(ILiquidity).interfaceId] = true;
        ds.supportedInterfaces[type(IDIVAOwnershipShared).interfaceId] = true;
        ds.supportedInterfaces[type(IPermissionedPositionToken).interfaceId] = true;
        ds.supportedInterfaces[type(IPool).interfaceId] = true;
        ds.supportedInterfaces[type(IPositionToken).interfaceId] = true;
        ds.supportedInterfaces[type(IPositionTokenFactory).interfaceId] = true;
        ds.supportedInterfaces[type(ISettlement).interfaceId] = true;
    }

    // Find facet for function that is called and execute the
    // function if a facet is found and return any value.
    fallback() external payable {
        LibDiamondStorage.DiamondStorage storage ds;

        bytes32 position = LibDiamondStorage.DIAMOND_STORAGE_POSITION;
        assembly {
            ds.slot := position
        }

        address facet = ds.selectorToFacetAndPosition[msg.sig].facetAddress;
        if (facet == address(0)) revert FunctionNotFound(msg.sig);

        assembly {
            // copy incoming call data
            calldatacopy(0, 0, calldatasize())

            // forward call to logic contract (facet)
            let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0)

            // retrieve return data
            returndatacopy(0, 0, returndatasize())

            // forward return data back to caller
            switch result
            case 0 {
                revert(0, returndatasize())
            }
            default {
                return(0, returndatasize())
            }
        }
    }

    receive() external payable {}
}

File 2 of 40 : LibDiamond.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.17;

import {IDiamondCut} from "../interfaces/IDiamondCut.sol";
import {LibDiamondStorage} from "./LibDiamondStorage.sol";

error NoSelectorsProvidedForFacetForCut(address _facetAddress);
error CannotAddSelectorsToZeroAddress(bytes4[] _selectors);
error NoBytecodeAtAddress(address _contractAddress, string _message);
error IncorrectFacetCutAction(uint8 _action);
error CannotAddFunctionToDiamondThatAlreadyExists(bytes4 _selector);
error CannotReplaceFunctionsFromFacetWithZeroAddress(bytes4[] _selectors);
error CannotReplaceFunctionWithTheSameFunctionFromTheSameFacet(
    bytes4 _selector
);
error RemoveFacetAddressMustBeZeroAddress(address _facetAddress);
error CannotRemoveFunctionThatDoesNotExist(bytes4 _selector);
error CannotRemoveImmutableFunction(bytes4 _selector);
error InitializationFunctionReverted(
    address _initializationContractAddress,
    bytes _calldata
);
error ZeroInitAddressNonEmptyCalldata(
    address _initializationContractAddress,
    bytes _calldata
);
error EmptyCalldataNonZeroInitAddress(
    address _initializationContractAddress,
    bytes _calldata
);

library LibDiamond {
    event DiamondCut(
        IDiamondCut.FacetCut[] _facetCut,
        address _init,
        bytes _calldata
    );

    // Internal function version of diamondCut
    function _diamondCut(
        IDiamondCut.FacetCut[] memory _facetCut,
        address _init,
        bytes memory _calldata
    ) internal {
        for (uint256 facetIndex; facetIndex < _facetCut.length; facetIndex++) {
            bytes4[] memory functionSelectors = _facetCut[facetIndex]
                .functionSelectors;
            address facetAddress = _facetCut[facetIndex].facetAddress;
            if (functionSelectors.length == 0) {
                revert NoSelectorsProvidedForFacetForCut(facetAddress);
            }
            IDiamondCut.FacetCutAction action = _facetCut[facetIndex].action;
            if (action == IDiamondCut.FacetCutAction.Add) {
                _addFunctions(facetAddress, functionSelectors);
            } else if (action == IDiamondCut.FacetCutAction.Replace) {
                _replaceFunctions(facetAddress, functionSelectors);
            } else if (action == IDiamondCut.FacetCutAction.Remove) {
                _removeFunctions(facetAddress, functionSelectors);
            } else {
                revert IncorrectFacetCutAction(uint8(action));
            }
        }
        emit DiamondCut(_facetCut, _init, _calldata);
        _initializeDiamondCut(_init, _calldata);
    }

    function _addFunctions(
        address _facetAddress,
        bytes4[] memory _functionSelectors
    ) internal {
        if (_functionSelectors.length == 0) {
            revert NoSelectorsProvidedForFacetForCut(_facetAddress);
        }
        LibDiamondStorage.DiamondStorage storage ds = LibDiamondStorage
            ._diamondStorage();
        if (_facetAddress == address(0)) {
            revert CannotAddSelectorsToZeroAddress(_functionSelectors);
        }
        uint96 selectorPosition = uint96(
            ds.facetFunctionSelectors[_facetAddress].functionSelectors.length
        );
        // add new facet address if it does not exist
        if (selectorPosition == 0) {
            _addFacet(ds, _facetAddress);
        }
        for (
            uint256 selectorIndex;
            selectorIndex < _functionSelectors.length;
            selectorIndex++
        ) {
            bytes4 selector = _functionSelectors[selectorIndex];
            address oldFacetAddress = ds
                .selectorToFacetAndPosition[selector]
                .facetAddress;
            if (oldFacetAddress != address(0)) {
                revert CannotAddFunctionToDiamondThatAlreadyExists(selector);
            }
            _addFunction(ds, selector, selectorPosition, _facetAddress);
            selectorPosition++;
        }
    }

    // Replacing a function means removing a function and adding a new function
    // from a different facet but with the same function signature as the one
    // removed. In other words, replacing a function in a diamond just means
    // changing the facet address where it comes from.
    function _replaceFunctions(
        address _facetAddress,
        bytes4[] memory _functionSelectors
    ) internal {
        if (_functionSelectors.length == 0) {
            revert NoSelectorsProvidedForFacetForCut(_facetAddress);
        }
        LibDiamondStorage.DiamondStorage storage ds = LibDiamondStorage
            ._diamondStorage();
        if (_facetAddress == address(0)) {
            revert CannotReplaceFunctionsFromFacetWithZeroAddress(
                _functionSelectors
            );
        }
        uint96 selectorPosition = uint96(
            ds.facetFunctionSelectors[_facetAddress].functionSelectors.length
        );
        // add new facet address if it does not exist
        if (selectorPosition == 0) {
            _addFacet(ds, _facetAddress);
        }
        for (
            uint256 selectorIndex;
            selectorIndex < _functionSelectors.length;
            selectorIndex++
        ) {
            bytes4 selector = _functionSelectors[selectorIndex];
            address oldFacetAddress = ds
                .selectorToFacetAndPosition[selector]
                .facetAddress;
            if (oldFacetAddress == _facetAddress) {
                revert CannotReplaceFunctionWithTheSameFunctionFromTheSameFacet(
                    selector
                );
            }
            _removeFunction(ds, oldFacetAddress, selector);
            _addFunction(ds, selector, selectorPosition, _facetAddress);
            selectorPosition++;
        }
    }

    function _removeFunctions(
        address _facetAddress,
        bytes4[] memory _functionSelectors
    ) internal {
        if (_functionSelectors.length == 0) {
            revert NoSelectorsProvidedForFacetForCut(_facetAddress);
        }
        LibDiamondStorage.DiamondStorage storage ds = LibDiamondStorage
            ._diamondStorage();
        // if function does not exist then do nothing and return
        if (_facetAddress != address(0)) {
            revert RemoveFacetAddressMustBeZeroAddress(_facetAddress);
        }
        for (
            uint256 selectorIndex;
            selectorIndex < _functionSelectors.length;
            selectorIndex++
        ) {
            bytes4 selector = _functionSelectors[selectorIndex];
            address oldFacetAddress = ds
                .selectorToFacetAndPosition[selector]
                .facetAddress;
            _removeFunction(ds, oldFacetAddress, selector);
        }
    }

    function _addFacet(
        LibDiamondStorage.DiamondStorage storage ds,
        address _facetAddress
    ) internal {
        _enforceHasContractCode(
            _facetAddress,
            "LibDiamondCut: New facet has no code"
        );
        ds.facetFunctionSelectors[_facetAddress].facetAddressPosition = ds
            .facetAddresses
            .length;
        ds.facetAddresses.push(_facetAddress);
    }

    function _addFunction(
        LibDiamondStorage.DiamondStorage storage ds,
        bytes4 _selector,
        uint96 _selectorPosition,
        address _facetAddress
    ) internal {
        ds
            .selectorToFacetAndPosition[_selector]
            .functionSelectorPosition = _selectorPosition;
        ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(
            _selector
        );
        ds.selectorToFacetAndPosition[_selector].facetAddress = _facetAddress;
    }

    function _removeFunction(
        LibDiamondStorage.DiamondStorage storage ds,
        address _facetAddress,
        bytes4 _selector
    ) internal {
        if (_facetAddress == address(0)) {
            revert CannotRemoveFunctionThatDoesNotExist(_selector);
        }
        // an immutable function is a function defined directly in a diamond
        if (_facetAddress == address(this)) {
            revert CannotRemoveImmutableFunction(_selector);
        }
        // replace selector with last selector, then delete last selector
        uint256 selectorPosition = ds
            .selectorToFacetAndPosition[_selector]
            .functionSelectorPosition;
        uint256 lastSelectorPosition = ds
            .facetFunctionSelectors[_facetAddress]
            .functionSelectors
            .length - 1;
        // if not the same then replace _selector with lastSelector
        if (selectorPosition != lastSelectorPosition) {
            bytes4 lastSelector = ds
                .facetFunctionSelectors[_facetAddress]
                .functionSelectors[lastSelectorPosition];
            ds.facetFunctionSelectors[_facetAddress].functionSelectors[
                    selectorPosition
                ] = lastSelector;
            ds
                .selectorToFacetAndPosition[lastSelector]
                .functionSelectorPosition = uint96(selectorPosition);
        }
        // delete the last selector
        ds.facetFunctionSelectors[_facetAddress].functionSelectors.pop();
        delete ds.selectorToFacetAndPosition[_selector];

        // if no more selectors for facet address then delete the facet address
        if (lastSelectorPosition == 0) {
            // replace facet address with last facet address and delete last facet address
            uint256 lastFacetAddressPosition = ds.facetAddresses.length - 1;
            uint256 facetAddressPosition = ds
                .facetFunctionSelectors[_facetAddress]
                .facetAddressPosition;
            if (facetAddressPosition != lastFacetAddressPosition) {
                address lastFacetAddress = ds.facetAddresses[
                    lastFacetAddressPosition
                ];
                ds.facetAddresses[facetAddressPosition] = lastFacetAddress;
                ds
                    .facetFunctionSelectors[lastFacetAddress]
                    .facetAddressPosition = facetAddressPosition;
            }
            ds.facetAddresses.pop();
            delete ds
                .facetFunctionSelectors[_facetAddress]
                .facetAddressPosition;
        }
    }

    function _initializeDiamondCut(address _init, bytes memory _calldata)
        internal
    {
        if (_init == address(0)) {
            if (_calldata.length > 0) {
                revert ZeroInitAddressNonEmptyCalldata(_init, _calldata);
            }
        } else {
            if (_calldata.length == 0) {
                revert EmptyCalldataNonZeroInitAddress(_init, _calldata);
            }
            if (_init != address(this)) {
                _enforceHasContractCode(
                    _init,
                    "LibDiamondCut: _init address has no code"
                );
            }
            (bool success, bytes memory error) = _init.delegatecall(_calldata);
            if (!success) {
                if (error.length > 0) {
                    // bubble up error
                    /// @solidity memory-safe-assembly
                    assembly {
                        let returndata_size := mload(error)
                        revert(add(32, error), returndata_size)
                    }
                } else {
                    revert InitializationFunctionReverted(_init, _calldata);
                }
            }
        }
    }

    function _enforceHasContractCode(
        address _contract,
        string memory _errorMessage
    ) internal view {
        uint256 contractSize;
        assembly {
            contractSize := extcodesize(_contract)
        }
        if (contractSize == 0) {
            revert NoBytecodeAtAddress(_contract, _errorMessage);
        }
    }
}

File 3 of 40 : LibDiamondStorage.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.17;

library LibDiamondStorage {
    // The hash for diamond storage position, which is:
    // keccak256("diamond.standard.diamond.storage")
    bytes32 constant DIAMOND_STORAGE_POSITION =
        0xc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c;

    struct FacetAddressAndPosition {
        address facetAddress;
        uint96 functionSelectorPosition; // position in facetFunctionSelectors.functionSelectors array
    }

    struct FacetFunctionSelectors {
        bytes4[] functionSelectors;
        uint256 facetAddressPosition; // position of facetAddress in facetAddresses array
    }

    struct DiamondStorage {
        // Maps function selector to the facet address and
        // the position of the selector in the facetFunctionSelectors.selectors array
        mapping(bytes4 => FacetAddressAndPosition) selectorToFacetAndPosition;
        // Maps facet addresses to function selectors
        mapping(address => FacetFunctionSelectors) facetFunctionSelectors;
        // Facet addresses
        address[] facetAddresses;
        // Used to query if a contract implements an interface.
        // Used to implement ERC-165.
        mapping(bytes4 => bool) supportedInterfaces;
        // Address of contract that stores the owner and implements the ownership
        // transfer mechanism
        address ownershipContract;
    }

    function _diamondStorage()
        internal
        pure
        returns (DiamondStorage storage ds)
    {
        bytes32 position = DIAMOND_STORAGE_POSITION;
        assembly {
            ds.slot := position
        }
    }
}

File 4 of 40 : LibDIVAStorage.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.17;

library LibDIVAStorage {
    // The hash for pool storage position, which is:
    // keccak256("diamond.standard.pool.storage")
    bytes32 constant POOL_STORAGE_POSITION =
        0x57b54c9a1067e6ab879c66c176c4e86e41fe1dcf5187b31dc2b93365087c7afb;

    // The hash for governance storage position, which is:
    // keccak256("diamond.standard.governance.storage")
    bytes32 constant GOVERNANCE_STORAGE_POSITION =
        0x898b136e888260ec0628fb6c3ad8f54cb15908878595b2abfc8c9ecda73a4daf;

    // The hash for fee claim storage position, which is:
    // keccak256("diamond.standard.fee.claim.storage")
    bytes32 constant FEE_CLAIM_STORAGE_POSITION =
        0x16b3e63c02e4dfaf74f59b1b7e9e81770bf30c0ed3fd4434b199357859900313;

    // Settlement status
    enum Status {
        Open,
        Submitted,
        Challenged,
        Confirmed
    }

    // Collection of pool related parameters; order was optimized to reduce storage costs
    struct Pool {
        uint256 floor; // Reference asset value at or below which the long token pays out 0 and the short token 1 (max payout) (18 decimals)
        uint256 inflection; // Reference asset value at which the long token pays out `gradient` and the short token `1-gradient` (18 decimals)
        uint256 cap; // Reference asset value at or above which the long token pays out 1 (max payout) and the short token 0 (18 decimals)
        uint256 gradient; // Long token payout at inflection (value between 0 and 1) (collateral token decimals)
        uint256 collateralBalance; // Current collateral balance of pool (collateral token decimals)
        uint256 finalReferenceValue; // Reference asset value at the time of expiration (18 decimals) - set to 0 at pool creation
        uint256 capacity; // Maximum collateral that the pool can accept (collateral token decimals)
        uint256 statusTimestamp; // Timestamp of status change - set to block.timestamp at pool creation
        address shortToken; // Short position token address
        uint96 payoutShort; // Payout amount per short position token net of fees (collateral token decimals) - set to 0 at pool creation
        address longToken; // Long position token address
        uint96 payoutLong; // Payout amount per long position token net of fees (collateral token decimals) - set to 0 at pool creation
        address collateralToken; // Address of the ERC20 collateral token
        uint96 expiryTime; // Expiration time of the pool (expressed as a unix timestamp in seconds)
        address dataProvider; // Address of data provider
        uint48 indexFees; // Index pointer to the applicable fees inside the Fees struct array
        uint48 indexSettlementPeriods; // Index pointer to the applicable periods inside the SettlementPeriods struct array
        Status statusFinalReferenceValue; // Status of final reference price (0 = Open, 1 = Submitted, 2 = Challenged, 3 = Confirmed) - set to 0 at pool creation
        string referenceAsset; // Reference asset string
    }

    // Collection of settlement related periods
    struct SettlementPeriods {
        uint256 startTime; // Timestamp at which the new set of settlement periods becomes applicable
        uint24 submissionPeriod; // Submission period length in seconds; max value: 15 days <= 2^24
        uint24 challengePeriod; // Challenge period length in seconds; max value: 15 days <= 2^24
        uint24 reviewPeriod; // Review period length in seconds; max value: 15 days <= 2^24
        uint24 fallbackSubmissionPeriod; // Fallback submission period length in seconds; max value: 15 days <= 2^24
    }

    // Collection of fee related parameters
    struct Fees {
        uint256 startTime; // timestamp at which the new set of fees becomes applicable
        uint96 protocolFee; // max value: 15000000000000000 = 1.5% <= 2^56
        uint96 settlementFee; // max value: 15000000000000000 = 1.5% <= 2^56
    }

    // Collection of governance related parameters
    struct GovernanceStorage {
        address previousTreasury; // Previous treasury address
        address treasury; // Pending/current treasury address
        uint256 startTimeTreasury; // Unix timestamp when the new treasury address is activated
        address previousFallbackDataProvider; // Previous fallback data provider address
        address fallbackDataProvider; // Pending/current fallback data provider
        uint256 startTimeFallbackDataProvider; // Unix timestamp when the new fallback provider is activated
        uint256 pauseReturnCollateralUntil; // Unix timestamp until when withdrawals are paused
        Fees[] fees; // Array including the fee regimes set over time
        SettlementPeriods[] settlementPeriods; // Array including the settlement period regimes set over time
    }

    struct FeeClaimStorage {
        mapping(address => mapping(address => uint256)) claimableFeeAmount; // collateralTokenAddress -> RecipientAddress -> amount
        mapping(uint256 => uint256) poolIdToTip; // poolId -> tip amount
    }

    struct PoolStorage {
        uint256 poolId;
        mapping(uint256 => Pool) pools;
        address positionTokenFactory;
    }

    function _poolStorage() internal pure returns (PoolStorage storage ps) {
        bytes32 position = POOL_STORAGE_POSITION;
        assembly {
            ps.slot := position
        }
    }

    function _governanceStorage()
        internal
        pure
        returns (GovernanceStorage storage gs)
    {
        bytes32 position = GOVERNANCE_STORAGE_POSITION;
        assembly {
            gs.slot := position
        }
    }

    function _feeClaimStorage()
        internal
        pure
        returns (FeeClaimStorage storage fs)
    {
        bytes32 position = FEE_CLAIM_STORAGE_POSITION;
        assembly {
            fs.slot := position
        }
    }
}

File 5 of 40 : IClaim.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.17;

interface IClaim {
    // Thrown if the recipient during fee claim transfer is the zero address
    error RecipientIsZeroAddress();

    // Thrown if the transfer amount exceeds the claimable fee amount
    error AmountExceedsClaimableFee();

    // Struct for `batchClaimFee` function input
    struct ArgsBatchClaimFee {
        address collateralToken;
        address recipient;
    }

    // Struct for `batchTransferFeeClaim` function input
    struct ArgsBatchTransferFeeClaim {
        address recipient;
        address collateralToken;
        uint256 amount;
    }

    /**
     * @notice Emitted when fee claim is transferred from entitled address
     * to another address
     * @param from Address that is transferring their fee claim
     * @param to Address of the fee claim recipient
     * @param collateralToken Collateral token address
     * @param amount Fee amount
     */
    event FeeClaimTransferred(
        address indexed from,
        address indexed to,
        address indexed collateralToken,
        uint256 amount
    );

    /**
     * @notice Emitted when fee is claimed
     * @param recipient Address of the fee recipient
     * @param collateralToken Collateral token address
     * @param amount Fee amount
     */
    event FeeClaimed(
        address indexed recipient,
        address indexed collateralToken,
        uint256 amount
    );

    /**
     * @notice Function to claim allocated fee
     * @dev List of collateral token addresses has to be obtained off-chain
     * (e.g., from TheGraph)
     * @param _collateralToken Collateral token address
     * @param _recipient Fee recipient address
     */
    function claimFee(address _collateralToken, address _recipient) external;

    /**
     * @notice Batch version of `claimFee`
     * @param _argsBatchClaimFee Struct array containing collateral token and
     * recipient addresses
     */
    function batchClaimFee(ArgsBatchClaimFee[] calldata _argsBatchClaimFee)
        external;

    /**
     * @notice Function to transfer fee claim from entitled address
     * to another address
     * @param _recipient Address of fee claim recipient
     * @param _collateralToken Collateral token address
     * @param _amount Amount (expressed as an integer with collateral token
     * decimals) to transfer to recipient
     */
    function transferFeeClaim(
        address _recipient,
        address _collateralToken,
        uint256 _amount
    ) external;

    /**
     * @notice Batch version of `transferFeeClaim`
     * @param _argsBatchTransferFeeClaim Struct array containing collateral tokens,
     * recipient addresses and amounts (expressed as an integer with collateral
     * token decimals)
     */
    function batchTransferFeeClaim(
        ArgsBatchTransferFeeClaim[] calldata _argsBatchTransferFeeClaim
    ) external;
}

File 6 of 40 : LibEIP712Storage.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.17;

library LibEIP712Storage {
    // The hash for eip712 storage position, which is:
    // keccak256("diamond.standard.eip712.storage")
    bytes32 constant EIP712_STORAGE_POSITION =
        0x8605704e9bc6b9116b88d76d80e5d463ac2b851042de18aae713a2e1c43f2fe5;

    struct EIP712Storage {
        // EIP712 domain separator (set in constructor in Diamond.sol)
        bytes32 EIP712_DOMAIN_SEPARATOR;
        // Chain id (set in constructor in Diamond.sol)
        uint256 CACHED_CHAIN_ID;
        // Mapping to store created poolId with typedOfferHash
        mapping(bytes32 => uint256) typedOfferHashToPoolId;
        // Mapping to store takerFilled amount with typedOfferHash
        mapping(bytes32 => uint256) typedOfferHashToTakerFilledAmount;
    }

    function _eip712Storage() internal pure returns (EIP712Storage storage es) {
        bytes32 position = EIP712_STORAGE_POSITION;
        assembly {
            es.slot := position
        }
    }
}

File 7 of 40 : IDiamondCut.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.17;

interface IDiamondCut {
    enum FacetCutAction {
        Add,
        Replace,
        Remove
    }
    // Add=0, Replace=1, Remove=2

    struct FacetCut {
        address facetAddress;
        FacetCutAction action;
        bytes4[] functionSelectors;
    }

    // Duplication of event defined in `LibDiamond.sol` as events emitted out of
    // library functions are not reflected in the contract ABI. Read more about it here:
    // https://web.archive.org/web/20180922101404/https://blog.aragon.org/library-driven-development-in-solidity-2bebcaf88736/
    event DiamondCut(FacetCut[] _facetCut, address _init, bytes _calldata);

    /// @notice Add/replace/remove any number of functions and optionally
    ///         execute a function with delegatecall
    /// @param _facetCut Contains the facet addresses and function selectors
    /// @param _init The address of the contract or facet to execute _calldata
    /// @param _calldata A function call, including function selector and arguments
    ///                  _calldata is executed with delegatecall on _init
    function diamondCut(
        FacetCut[] calldata _facetCut,
        address _init,
        bytes calldata _calldata
    ) external;
}

File 8 of 40 : IEIP712Add.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {LibEIP712} from "../libraries/LibEIP712.sol";

interface IEIP712Add {
    // Struct for `batchFillOfferAddLiquidity` function input
    struct ArgsBatchFillOfferAddLiquidity {
        LibEIP712.OfferAddLiquidity offerAddLiquidity;
        LibEIP712.Signature signature;
        uint256 takerFillAmount;
    }

    /**
     * @dev Emitted whenever an offer is filled
     * @param typedOfferHash Offer hash
     * @param maker Offer maker address
     * @param taker Offer taker address
     * @param takerFilledAmount Incremental taker filled amount
     */
    event OfferFilled(
        bytes32 indexed typedOfferHash,
        address indexed maker,
        address indexed taker,
        uint256 takerFilledAmount
    );

    /**
     * @notice Function to fill an EIP712 based offer to add liquidity to an existing pool.
     * @dev As opposed to `addLiquidity`, the collateral is contributed by
     * both `maker` and `taker` instead of `msg.sender` only according to the
     * ratios implied by `makerCollateralAmount` and `takerCollateralAmount` defined in
     * the offer details. As a result, both `maker` and `taker` need to have a sufficient
     * collateral token balance as well as sufficient allowance to `this` contract
     * to transfer the collateral token from their accounts.
     * The fillability and validity of an offer can be checked via
     * `getOfferRelevantStateAddLiquidity` prior to execution.
     * @param _offerAddLiquidity Struct containing the add liquidity offer details
     * @param _signature Offer signature
     * @param _takerFillAmount Taker collateral amount that the user attempts to fill
     */
    function fillOfferAddLiquidity(
        LibEIP712.OfferAddLiquidity calldata _offerAddLiquidity,
        LibEIP712.Signature calldata _signature,
        uint256 _takerFillAmount
    ) external;

    /**
     * @notice Batch version of `fillOfferAddLiquidity`
     * @param _argsBatchOfferAddLiquidity Struct array containing OfferAddLiquidity, signature
     * and taker fill amount
     */
    function batchFillOfferAddLiquidity(
        ArgsBatchFillOfferAddLiquidity[] calldata _argsBatchOfferAddLiquidity
    ) external;
}

File 9 of 40 : IEIP712Cancel.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {LibEIP712} from "../libraries/LibEIP712.sol";

interface IEIP712Cancel {
    /**
     * @notice Emitted whenever an offer is cancelled
     * @param typedOfferHash Offer hash
     * @param maker Offer maker address (equal to `msg.sender`)
     */
    event OfferCancelled(bytes32 indexed typedOfferHash, address indexed maker);

    /**
     * @notice Function to cancel a create pool offer
     * @dev An offer cancellation is reflected by setting the `takerFilledAmount`
     * to `max(uint256)` for the corresponding offer hash
     * @param _offerCreateContingentPool Struct containing the create pool offer details
     */
    function cancelOfferCreateContingentPool(
        LibEIP712.OfferCreateContingentPool calldata _offerCreateContingentPool
    ) external;

    /**
     * @notice Batch version of `cancelOfferCreateContingentPool`
     * @param _offersCreateContingentPool Array of OfferCreateContingentPool struct
     */
    function batchCancelOfferCreateContingentPool(
        LibEIP712.OfferCreateContingentPool[]
            calldata _offersCreateContingentPool
    ) external;

    /**
     * @notice Function to cancel an add liquidity offer
     * @dev An offer cancellation is reflected by setting the `takerFilledAmount`
     * to `max(uint256)` for the corresponding offer hash
     * @param _offerAddLiquidity Struct containing the add liquidity offer details
     */
    function cancelOfferAddLiquidity(
        LibEIP712.OfferAddLiquidity calldata _offerAddLiquidity
    ) external;

    /**
     * @notice Batch version of `cancelOfferAddLiquidity`
     * @param _offersAddLiquidity Array of OfferAddLiquidity struct
     */
    function batchCancelOfferAddLiquidity(
        LibEIP712.OfferAddLiquidity[] calldata _offersAddLiquidity
    ) external;

    /**
     * @notice Function to cancel a remove liquidity offer
     * @dev An offer cancellation is reflected by setting the `takerFilledAmount`
     * to `max(uint256)` for the corresponding offer hash
     * @param _offerRemoveLiquidity Struct containing the remove liquidity offer details
     */
    function cancelOfferRemoveLiquidity(
        LibEIP712.OfferRemoveLiquidity calldata _offerRemoveLiquidity
    ) external;

    /**
     * @notice Batch version of `cancelOfferRemoveLiquidity`
     * @param _offersRemoveLiquidity Array of OfferRemoveLiquidity struct
     */
    function batchCancelOfferRemoveLiquidity(
        LibEIP712.OfferRemoveLiquidity[] calldata _offersRemoveLiquidity
    ) external;
}

File 10 of 40 : IDiamondLoupe.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.17;

// A loupe is a small magnifying glass used to look at diamonds.
// These functions look at diamonds
interface IDiamondLoupe {
    /// These functions are expected to be called frequently
    /// by tools.

    struct Facet {
        address facetAddress;
        bytes4[] functionSelectors;
    }

    /// @notice Gets all facet addresses and their four byte function selectors.
    /// @return facets_ Facet
    function facets() external view returns (Facet[] memory facets_);

    /// @notice Gets all the function selectors supported by a specific facet.
    /// @param _facet The facet address.
    /// @return facetFunctionSelectors_
    function facetFunctionSelectors(address _facet)
        external
        view
        returns (bytes4[] memory facetFunctionSelectors_);

    /// @notice Get all the facet addresses used by a diamond.
    /// @return facetAddresses_
    function facetAddresses()
        external
        view
        returns (address[] memory facetAddresses_);

    /// @notice Gets the facet that supports the given selector.
    /// @dev If facet is not found return address(0).
    /// @param _functionSelector The function selector.
    /// @return facetAddress_ The facet address.
    function facetAddress(bytes4 _functionSelector)
        external
        view
        returns (address facetAddress_);
}

File 11 of 40 : IEIP712Remove.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {LibEIP712} from "../libraries/LibEIP712.sol";

interface IEIP712Remove {
    // Struct for `batchFillOfferRemoveLiquidity` function input
    struct ArgsBatchFillOfferRemoveLiquidity {
        LibEIP712.OfferRemoveLiquidity offerRemoveLiquidity;
        LibEIP712.Signature signature;
        uint256 positionTokenFillAmount;
    }

    /**
     * @dev Emitted whenever an offer is filled
     * @param typedOfferHash Offer hash
     * @param maker Offer maker address
     * @param taker Offer taker address
     * @param takerFilledAmount Incremental position token amount filled
     */
    event OfferFilled(
        bytes32 indexed typedOfferHash,
        address indexed maker,
        address indexed taker,
        uint256 takerFilledAmount
    );

    /**
     * @notice Function to fill an EIP712 based offer to remove liquidity from an existing pool.
     * @dev As opposed to `removeLiquidity`, the collateral is returned to the `maker`
     * and `taker` instead of `msg.sender` only according to the ratios implied by
     * `positionTokenAmount` and `makerCollateralAmount` defined in the offer details. In particular,
     * the collateral amount returned to the `taker` is given by `positionTokenAmount - makerCollateralAmount`
     * due to the 1:1 relationship between collateral and position token amount.
     * The fillability and validity of an offer can be checked via `getOfferRelevantStateRemoveLiquidity`
     * prior to execution.
     * @param _offerRemoveLiquidity Struct containing the remove liquidity offer details
     * @param _signature Offer signature
     * @param _positionTokenFillAmount Position token amount that the taker attempts to return
     */
    function fillOfferRemoveLiquidity(
        LibEIP712.OfferRemoveLiquidity calldata _offerRemoveLiquidity,
        LibEIP712.Signature calldata _signature,
        uint256 _positionTokenFillAmount
    ) external;

    /**
     * @notice Batch version of `fillOfferRemoveLiquidity`
     * @param _argsBatchOfferRemoveLiquidity Struct array containing OfferRemoveLiquidity, signature
     * and position token fill amount
     */
    function batchFillOfferRemoveLiquidity(
        ArgsBatchFillOfferRemoveLiquidity[]
            calldata _argsBatchOfferRemoveLiquidity
    ) external;
}

File 12 of 40 : LibEIP712.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.17;

import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import {PositionToken} from "../PositionToken.sol";
import {IPositionToken} from "../interfaces/IPositionToken.sol";
import {IEIP712Create} from "../interfaces/IEIP712Create.sol";
import {LibEIP712Storage} from "./LibEIP712Storage.sol";
import {LibDIVA} from "./LibDIVA.sol";
import {LibDIVAStorage} from "./LibDIVAStorage.sol";

// Thrown in `fillOfferCreateContingentPool` /  `fillOfferAddLiquidity` / `fillOfferRemoveLiquidity`
// if user tries to fill an amount smaller than the minimum provided in the offer
error TakerFillAmountSmallerMinimum();

// Thrown in `fillOfferCreateContingentPool` /  `fillOfferAddLiquidity` / `fillOfferRemoveLiquidity`
// if the provided `takerFillAmount` exceeds the remaining fillable amount
error TakerFillAmountExceedsFillableAmount();

// Thrown in `cancelOfferCreateContingentPool` / `cancelOfferAddLiquidity` / `cancelOfferRemoveLiquidity`
// if `msg.sender` is not equal to maker
error MsgSenderNotMaker();

// Thrown in `fillOfferCreateContingentPool` /  `fillOfferAddLiquidity` / `fillOfferRemoveLiquidity`
// if the signed offer and the provided signature do not match
error InvalidSignature();

// Thrown in `fillOfferCreateContingentPool` / `fillOfferAddLiquidity` / `fillOfferRemoveLiquidity`
// if offer is not fillable due to being invalid, cancelled, already filled or expired
error OfferInvalidCancelledFilledOrExpired();

// Thrown in `fillOfferCreateContingentPool` / `fillOfferAddLiquidity` / `fillOfferRemoveLiquidity`
// if offer is reserved for a different taker
error UnauthorizedTaker();

library LibEIP712 {
    using SafeERC20 for IERC20Metadata;

    // Enum for offer status
    enum OfferStatus {
        INVALID,
        CANCELLED,
        FILLED,
        EXPIRED,
        FILLABLE
    }

    // Signature structure
    struct Signature {
        uint8 v; // EC Signature data
        bytes32 r; // EC Signature data
        bytes32 s; // EC Signature data
    }

    // Argument for `fillOfferCreateContingentPool` function.
    struct OfferCreateContingentPool {
        address maker; // Signer/creator address of the offer
        address taker; // Address that is allowed to fill the offer; if zero address, then everyone can fill the offer
        uint256 makerCollateralAmount; // Collateral amount to be contributed to the contingent pool by maker
        uint256 takerCollateralAmount; // Collateral amount to be contributed to the contingent pool by taker
        bool makerIsLong; // 1 [0] if maker shall receive the long [short] position
        uint256 offerExpiry; // Offer expiration time
        uint256 minimumTakerFillAmount; // Minimum taker fill amount on first fill
        string referenceAsset; // Parameter for `createContingentPool`
        uint96 expiryTime; // Parameter for `createContingentPool`
        uint256 floor; // Parameter for `createContingentPool`
        uint256 inflection; // Parameter for `createContingentPool`
        uint256 cap; // Parameter for `createContingentPool`
        uint256 gradient; // Parameter for `createContingentPool`
        address collateralToken; // Parameter for `createContingentPool`
        address dataProvider; // Parameter for `createContingentPool`
        uint256 capacity; // Parameter for `createContingentPool`
        address permissionedERC721Token; // // Parameter for `createContingentPool`
        uint256 salt; // Arbitrary number to enforce uniqueness of the offer hash
    }

    // Argument for `fillOfferAddLiquidity` function.
    struct OfferAddLiquidity {
        address maker; // Signer/creator address of the offer
        address taker; // Address that is allowed to fill the offer; if zero address, then everyone can fill the offer
        uint256 makerCollateralAmount; // Collateral amount to be contributed to the contingent pool by maker
        uint256 takerCollateralAmount; // Collateral amount to be contributed to the contingent pool by taker
        bool makerIsLong; // 1 [0] if maker shall receive the long [short] position
        uint256 offerExpiry; // Offer expiration time
        uint256 minimumTakerFillAmount; // Minimum taker fill amount on first fill
        uint256 poolId; // Id of an existing pool
        uint256 salt; // Arbitrary number to enforce uniqueness of the offer hash
    }

    // Argument for `fillOfferRemoveLiquidity` function
    struct OfferRemoveLiquidity {
        address maker;
        address taker;
        uint256 positionTokenAmount; // Position token amount returned by taker and maker is equal
        uint256 makerCollateralAmount; // Collateral amount to be returned to maker. Amount returned to taker is positionTokenAmount - makerCollateralAmount
        bool makerIsLong; // 1 [0] if maker returns long [short] position token
        uint256 offerExpiry; // Offer expiration time
        uint256 minimumTakerFillAmount; // Minimum position token fill amount on first fill
        uint256 poolId; // Id of an existing pool
        uint256 salt; // Arbitrary number to enforce uniqueness of the offer hash
    }

    // Offer info structure
    struct OfferInfo {
        bytes32 typedOfferHash; // Offer hash
        OfferStatus status; // Offer status: 0: INVALID, 1: CANCELLED, 2: FILLED, 3: EXPIRED, 4: FILLABLE
        uint256 takerFilledAmount; // Already filled taker amount
    }

    // The type hash for eip712 domain is:
    // keccak256(
    //     abi.encodePacked(
    //         "EIP712Domain(",
    //         "string name,",
    //         "string version,",
    //         "uint256 chainId,",
    //         "address verifyingContract",
    //         ")"
    //     )
    // )
    bytes32 internal constant EIP712_DOMAIN_TYPEHASH =
        0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f;

    // The type hash for create pool offer is:
    // keccak256(
    //     abi.encodePacked(
    //         "OfferCreateContingentPool(",
    //         "address maker,"
    //         "address taker,"
    //         "uint256 makerCollateralAmount,"
    //         "uint256 takerCollateralAmount,"
    //         "bool makerIsLong,"
    //         "uint256 offerExpiry,"
    //         "uint256 minimumTakerFillAmount,"
    //         "string referenceAsset,"
    //         "uint96 expiryTime,"
    //         "uint256 floor,"
    //         "uint256 inflection,"
    //         "uint256 cap,"
    //         "uint256 gradient,"
    //         "address collateralToken,"
    //         "address dataProvider,"
    //         "uint256 capacity,"
    //         "address permissionedERC721Token,"
    //         "uint256 salt)"
    //     )
    // )
    bytes32 internal constant CREATE_POOL_OFFER_TYPEHASH =
        0xc628170201b0ce3a1a2f5407dc30d69b6cc12028198419cc3aa66a1ccbdabf96;

    // The type hash for add liquidity offer is:
    // keccak256(
    //     abi.encodePacked(
    //         "OfferAddLiquidity(",
    //         "address maker,"
    //         "address taker,"
    //         "uint256 makerCollateralAmount,"
    //         "uint256 takerCollateralAmount,"
    //         "bool makerIsLong,"
    //         "uint256 offerExpiry,"
    //         "uint256 minimumTakerFillAmount,"
    //         "uint256 poolId,"
    //         "uint256 salt)"
    //     )
    // )
    bytes32 internal constant ADD_LIQUIDITY_OFFER_TYPEHASH =
        0x975f3968a81decadba63b6466e62ce2251375eafc0c1a7533833ca65c7fd37d9;

    // The type hash for remove liquidity offer is:
    // keccak256(
    //     abi.encodePacked(
    //         "OfferRemoveLiquidity(",
    //         "address maker,"
    //         "address taker,"
    //         "uint256 positionTokenAmount,"
    //         "uint256 makerCollateralAmount,"
    //         "bool makerIsLong,"
    //         "uint256 offerExpiry,"
    //         "uint256 minimumTakerFillAmount,"
    //         "uint256 poolId,"
    //         "uint256 salt)"
    //     )
    // )
    bytes32 internal constant REMOVE_LIQUIDITY_OFFER_TYPEHASH =
        0xac00f11325081eb117c866f34ac4e3a902bed956f41d8fbfbf42418bdc02af16;

    // Max int value of a uint256, used to flag cancelled offers.
    uint256 internal constant MAX_INT = ~uint256(0);

    uint256 private constant ADDRESS_MASK = (1 << 160) - 1;
    uint256 private constant UINT_96_MASK = (1 << 96) - 1;
    uint256 private constant UINT_8_MASK = (1 << 8) - 1;

    function _chainId() internal view returns (uint256 chainId) {
        chainId = block.chainid;
    }

    /**
     * Accept message hash and returns hash message in EIP712 compatible form
     * So that it can be used to recover signer from signature signed using EIP712 formatted data
     * https://eips.ethereum.org/EIPS/eip-712
     * "\\x19" makes the encoding deterministic
     * "\\x01" is the version byte to make it compatible to EIP-191
     */
    function _toTypedMessageHash(bytes32 _messageHash)
        internal
        view
        returns (bytes32 typedMessageHash)
    {
        // Get domain separator to use in assembly
        bytes32 _EIP712_DOMAIN_SEPARATOR = _getDomainSeparator();

        // Assembly for more efficient computing:
        // Inspired by https://github.com/0xProject/protocol/blob/1fa093be6490cac52dfc17c31cd9fe9ff47ccc5e/contracts/utils/contracts/src/LibEIP712.sol#L87
        // keccak256(
        //     abi.encodePacked(
        //         "\x19\x01",
        //         LibEIP712Storage._eip712Storage().EIP712_DOMAIN_SEPARATOR,
        //         _messageHash
        //     )
        // );
        assembly {
            // Load free memory pointer
            let mem := mload(0x40)

            mstore(
                mem,
                0x1901000000000000000000000000000000000000000000000000000000000000
            ) // EIP191 header
            mstore(add(mem, 0x02), _EIP712_DOMAIN_SEPARATOR) // EIP712 domain hash
            mstore(add(mem, 0x22), _messageHash) // Hash of struct

            // Compute hash
            typedMessageHash := keccak256(mem, 0x42)
        }
    }

    // Returns the domain separator for the current chain.
    function _getDomainSeparator() internal view returns (bytes32) {
        LibEIP712Storage.EIP712Storage storage es = LibEIP712Storage
            ._eip712Storage();
        if (_chainId() == es.CACHED_CHAIN_ID) {
            return es.EIP712_DOMAIN_SEPARATOR;
        } else {
            return _getDomainHash();
        }
    }

    function _getDomainHash() internal view returns (bytes32 domainHash) {
        string memory name = "DIVA Protocol";
        string memory version = "1";
        uint256 chainId = _chainId();
        address verifyingContract = address(this);

        // Assembly for more efficient computing:
        // Inspired by https://github.com/0xProject/protocol/blob/1fa093be6490cac52dfc17c31cd9fe9ff47ccc5e/contracts/utils/contracts/src/LibEIP712.sol#L61
        // keccak256(
        //     abi.encode(
        //         EIP712_DOMAIN_TYPEHASH,
        //         keccak256(bytes(name)),
        //         keccak256(bytes(version)),
        //         chainId,
        //         verifyingContract
        //     )
        // )

        assembly {
            // Calculate hashes of dynamic data
            let nameHash := keccak256(add(name, 0x20), mload(name))
            let versionHash := keccak256(add(version, 0x20), mload(version))

            // Load free memory pointer
            let mem := mload(0x40)

            // Store params in memory
            mstore(mem, EIP712_DOMAIN_TYPEHASH)
            mstore(add(mem, 0x20), nameHash)
            mstore(add(mem, 0x40), versionHash)
            mstore(add(mem, 0x60), chainId)
            mstore(add(mem, 0x80), and(ADDRESS_MASK, verifyingContract))

            // Compute hash
            domainHash := keccak256(mem, 0xA0)
        }
    }

    function _takerFilledAmount(bytes32 _typedOfferHash)
        internal
        view
        returns (uint256)
    {
        return
            LibEIP712Storage._eip712Storage().typedOfferHashToTakerFilledAmount[
                _typedOfferHash
            ];
    }

    function _min256(uint256 _a, uint256 _b)
        internal
        pure
        returns (uint256 min256)
    {
        min256 = _a < _b ? _a : _b;
    }

    /**
     * @notice Function to get info of create contingent pool offer.
     * @param _offerCreateContingentPool Struct containing the create pool offer details
     * @return offerInfo Struct of offer info
     */
    function _getOfferInfoCreateContingentPool(
        OfferCreateContingentPool calldata _offerCreateContingentPool
    ) internal view returns (OfferInfo memory offerInfo) {
        // Get typed offer hash with `_offerCreateContingentPool`
        offerInfo.typedOfferHash = _toTypedMessageHash(
            _getOfferHashCreateContingentPool(_offerCreateContingentPool)
        );

        // Get offer status and takerFilledAmount
        _populateCommonOfferInfoFields(
            offerInfo,
            _offerCreateContingentPool.takerCollateralAmount,
            _offerCreateContingentPool.offerExpiry
        );
    }

    // Return hash of create pool offer details
    function _getOfferHashCreateContingentPool(
        OfferCreateContingentPool memory _offerCreateContingentPool
    ) internal pure returns (bytes32 offerHashCreateContingentPool) {
        // Assembly for more efficient computing:
        // Inspired by https://github.com/0xProject/protocol/blob/1fa093be6490cac52dfc17c31cd9fe9ff47ccc5e/contracts/zero-ex/contracts/src/features/libs/LibNativeOrder.sol#L179
        // keccak256(
        //     abi.encode(
        //         CREATE_POOL_OFFER_TYPEHASH,
        //         _offerCreateContingentPool.maker,
        //         _offerCreateContingentPool.taker,
        //         _offerCreateContingentPool.makerCollateralAmount,
        //         _offerCreateContingentPool.takerCollateralAmount,
        //         _offerCreateContingentPool.makerIsLong,
        //         _offerCreateContingentPool.offerExpiry,
        //         _offerCreateContingentPool.minimumTakerFillAmount,
        //         keccak256(bytes(_offerCreateContingentPool.referenceAsset)),
        //         _offerCreateContingentPool.expiryTime,
        //         _offerCreateContingentPool.floor,
        //         _offerCreateContingentPool.inflection,
        //         _offerCreateContingentPool.cap,
        //         _offerCreateContingentPool.gradient,
        //         _offerCreateContingentPool.collateralToken,
        //         _offerCreateContingentPool.dataProvider,
        //         _offerCreateContingentPool.capacity,
        //         _offerCreateContingentPool.permissionedERC721Token,
        //         _offerCreateContingentPool.salt
        //     )
        // )
        assembly {
            let mem := mload(0x40)
            mstore(mem, CREATE_POOL_OFFER_TYPEHASH)
            // _offerCreateContingentPool.maker;
            mstore(
                add(mem, 0x20),
                and(ADDRESS_MASK, mload(_offerCreateContingentPool))
            )
            // _offerCreateContingentPool.taker;
            mstore(
                add(mem, 0x40),
                and(ADDRESS_MASK, mload(add(_offerCreateContingentPool, 0x20)))
            )
            // _offerCreateContingentPool.makerCollateralAmount;
            mstore(add(mem, 0x60), mload(add(_offerCreateContingentPool, 0x40)))
            // _offerCreateContingentPool.takerCollateralAmount;
            mstore(add(mem, 0x80), mload(add(_offerCreateContingentPool, 0x60)))
            // _offerCreateContingentPool.makerIsLong;
            mstore(
                add(mem, 0xA0),
                and(UINT_8_MASK, mload(add(_offerCreateContingentPool, 0x80)))
            )
            // _offerCreateContingentPool.offerExpiry;
            mstore(add(mem, 0xC0), mload(add(_offerCreateContingentPool, 0xA0)))
            // _offerCreateContingentPool.minimumTakerFillAmount;
            mstore(add(mem, 0xE0), mload(add(_offerCreateContingentPool, 0xC0)))
            // _offerCreateContingentPool.referenceAsset;
            let referenceAsset := mload(add(_offerCreateContingentPool, 0xE0))
            mstore(
                add(mem, 0x100),
                keccak256(add(referenceAsset, 0x20), mload(referenceAsset))
            )
            // _offerCreateContingentPool.expiryTime;
            mstore(
                add(mem, 0x120),
                and(UINT_96_MASK, mload(add(_offerCreateContingentPool, 0x100)))
            )
            // _offerCreateContingentPool.floor;
            mstore(
                add(mem, 0x140),
                mload(add(_offerCreateContingentPool, 0x120))
            )
            // _offerCreateContingentPool.inflection;
            mstore(
                add(mem, 0x160),
                mload(add(_offerCreateContingentPool, 0x140))
            )
            // _offerCreateContingentPool.cap;
            mstore(
                add(mem, 0x180),
                mload(add(_offerCreateContingentPool, 0x160))
            )
            // _offerCreateContingentPool.gradient;
            mstore(
                add(mem, 0x1A0),
                mload(add(_offerCreateContingentPool, 0x180))
            )
            // _offerCreateContingentPool.collateralToken;
            mstore(
                add(mem, 0x1C0),
                and(ADDRESS_MASK, mload(add(_offerCreateContingentPool, 0x1A0)))
            )
            // _offerCreateContingentPool.dataProvider;
            mstore(
                add(mem, 0x1E0),
                and(ADDRESS_MASK, mload(add(_offerCreateContingentPool, 0x1C0)))
            )
            // _offerCreateContingentPool.capacity;
            mstore(
                add(mem, 0x200),
                mload(add(_offerCreateContingentPool, 0x1E0))
            )
            // _offerCreateContingentPool.permissionedERC721Token;
            mstore(
                add(mem, 0x220),
                and(ADDRESS_MASK, mload(add(_offerCreateContingentPool, 0x200)))
            )
            // _offerCreateContingentPool.salt;
            mstore(
                add(mem, 0x240),
                mload(add(_offerCreateContingentPool, 0x220))
            )
            offerHashCreateContingentPool := keccak256(mem, 0x260)
        }
    }

    /**
     * @dev Function to get offer status and taker filled amount for offerInfo.
     * @param _offerInfo Offer info struct pre-populated with offer hash.
     * @param _takerAmount` Taker collateral amount in `fillOfferCreateContingentPool`
     * and `fillOfferAddLiquidity` and position token amount in `fillOfferRemoveLiquidity`.
     * @param _offerExpiry Offer expiry.
     */
    function _populateCommonOfferInfoFields(
        OfferInfo memory _offerInfo,
        uint256 _takerAmount,
        uint256 _offerExpiry
    ) internal view {
        // Get the already filled taker amount for the given offer hash
        _offerInfo.takerFilledAmount = _takerFilledAmount(
            _offerInfo.typedOfferHash
        );

        // Check whether offer has non-zero value for positionTokenAmount (in remove) / takerCollateralAmount
        // (in add/create). An offer with takerCollateralAmount = 0, i.e. a donation offered by maker, can be
        // implemented via `createContingentPool`/`addLiquidity` directly by setting the donee as
        // the `longRecipient` or `shortRecipient`.
        if (_takerAmount == 0) {
            _offerInfo.status = OfferStatus.INVALID;
            return;
        }

        // Check whether offer is cancelled (taker filled amount is
        // set at MAX_INT if an offer is cancelled). It is acknowledged that
        // status will show CANCELLED if takerCollateralAmount = MAX_INT and
        // takerFilledAmount = MAX_INT. This mislabelling is not an issue
        // as all status checks reference FILLABLE status.
        if (_offerInfo.takerFilledAmount == MAX_INT) {
            _offerInfo.status = OfferStatus.CANCELLED;
            return;
        }

        // Check whether offer has already been filled
        if (_offerInfo.takerFilledAmount >= _takerAmount) {
            _offerInfo.status = OfferStatus.FILLED;
            return;
        }

        // Check for expiration
        if (_offerExpiry <= block.timestamp) {
            _offerInfo.status = OfferStatus.EXPIRED;
            return;
        }

        // Set offer status to fillable if none of the above is true
        _offerInfo.status = OfferStatus.FILLABLE;
    }

    /**
     * @dev Function to calculate maker fill amount given `_takerFillAmount`
     * @param _makerCollateralAmount Maker collateral amount as specified in the offer
     * @param _takerCollateralAmount taker collateral amount as specified in the offer
     * @param _takerFillAmount Taker collateral amount that the user attempts to fill
     * @return makerFillAmount Collateral amount to be contributed by the maker
     */
    function _calcMakerFillAmountAndPoolFillAmount(
        uint256 _makerCollateralAmount,
        uint256 _takerCollateralAmount,
        uint256 _takerFillAmount
    ) internal pure returns (uint256 makerFillAmount) {
        // Calc maker fill amount. An offer with `_takerCollateralAmount = 0`
        // is considered invalid and throws before it gets here (see `_checkFillableAndSignature`)
        makerFillAmount =
            (_takerFillAmount * _makerCollateralAmount) /
            _takerCollateralAmount;
    }

    /**
     * @dev Function to validate that a given signature belongs to a given offer hash
     * @param _typedOfferHash Offer hash
     * @param _signature Offer signature
     * @param _maker Maker address as specified in the offer
     */
    function _isSignatureValid(
        bytes32 _typedOfferHash,
        Signature memory _signature,
        address _maker
    ) internal pure returns (bool isSignatureValid) {
        // Recover offerMaker address with `_typedOfferHash` and `_signature` using tryRecover function from ECDSA library
        address recoveredOfferMaker = ECDSA.recover(
            _typedOfferHash,
            _signature.v,
            _signature.r,
            _signature.s
        );

        // Check that recoveredOfferMaker is not zero address
        if (recoveredOfferMaker == address(0)) {
            isSignatureValid = false;
        }
        // Check that maker address is equal to recoveredOfferMaker
        else {
            isSignatureValid = _maker == recoveredOfferMaker;
        }
    }

    /**
     * @dev Function to calculate actual taker fillable amount taking into account
     * a makers collateral token allowance and balance. Used inside
     * `getOfferRelevantStateCreateContingentPool` and `getOfferRelevantStateAddLiquidity`.
     * @param _maker Maker address as specified in the offer
     * @param _collateralToken Collateral token address as specified in the offer
     * @param _makerCollateralAmount Collateral amount to be contributed by maker
     * as specified in the offer
     * @param _takerCollateralAmount Collateral amount to be contributed by taker
     * as specified in the offer
     * @param _offerInfo Struct containing the offer hash, status and taker filled amount
     * @return actualTakerFillableAmount Actual fillable taker amount
     */
    function _getActualTakerFillableAmount(
        address _maker,
        address _collateralToken,
        uint256 _makerCollateralAmount,
        uint256 _takerCollateralAmount,
        OfferInfo memory _offerInfo
    ) internal view returns (uint256 actualTakerFillableAmount) {
        if (_makerCollateralAmount == 0) {
            // Use case: donation request by maker
            return (_takerCollateralAmount - _offerInfo.takerFilledAmount);
        }

        if (_offerInfo.status != OfferStatus.FILLABLE) {
            // Not fillable. This also includes the case where `_takerCollateralAmount` = 0
            return 0;
        }

        // Get the fillable maker amount based on the offer quantities and
        // previously filled amount
        uint256 makerFillableAmount = ((_takerCollateralAmount -
            _offerInfo.takerFilledAmount) * _makerCollateralAmount) /
            _takerCollateralAmount;

        // Clamp it to the maker fillable amount we can spend on behalf of the
        // maker
        makerFillableAmount = _min256(
            makerFillableAmount,
            _min256(
                IERC20(_collateralToken).allowance(_maker, address(this)),
                IERC20(_collateralToken).balanceOf(_maker)
            )
        );

        // Convert to taker fillable amount.
        // Division computes `floor(a / b)`. We use the identity (a, b integer):
        // ceil(a / b) = floor((a + b - 1) / b)
        // To implement `ceil(a / b)` using safeDiv.
        actualTakerFillableAmount =
            (makerFillableAmount *
                _takerCollateralAmount +
                _makerCollateralAmount -
                1) /
            _makerCollateralAmount;
    }

    /**
     * @dev Function to validate that `msg.sender` is equal to the maker
     * specified in the offer
     * @param _offerMaker Offer maker address
     */
    function _validateMessageSenderIsOfferMaker(address _offerMaker)
        internal
        view
    {
        // Check that `msg.sender` is `_offerMaker`
        if (msg.sender != _offerMaker) revert MsgSenderNotMaker();
    }

    /**
     * @dev Function to check offer fillability and signature validity
     * @param _signature Offer signature
     * @param _offerMaker Offer maker address
     * @param _offerTaker Offer taker address
     * @param _offerInfo Struct containing the offer hash, status and taker filled amount
     */
    function _checkFillableAndSignature(
        Signature calldata _signature,
        address _offerMaker,
        address _offerTaker,
        OfferInfo memory _offerInfo
    ) internal view {
        // Check that signature is valid
        if (
            !_isSignatureValid(
                _offerInfo.typedOfferHash,
                _signature,
                _offerMaker
            )
        ) revert InvalidSignature();

        // Must be fillable.
        if (_offerInfo.status != OfferStatus.FILLABLE)
            revert OfferInvalidCancelledFilledOrExpired();

        // Check that `msg.sender` is equal to `_offerTaker` or zero address in offer
        if (msg.sender != _offerTaker && _offerTaker != address(0))
            revert UnauthorizedTaker();
    }

    /**
     * @dev Function to validate that `_takerFillAmount` is greater than the minimum
     * and the implied overall taker filled amount does not exceed taker amount.
     * Increases `takerFilledAmount` after successfully passing the checks.
     * @param _takerAmount Taker amount as specified in the offer (collateral amount
     * in `fillOfferCreateContingentPool` and `fillOfferAddLiquidity` and position token amount
     * in `fillOfferRemoveLiquidity`).
     * @param _minimumTakerFillAmount Minimum taker fill amount as specified in the offer
     * @param _takerFillAmount Taker collateral amount that the user attempts to fill
     * @param _typedOfferHash Offer hash
     */
    function _validateTakerFillAmountAndIncreaseTakerFilledAmount(
        uint256 _takerAmount,
        uint256 _minimumTakerFillAmount,
        uint256 _takerFillAmount,
        bytes32 _typedOfferHash
    ) internal {
        // Get reference to relevant storage slot
        LibEIP712Storage.EIP712Storage storage es = LibEIP712Storage
            ._eip712Storage();

        // Check that `_takerFillAmount` is not smaller than `_minimumTakerFillAmount`.
        // This check is only relevant on first fill.
        if (
            _takerFillAmount +
                es.typedOfferHashToTakerFilledAmount[_typedOfferHash] <
            _minimumTakerFillAmount
        ) revert TakerFillAmountSmallerMinimum();

        // Check that `_takerFillAmount` is not higher than remaining fillable taker amount
        if (
            _takerFillAmount >
            _takerAmount - es.typedOfferHashToTakerFilledAmount[_typedOfferHash]
        ) revert TakerFillAmountExceedsFillableAmount();

        // Increase taker filled amount and store it in a mapping under the corresponding
        // offer hash
        es.typedOfferHashToTakerFilledAmount[
            _typedOfferHash
        ] += _takerFillAmount;
    }

    /**
     * @dev Function to fill an add liquidity offer. Signature validation is done
     * in the main function (`fillAddLiquidityOffer` and `fillOfferCreateContingentPool`)
     * prior to calling this function.
     * In `fillOfferCreateContingentPool`, the original create contingent pool offer
     * is used for signature validation.
     * @param _offerAddLiquidity Struct containing the add liquidity offer details
     * @param _takerFillAmount Taker collateral amount that the taker attempts to fill
     * @param _typedOfferHash Offer hash
     */
    function _fillOfferAddLiquidityLib(
        OfferAddLiquidity memory _offerAddLiquidity,
        uint256 _takerFillAmount,
        bytes32 _typedOfferHash
    ) internal {
        // Validate taker fill amount and increase taker filled amount
        _validateTakerFillAmountAndIncreaseTakerFilledAmount(
            _offerAddLiquidity.takerCollateralAmount,
            _offerAddLiquidity.minimumTakerFillAmount,
            _takerFillAmount,
            _typedOfferHash
        );

        // Calc maker fill amount
        uint256 _makerFillAmount = _calcMakerFillAmountAndPoolFillAmount(
            _offerAddLiquidity.makerCollateralAmount,
            _offerAddLiquidity.takerCollateralAmount,
            _takerFillAmount
        );

        // Get pool params using `poolId` specified in `_offerAddLiquidity`
        LibDIVAStorage.PoolStorage storage ps = LibDIVAStorage._poolStorage();
        LibDIVAStorage.Pool storage _pool = ps.pools[_offerAddLiquidity.poolId];

        // Check whether addition of liquidity is still possible. Reverts if pool expired
        // or new collateral balance exceeds pool capacity
        LibDIVA._checkAddLiquidityAllowed(
            _pool,
            _makerFillAmount + _takerFillAmount
        );

        // Transfer approved collateral token from maker and taker and mint position tokens to them
        LibDIVA._addLiquidityLib(
            LibDIVA.AddLiquidityParams({
                poolId: _offerAddLiquidity.poolId,
                collateralAmountMsgSender: _takerFillAmount,
                collateralAmountMaker: _makerFillAmount,
                maker: _offerAddLiquidity.maker,
                longRecipient: _offerAddLiquidity.makerIsLong
                    ? _offerAddLiquidity.maker
                    : msg.sender,
                shortRecipient: _offerAddLiquidity.makerIsLong
                    ? msg.sender
                    : _offerAddLiquidity.maker
            })
        );
    }

    /**
     * @notice Function to get info of add liquidity offer.
     * @param _offerAddLiquidity Struct containing the add liquidity offer details
     * @return offerInfo Struct of offer info
     */
    function _getOfferInfoAddLiquidity(
        OfferAddLiquidity calldata _offerAddLiquidity
    ) internal view returns (OfferInfo memory offerInfo) {
        // Get typed offer hash with `_offerAddLiquidity`
        offerInfo.typedOfferHash = _toTypedMessageHash(
            _getOfferHashAddLiquidity(_offerAddLiquidity)
        );

        // Get offer status and takerFilledAmount
        _populateCommonOfferInfoFields(
            offerInfo,
            _offerAddLiquidity.takerCollateralAmount,
            _offerAddLiquidity.offerExpiry
        );
    }

    // Return hash of add liquidity offer details
    function _getOfferHashAddLiquidity(
        OfferAddLiquidity memory _offerAddLiquidity
    ) internal pure returns (bytes32 offerHashAddLiquidity) {
        // Assembly for more efficient computing:
        // Inspired by https://github.com/0xProject/protocol/blob/1fa093be6490cac52dfc17c31cd9fe9ff47ccc5e/contracts/zero-ex/contracts/src/features/libs/LibNativeOrder.sol#L179
        // keccak256(
        //     abi.encode(
        //         ADD_LIQUIDITY_OFFER_TYPEHASH,
        //         _offerAddLiquidity.maker,
        //         _offerAddLiquidity.taker,
        //         _offerAddLiquidity.makerCollateralAmount,
        //         _offerAddLiquidity.takerCollateralAmount,
        //         _offerAddLiquidity.makerIsLong,
        //         _offerAddLiquidity.offerExpiry,
        //         _offerAddLiquidity.minimumTakerFillAmount,
        //         _offerAddLiquidity.poolId,
        //         _offerAddLiquidity.salt
        //     )
        // )
        assembly {
            let mem := mload(0x40)
            mstore(mem, ADD_LIQUIDITY_OFFER_TYPEHASH)
            // _offerAddLiquidity.maker;
            mstore(add(mem, 0x20), and(ADDRESS_MASK, mload(_offerAddLiquidity)))
            // _offerAddLiquidity.taker;
            mstore(
                add(mem, 0x40),
                and(ADDRESS_MASK, mload(add(_offerAddLiquidity, 0x20)))
            )
            // _offerAddLiquidity.makerCollateralAmount;
            mstore(add(mem, 0x60), mload(add(_offerAddLiquidity, 0x40)))
            // _offerAddLiquidity.takerCollateralAmount;
            mstore(add(mem, 0x80), mload(add(_offerAddLiquidity, 0x60)))
            // _offerAddLiquidity.makerIsLong;
            mstore(
                add(mem, 0xA0),
                and(UINT_8_MASK, mload(add(_offerAddLiquidity, 0x80)))
            )
            // _offerAddLiquidity.offerExpiry;
            mstore(add(mem, 0xC0), mload(add(_offerAddLiquidity, 0xA0)))
            // _offerAddLiquidity.minimumTakerFillAmount;
            mstore(add(mem, 0xE0), mload(add(_offerAddLiquidity, 0xC0)))
            // _offerAddLiquidity.poolId;
            mstore(add(mem, 0x100), mload(add(_offerAddLiquidity, 0xE0)))
            // _offerAddLiquidity.salt;
            mstore(add(mem, 0x120), mload(add(_offerAddLiquidity, 0x100)))
            offerHashAddLiquidity := keccak256(mem, 0x140)
        }
    }

    /**
     * @dev Function to fill a remove liquidity offer. Signature validation is done
     * in the main function (`fillRemoveLiquidityOffer`) prior to calling this function.
     * @param _offerRemoveLiquidity Struct containing the remove liquidity offer details
     * @param _takerFillAmount Position token amount that the taker attempts to fill
     * @param _typedOfferHash Offer hash
     */
    function _fillOfferRemoveLiquidityLib(
        OfferRemoveLiquidity memory _offerRemoveLiquidity,
        uint256 _takerFillAmount,
        bytes32 _typedOfferHash
    ) internal {
        // Validate taker fill amount and increase taker filled amount
        _validateTakerFillAmountAndIncreaseTakerFilledAmount(
            _offerRemoveLiquidity.positionTokenAmount,
            _offerRemoveLiquidity.minimumTakerFillAmount,
            _takerFillAmount,
            _typedOfferHash
        );

        // Get pool params using `poolId` specified in `_offerRemoveLiquidity`
        LibDIVAStorage.PoolStorage storage ps = LibDIVAStorage._poolStorage();
        LibDIVAStorage.Pool storage _pool = ps.pools[
            _offerRemoveLiquidity.poolId
        ];

        uint256 _collateralAmountRemovedNet = LibDIVA._removeLiquidityLib(
            LibDIVA.RemoveLiquidityParams({
                poolId: _offerRemoveLiquidity.poolId,
                amount: _takerFillAmount,
                longTokenHolder: _offerRemoveLiquidity.makerIsLong
                    ? _offerRemoveLiquidity.maker
                    : msg.sender,
                shortTokenHolder: _offerRemoveLiquidity.makerIsLong
                    ? msg.sender
                    : _offerRemoveLiquidity.maker
            })
        );

        uint256 _collateralAmountRemovedNetMaker = (_collateralAmountRemovedNet *
                (_offerRemoveLiquidity.makerCollateralAmount)) /
                (_offerRemoveLiquidity.positionTokenAmount);

        LibDIVA._returnCollateral(
            _pool,
            _offerRemoveLiquidity.maker,
            _collateralAmountRemovedNetMaker
        );

        LibDIVA._returnCollateral(
            _pool,
            msg.sender,
            _collateralAmountRemovedNet - _collateralAmountRemovedNetMaker
        );
    }

    /**
     * @notice Function to get info of remove liquidity offer.
     * @param _offerRemoveLiquidity Struct containing the remove liquidity offer details
     * @return offerInfo Struct of offer info
     */
    function _getOfferInfoRemoveLiquidity(
        OfferRemoveLiquidity calldata _offerRemoveLiquidity
    ) internal view returns (OfferInfo memory offerInfo) {
        // Get typed offer hash with `_offerRemoveLiquidity`
        offerInfo.typedOfferHash = _toTypedMessageHash(
            _getOfferHashRemoveLiquidity(_offerRemoveLiquidity)
        );

        // Invalidate remove liquidity offers where makerCollateralAmount > positionTokenAmount
        if (
            _offerRemoveLiquidity.makerCollateralAmount >
            _offerRemoveLiquidity.positionTokenAmount
        ) {
            offerInfo.status = OfferStatus.INVALID;
            // offerInfo.takerFilledAmount = 0; Not necesssary to set explicitly as it's automatically initialized to zero
            return offerInfo;
        }

        // Get offer status and takerFilledAmount
        _populateCommonOfferInfoFields(
            offerInfo,
            _offerRemoveLiquidity.positionTokenAmount,
            _offerRemoveLiquidity.offerExpiry
        );
    }

    // Return hash of remove liquidity offer details
    function _getOfferHashRemoveLiquidity(
        OfferRemoveLiquidity memory _offerRemoveLiquidity
    ) internal pure returns (bytes32 offerHashRemoveLiquidity) {
        // Assembly for more efficient computing:
        // Inspired by https://github.com/0xProject/protocol/blob/1fa093be6490cac52dfc17c31cd9fe9ff47ccc5e/contracts/zero-ex/contracts/src/features/libs/LibNativeOrder.sol#L179
        // keccak256(
        //     abi.encode(
        //         REMOVE_LIQUIDITY_OFFER_TYPEHASH,
        //         _offerRemoveLiquidity.maker,
        //         _offerRemoveLiquidity.taker,
        //         _offerRemoveLiquidity.positionTokenAmount,
        //         _offerRemoveLiquidity.makerCollateralAmount,
        //         _offerRemoveLiquidity.makerIsLong,
        //         _offerRemoveLiquidity.offerExpiry,
        //         _offerRemoveLiquidity.minimumTakerFillAmount,
        //         _offerRemoveLiquidity.poolId,
        //         _offerRemoveLiquidity.salt
        //     )
        // )
        assembly {
            let mem := mload(0x40)
            mstore(mem, REMOVE_LIQUIDITY_OFFER_TYPEHASH)
            // _offerRemoveLiquidity.maker;
            mstore(
                add(mem, 0x20),
                and(ADDRESS_MASK, mload(_offerRemoveLiquidity))
            )
            // _offerRemoveLiquidity.taker;
            mstore(
                add(mem, 0x40),
                and(ADDRESS_MASK, mload(add(_offerRemoveLiquidity, 0x20)))
            )
            // _offerRemoveLiquidity.positionTokenAmount;
            mstore(add(mem, 0x60), mload(add(_offerRemoveLiquidity, 0x40)))
            // _offerRemoveLiquidity.makerCollateralAmount;
            mstore(add(mem, 0x80), mload(add(_offerRemoveLiquidity, 0x60)))
            // _offerRemoveLiquidity.makerIsLong;
            mstore(
                add(mem, 0xA0),
                and(UINT_8_MASK, mload(add(_offerRemoveLiquidity, 0x80)))
            )
            // _offerRemoveLiquidity.offerExpiry;
            mstore(add(mem, 0xC0), mload(add(_offerRemoveLiquidity, 0xA0)))
            // _offerRemoveLiquidity.minimumTakerFillAmount;
            mstore(add(mem, 0xE0), mload(add(_offerRemoveLiquidity, 0xC0)))
            // _offerRemoveLiquidity.poolId;
            mstore(add(mem, 0x100), mload(add(_offerRemoveLiquidity, 0xE0)))
            // _offerRemoveLiquidity.salt;
            mstore(add(mem, 0x120), mload(add(_offerRemoveLiquidity, 0x100)))
            offerHashRemoveLiquidity := keccak256(mem, 0x140)
        }
    }

    /**
     * @dev Function to receive information on the fillability of a create contingent
     * pool offer and its validity in terms of signature and input parameters
     * for `createContingentPool` function
     * @param _offerCreateContingentPool Struct containing the create contingent pool
     * offer details
     * @param _signature Offer signature
     */
    function _getOfferRelevantStateCreateContingentPool(
        OfferCreateContingentPool calldata _offerCreateContingentPool,
        Signature calldata _signature
    )
        internal
        view
        returns (
            OfferInfo memory offerInfo,
            uint256 actualTakerFillableAmount,
            bool isSignatureValid,
            bool isValidInputParamsCreateContingentPool
        )
    {
        // Get offer info
        offerInfo = _getOfferInfoCreateContingentPool(
            _offerCreateContingentPool
        );

        // Calc actual taker fillable amount
        actualTakerFillableAmount = _getActualTakerFillableAmount(
            _offerCreateContingentPool.maker,
            _offerCreateContingentPool.collateralToken,
            _offerCreateContingentPool.makerCollateralAmount,
            _offerCreateContingentPool.takerCollateralAmount,
            offerInfo
        );

        // Check if signature is valid
        isSignatureValid = _isSignatureValid(
            offerInfo.typedOfferHash,
            _signature,
            _offerCreateContingentPool.maker
        );

        // Check validity of input parameters for `createContingentPool` function
        isValidInputParamsCreateContingentPool = LibDIVA
            ._validateInputParamsCreateContingentPool(
                LibDIVA.PoolParams({
                    referenceAsset: _offerCreateContingentPool.referenceAsset,
                    expiryTime: _offerCreateContingentPool.expiryTime,
                    floor: _offerCreateContingentPool.floor,
                    inflection: _offerCreateContingentPool.inflection,
                    cap: _offerCreateContingentPool.cap,
                    gradient: _offerCreateContingentPool.gradient,
                    collateralAmount: _offerCreateContingentPool
                        .makerCollateralAmount +
                        _offerCreateContingentPool.takerCollateralAmount,
                    collateralToken: _offerCreateContingentPool.collateralToken,
                    dataProvider: _offerCreateContingentPool.dataProvider,
                    capacity: _offerCreateContingentPool.capacity,
                    longRecipient: _offerCreateContingentPool.makerIsLong
                        ? _offerCreateContingentPool.maker
                        : msg.sender,
                    shortRecipient: _offerCreateContingentPool.makerIsLong
                        ? msg.sender
                        : _offerCreateContingentPool.maker,
                    permissionedERC721Token: _offerCreateContingentPool
                        .permissionedERC721Token
                }),
                IERC20Metadata(_offerCreateContingentPool.collateralToken)
                    .decimals()
            );
    }

    /**
     * @dev Function to receive information on the fillability of an add liquidity
     * pool offer and its signature validity
     * @param _offerAddLiquidity Struct containing the add liquidity offer details
     * @param _signature Offer signature
     * @return offerInfo Struct of offer info
     * @return actualTakerFillableAmount Actual fillable amount for taker
     * @return isSignatureValid Flag indicating whether the signature is valid or not
     * @return poolExists Flag indicating whether a pool exists or not
     */
    function _getOfferRelevantStateAddLiquidity(
        OfferAddLiquidity calldata _offerAddLiquidity,
        Signature calldata _signature
    )
        internal
        view
        returns (
            OfferInfo memory offerInfo,
            uint256 actualTakerFillableAmount,
            bool isSignatureValid,
            bool poolExists
        )
    {
        // Get offer info
        offerInfo = _getOfferInfoAddLiquidity(_offerAddLiquidity);

        // Get pool params using the `poolId` specified in `_offerAddLiquidity`
        LibDIVAStorage.PoolStorage storage ps = LibDIVAStorage._poolStorage();
        LibDIVAStorage.Pool storage _pool = ps.pools[_offerAddLiquidity.poolId];

        // Using collateralToken != address(0) to determine the existence of a pool. This works
        // because this case is excluded when creating a contingent pool as the zero address
        // doesn't implement the required functions (e.g., `transferFrom`) required to create
        // a contingent pool.
        if (_pool.collateralToken != address(0)) {
            // Calc actual taker fillable amount
            actualTakerFillableAmount = _getActualTakerFillableAmount(
                _offerAddLiquidity.maker,
                _pool.collateralToken,
                _offerAddLiquidity.makerCollateralAmount,
                _offerAddLiquidity.takerCollateralAmount,
                offerInfo
            );

            poolExists = true;
        } else {
            actualTakerFillableAmount = 0;
            poolExists = false;
        }

        // Check if signature is valid
        isSignatureValid = _isSignatureValid(
            offerInfo.typedOfferHash,
            _signature,
            _offerAddLiquidity.maker
        );
    }

    /**
     * @dev Function to receive information on the fillability of a remove liquidity
     * pool offer and its signature validity
     * @param _offerRemoveLiquidity Struct containing the remove liquidity offer details
     * @param _signature Offer signature
     * @return offerInfo Struct of offer info
     * @return actualTakerFillableAmount Actual fillable position token amount for taker
     * @return isSignatureValid Flag indicating whether the signature is valid or not
     * @return poolExists Flag indicating whether a pool exists or not
     */
    function _getOfferRelevantStateRemoveLiquidity(
        OfferRemoveLiquidity calldata _offerRemoveLiquidity,
        Signature calldata _signature
    )
        internal
        view
        returns (
            OfferInfo memory offerInfo,
            uint256 actualTakerFillableAmount,
            bool isSignatureValid,
            bool poolExists
        )
    {
        // Get offer info
        offerInfo = _getOfferInfoRemoveLiquidity(_offerRemoveLiquidity);

        // Get pool params using the `poolId` specified in `_offerRemoveLiquidity`
        LibDIVAStorage.PoolStorage storage ps = LibDIVAStorage._poolStorage();
        LibDIVAStorage.Pool storage _pool = ps.pools[
            _offerRemoveLiquidity.poolId
        ];

        // Using collateralToken != address(0) to determine the existence of a pool. This works
        // because this case is excluded when creating a contingent pool as the zero address
        // doesn't implement the required functions (e.g., `transferFrom`) required to create
        // a contingent pool.
        if (_pool.collateralToken != address(0)) {
            // Calc actual taker fillable amount
            if (offerInfo.status != OfferStatus.FILLABLE) {
                actualTakerFillableAmount = 0;
            } else {
                uint256 _makerPositionTokenBalance;
                if (_offerRemoveLiquidity.makerIsLong) {
                    _makerPositionTokenBalance = IERC20(_pool.longToken)
                        .balanceOf(_offerRemoveLiquidity.maker);
                } else {
                    _makerPositionTokenBalance = IERC20(_pool.shortToken)
                        .balanceOf(_offerRemoveLiquidity.maker);
                }

                actualTakerFillableAmount = _min256(
                    _offerRemoveLiquidity.positionTokenAmount -
                        offerInfo.takerFilledAmount,
                    _makerPositionTokenBalance
                );
            }

            poolExists = true;
        } else {
            actualTakerFillableAmount = 0;
            poolExists = false;
        }

        // Check if signature is valid
        isSignatureValid = _isSignatureValid(
            offerInfo.typedOfferHash,
            _signature,
            _offerRemoveLiquidity.maker
        );
    }
}

File 13 of 40 : IEIP712Create.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {LibEIP712} from "../libraries/LibEIP712.sol";

interface IEIP712Create {
    // Struct for `batchFillOfferCreateContingentPool` function input
    struct ArgsBatchFillOfferCreateContingentPool {
        LibEIP712.OfferCreateContingentPool offerCreateContingentPool;
        LibEIP712.Signature signature;
        uint256 takerFillAmount;
    }

    /**
     * @dev Emitted whenever an offer is filled
     * @param typedOfferHash Offer hash
     * @param maker Offer maker address
     * @param taker Offer taker address
     * @param takerFilledAmount Incremental taker filled amount
     */
    event OfferFilled(
        bytes32 indexed typedOfferHash,
        address indexed maker,
        address indexed taker,
        uint256 takerFilledAmount
    );

    /**
     * @notice Function to fill an EIP712 based offer to a create contingent pool.
     * @dev As opposed to `createContingentPool`, the collateral is contributed by
     * both `maker` and `taker` instead of `msg.sender` only according to the
     * ratios implied by `makerCollateralAmount` and `takerCollateralAmount` defined in
     * the offer details.
     * As a result, both `maker` and `taker` need to have a sufficient
     * collateral token balance as well as sufficient allowance to `this` contract
     * to transfer the collateral token from their accounts.
     * The fillability and validity of an offer can be checked via
     * `getOfferRelevantStateCreateContingentPool` prior to execution.
     * @param _offerCreateContingentPool Struct containing the create pool offer details
     * @param _signature Offer signature
     * @param _takerFillAmount Taker collateral amount that the user attempts to fill
     */
    function fillOfferCreateContingentPool(
        LibEIP712.OfferCreateContingentPool calldata _offerCreateContingentPool,
        LibEIP712.Signature calldata _signature,
        uint256 _takerFillAmount
    ) external;

    /**
     * @notice Batch version of `fillOfferCreateContingentPool`
     * @param _argsBatchFillOfferCreateContingentPool Struct array containing
     * offerCreateContingentPool, signature and taker fill amount
     */
    function batchFillOfferCreateContingentPool(
        ArgsBatchFillOfferCreateContingentPool[]
            calldata _argsBatchFillOfferCreateContingentPool
    ) external;
}

File 14 of 40 : IGovernance.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.17;

interface IGovernance {
    enum FeeType {
        PROTOCOL_FEE,
        SETTLEMENT_FEE
    }

    enum SettlementPeriodType {
        SUBMISSION_PERIOD,
        CHALLENGE_PERIOD,
        REVIEW_PERIOD,
        FALLBACK_SUBMISSION_PERIOD
    }

    // Thrown in `updateFees` if contract owner attempts to set
    // 0 < protocol/settlement fee < 0.01% (non-zero minimum)
    error FeeBelowMinimum();

    // Thrown in `updateFees` if contract owner attempts to set
    // protocol/settlement fee > 1.5% (maximum)
    error FeeAboveMaximum();

    // Thrown in `updateSettlementPeriods` if contract owner attempts to set
    // a settlement related period to less than 3 day or more than 15 days
    error OutOfBounds();

    // Thrown in `updateTreasury` and `updateFallbackDataProvider` if contract
    // owner attempts to set the treasury or fallback data provider address equal
    // to the zero address
    error ZeroAddress();

    // Thrown in `pauseReturnCollateral` if contract owner attempts to pause
    // `redeemPositionToken` and `removeLiquidity` before the two day delay period
    // has passed
    error TooEarlyToPauseAgain();

    // Thrown in `updateFees` if there is already a pending fees update
    error PendingFeesUpdate(uint256 _timestampBlock, uint256 _startTimeFees);

    // Thrown in `updateSettlementPeriods` if there is already a pending
    // settlement periods update
    error PendingSettlementPeriodsUpdate(
        uint256 _timestampBlock,
        uint256 _startTimeSettlementPeriods
    );

    // Thrown in `updateFallbackDataProvider` if there is already a
    // pending fallback data provider update
    error PendingFallbackDataProviderUpdate(
        uint256 _timestampBlock,
        uint256 _startTimeFallbackDataProvider
    );

    // Thrown in `setTreasury` if there is already a
    // pending treasury address update
    error PendingTreasuryUpdate(
        uint256 _timestampBlock,
        uint256 _startTimeTreasury
    );

    // Thrown in `revokeLastFeesSet` if the fees update to be revoked is already active
    error FeesAlreadyActive(uint256 _timestampBlock, uint256 _startTimeFees);

    // Thrown in `revokeLastSettlementPeriodsSet` if the settlement periods update
    // to be revoked is already active
    error SettlementPeriodsAlreadyActive(
        uint256 _timestampBlock,
        uint256 _startTimeSettlementPeriods
    );

    // Thrown in `revokePendingFallbackDataProviderUpdate` if the fallback data provider
    // update to be revoked is already active
    error FallbackProviderAlreadyActive(
        uint256 _timestampBlock,
        uint256 _startTimeFallbackDataProvider
    );

    // Thrown in `revokePendingTreasuryUpdate` if the treasury address update
    // to be revoked is already active
    error TreasuryAlreadyActive(
        uint256 _timestampBlock,
        uint256 _startTimeTreasury
    );

    /**
     * @notice Emitted when a fee parameter is updated by the contract owner.
     * @param from Address that initiated the change (contract owner).
     * @param fee New fee amount in % expressed as an integer with 18 decimals
     * (e.g., 2500000000000000 for 0.25%).
     * @param startTime Timestamp in seconds since epoch at which the
     * new fee will be activated.
     * @param feeType Fee Type.
     */
    event FeeUpdated(
        address indexed from,
        uint96 fee,
        uint256 startTime,
        FeeType feeType
    );

    /**
     * @notice Emitted when a settlement related period is updated by the contract owner.
     * @param from Address that initiated the change (contract owner).
     * @param period New period length in seconds.
     * @param startTime The timestamp in seconds since epoch at which the
     * new settlement period will be activated.
     * @param periodType Settlement period type.
     */
    event SettlementPeriodUpdated(
        address indexed from,
        uint24 period,
        uint256 startTime,
        SettlementPeriodType periodType
    );

    /**
     * @notice Emitted when the treasury address is set.
     * @param from The address that initiated the change (contract owner).
     * @param treasury New treasury address.
     * @param startTimeTreasury Timestamp in seconds since epoch at which
     * the new treasury address will be activated.
     */
    event TreasuryUpdated(
        address indexed from,
        address indexed treasury,
        uint256 startTimeTreasury
    );

    /**
     * @notice Emitted when the fallback data provider is updated.
     * @param from The address that initiated the change (contract owner).
     * @param fallbackDataProvider New fallback data provider.
     * @param startTimeFallbackDataProvider Timestamp in seconds since epoch
     * at which the new fallback provider will be activated.
     */
    event FallbackDataProviderUpdated(
        address indexed from,
        address indexed fallbackDataProvider,
        uint256 startTimeFallbackDataProvider
    );

    /**
     * @notice Emitted when the `pauseReturnCollateral` function is called
     * by the contract owner to pause withdrawals via `removeLiquidity`
     * and `redeemPositionToken`.
     * @param from Address that initiated the change (contract owner).
     * @param pausedUntil Timestamp in seconds since epoch until when withdrawals
     * are paused.
     */
    event ReturnCollateralPaused(address indexed from, uint256 pausedUntil);

    /**
     * @notice Emitted when the `unpauseReturnCollateral` function is called
     * by the contract owner to unpause withdrawals.
     * @param from Address that initiated the change (contract owner).
     * @param timestamp Block timestamp prevailing at the time of the call.
     */
    event ReturnCollateralUnpaused(address indexed from, uint256 timestamp);

    /**
     * @notice Emitted when a pending fees update is revoked.
     * @param revokedBy The address that initiated the revocation.
     * @param revokedFee Pending fee that was revoked.
     * @param restoredFee Previous fee that was restored.
     * @param feeType Fee type.
     */
    event PendingFeeUpdateRevoked(
        address indexed revokedBy,
        uint96 revokedFee,
        uint96 restoredFee,
        FeeType feeType
    );

    /**
     * @notice Emitted when a pending settlement periods update is revoked.
     * @param revokedBy The address that initiated the revocation.
     * @param revokedPeriod Pending period length that was revoked.
     * @param restoredPeriod Previous period length that was restored.
     * @param periodType Settlement period type.
     */
    event PendingSettlementPeriodUpdateRevoked(
        address indexed revokedBy,
        uint24 revokedPeriod,
        uint24 restoredPeriod,
        SettlementPeriodType periodType
    );

    /**
     * @notice Emitted when a pending fallback data provider update is revoked.
     * @param revokedBy The address that initiated the revocation.
     * @param revokedFallbackDataProvider Pending fallback data provider that was
     * revoked.
     * @param restoredFallbackDataProvider Previous fallback data provider that was
     * restored.
     */
    event PendingFallbackDataProviderUpdateRevoked(
        address indexed revokedBy,
        address indexed revokedFallbackDataProvider,
        address indexed restoredFallbackDataProvider
    );

    /**
     * @notice Emitted when a pending treasury address update is revoked.
     * @param revokedBy The address that initiated the revocation.
     * @param revokedTreasury Pending treasury address that was revoked.
     * @param restoredTreasury Previous treasury address that was restored.
     */
    event PendingTreasuryUpdateRevoked(
        address indexed revokedBy,
        address indexed revokedTreasury,
        address indexed restoredTreasury
    );

    /**
     * @notice Function to update the protocol and settlement fee.
     * @dev Activation is restricted to the contract owner and subject to
     * a 60-day delay. To keep a fee parameter unchanged, simply pass the current
     * value as argument. New fees will only apply for pools that are created
     * at or after activation time.
     *
     * Reverts if:
     * - `msg.sender` is not contract owner.
     * - one of the new fee parameters is smaller than 0.01% (100000000000000
     *   in integer terms with 18 decimals) or greater than 1.5% (15000000000000000
     *   in integer terms with 18 decimals) if fee > 0; 0% is possible though.
     * - there is already a pending fee update.
     * @param _protocolFee New protocol fee.
     * @param _settlementFee New settlement fee.
     */
    function updateFees(uint96 _protocolFee, uint96 _settlementFee) external;

    /**
     * @notice Function to update settlement related periods.
     * @dev Activation is restricted to the contract owner and subject to
     * a 60-day delay. To keep a period unchanged, simply pass the current
     * value as argument. New periods will only apply for pools that
     * are created at or after activation time.
     *
     * Reverts if:
     * - `msg.sender` is not contract owner.
     * - one of the new periods is outside of the allowed range (i.e., less than 3 days or more than 15 days).
     * - there is already a pending settlement period update.
     * @param _submissionPeriod New submission period in seconds.
     * @param _challengePeriod New challenge period in seconds.
     * @param _reviewPeriod New review period in seconds.
     * @param _fallbackSubmissionPeriod New fallback submission period in seconds.
     */
    function updateSettlementPeriods(
        uint24 _submissionPeriod,
        uint24 _challengePeriod,
        uint24 _reviewPeriod,
        uint24 _fallbackSubmissionPeriod
    ) external;

    /**
     * @notice Function to update the fallback data provider address.
     * @dev Activation is restricted to the contract owner and subject
     * to a 60-day delay. The fallback provider is a global protocol
     * parameter that affects all outstanding pools after activation.
     *
     * Reverts if:
     * - `msg.sender` is not contract owner.
     * - provided address equals zero address.
     * - there is already a pending fallback data provider update.
     * @param _fallbackDataProvider New fallback data provider address.
     */
    function updateFallbackDataProvider(address _fallbackDataProvider) external;

    /**
     * @notice Function to update the treasury address where protocol fees are
     * directed to.
     * @dev Activation is restricted to the contract owner and subject
     * to a 2-day delay.
     *
     * Reverts if:
     * - `msg.sender` is not contract owner.
     * - provided address equals zero address.
     * - there is already a pending treasury address update.
     * @param _treasury New treasury address.
     */
    function updateTreasury(address _treasury) external;

    /**
     * @notice Function to pause the withdrawal of collateral
     * via `removeLiquidity` and `redeemPositionToken`. Note that the pause
     * is limited to a maximum of 8 days and the owner has to wait for at least
     * 2 days before it can be activated again. It is important to highlight
     * that the settlement process will not be interrupted by a pause ensuring
     * that all outstanding pools can be settled correctly. It merely delays
     * the time users can start redeeming their position tokens.
     * @dev The function does not implement a delay to allow the contract owner
     * to act quickly if needed.
     *
     * Reverts if:
     * - `msg.sender` is not contract owner.
     * - triggered during the 2-day delay window after the end of a pause.
     */
    function pauseReturnCollateral() external;

    /**
     * @notice Function to unpause the withdrawal of collateral.
     * @dev Withdrawals are unpaused by updating the `pauseReturnCollateralUntil`
     * variable to the block's timestamp prevailing at the time of the call.
     * The function does not implement a delay.
     */
    function unpauseReturnCollateral() external;

    /**
     * @notice Function to revoke a pending fees update and restore the
     * previous ones.
     * @dev Reverts if:
     * - `msg.sender` is not contract owner.
     * - new fee regime is already active.
     */
    function revokePendingFeesUpdate() external;

    /**
     * @notice Function to revoke a pending settlement periods update and
     * restore the previous ones.
     * @dev Reverts if:
     * - `msg.sender` is not contract owner.
     * - new settlement fee regime is already active.
     */
    function revokePendingSettlementPeriodsUpdate() external;

    /**
     * @notice Function to revoke a pending fallback data provider update
     * and restore the previous one.
     * @dev Reverts if:
     * - `msg.sender` is not contract owner.
     * - new fallback data provider is already active.
     */
    function revokePendingFallbackDataProviderUpdate() external;

    /**
     * @notice Function to revoke a pending treasury address update
     * and restore the previous one.
     * @dev Reverts if:
     * - `msg.sender` is not contract owner.
     * - new treasury address is already active.
     */
    function revokePendingTreasuryUpdate() external;
}

File 15 of 40 : IERC165.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.17;

interface IERC165 {
    /**
     * @notice Query if a contract implements an interface.
     * @dev Interface identification is specified in ERC-165. This function
     * uses less than 30,000 gas.
     * @param interfaceId The interface identifier, as specified in ERC-165.
     * @return `true` if the contract implements `interfaceID` and
     * `interfaceID` is not 0xffffffff, `false` otherwise.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 16 of 40 : IGetter.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.17;

import {LibDIVAStorage} from "../libraries/LibDIVAStorage.sol";
import {LibEIP712} from "../libraries/LibEIP712.sol";

interface IGetter {
    /**
     * @notice Returns the latest pool Id.
     * @return Pool Id.
     */
    function getLatestPoolId() external view returns (uint256);

    /**
     * @notice Returns the pool parameters for a given pool Id. To
     * obtain the fees and settlement periods applicable for the pool,
     * use the `getFees` and `getSettlementPeriods` functions
     * respectively, passing in the returend `indexFees` and
     * `indexSettlementPeriods` as arguments.
     * @param _poolId Id of the pool.
     * @return Pool struct.
     */
    function getPoolParameters(uint256 _poolId)
        external
        view
        returns (LibDIVAStorage.Pool memory);

    /**
     * @notice Same as `getPoolParameters` but using the position token
     * address as input.
     * @param _positionToken Position token address.
     * @return Pool struct.
     */
    function getPoolParametersByAddress(address _positionToken)
        external
        view
        returns (LibDIVAStorage.Pool memory);

    /**
     * @notice Returns the currently applicable governance parameters; ignores
     * parameters pending activation.
     * @return currentFees The current applicable fees.
     * @return currentSettlementPeriods The current applicable settlement periods.
     * @return treasury Current treasury address.
     * @return fallbackDataProvider Current fallback data provider address.
     * @return pauseReturnCollateralUntil Return of collateral paused until in seconds.
     */
    function getGovernanceParameters()
        external
        view
        returns (
            LibDIVAStorage.Fees memory currentFees,
            LibDIVAStorage.SettlementPeriods memory currentSettlementPeriods,
            address treasury,
            address fallbackDataProvider,
            uint256 pauseReturnCollateralUntil
        );

    /**
     * @notice Returns the protocol and settlement fees applicable for
     * a given `_indexFees`.
     * @param _indexFees The index of fees.
     * @return Fees struct.
     */
    function getFees(uint48 _indexFees)
        external
        view
        returns (LibDIVAStorage.Fees memory);

    /**
     * @notice Returns the settlement related periods applicable to
     * a given `_indexSettlementPeriods`.
     * @param _indexSettlementPeriods The index of settlement periods.
     * @return SettlementPeriods struct.
     */
    function getSettlementPeriods(uint48 _indexSettlementPeriods)
        external
        view
        returns (LibDIVAStorage.SettlementPeriods memory);

    /**
     * @notice Returns the last `_nbrLastUpdates` updates of the fees,
     * including any pending updates.
     * @dev `_nbrLastUpdates = 1` returns the most recent update, which
     * may be active or still pending. If the specified number of `_nbrLastUpdates`
     * exceeds the number of available updates, the maximum history will be
     * returned without any error. Returns an empty array if `_nbrLastUpdates = 0`.
     * @param _nbrLastUpdates Number of most recent updates to return.
     * @return Fees struct array.
     */
    function getFeesHistory(uint256 _nbrLastUpdates)
        external
        view
        returns (LibDIVAStorage.Fees[] memory);

    /**
     * @notice Returns the last `_nbrLastUpdates` updates of the settlement periods,
     * including any pending updates.
     * @dev `_nbrLastUpdates = 1` returns the most recent update, which may
     * be active or still pending. If the specified number of `_nbrLastUpdates`
     * exceeds the number of available updates, the maximum history will be
     * returned without any error. Returns an empty array if `_nbrLastUpdates = 0`.
     * @param _nbrLastUpdates Number of most recent updates to return.
     * @return Settlement periods struct array.
     */
    function getSettlementPeriodsHistory(uint256 _nbrLastUpdates)
        external
        view
        returns (LibDIVAStorage.SettlementPeriods[] memory);

    /**
     * @notice Returns the total number of fee updates. At least 1 as the initial
     * fees are set at contract deployment.
     */
    function getFeesHistoryLength() external view returns (uint256);

    /**
     * @notice Returns the total number of settlement period updates. At least 1 as
     * the initial settlement periods are set at contract deployment.
     */
    function getSettlementPeriodsHistoryLength()
        external
        view
        returns (uint256);

    /**
     * @notice Returns the latest update of the fallback data provider, including
     * the activation time and the previous data provider. Since the fallback data
     * provider applies to all pools globally, only the previous data provider
     * is stored for historical reference.
     * @return previousFallbackDataProvider Previous fallback data provider address.
     * @return fallbackDataProvider Latest update of the fallback data provider address.
     * @return startTimeFallbackDataProvider Timestamp in seconds since epoch at which
     * `fallbackDataProvider` is activated.
     */
    function getFallbackDataProviderInfo()
        external
        view
        returns (
            address previousFallbackDataProvider,
            address fallbackDataProvider,
            uint256 startTimeFallbackDataProvider
        );

    /**
     * @notice Returns the latest update of the treasury address, including
     * the activation time and the previous treasury address. Only the
     * previous data address is stored for historical reference.
     * @return previousTreasury Previous treasury address.
     * @return treasury Latest update of the treasury address.
     * @return startTimeTreasury Timestamp in seconds since epoch at which
     * `treasury` is activated.
     */
    function getTreasuryInfo()
        external
        view
        returns (
            address previousTreasury,
            address treasury,
            uint256 startTimeTreasury
        );

    /**
     * @notice Returns the claims by collateral tokens for a given account.
     * @param _recipient Recipient address.
     * @param _collateralToken Collateral token address.
     * @return Fee claim amount.
     */
    function getClaim(address _collateralToken, address _recipient)
        external
        view
        returns (uint256);

    /**
     * @notice Returns the collateral token tip amount for a given
     * pool. Returns zero after a pool has been confirmed and tip has been
     * credited to the `claimableFeeAmount`, which can be retrieved using
     * the `getClaim` function.
     * @param _poolId Id of pool.
     * @return Tip amount expressed as an integer in collateral token decimals.
     */
    function getTip(uint256 _poolId) external view returns (uint256);

    /**
     * @notice Returns the poolId for a given `_typedOfferHash` derived from a
     * create contingent pool offer (EIP712 specific). Note that for an
     * add liquidity offer, the function will return 0 as the `poolId`
     * is part of the offer terms and not stored inside the contract.
     * @param _typedOfferHash Typed offer hash.
     * @return Pool Id linked to the offer.
     */
    function getPoolIdByTypedCreateOfferHash(bytes32 _typedOfferHash)
        external
        view
        returns (uint256);

    /**
     * @notice Returns the filled amount for a given `_typedOfferHash` (EIP712 specific).
     * @param _typedOfferHash Typed offer hash.
     * @return PoolId linked to the offer.
     */
    function getTakerFilledAmount(bytes32 _typedOfferHash)
        external
        view
        returns (uint256);

    /**
     * @notice Returns the chain Id.
     */
    function getChainId() external view returns (uint256);

    /**
     * @notice Function to get state of create contingent pool offer.
     * @param _offerCreateContingentPool Struct containing the create pool offer details
     * @param _signature Signature of signed message with `_offerCreateContingentPool` by `maker`
     * @return offerInfo Struct of offer info:
     * - typedOfferHash: Typed hash value of offer.
     * - status: Status of offer.
     * - takerFilledAmount: Already filled amount by taker.
     * @return actualTakerFillableAmount Actual fillable amount for taker.
     * @return isSignatureValid True if signature is valid, false otherwise.
     * @return isValidInputParamsCreateContingentPool True if input parameters specifying the
     * create contingent pool are valid, false otherwise.
     */
    function getOfferRelevantStateCreateContingentPool(
        LibEIP712.OfferCreateContingentPool calldata _offerCreateContingentPool,
        LibEIP712.Signature calldata _signature
    )
        external
        view
        returns (
            LibEIP712.OfferInfo memory offerInfo,
            uint256 actualTakerFillableAmount,
            bool isSignatureValid,
            bool isValidInputParamsCreateContingentPool
        );

    /**
     * @notice Function to get state of add liquidity offer.
     * @param _offerAddLiquidity Struct containing the add liquidity offer details.
     * @param _signature Signature of signed message with `_offerAddLiquidity` by `maker`.
     * @return offerInfo Struct of offer info.
     * @return actualTakerFillableAmount Actual fillable amount for taker.
     * @return isSignatureValid Flag indicating whether the signature is valid or not.
     * @return poolExists Flag indicating whether a pool exists or not.
     */
    function getOfferRelevantStateAddLiquidity(
        LibEIP712.OfferAddLiquidity calldata _offerAddLiquidity,
        LibEIP712.Signature calldata _signature
    )
        external
        view
        returns (
            LibEIP712.OfferInfo memory offerInfo,
            uint256 actualTakerFillableAmount,
            bool isSignatureValid,
            bool poolExists
        );

    /**
     * @notice Function to get state of remove liquidity offer.
     * @param _offerRemoveLiquidity Struct containing the remove liquidity offer details.
     * @param _signature Signature of signed message with `_offerRemoveLiquidity` by `maker`.
     * @return offerInfo Struct of offer info.
     * @return actualTakerFillableAmount Actual fillable amount for taker.
     * @return isSignatureValid Flag indicating whether the signature is valid or not.
     * @return poolExists Flag indicating whether a pool exists or not.
     */
    function getOfferRelevantStateRemoveLiquidity(
        LibEIP712.OfferRemoveLiquidity calldata _offerRemoveLiquidity,
        LibEIP712.Signature calldata _signature
    )
        external
        view
        returns (
            LibEIP712.OfferInfo memory offerInfo,
            uint256 actualTakerFillableAmount,
            bool isSignatureValid,
            bool poolExists
        );

    /**
     * @notice Get the address of the ownership contract.
     * @return ownershipContract_ The address of the ownership contract.
     */
    function getOwnershipContract()
        external
        view
        returns (address ownershipContract_);

    /**
     * @notice Function to return the owner stored in ownership contract.
     * @return owner_ The address of the owner.
     */
    function getOwner() external view returns (address owner_);
}

File 17 of 40 : ILiquidity.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.17;

interface ILiquidity {
    // Thrown in `addLiquidity` if both `longRecipient` and `shortRecipient`
    // equal to the zero address.
    error ZeroLongAndShortRecipients();

    // Struct for `batchAddLiquidity` function input
    struct ArgsBatchAddLiquidity {
        uint256 poolId;
        uint256 collateralAmountIncr;
        address longRecipient;
        address shortRecipient;
    }

    // Struct for `batchRemoveLiquidity` function input
    struct ArgsBatchRemoveLiquidity {
        uint256 poolId;
        uint256 amount;
    }

    // Duplication of event defined in `LibDIVA.sol` as events emitted out of
    // library functions are not reflected in the contract ABI. Read more about it here:
    // https://web.archive.org/web/20180922101404/https://blog.aragon.org/library-driven-development-in-solidity-2bebcaf88736/
    event LiquidityAdded(
        uint256 indexed poolId,
        address indexed longRecipient,
        address indexed shortRecipient,
        uint256 collateralAmount
    );

    // Duplication of event defined in `LibDIVA.sol` as events emitted out of
    // library functions are not reflected in the contract ABI. Read more about it here:
    // https://web.archive.org/web/20180922101404/https://blog.aragon.org/library-driven-development-in-solidity-2bebcaf88736/
    event LiquidityRemoved(
        uint256 indexed poolId,
        address indexed longTokenHolder,
        address indexed shortTokenHolder,
        uint256 collateralAmount
    );

    event FeeClaimAllocated(
        uint256 indexed poolId,
        address indexed recipient,
        uint256 amount
    );

    /**
     * @notice Function to add collateral to an existing pool. Mints new
     * long and short position tokens with supply equal to collateral
     * amount added and sends them to `_longRecipient` and `_shortRecipient`,
     * respectively.
     * @dev Requires prior ERC20 approval.
     * @param _poolId Id of the pool to add collateral to.
     * @param _collateralAmountIncr Incremental collateral amount to be
     * added to the pool expressed as an integer with collateral token decimals.
     * @param _longRecipient: Address that shall receive the long position tokens.
     * Zero address is a valid input to enable conditional burn use cases.
     * @param _shortRecipient: Address that shall receive the short position tokens.
     * Zero address is a valid input to enable conditional burn use cases.
     */
    function addLiquidity(
        uint256 _poolId,
        uint256 _collateralAmountIncr,
        address _longRecipient,
        address _shortRecipient
    ) external;

    /**
     * @notice Batch version of `addLiquidity`
     * @param _argsBatchAddLiquidity Struct array containing pool id,
     * collateral amount to add, long recipient and short recipient
     */
    function batchAddLiquidity(
        ArgsBatchAddLiquidity[] calldata _argsBatchAddLiquidity
    ) external;

    /**
     * @notice Function to remove collateral from an existing pool.
     * @dev Requires `msg.sender` to return an equal amount of long and short
     * position tokens which are burnt. Collateral amount returned to the user
     * is net of fees. Protocol and settlement fees for DIVA treasury and
     * data provider, respectively, are retained within the contract and can
     * be claimed via `claimFee` function.
     * @param _poolId Id of the pool that a user wants to remove collateral
     * from.
     * @param _amount Number of position tokens to return (1:1 to collateral
     * amount).
     */
    function removeLiquidity(uint256 _poolId, uint256 _amount) external;

    /**
     * @notice Batch version of `removeLiquidity`
     * @param _argsBatchRemoveLiquidity Struct array containing pool id
     * and amount
     */
    function batchRemoveLiquidity(
        ArgsBatchRemoveLiquidity[] calldata _argsBatchRemoveLiquidity
    ) external;
}

File 18 of 40 : IDIVAOwnershipShared.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.17;

interface IDIVAOwnershipShared {
    /**
     * @notice Function to return the current DIVA Protocol owner address.
     * @return Current owner address. On main chain, equal to the existing owner
     * during an on-going election cycle and equal to the new owner afterwards. On secondary
     * chain, equal to the address reported via Tellor oracle.
     */
    function getCurrentOwner() external view returns (address);
}

File 19 of 40 : IPermissionedPositionToken.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.17;

import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";

/**
 * @notice Permissioned version of the position token contract
 */
interface IPermissionedPositionToken is IERC20Upgradeable {
    /**
     * @notice Function to initialize the position token instance
     */
    function initialize(
        string memory symbol_, // name is set equal to symbol
        uint256 poolId_,
        uint8 decimals_,
        address owner_,
        address permissionedERC721Token_
    ) external;

    /**
     * @notice Function to mint ERC20 position tokens. Called during
     * `createContingentPool` and `addLiquidity`. Can only be called by the
     * owner of the position token which is the Diamond contract in the
     * context of DIVA.
     * @param _recipient The account receiving the position tokens.
     * @param _amount The number of position tokens to mint.
     */
    function mint(address _recipient, uint256 _amount) external;

    /**
     * @notice Function to burn position tokens. Called within `redeemPositionToken`
     * and `removeLiquidity`. Can only be called by the owner of the position
     * token which is the Diamond contract in the context of DIVA.
     * @param _redeemer Address redeeming positions tokens in return for
     * collateral.
     * @param _amount The number of position tokens to burn.
     */
    function burn(address _redeemer, uint256 _amount) external;

    /**
     * @notice Returns the Id of the contingent pool that the position token is
     * linked to in the context of DIVA.
     */
    function poolId() external view returns (uint256);

    /**
     * @notice Returns the owner of the position token (Diamond contract in the
     * context of DIVA).
     */
    function owner() external view returns (address);

    /**
     * @notice Return permissioned ERC721 token address
     */
    function permissionedERC721Token() external view returns (address);
}

File 20 of 40 : IPositionToken.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.17;

import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";

/**
 * @notice Position token contract
 * @dev The `PositionToken` contract inherits from ERC20 contract and stores
 * the Id of the pool that the position token is linked to. It implements a
 * `mint` and a `burn` function which can only be called by the `PositionToken`
 * contract owner.
 *
 * Two `PositionToken` contracts are deployed during pool creation process
 * (`createContingentPool`) with Diamond contract being set as the owner.
 * The `mint` function is used during pool creation (`createContingentPool`)
 * and addition of liquidity (`addLiquidity`). Position tokens are burnt
 * during token redemption (`redeemPositionToken`) and removal of liquidity
 * (`removeLiquidity`). The address of the position tokens is stored in the
 * pool parameters within Diamond contract and used to verify the tokens that
 * a user sends back to withdraw collateral.
 *
 * Position tokens have the same number of decimals as the underlying
 * collateral token.
 */
interface IPositionToken is IERC20Upgradeable {
    /**
     * @notice Function to initialize the position token instance
     */
    function initialize(
        string memory symbol_, // name is set equal to symbol
        uint256 poolId_,
        uint8 decimals_,
        address owner_
    ) external;

    /**
     * @notice Function to mint ERC20 position tokens.
     * @dev Called during  `createContingentPool` and `addLiquidity`.
     * Can only be called by the owner of the position token which
     * is the Diamond contract in the context of DIVA.
     * @param _recipient The account receiving the position tokens.
     * @param _amount The number of position tokens to mint.
     */
    function mint(address _recipient, uint256 _amount) external;

    /**
     * @notice Function to burn position tokens.
     * @dev Called within `redeemPositionToken` and `removeLiquidity`.
     * Can only be called by the owner of the position token which
     * is the Diamond contract in the context of DIVA.
     * @param _redeemer Address redeeming positions tokens in return for
     * collateral.
     * @param _amount The number of position tokens to burn.
     */
    function burn(address _redeemer, uint256 _amount) external;

    /**
     * @notice Returns the Id of the contingent pool that the position token is
     * linked to in the context of DIVA.
     */
    function poolId() external view returns (uint256);

    /**
     * @notice Returns the owner of the position token (Diamond contract in the
     * context of DIVA).
     */
    function owner() external view returns (address);
}

File 21 of 40 : IPool.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.17;

import {LibDIVA} from "../libraries/LibDIVA.sol";

interface IPool {
    // Duplication of event defined in `LibDIVA.sol` as events emitted out of
    // library functions are not reflected in the contract ABI. Read more about it here:
    // https://web.archive.org/web/20180922101404/https://blog.aragon.org/library-driven-development-in-solidity-2bebcaf88736/
    event PoolIssued(
        uint256 indexed poolId,
        address indexed longRecipient,
        address indexed shortRecipient,
        uint256 collateralAmount,
        address permissionedERC721Token
    );

    /**
     * @notice Function to issue long and short position tokens to
     * `longRecipient` and `shortRecipient` upon collateral deposit by `msg.sender`. 
     * Provided collateral is kept inside the contract until position tokens are 
     * redeemed by calling `redeemPositionToken` or `removeLiquidity`.
     * @dev Position token supply equals `collateralAmount` (minimum 1e6).
     * Position tokens have the same number of decimals as the collateral token.
     * Only ERC20 tokens with 6 <= decimals <= 18 are accepted as collateral.
     * Tokens with flexible supply like Ampleforth should not be used. When
     * interest/yield bearing tokens are considered, only use tokens with a
     * constant balance mechanism such as Compound's cToken or the wrapped
     * version of Lido's staked ETH (wstETH).
     * ETH is not supported as collateral in v1. It has to be wrapped into WETH
       before deposit.
     * @param _poolParams Struct containing the pool specification:
     * - referenceAsset: The name of the reference asset (e.g., Tesla-USD or
         ETHGasPrice-GWEI).
     * - expiryTime: Expiration time of the position tokens expressed as a unix
         timestamp in seconds.
     * - floor: Value of underlying at or below which the short token will pay
         out the max amount and the long token zero. Expressed as an integer with
         18 decimals.
     * - inflection: Value of underlying at which the long token will payout
         out `gradient` and the short token `1-gradient`. Expressed as an
         integer with 18 decimals.
     * - cap: Value of underlying at or above which the long token will pay
         out the max amount and short token zero. Expressed as an integer with
         18 decimals.
     * - gradient: Long token payout at inflection. The short token payout at
         inflection is `1-gradient`. Expressed as an integer with collateral token
         decimals.
     * - collateralAmount: Collateral amount to be deposited into the pool to
         back the position tokens. Expressed as an integer with collateral token
         decimals.
     * - collateralToken: ERC20 collateral token address.
     * - dataProvider: Address that is supposed to report the final value of
         the reference asset.
     * - capacity: The maximum collateral amount that the pool can accept. Expressed
         as an integer with collateral token decimals.
     * - longRecipient: Address that shall receive the long position tokens. 
     *   Zero address is a valid input to enable conditional burn use cases.
     * - shortRecipient: Address that shall receive the short position tokens.
     *   Zero address is a valid input to enable conditional burn use cases.
     * - permissionedERC721Token: Address of ERC721 token that is allowed to transfer the
     *   position token. Zero address if position token is supposed to be permissionless.
     * @return poolId
     */
    function createContingentPool(LibDIVA.PoolParams memory _poolParams)
        external
        returns (uint256);

    /**
     * @notice Batch version of `createContingentPool`
     * @param _poolsParams Array of PoolParams struct
     */
    function batchCreateContingentPool(LibDIVA.PoolParams[] memory _poolsParams)
        external
        returns (uint256[] memory);
}

File 22 of 40 : IPositionTokenFactory.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.17;

interface IPositionTokenFactory {
    /**
     * @notice Creates a clone of the permissionless position token contract.
     * @param _symbol Symbol string of the position token. Name is set equal to symbol.
     * @param _poolId The Id of the contingent pool that the position token belongs to.
     * @param _decimals Decimals of position token (same as collateral token).
     * @param _owner Owner of the position token. Should always be DIVA Protocol address.
     * @param _permissionedERC721Token Address of permissioned ERC721 token.
     * @return clone Returns the address of the clone contract.
     */
    function createPositionToken(
        string memory _symbol,
        uint256 _poolId,
        uint8 _decimals,
        address _owner,
        address _permissionedERC721Token
    ) external returns (address clone);

    /**
     * @notice Address where the position token implementation contract is stored.
     * @dev This is needed since we are using a clone proxy.
     * @return The implementation address.
     */
    function positionTokenImplementation() external view returns (address);
}

File 23 of 40 : ISettlement.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.17;

import {LibDIVAStorage} from "../libraries/LibDIVAStorage.sol";

interface ISettlement {
    // Thrown in `setFinalReferenceValue` if data provider attempts
    // to submit a value when status is submitted or confirmed
    error AlreadySubmittedOrConfirmed();

    // Thrown in `setFinalReferenceValue` if data provider attempts
    // to submit a value for a pool that didn't expire yet
    error PoolNotExpired();

    // Thrown in `setFinalReferenceValue` if `msg.sender` is not the
    // data provider for the given pool
    error NotDataProvider();

    // Thrown in `setFinalReferenceValue` if `msg.sender` is not the
    // fallback provider if called during the fallback period
    error NotFallbackDataProvider();

    // Thrown in `challengeFinalReferenceValue` if, after the end of the
    // review period, i) a data provider attempts to submit a value or
    // ii) a user attempts to submit a challenge
    error ReviewPeriodExpired();

    // Thrown in `challengeFinalReferenceValue` if a user that doesn't
    // own any position tokens attempts to submit a challenge
    error NoPositionTokens();

    // Thrown in `challengeFinalReferenceValue` if a user attempts to
    // challenge a value submission after the challenge period has expired
    error ChallengePeriodExpired();

    // Thrown in `challengeFinalReferenceValue` if user attempts to challenge
    // whe status is "Open" or "Confirmed"
    error NothingToChallenge();

    // Thrown in `redeemPositionToken` if return of collateral is paused
    error ReturnCollateralPaused();

    // Thrown in `redeemPositionToken` if token to redeem is an invalid
    // position token address
    error InvalidPositionToken();

    // Thrown in `redeemPositionToken` if a user attempts to redeem a
    // position token where the final reference value was not yet set
    error FinalReferenceValueNotSet();

    // Thrown in `redeemPositionToken` if a user attempts to redeem a
    // position token where status is "Submitted" and challenge period
    // did not expire yet
    error ChallengePeriodNotExpired();

    // Thrown in `redeemPositionToken` if a user attempts to redeem a
    // position token where status is "Challenged" and the review period
    // did not expire yet
    error ReviewPeriodNotExpired();

    // Struct for `batchSetFinalReferenceValue` function input
    struct ArgsBatchSetFinalReferenceValue {
        uint256 poolId;
        uint256 finalReferenceValue;
        bool allowChallenge;
    }

    // Struct for `batchChallengeFinalReferenceValue` function input
    struct ArgsBatchChallengeFinalReferenceValue {
        uint256 poolId;
        uint256 proposedFinalReferenceValue;
    }

    // Struct for `batchRedeemPositionToken` function input
    struct ArgsBatchRedeemPositionToken {
        address positionToken;
        uint256 amount;
    }

    /**
     * @notice Emitted when the status of the final reference value changes.
     * @param statusFinalReferenceValue The status of the final value:
     * 0=Open, 1=Submitted, 2=Challenged, or 3=Confirmed
     * @param by Address that triggered the underlying function.
     * @param poolId The Id of the pool in settlement.
     * @param proposedFinalReferenceValue Final reference value proposed by
     * the `msg.sender`.
     */
    event StatusChanged(
        LibDIVAStorage.Status indexed statusFinalReferenceValue,
        address indexed by,
        uint256 indexed poolId,
        uint256 proposedFinalReferenceValue
    );

    /**
     * @notice Emitted when position tokens are redeemed.
     * @param poolId The Id of the pool that the position token belongs to.
     * @param positionToken Address of the position token to redeem.
     * @param amountPositionToken Position token amount returned by user.
     * @param collateralAmountReturned Collateral amount returned to user.
     * @param returnedTo Address that is returned collateral.
     */
    event PositionTokenRedeemed(
        uint256 indexed poolId,
        address indexed positionToken,
        uint256 amountPositionToken,
        uint256 collateralAmountReturned,
        address indexed returnedTo
    );

    // Duplication of event defined in `LibDIVA.sol` as events emitted out of
    // library functions are not reflected in the contract ABI. Read more about it here:
    // https://web.archive.org/web/20180922101404/https://blog.aragon.org/library-driven-development-in-solidity-2bebcaf88736/
    event FeeClaimAllocated(
        uint256 indexed poolId,
        address indexed recipient,
        uint256 amount
    );

    // Duplication of event defined in `LibDIVA.sol` as events emitted out of
    // library functions are not reflected in the contract ABI. Read more about it here:
    // https://web.archive.org/web/20180922101404/https://blog.aragon.org/library-driven-development-in-solidity-2bebcaf88736/
    event TipAllocated(
        uint256 indexed poolId,
        address indexed recipient,
        uint256 amount
    );

    /**
     * @notice Function to submit the final reference value for a given pool Id.
     * @param _poolId The pool Id for which the final value is submitted.
     * @param _finalReferenceValue Proposed final value by the data provider
     * expressed as an integer with 18 decimals.
     * @param _allowChallenge Flag indicating whether the challenge functionality
     * is enabled or disabled for the submitted value. If 0, then the submitted
     * final value will be directly confirmed and position token holders can start
     * redeeming their position tokens. If 1, then position token holders can
     * challenge the submitted value. This flag was introduced to account for
     * decentralized oracle solutions like Uniswap v3 or Chainlink where a
     * dispute mechanism doesn't make sense.
     */
    function setFinalReferenceValue(
        uint256 _poolId,
        uint256 _finalReferenceValue,
        bool _allowChallenge
    ) external;

    /**
     * @notice Batch version of `setFinalReferenceValue`
     * @param _argsBatchSetFinalReferenceValue Struct array containing pool id,
     * final reference value and allowChallenge
     */
    function batchSetFinalReferenceValue(
        ArgsBatchSetFinalReferenceValue[]
            calldata _argsBatchSetFinalReferenceValue
    ) external;

    /**
     * @notice Function to challenge the final value submitted by the data
     * provider.
     * @dev Only position token holders associated with the corresponding pool
     * are allowed to challenge. Function can be triggered multiple times.
     * `_proposedFinalReferenceValue` passed in as argument is not stored
     * in pool parameters but emitted as part of the `StatusChanged` event.
     * @param _poolId Pool Id for which the submitted final value is challenged.
     * @param _proposedFinalReferenceValue The proposed final value by the
     * challenger expressed as an integer with 18 decimals.
     */
    function challengeFinalReferenceValue(
        uint256 _poolId,
        uint256 _proposedFinalReferenceValue
    ) external;

    /**
     * @notice Batch version of `challengeFinalReferenceValue`
     * @param _argsBatchChallengeFinalReferenceValue Struct array containing pool id
     * and proposedFinalReferenceValue
     */
    function batchChallengeFinalReferenceValue(
        ArgsBatchChallengeFinalReferenceValue[]
            calldata _argsBatchChallengeFinalReferenceValue
    ) external;

    /**
     * @notice Function to redeem position tokens. Position tokens are burnt
     * during that process.
     * @dev If the submission period expired without a challenge or a review
     * period expired without another input from the data provider, the
     * previously submitted final value is confirmed inside the function at
     * first user redemption.
     * @param _positionToken address of the position token to be redeemed.
     * @param _amount number of position tokens to be redeemed..
     */
    function redeemPositionToken(address _positionToken, uint256 _amount)
        external;

    /**
     * @notice Batch version of `redeemPositionToken`
     * @param _argsBatchRedeemPositionToken Struct array containing position token
     * and amount
     */
    function batchRedeemPositionToken(
        ArgsBatchRedeemPositionToken[] calldata _argsBatchRedeemPositionToken
    ) external;
}

File 24 of 40 : PositionToken.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.17;

import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import {IPositionToken} from "./interfaces/IPositionToken.sol";

/**
 * @dev Implementation contract for position token clones
 */
contract PositionToken is IPositionToken, ERC20Upgradeable {

    uint256 private _poolId;
    address private _owner;
    uint8 private _decimals;

    constructor() {
        /* @dev To prevent the implementation contract from being used, invoke the {_disableInitializers}
         * function in the constructor to automatically lock it when it is deployed.
         * For more information, refer to @openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol
         */
        _disableInitializers();
    }

    modifier onlyOwner() {
        require(
            _owner == msg.sender,
            "PositionToken: caller is not owner"
            );
        _;
    }

    function mint(
        address _recipient,
        uint256 _amount
        ) external override onlyOwner {
        _mint(_recipient, _amount);
    }

    function burn(
        address _redeemer,
        uint256 _amount
        ) external override onlyOwner {
        _burn(_redeemer, _amount);
    }

    function poolId() external view override returns (uint256) {
        return _poolId;
    }

    function owner() external view override returns (address) {
        return _owner;
    }

    function decimals() public view override returns (uint8) {
        return _decimals;
    }

    function initialize(
        string memory symbol_,
        uint256 poolId_,
        uint8 decimals_,
        address owner_
    ) external override initializer {

        __ERC20_init(symbol_, symbol_);

        _owner = owner_;
        _poolId = poolId_;
        _decimals = decimals_;
    }
}

File 25 of 40 : LibDIVA.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.17;

import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import {PositionToken} from "../PositionToken.sol";
import {IPositionToken} from "../interfaces/IPositionToken.sol";
import {IPositionTokenFactory} from "../interfaces/IPositionTokenFactory.sol";
import {SafeDecimalMath} from "./SafeDecimalMath.sol";
import {LibDIVAStorage} from "./LibDIVAStorage.sol";
import {LibOwnership} from "../libraries/LibOwnership.sol";

// Thrown in `removeLiquidity` or `redeemPositionToken` if collateral amount
// to be returned to user during exceeds the pool's collateral balance
error AmountExceedsPoolCollateralBalance();

// Thrown in `removeLiquidity` if the fee amount to be allocated exceeds the
// pool's current collateral balance
error FeeAmountExceedsPoolCollateralBalance();

// Thrown in `addLiquidity` if the pool is already expired
error PoolExpired();

// Thrown in `createContingentPool` if the input parameters are invalid
error InvalidInputParamsCreateContingentPool();

// Thrown in `addLiquidity` if adding additional collateral would
// result in the pool capacity being exceeded
error PoolCapacityExceeded();

// Thrown in `removeLiquidity` if return collateral is paused
error ReturnCollateralPaused();

// Thrown in `removeLiquidity` if status of `finalReferenceValue`
// is already "Confirmed"
error FinalValueAlreadyConfirmed();

// Thrown in `removeLiquidity` if a user's short or long position
// token balance is smaller than the indicated amount
error InsufficientShortOrLongBalance();

// Thrown in `removeLiquidity` if `_amount` provided by user results
// in a zero protocol fee amount; user should increase their `_amount`
error ZeroProtocolFee();

// Thrown in `removeLiquidity` if `_amount` provided by user results
// in zero settlement fee amount; user should increase `_amount`
error ZeroSettlementFee();

library LibDIVA {
    using SafeDecimalMath for uint256;
    using SafeERC20 for IERC20Metadata;

    // Argument for `createContingentPool` function
    struct PoolParams {
        string referenceAsset;
        uint96 expiryTime;
        uint256 floor;
        uint256 inflection;
        uint256 cap;
        uint256 gradient;
        uint256 collateralAmount;
        address collateralToken;
        address dataProvider;
        uint256 capacity;
        address longRecipient;
        address shortRecipient;
        address permissionedERC721Token;
    }

    // Argument for `_createContingentPoolLib` function
    struct CreatePoolParams {
        PoolParams poolParams;
        uint256 collateralAmountMsgSender;
        uint256 collateralAmountMaker;
        address maker;
    }

    // Argument for `_addLiquidityLib` to avoid stack-too-deep error
    struct AddLiquidityParams {
        uint256 poolId;
        uint256 collateralAmountMsgSender;
        uint256 collateralAmountMaker;
        address maker;
        address longRecipient;
        address shortRecipient;
    }

    // Argument for `_removeLiquidityLib` to avoid stack-too-deep error
    struct RemoveLiquidityParams {
        uint256 poolId;
        uint256 amount;
        address longTokenHolder;
        address shortTokenHolder;
    }

    /**
     * @notice Emitted when fees are allocated.
     * @dev Collateral token can be looked up via the `getPoolParameters`
     * function using the emitted `poolId`.
     * @param poolId The Id of the pool that the fee applies to.
     * @param recipient Address that is allocated the fees.
     * @param amount Fee amount allocated.
     */
    event FeeClaimAllocated(
        uint256 indexed poolId,
        address indexed recipient,
        uint256 amount
    );

    /**
     * @notice Emitted when a new pool is created.
     * @param poolId The Id of the newly created contingent pool.
     * @param longRecipient The address that received the long position tokens.
     * @param shortRecipient The address that received the short position tokens.
     * @param collateralAmount The collateral amount deposited into the pool.
     * @param permissionedERC721Token Address of ERC721 token that the transfer
     * restrictions apply to.
     */
    event PoolIssued(
        uint256 indexed poolId,
        address indexed longRecipient,
        address indexed shortRecipient,
        uint256 collateralAmount,
        address permissionedERC721Token
    );

    /**
     * @notice Emitted when new collateral is added to an existing pool.
     * @param poolId The Id of the pool that collateral was added to.
     * @param longRecipient The address that received the long position token.
     * @param shortRecipient The address that received the short position token.
     * @param collateralAmount The collateral amount added.
     */
    event LiquidityAdded(
        uint256 indexed poolId,
        address indexed longRecipient,
        address indexed shortRecipient,
        uint256 collateralAmount
    );

    /**
     * @notice Emitted when collateral is removed from an existing pool.
     * @param poolId The Id of the pool that collateral was removed from.
     * @param longTokenHolder The address of the user that contributed the long token.
     * @param shortTokenHolder The address of the user that contributed the short token.
     * @param collateralAmount The collateral amount removed from the pool.
     */
    event LiquidityRemoved(
        uint256 indexed poolId,
        address indexed longTokenHolder,
        address indexed shortTokenHolder,
        uint256 collateralAmount
    );

    /**
     * @notice Emitted when a tip has been credited to the data provider after
     * the final value is confirmed.
     * @param poolId Id of the pool for which the tip is credited
     * @param recipient Address of the tip recipient, typically the data provider
     * @param amount Tip amount allocated (in collateral token)
     */
    event TipAllocated(
        uint256 indexed poolId,
        address indexed recipient,
        uint256 amount
    );

    function _poolParameters(uint256 _poolId)
        internal
        view
        returns (LibDIVAStorage.Pool memory)
    {
        return LibDIVAStorage._poolStorage().pools[_poolId];
    }

    function _getLatestPoolId() internal view returns (uint256) {
        return LibDIVAStorage._poolStorage().poolId;
    }

    function _getClaim(address _collateralToken, address _recipient)
        internal
        view
        returns (uint256)
    {
        return
            LibDIVAStorage._feeClaimStorage().claimableFeeAmount[
                _collateralToken
            ][_recipient];
    }

    function _getTip(uint256 _poolId) internal view returns (uint256) {
        return LibDIVAStorage._feeClaimStorage().poolIdToTip[_poolId];
    }

    /**
     * @dev Internal function to transfer the collateral to the user.
     * Openzeppelin's `safeTransfer` method is used to handle different
     * implementations of the ERC20 standard.
     * @param _pool Pool struct.
     * @param _receiver Recipient address.
     * @param _amount Collateral amount to return.
     */
    function _returnCollateral(
        LibDIVAStorage.Pool storage _pool,
        address _receiver,
        uint256 _amount
    ) internal {
        IERC20Metadata collateralToken = IERC20Metadata(_pool.collateralToken);

        // That case shouldn't happen, but if it happens unexpectedly, then
        // it will throw here.
        if (_amount > _pool.collateralBalance)
            revert AmountExceedsPoolCollateralBalance();

        _pool.collateralBalance -= _amount;

        collateralToken.safeTransfer(_receiver, _amount);
    }

    /**
     * @notice Internal function to calculate the payoff per long and short token,
     * net of fees, and store it in `payoutLong` and `payoutShort` inside pool
     * parameters.
     * @dev Called inside `redeemPositionToken` and `setFinalReferenceValue`
     * functions after status of final reference value has been confirmed.
     * @param _pool Pool struct.
     * @param _fees Fees struct.
     * @param _collateralTokenDecimals Collateral token decimals. Passed as
     * argument to avoid reading from storage again.
     */
    function _setPayoutAmount(
        LibDIVAStorage.Pool storage _pool,
        LibDIVAStorage.Fees memory _fees,
        uint8 _collateralTokenDecimals
    ) internal {
        // Calculate payoff per short and long token. Output is in collateral
        // token decimals.
        (_pool.payoutShort, _pool.payoutLong) = _calcPayoffs(
            _pool.floor,
            _pool.inflection,
            _pool.cap,
            _pool.gradient,
            _pool.finalReferenceValue,
            _collateralTokenDecimals,
            _fees.protocolFee + _fees.settlementFee
        );
    }

    /**
     * @notice Internal function used within `setFinalReferenceValue` and
     * `redeemPositionToken` to calculate and allocate fee claims to recipient
     * (DIVA Treasury or data provider). Fee is applied to the overall
     * collateral remaining in the pool and allocated in full the first time
     * the respective function is triggered.
     * @dev Fees can be claimed via the `claimFee` function.
     * @param _poolId Pool Id.
     * @param _pool Pool struct.
     * @param _fee Percentage fee expressed as an integer with 18 decimals
     * @param _recipient Fee recipient address.
     * @param _collateralBalance Current pool collateral balance expressed as
     * an integer with collateral token decimals.
     * @param _collateralTokenDecimals Collateral token decimals.
     */
    function _calcAndAllocateFeeClaim(
        uint256 _poolId,
        LibDIVAStorage.Pool storage _pool,
        uint96 _fee,
        address _recipient,
        uint256 _collateralBalance,
        uint8 _collateralTokenDecimals
    ) internal {
        uint256 _feeAmount = _calcFee(
            _fee,
            _collateralBalance,
            _collateralTokenDecimals
        );

        _allocateFeeClaim(_poolId, _pool, _recipient, _feeAmount);
    }

    /**
     * @notice Internal function to allocate fees to `recipient`.
     * @dev The balance of the recipient is tracked inside the contract and
     * can be claimed via `claimFee` function.
     * @param _poolId Pool Id that the fee applies to.
     * @param _pool Pool struct.
     * @param _recipient Address of the fee recipient.
     * @param _feeAmount Total fee amount expressed as an integer with
     * collateral token decimals.
     */
    function _allocateFeeClaim(
        uint256 _poolId,
        LibDIVAStorage.Pool storage _pool,
        address _recipient,
        uint256 _feeAmount
    ) internal {
        // Get reference to the relevant storage slot
        LibDIVAStorage.FeeClaimStorage storage fs = LibDIVAStorage
            ._feeClaimStorage();

        // Check that fee amount to be allocated doesn't exceed the pool's
        // current `collateralBalance`. This check should never trigger, but
        // kept for safety.
        if (_feeAmount > _pool.collateralBalance)
            revert FeeAmountExceedsPoolCollateralBalance();

        // Reduce `collateralBalance` in pool parameters and increase fee claim
        _pool.collateralBalance -= _feeAmount;
        fs.claimableFeeAmount[_pool.collateralToken][_recipient] += _feeAmount;

        // Log poolId, recipient and fee amount
        emit FeeClaimAllocated(_poolId, _recipient, _feeAmount);
    }

    /**
     * @notice Internal function to transfer the tip to the data provider when the
     * final reference value is confirmed.
     * @dev `poolIdToTip` is set to zero and credited to the fee claim in that process.
     * @param _poolId Id of pool.
     * @param _recipient Tip recipient.
     */
    function _allocateTip(uint256 _poolId, address _recipient) internal {
        // Get references to relevant storage slots
        LibDIVAStorage.FeeClaimStorage storage fs = LibDIVAStorage
            ._feeClaimStorage();
        LibDIVAStorage.PoolStorage storage ps = LibDIVAStorage._poolStorage();

        // Initialize Pool struct
        LibDIVAStorage.Pool storage _pool = ps.pools[_poolId];

        // Get tip for pool
        uint256 _tip = fs.poolIdToTip[_poolId];

        // Credit tip to the claimable fee amount
        fs.poolIdToTip[_poolId] = 0;
        fs.claimableFeeAmount[_pool.collateralToken][_recipient] += _tip;

        // Log event
        emit TipAllocated(_poolId, _recipient, _tip);
    }

    /**
     * @notice Function to calculate the fee amount for a given collateral amount.
     * @dev Output is an integer expressed with collateral token decimals.
     * As fee parameter has 18 decimals but collateral tokens may have
     * less, scaling needs to be applied when using `SafeDecimalMath` library.
     * @param _fee Percentage fee expressed as an integer with 18 decimals
     * (e.g., 0.25% is 2500000000000000).
     * @param _collateralAmount Collateral amount that is used as the basis for
     * the fee calculation expressed as an integer with collateral token decimals.
     * @param _collateralTokenDecimals Collateral token decimals.
     * @return The fee amount expressed as an integer with collateral token decimals.
     */
    function _calcFee(
        uint96 _fee,
        uint256 _collateralAmount,
        uint8 _collateralTokenDecimals
    ) internal pure returns (uint256) {
        uint256 _SCALINGFACTOR = uint256(10**(18 - _collateralTokenDecimals));

        uint256 _feeAmount = uint256(_fee).multiplyDecimal(
            _collateralAmount * _SCALINGFACTOR
        ) / _SCALINGFACTOR;

        return _feeAmount;
    }

    /**
     * @notice Function to calculate the payoffs per long and short token,
     * net of fees.
     * @dev Scaling applied during calculations to handle different decimals.
     * @param _floor Value of underlying at or below which the short token
     * will pay out the max amount and the long token zero. Expressed as an
     * integer with 18 decimals.
     * @param _inflection Value of underlying at which the long token will
     * payout out `_gradient` and the short token `1-_gradient`. Expressed
     * as an integer with 18 decimals.
     * @param _cap Value of underlying at or above which the long token will
     * pay out the max amount and short token zero. Expressed as an integer
     * with 18 decimals.
     * @param _gradient Long token payout at inflection (0 <= _gradient <= 1).
     * Expressed as an integer with collateral token decimals.
     * @param _finalReferenceValue Final value submitted by data provider
     * expressed as an integer with 18 decimals.
     * @param _collateralTokenDecimals Collateral token decimals.
     * @param _fee Fee in percent expressed as an integer with 18 decimals.
     * @return payoffShortNet Payoff per short token (net of fees) expressed
     * as an integer with collateral token decimals.
     * @return payoffLongNet Payoff per long token (net of fees) expressed
     * as an integer with collateral token decimals.
     */
    function _calcPayoffs(
        uint256 _floor,
        uint256 _inflection,
        uint256 _cap,
        uint256 _gradient,
        uint256 _finalReferenceValue,
        uint256 _collateralTokenDecimals,
        uint96 _fee // max value: 5% <= 2^96
    ) internal pure returns (uint96 payoffShortNet, uint96 payoffLongNet) {
        uint256 _SCALINGFACTOR = uint256(10**(18 - _collateralTokenDecimals));
        uint256 _UNIT = SafeDecimalMath.UNIT;
        uint256 _payoffLong;
        uint256 _payoffShort;
        // Note: _gradient * _SCALINGFACTOR not stored in memory for calculations
        // as it would result in a stack-too-deep error

        if (_finalReferenceValue == _inflection) {
            _payoffLong = _gradient * _SCALINGFACTOR;
        } else if (_finalReferenceValue <= _floor) {
            _payoffLong = 0;
        } else if (_finalReferenceValue >= _cap) {
            _payoffLong = _UNIT;
        } else if (_finalReferenceValue < _inflection) {
            _payoffLong = (
                (_gradient * _SCALINGFACTOR).multiplyDecimal(
                    _finalReferenceValue - _floor
                )
            ).divideDecimal(_inflection - _floor);
        } else if (_finalReferenceValue > _inflection) {
            _payoffLong =
                _gradient *
                _SCALINGFACTOR +
                (
                    (_UNIT - _gradient * _SCALINGFACTOR).multiplyDecimal(
                        _finalReferenceValue - _inflection
                    )
                ).divideDecimal(_cap - _inflection);
        }

        _payoffShort = _UNIT - _payoffLong;

        payoffShortNet = uint96(
            _payoffShort.multiplyDecimal(_UNIT - _fee) / _SCALINGFACTOR
        );
        payoffLongNet = uint96(
            _payoffLong.multiplyDecimal(_UNIT - _fee) / _SCALINGFACTOR
        );

        return (payoffShortNet, payoffLongNet); // collateral token decimals
    }

    function _createContingentPoolLib(CreatePoolParams memory _createPoolParams)
        internal
        returns (uint256)
    {
        // Restrict ability to create pools to owner in this pilot version
        // of the contract
        LibOwnership._enforceIsContractOwner();

        // Get reference to relevant storage slots
        LibDIVAStorage.PoolStorage storage ps = LibDIVAStorage._poolStorage();
        LibDIVAStorage.GovernanceStorage storage gs = LibDIVAStorage
            ._governanceStorage();

        // Create reference to collateral token corresponding to the provided pool Id
        IERC20Metadata collateralToken = IERC20Metadata(
            _createPoolParams.poolParams.collateralToken
        );

        uint8 _collateralTokenDecimals = collateralToken.decimals();

        // Check validity of input parameters
        if (
            !_validateInputParamsCreateContingentPool(
                _createPoolParams.poolParams,
                _collateralTokenDecimals
            )
        ) revert InvalidInputParamsCreateContingentPool();

        // Increment `poolId` every time a new pool is created. Index
        // starts at 1. No overflow risk when using compiler version >= 0.8.0.
        ++ps.poolId;

        // Cache new poolId to avoid reading from storage
        uint256 _poolId = ps.poolId;

        // Transfer approved collateral tokens from `msg.sender` to `this`.
        collateralToken.safeTransferFrom(
            msg.sender,
            address(this),
            _createPoolParams.collateralAmountMsgSender
        );

        // Transfer approved collateral tokens from maker. Applies only for `fillOfferCreateContingentPool`
        // when makerFillAmount > 0. Requires prior approval from `maker` to execute this transaction.
        if (_createPoolParams.collateralAmountMaker != 0) {
            collateralToken.safeTransferFrom(
                _createPoolParams.maker,
                address(this),
                _createPoolParams.collateralAmountMaker
            );
        }

        // Deploy two `PositionToken` contract clones, one that represents shares in the short
        // and one that represents shares in the long position.
        // Naming convention for short/long token: S13/L13 where 13 is the poolId
        // Diamond contract (address(this) due to delegatecall) is set as the
        // owner of the position tokens and is the only account that is
        // authorized to call the `mint` and `burn` function therein.
        // Note that position tokens have same number of decimals as collateral token.
        address _shortToken = IPositionTokenFactory(ps.positionTokenFactory)
            .createPositionToken(
                string(abi.encodePacked("S", Strings.toString(_poolId))), // name is equal to symbol
                _poolId,
                _collateralTokenDecimals,
                address(this),
                _createPoolParams.poolParams.permissionedERC721Token
            );

        address _longToken = IPositionTokenFactory(ps.positionTokenFactory)
            .createPositionToken(
                string(abi.encodePacked("L", Strings.toString(_poolId))), // name is equal to symbol
                _poolId,
                _collateralTokenDecimals,
                address(this),
                _createPoolParams.poolParams.permissionedERC721Token
            );

        (uint48 _indexFees, ) = _getCurrentFees(gs);
        (uint48 _indexSettlementPeriods, ) = _getCurrentSettlementPeriods(gs);

        // Store `Pool` struct in `pools` mapping for the newly generated `poolId`
        ps.pools[_poolId] = LibDIVAStorage.Pool(
            _createPoolParams.poolParams.floor,
            _createPoolParams.poolParams.inflection,
            _createPoolParams.poolParams.cap,
            _createPoolParams.poolParams.gradient,
            _createPoolParams.poolParams.collateralAmount,
            0, // finalReferenceValue
            _createPoolParams.poolParams.capacity,
            block.timestamp,
            _shortToken,
            0, // payoutShort
            _longToken,
            0, // payoutLong
            _createPoolParams.poolParams.collateralToken,
            _createPoolParams.poolParams.expiryTime,
            address(_createPoolParams.poolParams.dataProvider),
            _indexFees,
            _indexSettlementPeriods,
            LibDIVAStorage.Status.Open,
            _createPoolParams.poolParams.referenceAsset
        );

        // Number of position tokens is set equal to the total collateral to
        // standardize the max payout at 1.0. Position tokens are sent to the recipients
        // provided as part of the input parameters.
        IPositionToken(_shortToken).mint(
            _createPoolParams.poolParams.shortRecipient,
            _createPoolParams.poolParams.collateralAmount
        );
        IPositionToken(_longToken).mint(
            _createPoolParams.poolParams.longRecipient,
            _createPoolParams.poolParams.collateralAmount
        );

        // Log pool creation
        emit PoolIssued(
            _poolId,
            _createPoolParams.poolParams.longRecipient,
            _createPoolParams.poolParams.shortRecipient,
            _createPoolParams.poolParams.collateralAmount,
            _createPoolParams.poolParams.permissionedERC721Token
        );

        return _poolId;
    }

    function _validateInputParamsCreateContingentPool(
        PoolParams memory _poolParams,
        uint8 _collateralTokenDecimals
    ) internal view returns (bool) {
        // Expiry time should not be equal to or smaller than `block.timestamp`
        if (_poolParams.expiryTime <= block.timestamp) {
            return false;
        }

        // Reference asset should not be empty string
        if (bytes(_poolParams.referenceAsset).length == 0) {
            return false;
        }

        // Floor should not be greater than inflection
        if (_poolParams.floor > _poolParams.inflection) {
            return false;
        }

        // Cap should not be smaller than inflection
        if (_poolParams.cap < _poolParams.inflection) {
            return false;
        }

        // Data provider should not be zero address
        if (_poolParams.dataProvider == address(0)) {
            return false;
        }

        // Gradient should not be greater than 1 (integer in collateral token decimals)
        if (_poolParams.gradient > uint256(10**_collateralTokenDecimals)) {
            return false;
        }

        // Collateral amount should not be smaller than 1e6
        if (_poolParams.collateralAmount < 10**6) {
            return false;
        }

        // Collateral amount should not be greater than pool capacity
        if (_poolParams.collateralAmount > _poolParams.capacity) {
            return false;
        }

        // Collateral token should not have decimals larger than 18 or smaller than 6
        if ((_collateralTokenDecimals > 18) || (_collateralTokenDecimals < 6)) {
            return false;
        }

        // `longRecipient` and `shortRecipient` should not be both zero address
        if (
            _poolParams.longRecipient == address(0) &&
            _poolParams.shortRecipient == address(0)
        ) {
            return false;
        }

        return true;

        // Note: Conscious decision to allow either `longRecipient` or `shortRecipient` to
        // to be equal to the zero address to enable conditional burn use cases.
    }

    // Function to transfer collateral from msg.sender/maker to `this` and mint position token
    function _addLiquidityLib(AddLiquidityParams memory addLiquidityParams)
        internal
    {
        // Get reference to relevant storage slot
        LibDIVAStorage.PoolStorage storage ps = LibDIVAStorage._poolStorage();

        // Initialize Pool struct
        LibDIVAStorage.Pool storage _pool = ps.pools[addLiquidityParams.poolId];

        // Connect to collateral token contract of the given pool Id
        IERC20Metadata collateralToken = IERC20Metadata(_pool.collateralToken);

        // Transfer approved collateral tokens from `msg.sender` (taker in `fillOfferAddLiquidity`) to `this`.
        // Requires prior approval from `msg.sender` to execute this transaction.
        collateralToken.safeTransferFrom(
            msg.sender,
            address(this),
            addLiquidityParams.collateralAmountMsgSender
        );

        // Transfer approved collateral tokens from maker. Applies only for `fillOfferAddLiquidity`
        // when makerFillAmount > 0. Requires prior approval from `maker` to execute this transaction.
        if (addLiquidityParams.collateralAmountMaker != 0) {
            collateralToken.safeTransferFrom(
                addLiquidityParams.maker,
                address(this),
                addLiquidityParams.collateralAmountMaker
            );
        }

        uint256 _collateralAmountIncr = addLiquidityParams
            .collateralAmountMsgSender +
            addLiquidityParams.collateralAmountMaker;

        // Increase `collateralBalance`
        _pool.collateralBalance += _collateralAmountIncr;

        // Mint long and short position tokens and send to `shortRecipient` and
        // `_longRecipient`, respectively (additional supply equals `_collateralAmountIncr`)
        IPositionToken(_pool.shortToken).mint(
            addLiquidityParams.shortRecipient,
            _collateralAmountIncr
        );
        IPositionToken(_pool.longToken).mint(
            addLiquidityParams.longRecipient,
            _collateralAmountIncr
        );

        // Log addition of collateral
        emit LiquidityAdded(
            addLiquidityParams.poolId,
            addLiquidityParams.longRecipient,
            addLiquidityParams.shortRecipient,
            _collateralAmountIncr
        );
    }

    function _checkAddLiquidityAllowed(
        LibDIVAStorage.Pool storage _pool,
        uint256 _collateralAmountIncr
    ) internal view {
        // Check that pool has not expired yet
        if (block.timestamp >= _pool.expiryTime) revert PoolExpired();

        // Check that new total pool collateral does not exceed the maximum
        // capacity of the pool
        if ((_pool.collateralBalance + _collateralAmountIncr) > _pool.capacity)
            revert PoolCapacityExceeded();
    }

    function _removeLiquidityLib(
        RemoveLiquidityParams memory _removeLiquidityParams
    ) internal returns (uint256 collateralAmountRemovedNet) {
        // Get references to relevant storage slots
        LibDIVAStorage.PoolStorage storage ps = LibDIVAStorage._poolStorage();
        LibDIVAStorage.GovernanceStorage storage gs = LibDIVAStorage
            ._governanceStorage();

        // Confirm that functionality is not paused
        if (block.timestamp < gs.pauseReturnCollateralUntil)
            revert ReturnCollateralPaused();

        // Initialize Pool struct
        LibDIVAStorage.Pool storage _pool = ps.pools[
            _removeLiquidityParams.poolId
        ];

        // If status is Confirmed, users should use `redeemPositionToken` function
        // to withdraw collateral
        if (_pool.statusFinalReferenceValue == LibDIVAStorage.Status.Confirmed)
            revert FinalValueAlreadyConfirmed();

        // Create reference to short and long position tokens for the given pool
        IPositionToken shortToken = IPositionToken(_pool.shortToken);
        IPositionToken longToken = IPositionToken(_pool.longToken);

        // Check that `shortTokenHolder` and `longTokenHolder` own the corresponding
        // `_amount` of short and long position tokens. In particular, this check will
        // revert when a user tries to remove an amount that exceeds the overall position token
        // supply which is the maximum amount that a user can own.
        if (
            shortToken.balanceOf(_removeLiquidityParams.shortTokenHolder) <
            _removeLiquidityParams.amount ||
            longToken.balanceOf(_removeLiquidityParams.longTokenHolder) <
            _removeLiquidityParams.amount
        ) revert InsufficientShortOrLongBalance();

        // Get fee parameters applicable for given `_poolId`
        LibDIVAStorage.Fees memory _fees = gs.fees[_pool.indexFees];

        uint256 _protocolFee;
        uint256 _settlementFee;

        if (_fees.protocolFee > 0) {
            // Calculate protocol fees to charge (note that collateral amount
            // to return is equal to `_amount`)
            _protocolFee = _calcFee(
                _fees.protocolFee,
                _removeLiquidityParams.amount,
                IERC20Metadata(_pool.collateralToken).decimals()
            );
            // User has to increase `_amount` if fee is 0
            if (_protocolFee == 0) revert ZeroProtocolFee();
        } // else _protocolFee = 0 (default value for uint256)

        if (_fees.settlementFee > 0) {
            // Calculate settlement fees to charge
            _settlementFee = _calcFee(
                _fees.settlementFee,
                _removeLiquidityParams.amount,
                IERC20Metadata(_pool.collateralToken).decimals()
            );
            // User has to increase `_amount` if fee is 0
            if (_settlementFee == 0) revert ZeroSettlementFee();
        } // else _settlementFee = 0 (default value for uint256)

        // Burn short and long position tokens
        shortToken.burn(
            _removeLiquidityParams.shortTokenHolder,
            _removeLiquidityParams.amount
        );
        longToken.burn(
            _removeLiquidityParams.longTokenHolder,
            _removeLiquidityParams.amount
        );

        // Allocate protocol fee to DIVA treasury. Fee is held within this
        // contract and can be claimed via `claimFee` function.
        // `collateralBalance` is reduced inside `_allocateFeeClaim`.
        _allocateFeeClaim(
            _removeLiquidityParams.poolId,
            _pool,
            LibDIVAStorage._governanceStorage().treasury,
            _protocolFee
        );

        // Allocate settlement fee to data provider. Fee is held within this
        // contract and can be claimed via `claimFee` function.
        _allocateFeeClaim(
            _removeLiquidityParams.poolId,
            _pool,
            _pool.dataProvider,
            _settlementFee
        );

        // Collateral amount to return net of fees
        collateralAmountRemovedNet =
            _removeLiquidityParams.amount -
            _protocolFee -
            _settlementFee;

        // Log removal of liquidity
        emit LiquidityRemoved(
            _removeLiquidityParams.poolId,
            _removeLiquidityParams.longTokenHolder,
            _removeLiquidityParams.shortTokenHolder,
            _removeLiquidityParams.amount
        );
    }

    function _getFeesHistory(
        uint256 _nbrLastUpdates,
        LibDIVAStorage.GovernanceStorage storage _gs
    ) internal view returns (LibDIVAStorage.Fees[] memory) {
        if (_nbrLastUpdates > 0) {
            // Cache length to avoid reading from storage on every loop
            uint256 _len = _gs.fees.length;

            // Cap `_nbrLastUpdates` at max history rather than throwing an error
            _nbrLastUpdates = _nbrLastUpdates > _len ? _len : _nbrLastUpdates;

            // Define the size of the array to be returned
            LibDIVAStorage.Fees[] memory _fees = new LibDIVAStorage.Fees[](
                _nbrLastUpdates
            );

            // Iterate through the fees array starting from the latest item
            for (uint256 i = _len; i > _len - _nbrLastUpdates; ) {
                _fees[_len - i] = _gs.fees[i - 1]; // first element of _fees represents latest fees
                unchecked {
                    --i;
                }
            }
            return _fees;
        } else {
            return new LibDIVAStorage.Fees[](0);
        }
    }

    function _getSettlementPeriodsHistory(
        uint256 _nbrLastUpdates,
        LibDIVAStorage.GovernanceStorage storage _gs
    ) internal view returns (LibDIVAStorage.SettlementPeriods[] memory) {
        if (_nbrLastUpdates > 0) {
            // Cache length to avoid reading from storage on every loop
            uint256 _len = _gs.settlementPeriods.length;

            // Cap `_nbrLastUpdates` at max history rather than throwing an error
            _nbrLastUpdates = _nbrLastUpdates > _len ? _len : _nbrLastUpdates;

            // Define the size of the array to be returned
            LibDIVAStorage.SettlementPeriods[]
                memory _settlementPeriods = new LibDIVAStorage.SettlementPeriods[](
                    _nbrLastUpdates
                );

            // Iterate through the settlement periods array starting from the latest item
            for (uint256 i = _len; i > _len - _nbrLastUpdates; ) {
                _settlementPeriods[_len - i] = _gs.settlementPeriods[i - 1]; // first element of _fees represents latest fees
                unchecked {
                    --i;
                }
            }
            return _settlementPeriods;
        } else {
            return new LibDIVAStorage.SettlementPeriods[](0);
        }
    }

    function _getCurrentFees(LibDIVAStorage.GovernanceStorage storage _gs)
        internal
        view
        returns (uint48 index, LibDIVAStorage.Fees memory fees)
    {
        // Get length of `fees` array
        uint256 _len = _gs.fees.length;

        // Load latest fee regime
        LibDIVAStorage.Fees memory _fees = _gs.fees[_len - 1];

        // Return the latest array entry & index if already past activation time,
        // otherwise return the second last entry
        if (_fees.startTime > block.timestamp) {
            index = uint48(_len - 2);
        } else {
            index = uint48(_len - 1);
        }
        fees = _gs.fees[index];
    }

    function _getCurrentSettlementPeriods(
        LibDIVAStorage.GovernanceStorage storage _gs
    )
        internal
        view
        returns (
            uint48 index,
            LibDIVAStorage.SettlementPeriods memory settlementPeriods
        )
    {
        // Get length of `settlementPeriods` array
        uint256 _len = _gs.settlementPeriods.length;

        // Load latest settlement periods regime
        LibDIVAStorage.SettlementPeriods memory _settlementPeriods = _gs
            .settlementPeriods[_len - 1];

        // Return the latest array entry & index if already past activation time,
        // otherwise return the second last entry
        if (_settlementPeriods.startTime > block.timestamp) {
            index = uint48(_len - 2);
        } else {
            index = uint48(_len - 1);
        }
        settlementPeriods = _gs.settlementPeriods[index];
    }

    function _getCurrentFallbackDataProvider(
        LibDIVAStorage.GovernanceStorage storage _gs
    ) internal view returns (address) {
        // Return the new fallback data provider if `block.timestamp` is at or past
        // the activation time, else return the current fallback data provider
        return
            block.timestamp < _gs.startTimeFallbackDataProvider
                ? _gs.previousFallbackDataProvider
                : _gs.fallbackDataProvider;
    }

    function _getCurrentTreasury(LibDIVAStorage.GovernanceStorage storage _gs)
        internal
        view
        returns (address)
    {
        // Return the new treasury address if `block.timestamp` is at or past
        // the activation time, else return the current treasury address
        return
            block.timestamp < _gs.startTimeTreasury
                ? _gs.previousTreasury
                : _gs.treasury;
    }

    function _getFallbackDataProviderInfo(
        LibDIVAStorage.GovernanceStorage storage _gs
    )
        internal
        view
        returns (
            address previousFallbackDataProvider,
            address fallbackDataProvider,
            uint256 startTimeFallbackDataProvider
        )
    {
        // Return values
        previousFallbackDataProvider = _gs.previousFallbackDataProvider;
        fallbackDataProvider = _gs.fallbackDataProvider;
        startTimeFallbackDataProvider = _gs.startTimeFallbackDataProvider;
    }

    function _getTreasuryInfo(LibDIVAStorage.GovernanceStorage storage _gs)
        internal
        view
        returns (
            address previousTreasury,
            address treasury,
            uint256 startTimeTreasury
        )
    {
        // Return values
        previousTreasury = _gs.previousTreasury;
        treasury = _gs.treasury;
        startTimeTreasury = _gs.startTimeTreasury;
    }
}

File 26 of 40 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _HEX_SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }
}

File 27 of 40 : ECDSA.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.3) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.0;

import "../Strings.sol";

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS,
        InvalidSignatureV
    }

    function _throwError(RecoverError error) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert("ECDSA: invalid signature");
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert("ECDSA: invalid signature length");
        } else if (error == RecoverError.InvalidSignatureS) {
            revert("ECDSA: invalid signature 's' value");
        } else if (error == RecoverError.InvalidSignatureV) {
            revert("ECDSA: invalid signature 'v' value");
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature` or error string. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength);
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, signature);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address, RecoverError) {
        bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
        uint8 v = uint8((uint256(vs) >> 255) + 27);
        return tryRecover(hash, v, r, s);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     *
     * _Available since v4.2._
     */
    function recover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, r, vs);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address, RecoverError) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS);
        }
        if (v != 27 && v != 28) {
            return (address(0), RecoverError.InvalidSignatureV);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature);
        }

        return (signer, RecoverError.NoError);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from `s`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
    }

    /**
     * @dev Returns an Ethereum Signed Typed Data, created from a
     * `domainSeparator` and a `structHash`. This produces hash corresponding
     * to the one signed with the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
     * JSON-RPC method as part of EIP-712.
     *
     * See {recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
    }
}

File 28 of 40 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 29 of 40 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 30 of 40 : ERC20Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0-rc.1) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.0;

import "./IERC20Upgradeable.sol";
import "./extensions/IERC20MetadataUpgradeable.sol";
import "../../utils/ContextUpgradeable.sol";
import "../../proxy/utils/Initializable.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable {
    mapping(address => uint256) private _balances;

    mapping(address => mapping(address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * The default value of {decimals} is 18. To select a different value for
     * {decimals} you should overload it.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing {
        __ERC20_init_unchained(name_, symbol_);
    }

    function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the value {ERC20} uses, unless this function is
     * overridden;
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address to, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `amount`.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, amount);
        _transfer(from, to, amount);
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, allowance(owner, spender) + addedValue);
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        address owner = _msgSender();
        uint256 currentAllowance = allowance(owner, spender);
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        unchecked {
            _approve(owner, spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    /**
     * @dev Moves `amount` of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     */
    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {
        require(from != address(0), "ERC20: transfer from the zero address");
        require(to != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(from, to, amount);

        uint256 fromBalance = _balances[from];
        require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[from] = fromBalance - amount;
            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
            // decrementing then incrementing.
            _balances[to] += amount;
        }

        emit Transfer(from, to, amount);

        _afterTokenTransfer(from, to, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply += amount;
        unchecked {
            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
            _balances[account] += amount;
        }
        emit Transfer(address(0), account, amount);

        _afterTokenTransfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
            // Overflow not possible: amount <= accountBalance <= totalSupply.
            _totalSupply -= amount;
        }

        emit Transfer(account, address(0), amount);

        _afterTokenTransfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
     *
     * Does not update the allowance amount in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Might emit an {Approval} event.
     */
    function _spendAllowance(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            require(currentAllowance >= amount, "ERC20: insufficient allowance");
            unchecked {
                _approve(owner, spender, currentAllowance - amount);
            }
        }
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}

    /**
     * @dev Hook that is called after any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * has been transferred to `to`.
     * - when `from` is zero, `amount` tokens have been minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[45] private __gap;
}

File 31 of 40 : IERC20Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20Upgradeable {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

File 32 of 40 : ContextUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
    }

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

File 33 of 40 : IERC20MetadataUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20Upgradeable.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20MetadataUpgradeable is IERC20Upgradeable {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 34 of 40 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0-rc.1) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.2;

import "../../utils/AddressUpgradeable.sol";

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     * @custom:oz-retyped-from bool
     */
    uint8 private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint8 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
     * constructor.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        bool isTopLevelCall = !_initializing;
        require(
            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
            "Initializable: contract is already initialized"
        );
        _initialized = 1;
        if (isTopLevelCall) {
            _initializing = true;
        }
        _;
        if (isTopLevelCall) {
            _initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: setting the version to 255 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint8 version) {
        require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
        _initialized = version;
        _initializing = true;
        _;
        _initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        require(!_initializing, "Initializable: contract is initializing");
        if (_initialized < type(uint8).max) {
            _initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }

    /**
     * @dev Internal function that returns the initialized version. Returns `_initialized`
     */
    function _getInitializedVersion() internal view returns (uint8) {
        return _initialized;
    }

    /**
     * @dev Internal function that returns the initialized version. Returns `_initializing`
     */
    function _isInitializing() internal view returns (bool) {
        return _initializing;
    }
}

File 35 of 40 : AddressUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0-rc.1) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

File 36 of 40 : SafeDecimalMath.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.17;

/**
 * @notice Reduced version of Synthetix' SafeDecimalMath library for decimal
 * calculations:
 * https://github.com/Synthetixio/synthetix/blob/master/contracts/SafeDecimalMath.sol
 * Note that the code was adjusted for solidity 0.8.17 where SafeMath is no
 * longer required to handle overflows
 */

library SafeDecimalMath {
    /* Number of decimal places in the representations. */
    uint8 public constant decimals = 18;

    /* The number representing 1.0. */
    uint256 public constant UNIT = 10**uint256(decimals);

    /**
     * @return Provides an interface to UNIT.
     */
    function unit() external pure returns (uint256) {
        return UNIT;
    }

    /**
     * @return The result of multiplying x and y, interpreting the operands
     * as fixed-point decimals.
     *
     * @dev A unit factor is divided out after the product of x and y is
     * evaluated, so that product must be less than 2**256. As this is an
     * integer division, the internal division always rounds down. This helps
     * save on gas. Rounding is more expensive on gas.
     */
    function multiplyDecimal(uint256 x, uint256 y)
        internal
        pure
        returns (uint256)
    {
        // Divide by UNIT to remove the extra factor introduced by the product
        return (x * y) / UNIT;
    }

    /**
     * @return The result of safely dividing x and y. The return value is a high
     * precision decimal.
     *
     * @dev y is divided after the product of x and the standard precision unit
     * is evaluated, so the product of x and UNIT must be less than 2**256. As
     * this is an integer division, the result is always rounded down.
     * This helps save on gas. Rounding is more expensive on gas.
     */
    function divideDecimal(uint256 x, uint256 y)
        internal
        pure
        returns (uint256)
    {
        // Reintroduce the UNIT factor that will be divided out by y
        return (x * UNIT) / y;
    }
}

File 37 of 40 : LibOwnership.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.17;

import {IDIVAOwnershipShared} from "../interfaces/IDIVAOwnershipShared.sol";
import {LibDiamondStorage} from "./LibDiamondStorage.sol";

// Thrown if `msg.sender` is not contract owner
error NotContractOwner(address _user, address _contractOwner);

library LibOwnership {
    function _contractOwner() internal view returns (address contractOwner_) {
        LibDiamondStorage.DiamondStorage storage ds = LibDiamondStorage
            ._diamondStorage();
        contractOwner_ = IDIVAOwnershipShared(ds.ownershipContract)
            .getCurrentOwner();
    }

    function _ownershipContract()
        internal
        view
        returns (address ownershipContract_)
    {
        LibDiamondStorage.DiamondStorage storage ds = LibDiamondStorage
            ._diamondStorage();
        ownershipContract_ = ds.ownershipContract;
    }

    function _enforceIsContractOwner() internal view {
        address _owner = _contractOwner();
        if (msg.sender != _owner) revert NotContractOwner(msg.sender, _owner);
    }
}

File 38 of 40 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

File 39 of 40 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly
                /// @solidity memory-safe-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 40 of 40 : draft-IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_ownershipContract","type":"address"},{"internalType":"address","name":"_fallbackDataProvider","type":"address"},{"internalType":"address","name":"_diamondCutFacet","type":"address"},{"internalType":"address","name":"_treasury","type":"address"},{"internalType":"address","name":"_positionTokenFactory","type":"address"}],"stateMutability":"payable","type":"constructor"},{"inputs":[{"internalType":"bytes4","name":"_selector","type":"bytes4"}],"name":"CannotAddFunctionToDiamondThatAlreadyExists","type":"error"},{"inputs":[{"internalType":"bytes4[]","name":"_selectors","type":"bytes4[]"}],"name":"CannotAddSelectorsToZeroAddress","type":"error"},{"inputs":[{"internalType":"bytes4","name":"_selector","type":"bytes4"}],"name":"CannotRemoveFunctionThatDoesNotExist","type":"error"},{"inputs":[{"internalType":"bytes4","name":"_selector","type":"bytes4"}],"name":"CannotRemoveImmutableFunction","type":"error"},{"inputs":[{"internalType":"bytes4","name":"_selector","type":"bytes4"}],"name":"CannotReplaceFunctionWithTheSameFunctionFromTheSameFacet","type":"error"},{"inputs":[{"internalType":"bytes4[]","name":"_selectors","type":"bytes4[]"}],"name":"CannotReplaceFunctionsFromFacetWithZeroAddress","type":"error"},{"inputs":[{"internalType":"address","name":"_initializationContractAddress","type":"address"},{"internalType":"bytes","name":"_calldata","type":"bytes"}],"name":"EmptyCalldataNonZeroInitAddress","type":"error"},{"inputs":[{"internalType":"bytes4","name":"_functionSelector","type":"bytes4"}],"name":"FunctionNotFound","type":"error"},{"inputs":[{"internalType":"uint8","name":"_action","type":"uint8"}],"name":"IncorrectFacetCutAction","type":"error"},{"inputs":[{"internalType":"address","name":"_initializationContractAddress","type":"address"},{"internalType":"bytes","name":"_calldata","type":"bytes"}],"name":"InitializationFunctionReverted","type":"error"},{"inputs":[{"internalType":"address","name":"_contractAddress","type":"address"},{"internalType":"string","name":"_message","type":"string"}],"name":"NoBytecodeAtAddress","type":"error"},{"inputs":[{"internalType":"address","name":"_facetAddress","type":"address"}],"name":"NoSelectorsProvidedForFacetForCut","type":"error"},{"inputs":[{"internalType":"address","name":"_facetAddress","type":"address"}],"name":"RemoveFacetAddressMustBeZeroAddress","type":"error"},{"inputs":[],"name":"ZeroFallbackDataProviderAddress","type":"error"},{"inputs":[{"internalType":"address","name":"_initializationContractAddress","type":"address"},{"internalType":"bytes","name":"_calldata","type":"bytes"}],"name":"ZeroInitAddressNonEmptyCalldata","type":"error"},{"inputs":[],"name":"ZeroOwnershipContractAddress","type":"error"},{"inputs":[],"name":"ZeroPositionTokenFactoryAddress","type":"error"},{"inputs":[],"name":"ZeroTreasuryAddress","type":"error"},{"stateMutability":"payable","type":"fallback"},{"stateMutability":"payable","type":"receive"}]

60806040526040516200270a3803806200270a8339810160408190526200002691620013dd565b6001600160a01b0385166200004e576040516325182ed960e11b815260040160405180910390fd5b6001600160a01b0384166200007657604051633371d86d60e11b815260040160405180910390fd5b6001600160a01b0382166200009e576040516351dc806d60e11b815260040160405180910390fd5b6001600160a01b038116620000c6576040516365325d1960e11b815260040160405180910390fd5b604080516001808252818301909252600091816020015b60408051606080820183526000808352602083015291810191909152815260200190600190039081620000dd5750506040805160018082528183019092529192506000919060208083019080368337019050509050631f931c1c60e01b816000815181106200015057620001506200144d565b6001600160e01b031990921660209283029190910182015260408051606081019091526001600160a01b0387168152908101600081526020018281525082600081518110620001a357620001a36200144d565b6020026020010181905250620001d6826000604051806020016040528060008152506200068c60201b620000ab1760201c565b6000620001ed6200086d60201b6200025b1760201c565b90506000620002066200089160201b6200027f1760201c565b905060006200021f620008b560201b620002a31760201c565b9050600062000238620008d960201b620002c71760201c565b90508260070160405180606001604052804281526020016608e1bc9bf040006001600160601b031681526020016601c6bf526340006001600160601b031681525090806001815401808255809150506001900390600052602060002090600202016000909190919091506000820151816000015560208201518160010160006101000a8154816001600160601b0302191690836001600160601b03160217905550604082015181600101600c6101000a8154816001600160601b0302191690836001600160601b031602179055505050826008016040518060a0016040528042815260200162093a8062ffffff1681526020016203f48062ffffff1681526020016206978062ffffff168152602001620d2f0062ffffff1681525090806001815401808255809150506001900390600052602060002090600202016000909190919091506000820151816000015560208201518160010160006101000a81548162ffffff021916908362ffffff16021790555060408201518160010160036101000a81548162ffffff021916908362ffffff16021790555060608201518160010160066101000a81548162ffffff021916908362ffffff16021790555060808201518160010160096101000a81548162ffffff021916908362ffffff1602179055505050428360020181905550878360010160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550428360050181905550898360040160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550868260020160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550620004be620008fd60201b620002eb1760201c565b8160000181905550620004db6200099f60201b6200038d1760201c565b6001918201556004840180546001600160a01b0319166001600160a01b039c909c169b909b17909a55505063ddcd615960e01b600090815260039091016020526040808220805460ff199081168b179091556307e4c70760e21b8352818320805482168b1790556348e2b09360e01b8352818320805482168b1790556335799c4d60e01b8352818320805482168b179055631c69fbfb60e01b8352818320805482168b1790556333b88ff360e01b8352818320805482168b17905563f98bde8160e01b8352818320805482168b1790556301ffc9a760e01b8352818320805482168b17905563388660f560e11b8352818320805482168b179055635fa9073960e01b8352818320805482168b17905563755e2f3560e11b8352818320805482168b17905563a18a186b60e01b8352818320805482168b17905563dae73f4560e01b8352818320805482168b17905563d7c5023b60e01b8352818320805482168b17905563ad9123a560e01b8352818320805482168b179055630c91276560e21b8352818320805482168b179055631352104f60e11b8352912080549091169097179096555062001705945050505050565b60005b83518110156200081e576000848281518110620006b057620006b06200144d565b60200260200101516040015190506000858381518110620006d557620006d56200144d565b60200260200101516000015190508151600003620007165760405163e767f91f60e01b81526001600160a01b03821660048201526024015b60405180910390fd5b60008684815181106200072d576200072d6200144d565b60200260200101516020015190506000600281111562000751576200075162001463565b81600281111562000766576200076662001463565b036200077e57620007788284620009a3565b62000805565b600181600281111562000795576200079562001463565b03620007a75762000778828462000b99565b6002816002811115620007be57620007be62001463565b03620007d05762000778828462000d9a565b806002811115620007e557620007e562001463565b604051633ff4d20f60e11b815260ff90911660048201526024016200070d565b505050808062000815906200148f565b9150506200068f565b507f8faa70878671ccd212d20771b795c50af8fd3ff6cf27f4bde57e5d4de0aeb6738383836040516200085493929190620014ff565b60405180910390a162000868828262000e98565b505050565b7fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c90565b7f898b136e888260ec0628fb6c3ad8f54cb15908878595b2abfc8c9ecda73a4daf90565b7f57b54c9a1067e6ab879c66c176c4e86e41fe1dcf5187b31dc2b93365087c7afb90565b7f8605704e9bc6b9116b88d76d80e5d463ac2b851042de18aae713a2e1c43f2fe590565b604080518082018252600d81526c1112559048141c9bdd1bd8dbdb609a1b60208083019182528351808501855260018152603160f81b908201529151902082517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8152918201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69181019190915246606082015230608082015260a0902090565b4690565b8051600003620009d25760405163e767f91f60e01b81526001600160a01b03831660048201526024016200070d565b6000620009e96200086d60201b6200025b1760201c565b90506001600160a01b03831662000a1757816040516302b8da0760e21b81526004016200070d919062001606565b6001600160a01b0383166000908152600182016020526040812054906001600160601b038216900362000a505762000a50828562000fcb565b60005b835181101562000b9257600084828151811062000a745762000a746200144d565b6020908102919091018101516001600160e01b031981166000908152918690526040909120549091506001600160a01b0316801562000ad35760405163ebbf5d0760e01b81526001600160e01b0319831660048201526024016200070d565b6001600160e01b0319821660008181526020878152604080832080546001600160a01b03908116600160a01b6001600160601b038c16021782558c168085526001808c0185529285208054938401815585528385206008840401805463ffffffff60079095166004026101000a948502191660e08a901c94909402939093179092559390925287905281546001600160a01b0319161790558362000b778162001656565b9450505050808062000b89906200148f565b91505062000a53565b5050505050565b805160000362000bc85760405163e767f91f60e01b81526001600160a01b03831660048201526024016200070d565b600062000bdf6200086d60201b6200025b1760201c565b90506001600160a01b03831662000c0d578160405163cd98a96f60e01b81526004016200070d919062001606565b6001600160a01b0383166000908152600182016020526040812054906001600160601b038216900362000c465762000c46828562000fcb565b60005b835181101562000b9257600084828151811062000c6a5762000c6a6200144d565b6020908102919091018101516001600160e01b031981166000908152918690526040909120549091506001600160a01b03908116908716810362000cce57604051631ac6ce8d60e11b81526001600160e01b0319831660048201526024016200070d565b62000cdb85828462001038565b6001600160e01b0319821660008181526020878152604080832080546001600160a01b03908116600160a01b6001600160601b038c16021782558c168085526001808c0185529285208054938401815585528385206008840401805463ffffffff60079095166004026101000a948502191660e08a901c94909402939093179092559390925287905281546001600160a01b0319161790558362000d7f8162001656565b9450505050808062000d91906200148f565b91505062000c49565b805160000362000dc95760405163e767f91f60e01b81526001600160a01b03831660048201526024016200070d565b600062000de06200086d60201b6200025b1760201c565b90506001600160a01b0383161562000e175760405163d091bc8160e01b81526001600160a01b03841660048201526024016200070d565b60005b825181101562000e9257600083828151811062000e3b5762000e3b6200144d565b6020908102919091018101516001600160e01b031981166000908152918590526040909120549091506001600160a01b031662000e7a84828462001038565b5050808062000e89906200148f565b91505062000e1a565b50505050565b6001600160a01b03821662000ed25780511562000ece57818160405163197a7b0d60e31b81526004016200070d92919062001687565b5050565b805160000362000efb578181604051639da6a89760e01b81526004016200070d92919062001687565b6001600160a01b038216301462000f315762000f3182604051806060016040528060288152602001620026be6028913962001395565b600080836001600160a01b03168360405162000f4e9190620016b5565b600060405180830381855af49150503d806000811462000f8b576040519150601f19603f3d011682016040523d82523d6000602084013e62000f90565b606091505b50915091508162000e925780511562000fac5780518082602001fd5b838360405163192105d760e01b81526004016200070d92919062001687565b62000ff081604051806060016040528060248152602001620026e66024913962001395565b6002820180546001600160a01b0390921660008181526001948501602090815260408220860185905594840183559182529290200180546001600160a01b0319169091179055565b6001600160a01b0382166200106d57604051637a08a22d60e01b81526001600160e01b0319821660048201526024016200070d565b306001600160a01b03831603620010a457604051630df5fd6160e31b81526001600160e01b0319821660048201526024016200070d565b6001600160e01b03198116600090815260208481526040808320546001600160a01b0386168452600180880190935290832054600160a01b9091046001600160601b03169291620010f591620016d3565b9050808214620011ee576001600160a01b038416600090815260018601602052604081208054839081106200112e576200112e6200144d565b600091825260208083206008830401546001600160a01b038916845260018a019091526040909220805460079092166004026101000a90920460e01b9250829190859081106200118257620011826200144d565b600091825260208083206008830401805463ffffffff60079094166004026101000a938402191660e09590951c929092029390931790556001600160e01b03199290921682528690526040902080546001600160a01b0316600160a01b6001600160601b038516021790555b6001600160a01b038416600090815260018601602052604090208054806200121a576200121a620016ef565b60008281526020808220600860001990940193840401805463ffffffff600460078716026101000a0219169055919092556001600160e01b0319851682528690526040812081905581900362000b925760028501546000906200128090600190620016d3565b6001600160a01b038616600090815260018089016020526040909120015490915080821462001336576000876002018381548110620012c357620012c36200144d565b6000918252602090912001546002890180546001600160a01b039092169250829184908110620012f757620012f76200144d565b600091825260208083209190910180546001600160a01b0319166001600160a01b03948516179055929091168152600189810190925260409020018190555b866002018054806200134c576200134c620016ef565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b0388168252600189810190915260408220015550505050505050565b813b60008190036200086857828260405163919834b960e01b81526004016200070d92919062001687565b80516001600160a01b0381168114620013d857600080fd5b919050565b600080600080600060a08688031215620013f657600080fd5b6200140186620013c0565b94506200141160208701620013c0565b93506200142160408701620013c0565b92506200143160608701620013c0565b91506200144160808701620013c0565b90509295509295909350565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201620014a457620014a462001479565b5060010190565b60005b83811015620014c8578181015183820152602001620014ae565b50506000910152565b60008151808452620014eb816020860160208601620014ab565b601f01601f19169290920160200192915050565b60006060808301818452808751808352608092508286019150828160051b8701016020808b0160005b84811015620015d457898403607f19018652815180516001600160a01b031685528381015189860190600381106200157057634e487b7160e01b600052602160045260246000fd5b868601526040918201519186018a905281519081905290840190600090898701905b80831015620015be5783516001600160e01b031916825292860192600192909201919086019062001592565b5097850197955050509082019060010162001528565b50506001600160a01b038a16908801528681036040880152620015f88189620014d1565b9a9950505050505050505050565b6020808252825182820181905260009190848201906040850190845b818110156200164a5783516001600160e01b0319168352928401929184019160010162001622565b50909695505050505050565b60006001600160601b038281166002600160601b031981016200167d576200167d62001479565b6001019392505050565b6001600160a01b0383168152604060208201819052600090620016ad90830184620014d1565b949350505050565b60008251620016c9818460208701620014ab565b9190910192915050565b81810381811115620016e957620016e962001479565b92915050565b634e487b7160e01b600052603160045260246000fd5b610fa980620017156000396000f3fe60806040523661000b57005b600080356001600160e01b03191681527fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c602081905260409091205481906001600160a01b031680610087576000356001600160e01b031916604051630a82dd7360e31b815260040161007e9190610c7c565b60405180910390fd5b3660008037600080366000845af43d6000803e8080156100a6573d6000f35b3d6000fd5b60005b83518110156102105760008482815181106100cb576100cb610c91565b602002602001015160400151905060008583815181106100ed576100ed610c91565b602002602001015160000151905081516000036101285760405163e767f91f60e01b81526001600160a01b038216600482015260240161007e565b600086848151811061013c5761013c610c91565b60200260200101516020015190506000600281111561015d5761015d610ca7565b81600281111561016f5761016f610ca7565b036101835761017e8284610391565b6101fa565b600181600281111561019757610197610ca7565b036101a65761017e82846104d1565b60028160028111156101ba576101ba610ca7565b036101c95761017e828461061a565b8060028111156101db576101db610ca7565b604051633ff4d20f60e11b815260ff909116600482015260240161007e565b505050808061020890610cd3565b9150506100ae565b507f8faa70878671ccd212d20771b795c50af8fd3ff6cf27f4bde57e5d4de0aeb67383838360405161024493929190610d3c565b60405180910390a161025682826106fe565b505050565b7fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c90565b7f898b136e888260ec0628fb6c3ad8f54cb15908878595b2abfc8c9ecda73a4daf90565b7f57b54c9a1067e6ab879c66c176c4e86e41fe1dcf5187b31dc2b93365087c7afb90565b7f8605704e9bc6b9116b88d76d80e5d463ac2b851042de18aae713a2e1c43f2fe590565b604080518082018252600d81526c1112559048141c9bdd1bd8dbdb609a1b60208083019182528351808501855260018152603160f81b908201529151902082517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8152918201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69181019190915246606082015230608082015260a0902090565b4690565b80516000036103be5760405163e767f91f60e01b81526001600160a01b038316600482015260240161007e565b60006103c861025b565b90506001600160a01b0383166103f357816040516302b8da0760e21b815260040161007e9190610e3c565b6001600160a01b0383166000908152600182016020526040812054906001600160601b038216900361042957610429828561081e565b60005b83518110156104ca57600084828151811061044957610449610c91565b6020908102919091018101516001600160e01b031981166000908152918690526040909120549091506001600160a01b0316801561049c578160405163ebbf5d0760e01b815260040161007e9190610c7c565b6104a88583868a610888565b836104b281610e8a565b945050505080806104c290610cd3565b91505061042c565b5050505050565b80516000036104fe5760405163e767f91f60e01b81526001600160a01b038316600482015260240161007e565b600061050861025b565b90506001600160a01b038316610533578160405163cd98a96f60e01b815260040161007e9190610e3c565b6001600160a01b0383166000908152600182016020526040812054906001600160601b038216900361056957610569828561081e565b60005b83518110156104ca57600084828151811061058957610589610c91565b6020908102919091018101516001600160e01b031981166000908152918690526040909120549091506001600160a01b0390811690871681036105e15781604051631ac6ce8d60e11b815260040161007e9190610c7c565b6105ec858284610928565b6105f88583868a610888565b8361060281610e8a565b9450505050808061061290610cd3565b91505061056c565b80516000036106475760405163e767f91f60e01b81526001600160a01b038316600482015260240161007e565b600061065161025b565b90506001600160a01b038316156106865760405163d091bc8160e01b81526001600160a01b038416600482015260240161007e565b60005b82518110156106f85760008382815181106106a6576106a6610c91565b6020908102919091018101516001600160e01b031981166000908152918590526040909120549091506001600160a01b03166106e3848284610928565b505080806106f090610cd3565b915050610689565b50505050565b6001600160a01b0382166107345780511561073057818160405163197a7b0d60e31b815260040161007e929190610eb0565b5050565b805160000361075a578181604051639da6a89760e01b815260040161007e929190610eb0565b6001600160a01b038216301461078c5761078c82604051806060016040528060288152602001610f2860289139610c54565b600080836001600160a01b0316836040516107a79190610edc565b600060405180830381855af49150503d80600081146107e2576040519150601f19603f3d011682016040523d82523d6000602084013e6107e7565b606091505b5091509150816106f8578051156108015780518082602001fd5b838360405163192105d760e01b815260040161007e929190610eb0565b61084081604051806060016040528060248152602001610f5060249139610c54565b6002820180546001600160a01b0390921660008181526001948501602090815260408220860185905594840183559182529290200180546001600160a01b0319169091179055565b6001600160e01b0319831660008181526020868152604080832080546001600160601b03909716600160a01b026001600160a01b0397881617815594909516808352600180890183529583208054968701815583528183206008870401805460e09890981c60046007909816979097026101000a96870263ffffffff9097021990971695909517909555529290915281546001600160a01b031916179055565b6001600160a01b0382166109515780604051637a08a22d60e01b815260040161007e9190610c7c565b306001600160a01b0383160361097c5780604051630df5fd6160e31b815260040161007e9190610c7c565b6001600160e01b03198116600090815260208481526040808320546001600160a01b0386168452600180880190935290832054600160a01b9091046001600160601b031692916109cb91610ef8565b9050808214610abd576001600160a01b03841660009081526001860160205260408120805483908110610a0057610a00610c91565b600091825260208083206008830401546001600160a01b038916845260018a019091526040909220805460079092166004026101000a90920460e01b925082919085908110610a5157610a51610c91565b600091825260208083206008830401805463ffffffff60079094166004026101000a938402191660e09590951c929092029390931790556001600160e01b03199290921682528690526040902080546001600160a01b0316600160a01b6001600160601b038516021790555b6001600160a01b03841660009081526001860160205260409020805480610ae657610ae6610f11565b60008281526020808220600860001990940193840401805463ffffffff600460078716026101000a0219169055919092556001600160e01b031985168252869052604081208190558190036104ca576002850154600090610b4990600190610ef8565b6001600160a01b0386166000908152600180890160205260409091200154909150808214610bf8576000876002018381548110610b8857610b88610c91565b6000918252602090912001546002890180546001600160a01b039092169250829184908110610bb957610bb9610c91565b600091825260208083209190910180546001600160a01b0319166001600160a01b03948516179055929091168152600189810190925260409020018190555b86600201805480610c0b57610c0b610f11565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b0388168252600189810190915260408220015550505050505050565b813b600081900361025657828260405163919834b960e01b815260040161007e929190610eb0565b6001600160e01b031991909116815260200190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201610ce557610ce5610cbd565b5060010190565b60005b83811015610d07578181015183820152602001610cef565b50506000910152565b60008151808452610d28816020860160208601610cec565b601f01601f19169290920160200192915050565b60006060808301818452808751808352608092508286019150828160051b8701016020808b0160005b84811015610e0c57898403607f19018652815180516001600160a01b03168552838101518986019060038110610dab57634e487b7160e01b600052602160045260246000fd5b868601526040918201519186018a905281519081905290840190600090898701905b80831015610df75783516001600160e01b0319168252928601926001929092019190860190610dcd565b50978501979550505090820190600101610d65565b50506001600160a01b038a16908801528681036040880152610e2e8189610d10565b9a9950505050505050505050565b6020808252825182820181905260009190848201906040850190845b81811015610e7e5783516001600160e01b03191683529284019291840191600101610e58565b50909695505050505050565b60006001600160601b03808316818103610ea657610ea6610cbd565b6001019392505050565b6001600160a01b0383168152604060208201819052600090610ed490830184610d10565b949350505050565b60008251610eee818460208701610cec565b9190910192915050565b81810381811115610f0b57610f0b610cbd565b92915050565b634e487b7160e01b600052603160045260246000fdfe4c69624469616d6f6e644375743a205f696e6974206164647265737320686173206e6f20636f64654c69624469616d6f6e644375743a204e657720666163657420686173206e6f20636f6465a26469706673582212205b48785d89035e39fac6927c76b18177d3bcdcfdbad676b1b5c59f3daaaa44fb64736f6c634300081100334c69624469616d6f6e644375743a205f696e6974206164647265737320686173206e6f20636f64654c69624469616d6f6e644375743a204e657720666163657420686173206e6f20636f646500000000000000000000000093885274237fa82aa2e83a06dbc41e780bd2295e000000000000000000000000742371ea91b42db8c5536326908f3154cd1a3a77000000000000000000000000ccc44443bf87369543587c2d7e17719af52ca626000000000000000000000000742371ea91b42db8c5536326908f3154cd1a3a77000000000000000000000000a4f14bae115fca9cafff000632feb9d8f00293e2

Deployed Bytecode

0x60806040523661000b57005b600080356001600160e01b03191681527fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c602081905260409091205481906001600160a01b031680610087576000356001600160e01b031916604051630a82dd7360e31b815260040161007e9190610c7c565b60405180910390fd5b3660008037600080366000845af43d6000803e8080156100a6573d6000f35b3d6000fd5b60005b83518110156102105760008482815181106100cb576100cb610c91565b602002602001015160400151905060008583815181106100ed576100ed610c91565b602002602001015160000151905081516000036101285760405163e767f91f60e01b81526001600160a01b038216600482015260240161007e565b600086848151811061013c5761013c610c91565b60200260200101516020015190506000600281111561015d5761015d610ca7565b81600281111561016f5761016f610ca7565b036101835761017e8284610391565b6101fa565b600181600281111561019757610197610ca7565b036101a65761017e82846104d1565b60028160028111156101ba576101ba610ca7565b036101c95761017e828461061a565b8060028111156101db576101db610ca7565b604051633ff4d20f60e11b815260ff909116600482015260240161007e565b505050808061020890610cd3565b9150506100ae565b507f8faa70878671ccd212d20771b795c50af8fd3ff6cf27f4bde57e5d4de0aeb67383838360405161024493929190610d3c565b60405180910390a161025682826106fe565b505050565b7fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c90565b7f898b136e888260ec0628fb6c3ad8f54cb15908878595b2abfc8c9ecda73a4daf90565b7f57b54c9a1067e6ab879c66c176c4e86e41fe1dcf5187b31dc2b93365087c7afb90565b7f8605704e9bc6b9116b88d76d80e5d463ac2b851042de18aae713a2e1c43f2fe590565b604080518082018252600d81526c1112559048141c9bdd1bd8dbdb609a1b60208083019182528351808501855260018152603160f81b908201529151902082517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8152918201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69181019190915246606082015230608082015260a0902090565b4690565b80516000036103be5760405163e767f91f60e01b81526001600160a01b038316600482015260240161007e565b60006103c861025b565b90506001600160a01b0383166103f357816040516302b8da0760e21b815260040161007e9190610e3c565b6001600160a01b0383166000908152600182016020526040812054906001600160601b038216900361042957610429828561081e565b60005b83518110156104ca57600084828151811061044957610449610c91565b6020908102919091018101516001600160e01b031981166000908152918690526040909120549091506001600160a01b0316801561049c578160405163ebbf5d0760e01b815260040161007e9190610c7c565b6104a88583868a610888565b836104b281610e8a565b945050505080806104c290610cd3565b91505061042c565b5050505050565b80516000036104fe5760405163e767f91f60e01b81526001600160a01b038316600482015260240161007e565b600061050861025b565b90506001600160a01b038316610533578160405163cd98a96f60e01b815260040161007e9190610e3c565b6001600160a01b0383166000908152600182016020526040812054906001600160601b038216900361056957610569828561081e565b60005b83518110156104ca57600084828151811061058957610589610c91565b6020908102919091018101516001600160e01b031981166000908152918690526040909120549091506001600160a01b0390811690871681036105e15781604051631ac6ce8d60e11b815260040161007e9190610c7c565b6105ec858284610928565b6105f88583868a610888565b8361060281610e8a565b9450505050808061061290610cd3565b91505061056c565b80516000036106475760405163e767f91f60e01b81526001600160a01b038316600482015260240161007e565b600061065161025b565b90506001600160a01b038316156106865760405163d091bc8160e01b81526001600160a01b038416600482015260240161007e565b60005b82518110156106f85760008382815181106106a6576106a6610c91565b6020908102919091018101516001600160e01b031981166000908152918590526040909120549091506001600160a01b03166106e3848284610928565b505080806106f090610cd3565b915050610689565b50505050565b6001600160a01b0382166107345780511561073057818160405163197a7b0d60e31b815260040161007e929190610eb0565b5050565b805160000361075a578181604051639da6a89760e01b815260040161007e929190610eb0565b6001600160a01b038216301461078c5761078c82604051806060016040528060288152602001610f2860289139610c54565b600080836001600160a01b0316836040516107a79190610edc565b600060405180830381855af49150503d80600081146107e2576040519150601f19603f3d011682016040523d82523d6000602084013e6107e7565b606091505b5091509150816106f8578051156108015780518082602001fd5b838360405163192105d760e01b815260040161007e929190610eb0565b61084081604051806060016040528060248152602001610f5060249139610c54565b6002820180546001600160a01b0390921660008181526001948501602090815260408220860185905594840183559182529290200180546001600160a01b0319169091179055565b6001600160e01b0319831660008181526020868152604080832080546001600160601b03909716600160a01b026001600160a01b0397881617815594909516808352600180890183529583208054968701815583528183206008870401805460e09890981c60046007909816979097026101000a96870263ffffffff9097021990971695909517909555529290915281546001600160a01b031916179055565b6001600160a01b0382166109515780604051637a08a22d60e01b815260040161007e9190610c7c565b306001600160a01b0383160361097c5780604051630df5fd6160e31b815260040161007e9190610c7c565b6001600160e01b03198116600090815260208481526040808320546001600160a01b0386168452600180880190935290832054600160a01b9091046001600160601b031692916109cb91610ef8565b9050808214610abd576001600160a01b03841660009081526001860160205260408120805483908110610a0057610a00610c91565b600091825260208083206008830401546001600160a01b038916845260018a019091526040909220805460079092166004026101000a90920460e01b925082919085908110610a5157610a51610c91565b600091825260208083206008830401805463ffffffff60079094166004026101000a938402191660e09590951c929092029390931790556001600160e01b03199290921682528690526040902080546001600160a01b0316600160a01b6001600160601b038516021790555b6001600160a01b03841660009081526001860160205260409020805480610ae657610ae6610f11565b60008281526020808220600860001990940193840401805463ffffffff600460078716026101000a0219169055919092556001600160e01b031985168252869052604081208190558190036104ca576002850154600090610b4990600190610ef8565b6001600160a01b0386166000908152600180890160205260409091200154909150808214610bf8576000876002018381548110610b8857610b88610c91565b6000918252602090912001546002890180546001600160a01b039092169250829184908110610bb957610bb9610c91565b600091825260208083209190910180546001600160a01b0319166001600160a01b03948516179055929091168152600189810190925260409020018190555b86600201805480610c0b57610c0b610f11565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b0388168252600189810190915260408220015550505050505050565b813b600081900361025657828260405163919834b960e01b815260040161007e929190610eb0565b6001600160e01b031991909116815260200190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201610ce557610ce5610cbd565b5060010190565b60005b83811015610d07578181015183820152602001610cef565b50506000910152565b60008151808452610d28816020860160208601610cec565b601f01601f19169290920160200192915050565b60006060808301818452808751808352608092508286019150828160051b8701016020808b0160005b84811015610e0c57898403607f19018652815180516001600160a01b03168552838101518986019060038110610dab57634e487b7160e01b600052602160045260246000fd5b868601526040918201519186018a905281519081905290840190600090898701905b80831015610df75783516001600160e01b0319168252928601926001929092019190860190610dcd565b50978501979550505090820190600101610d65565b50506001600160a01b038a16908801528681036040880152610e2e8189610d10565b9a9950505050505050505050565b6020808252825182820181905260009190848201906040850190845b81811015610e7e5783516001600160e01b03191683529284019291840191600101610e58565b50909695505050505050565b60006001600160601b03808316818103610ea657610ea6610cbd565b6001019392505050565b6001600160a01b0383168152604060208201819052600090610ed490830184610d10565b949350505050565b60008251610eee818460208701610cec565b9190910192915050565b81810381811115610f0b57610f0b610cbd565b92915050565b634e487b7160e01b600052603160045260246000fdfe4c69624469616d6f6e644375743a205f696e6974206164647265737320686173206e6f20636f64654c69624469616d6f6e644375743a204e657720666163657420686173206e6f20636f6465a26469706673582212205b48785d89035e39fac6927c76b18177d3bcdcfdbad676b1b5c59f3daaaa44fb64736f6c63430008110033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000093885274237fa82aa2e83a06dbc41e780bd2295e000000000000000000000000742371ea91b42db8c5536326908f3154cd1a3a77000000000000000000000000ccc44443bf87369543587c2d7e17719af52ca626000000000000000000000000742371ea91b42db8c5536326908f3154cd1a3a77000000000000000000000000a4f14bae115fca9cafff000632feb9d8f00293e2

-----Decoded View---------------
Arg [0] : _ownershipContract (address): 0x93885274237Fa82AA2e83A06dBc41e780bD2295e
Arg [1] : _fallbackDataProvider (address): 0x742371ea91B42DB8C5536326908f3154cD1a3A77
Arg [2] : _diamondCutFacet (address): 0xcCC44443BF87369543587c2d7e17719aF52Ca626
Arg [3] : _treasury (address): 0x742371ea91B42DB8C5536326908f3154cD1a3A77
Arg [4] : _positionTokenFactory (address): 0xa4f14bAE115fca9cAfFF000632feB9d8f00293e2

-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 00000000000000000000000093885274237fa82aa2e83a06dbc41e780bd2295e
Arg [1] : 000000000000000000000000742371ea91b42db8c5536326908f3154cd1a3a77
Arg [2] : 000000000000000000000000ccc44443bf87369543587c2d7e17719af52ca626
Arg [3] : 000000000000000000000000742371ea91b42db8c5536326908f3154cd1a3a77
Arg [4] : 000000000000000000000000a4f14bae115fca9cafff000632feb9d8f00293e2


Block Transaction Gas Used Reward
view all blocks produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.