creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "@openzeppelin/contracts/token/ERC20/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the value of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the value of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the\n     * allowance mechanism. `value` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"
      },
      "contracts/governance/IVotingEscrow.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8.21;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface IVotingEscrow is IERC20 {\n    struct LockedBalance {\n        int128 amount;\n        uint256 end;\n    }\n\n    function locked(address) external view returns (LockedBalance memory);\n}\n"
      },
      "contracts/passport/IPassportIssuer.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8.21;\n\ninterface IPassportIssuer {\n    function revokeUnderBalance() external view returns (uint256);\n\n    function passportStatus(address account) external view returns (uint8);\n}\n"
      },
      "contracts/utils/IPassportUtils.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8.21;\n\n/**\n *        ---------::::\n *     ---------:---::::::\n *   -----------::---:::::::\n *  ------------:.:--::::::::\n * -------------: .:--::::::::\n * -------------:   .:::::::::\n * -------------:.......::::::\n * -----:..    .:-------::::::\n * --------:.. .:-------::::::\n * ----------:..:--------:::::\n *  -----------.:--------::::\n *   ----------::--------:::\n *     -------------------\n *        -------------\n *\n *         Nation3 DAO\n *     https://nation3.org\n */\ninterface IPassportUtils {\n    /**\n     * Returns `true` if an account is the owner of a passport.\n     */\n    function isOwner(address account) external view returns (bool);\n\n    /**\n     * Returns the owner of a passport.\n     *\n     * @param passportID The identifier of an NFT passport\n     */\n    function getOwnerAddress(uint16 passportID) external view returns (address);\n\n    /**\n     * Returns `true` if a citizen's passport has become revocable.\n     *\n     * @param citizen The address of an NFT passport's owner\n     */\n    function isExpired(address citizen) external view returns (bool);\n\n    /**\n     * Returns the Unix epoch time when a citizen's passport will become revocable.\n     *\n     * @param citizen The address of an NFT passport's owner\n     */\n    function getExpirationTimestamp(\n        address citizen\n    ) external view returns (uint256);\n\n    /**\n     * Calculates the Unix epoch time when vote-escrowed `$NATION` will drop below a given threshold.\n     *\n     * @param lockAmount The amount of `$NATION` tokens that were locked\n     * @param lockEnd The lock expiration date in seconds\n     * @param votingEscrowThreshold The vote-escrowed `$NATION` balance when a passport will become revocable\n     * @return Timestamp in seconds, or `0` if the lock amount is below the threshold\n     */\n    function calculateThresholdTimestamp(\n        uint256 lockAmount,\n        uint256 lockEnd,\n        uint256 votingEscrowThreshold\n    ) external view returns (uint256);\n}\n"
      },
      "contracts/utils/PassportUtils.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8.21;\n\nimport \"./IPassportUtils.sol\";\nimport \"../passport/IPassportIssuer.sol\";\nimport \"../governance/IVotingEscrow.sol\";\n\n/**\n *        ---------::::\n *     ---------:---::::::\n *   -----------::---:::::::\n *  ------------:.:--::::::::\n * -------------: .:--::::::::\n * -------------:   .:::::::::\n * -------------:.......::::::\n * -----:..    .:-------::::::\n * --------:.. .:-------::::::\n * ----------:..:--------:::::\n *  -----------.:--------::::\n *   ----------::--------:::\n *     -------------------\n *        -------------\n *\n *         Nation3 DAO\n *     https://nation3.org\n */\ncontract PassportUtils is IPassportUtils {\n    string public constant VERSION = \"0.6.9\";\n    IPassportIssuer public passportIssuer;\n    IVotingEscrow public votingEscrow;\n\n    constructor(address passportIssuerAddress, address votingEscrowAddress) {\n        passportIssuer = IPassportIssuer(passportIssuerAddress);\n        votingEscrow = IVotingEscrow(votingEscrowAddress);\n    }\n\n    /**\n     * @inheritdoc IPassportUtils\n     */\n    function isOwner(address account) public view returns (bool) {\n        uint8 passportStatus = passportIssuer.passportStatus(account);\n        return passportStatus == 1;\n    }\n\n    /**\n     * @inheritdoc IPassportUtils\n     */\n    function getOwnerAddress(uint16 passportID) public view returns (address) {\n        // TO DO\n    }\n\n    /**\n     * @inheritdoc IPassportUtils\n     */\n    function isExpired(address citizen) public view returns (bool) {\n        uint256 revokeUnderBalance = passportIssuer.revokeUnderBalance();\n        uint256 votingEscrowBalance = votingEscrow.balanceOf(citizen);\n        return votingEscrowBalance < revokeUnderBalance;\n    }\n\n    /**\n     * @inheritdoc IPassportUtils\n     */\n    function getExpirationTimestamp(\n        address citizen\n    ) public view returns (uint256) {\n        IVotingEscrow.LockedBalance memory lockedBalance = votingEscrow.locked(\n            citizen\n        );\n        uint256 lockAmount = uint256(int256(lockedBalance.amount));\n        uint256 lockEnd = lockedBalance.end;\n        uint256 revokeUnderBalance = passportIssuer.revokeUnderBalance();\n        return\n            calculateThresholdTimestamp(\n                lockAmount,\n                lockEnd,\n                revokeUnderBalance\n            );\n    }\n\n    /**\n     * @inheritdoc IPassportUtils\n     */\n    function calculateThresholdTimestamp(\n        uint256 lockAmount,\n        uint256 lockEnd,\n        uint256 votingEscrowThreshold\n    ) public pure returns (uint256) {\n        if (lockAmount < votingEscrowThreshold) {\n            return 0;\n        }\n\n        uint256 maxLockPeriod = 4 * 365 days;\n\n        uint256 thresholdPercentageOfLocked = (100 ether *\n            votingEscrowThreshold) / lockAmount;\n\n        uint256 secondsFromThresholdToUnlock = (maxLockPeriod *\n            thresholdPercentageOfLocked) / 100 ether;\n\n        return lockEnd - secondsFromThresholdToUnlock;\n    }\n}\n"
      }
    },
    "settings": {
      "evmVersion": "paris",
      "optimizer": {
        "enabled": false,
        "runs": 200
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}