ETH Price: $2,953.27 (+0.56%)

Contract Diff Checker

Contract Name:
RubyScoreVeraxPortal

Contract Source Code:

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor() {
        _paused = false;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        require(!paused(), "Pausable: paused");
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        require(paused(), "Pausable: not paused");
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC1155/IERC1155.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 *
 * _Available since v3.1._
 */
interface IERC1155 is IERC165 {
    /**
     * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    /**
     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
     * transfers.
     */
    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /**
     * @dev Returns the amount of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(
        address[] calldata accounts,
        uint256[] calldata ids
    ) external view returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @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 Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

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

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import {IAttestationRegistry} from "../interfaces/IAttestationRegistry.sol";
import {IModuleRegistry} from "../interfaces/IModuleRegistry.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import {IPortalRegistry} from "../interfaces/IPortalRegistry.sol";
import {IRouter} from "../interfaces/IRouter.sol";
import {IPortal} from "../interfaces/IPortal.sol";
import {AttestationPayload} from "../interfaces/Structs.sol";

/**
 * @title Abstract Portal
 * @author Consensys
 * @notice This contract is an abstract contract with basic Portal logic
 *         to be inherited. We strongly encourage all Portals to implement
 *         this contract.
 */
abstract contract AbstractPortal is IPortal {
    IRouter public router;
    address[] public modules;
    IModuleRegistry public moduleRegistry;
    IAttestationRegistry public attestationRegistry;
    IPortalRegistry public portalRegistry;

    /// @notice Error thrown when someone else than the portal's owner is trying to revoke
    error OnlyPortalOwner();

    /**
     * @notice Contract constructor
     * @param _modules list of modules to use for the portal (can be empty)
     * @param _router Router's address
     * @dev This sets the addresses for the IAttestationRegistry, IModuleRegistry and IPortalRegistry
     */
    constructor(address[] memory _modules, address _router) {
        modules = _modules;
        router = IRouter(_router);
        attestationRegistry = IAttestationRegistry(router.getAttestationRegistry());
        moduleRegistry = IModuleRegistry(router.getModuleRegistry());
        portalRegistry = IPortalRegistry(router.getPortalRegistry());
    }

    /**
     * @notice Optional method to withdraw funds from the Portal
     * @param to the address to send the funds to
     * @param amount the amount to withdraw
     */
    function withdraw(address payable to, uint256 amount) external virtual;

    /**
     * @notice Attest the schema with given attestationPayload and validationPayload
     * @param attestationPayload the payload to attest
     * @param validationPayloads the payloads to validate via the modules to issue the attestations
     * @dev Runs all modules for the portal and registers the attestation using IAttestationRegistry
     */
    function attest(AttestationPayload memory attestationPayload, bytes[] memory validationPayloads) public payable {
        moduleRegistry.runModules(modules, attestationPayload, validationPayloads, msg.value);

        _onAttest(attestationPayload, getAttester(), msg.value);

        attestationRegistry.attest(attestationPayload, getAttester());
    }

    /**
     * @notice Bulk attest the schema with payloads to attest and validation payloads
     * @param attestationsPayloads the payloads to attest
     * @param validationPayloads the payloads to validate via the modules to issue the attestations
     */
    function bulkAttest(AttestationPayload[] memory attestationsPayloads, bytes[][] memory validationPayloads) public {
        moduleRegistry.bulkRunModules(modules, attestationsPayloads, validationPayloads);

        _onBulkAttest(attestationsPayloads, validationPayloads);

        attestationRegistry.bulkAttest(attestationsPayloads, getAttester());
    }

    /**
     * @notice Replaces the attestation for the given identifier and replaces it with a new attestation
     * @param attestationId the ID of the attestation to replace
     * @param attestationPayload the attestation payload to create the new attestation and register it
     * @param validationPayloads the payloads to validate via the modules to issue the attestation
     * @dev Runs all modules for the portal and registers the attestation using IAttestationRegistry
     */
    function replace(
        bytes32 attestationId,
        AttestationPayload memory attestationPayload,
        bytes[] memory validationPayloads
    ) public payable {
        moduleRegistry.runModules(modules, attestationPayload, validationPayloads, msg.value);

        _onReplace(attestationId, attestationPayload, getAttester(), msg.value);

        attestationRegistry.replace(attestationId, attestationPayload, getAttester());
    }

    /**
     * @notice Bulk replaces the attestation for the given identifiers and replaces them with new attestations
     * @param attestationIds the list of IDs of the attestations to replace
     * @param attestationsPayloads the list of attestation payloads to create the new attestations and register them
     * @param validationPayloads the payloads to validate via the modules to issue the attestations
     */
    function bulkReplace(
        bytes32[] memory attestationIds,
        AttestationPayload[] memory attestationsPayloads,
        bytes[][] memory validationPayloads
    ) public {
        moduleRegistry.bulkRunModules(modules, attestationsPayloads, validationPayloads);

        _onBulkReplace(attestationIds, attestationsPayloads, validationPayloads);

        attestationRegistry.bulkReplace(attestationIds, attestationsPayloads, getAttester());
    }

    /**
     * @notice Revokes an attestation for the given identifier
     * @param attestationId the ID of the attestation to revoke
     * @dev By default, revocation is only possible by the portal owner
     * We strongly encourage implementing such a rule in your Portal if you intend on overriding this method
     */
    function revoke(bytes32 attestationId) public {
        _onRevoke(attestationId);

        attestationRegistry.revoke(attestationId);
    }

    /**
     * @notice Bulk revokes a list of attestations for the given identifiers
     * @param attestationIds the IDs of the attestations to revoke
     */
    function bulkRevoke(bytes32[] memory attestationIds) public {
        _onBulkRevoke(attestationIds);

        attestationRegistry.bulkRevoke(attestationIds);
    }

    /**
     * @notice Get all the modules addresses used by the Portal
     * @return The list of modules addresses linked to the Portal
     */
    function getModules() external view returns (address[] memory) {
        return modules;
    }

    /**
     * @notice Verifies that a specific interface is implemented by the Portal, following ERC-165 specification
     * @param interfaceID the interface identifier checked in this call
     * @return The list of modules addresses linked to the Portal
     */
    function supportsInterface(bytes4 interfaceID) public pure virtual override returns (bool) {
        return
            interfaceID == type(AbstractPortal).interfaceId ||
            interfaceID == type(IPortal).interfaceId ||
            interfaceID == type(IERC165).interfaceId;
    }

    /**
     * @notice Defines the address of the entity issuing attestations to the subject
     * @dev We strongly encourage a reflection when overriding this rule: who should be set as the attester?
     */
    function getAttester() public view virtual returns (address) {
        return msg.sender;
    }

    /**
     * @notice Optional method run before a payload is attested
     * @param attestationPayload the attestation payload supposed to be attested
     * @param attester the address of the attester
     * @param value the value sent with the attestation
     */
    function _onAttest(
        AttestationPayload memory attestationPayload,
        address attester,
        uint256 value
    ) internal virtual {}

    /**
     * @notice Optional method run when an attestation is replaced
     * @param attestationId the ID of the attestation being replaced
     * @param attestationPayload the attestation payload to create attestation and register it
     * @param attester the address of the attester
     * @param value the value sent with the attestation
     */
    function _onReplace(
        bytes32 attestationId,
        AttestationPayload memory attestationPayload,
        address attester,
        uint256 value
    ) internal virtual {}

    /**
     * @notice Optional method run when attesting a batch of payloads
     * @param attestationsPayloads the payloads to attest
     * @param validationPayloads the payloads to validate in order to issue the attestations
     */
    function _onBulkAttest(
        AttestationPayload[] memory attestationsPayloads,
        bytes[][] memory validationPayloads
    ) internal virtual {}

    function _onBulkReplace(
        bytes32[] memory attestationIds,
        AttestationPayload[] memory attestationsPayloads,
        bytes[][] memory validationPayloads
    ) internal virtual {}

    /**
     * @notice Optional method run when an attestation is revoked or replaced
     * @dev    IMPORTANT NOTE: By default, revocation is only possible by the portal owner
     */
    function _onRevoke(bytes32 /*attestationId*/) internal virtual {
        if (msg.sender != portalRegistry.getPortalByAddress(address(this)).ownerAddress) revert OnlyPortalOwner();
    }

    /**
     * @notice Optional method run when a batch of attestations are revoked or replaced
     * @dev    IMPORTANT NOTE: By default, revocation is only possible by the portal owner
     */
    function _onBulkRevoke(bytes32[] memory /*attestationIds*/) internal virtual {
        if (msg.sender != portalRegistry.getPortalByAddress(address(this)).ownerAddress) revert OnlyPortalOwner();
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import {Attestation, AttestationPayload} from "./Structs.sol";
import {IRouter} from "./IRouter.sol";

interface IAttestationRegistry {
    /// @notice Event emitted when an attestation is registered
    event AttestationRegistered(bytes32 indexed attestationId);

    function router() external view returns (IRouter);

    function attestations(bytes32 attestationId) external view returns (Attestation memory);

    function initialize() external;

    function updateRouter(address _router) external;

    function updateChainPrefix(uint256 _chainPrefix) external;

    function onlyPortals(address portal) external view;

    function attest(AttestationPayload calldata attestationPayload, address attester) external;

    function bulkAttest(AttestationPayload[] calldata attestationsPayloads, address attester) external;

    function massImport(AttestationPayload[] calldata attestationsPayloads, address portal) external;

    function replace(bytes32 attestationId, AttestationPayload calldata attestationPayload, address attester) external;

    function bulkReplace(
        bytes32[] calldata attestationIds,
        AttestationPayload[] calldata attestationPayloads,
        address attester
    ) external;

    function revoke(bytes32 attestationId) external;

    function bulkRevoke(bytes32[] memory attestationIds) external;

    function isRegistered(bytes32 attestationId) external view returns (bool);

    function isRevocable(address portalId) external view returns (bool);

    function getAttestation(bytes32 attestationId) external view returns (Attestation memory);

    function incrementVersionNumber() external returns (uint16);

    function getVersionNumber() external view returns (uint16);

    function getAttestationIdCounter() external view returns (uint32);

    function getChainPrefix() external view returns (uint256);

    function balanceOf(address account, uint256 id) external view returns (uint256);

    function balanceOfBatch(address[] memory accounts, uint256[] memory ids) external view returns (uint256[] memory);
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import {Module, AttestationPayload} from "./Structs.sol";
import {IRouter} from "./IRouter.sol";

interface IModuleRegistry {
    function router() external view returns (IRouter);

    function modules(address moduleAddress) external view returns (Module memory);

    function moduleAddresses(uint256 index) external view returns (address);

    function initialize() external;

    function updateRouter(address _router) external;

    function isContractAddress(address contractAddress) external view returns (bool);

    function onlyIssuers(address issuer) external view;

    function register(string memory name, string memory description, address moduleAddress) external;

    function runModules(
        address[] memory modulesAddresses,
        AttestationPayload memory attestationPayload,
        bytes[] memory validationPayloads,
        uint256 value
    ) external;

    function bulkRunModules(
        address[] memory modulesAddresses,
        AttestationPayload[] memory attestationsPayloads,
        bytes[][] memory validationPayloads
    ) external;

    function getModulesNumber() external view returns (uint256);

    function isRegistered(address moduleAddress) external view returns (bool);
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import {IERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";

/**
 * @title IPortal
 * @author Consensys
 * @notice This contract is the interface to be implemented by any Portal.
 *         NOTE: A portal must implement this interface to registered on
 *         the PortalRegistry contract.
 */
interface IPortal is IERC165 {
    /**
     * @notice Get all the modules addresses used by the Portal
     * @return The list of modules addresses linked to the Portal
     */
    function getModules() external view returns (address[] memory);

    /**
     * @notice Defines the address of the entity issuing attestations to the subject
     * @dev We strongly encourage a reflection when implementing this method
     */
    function getAttester() external view returns (address);
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import {Portal} from "./Structs.sol";
import {IRouter} from "./IRouter.sol";

interface IPortalRegistry {
    function router() external view returns (IRouter);

    function portals(address id) external view returns (Portal memory);

    function issuers(address issuerAddress) external view returns (bool);

    function portalAddresses(uint256 index) external view returns (address);

    function initialize() external;

    function updateRouter(address _router) external;

    function setIssuer(address issuer) external;

    function removeIssuer(address issuer) external;

    function isIssuer(address issuer) external view returns (bool);

    function register(
        address id,
        string memory name,
        string memory description,
        bool isRevocable,
        string memory ownerName
    ) external;

    function revoke(address id) external;

    function deployDefaultPortal(
        address[] calldata modules,
        string memory name,
        string memory description,
        bool isRevocable,
        string memory ownerName
    ) external;

    function getPortalByAddress(address id) external view returns (Portal memory);

    function isRegistered(address id) external view returns (bool);

    function getPortalsCount() external view returns (uint256);
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

/**
 * @title Router
 * @author Consensys
 * @notice This contract aims to provides a single entrypoint for the Verax registries
 */
interface IRouter {
    /**
     * @notice Gives the address for the AttestationRegistry contract
     * @return The current address of the AttestationRegistry contract
     */
    function getAttestationRegistry() external view returns (address);

    /**
     * @notice Gives the address for the ModuleRegistry contract
     * @return The current address of the ModuleRegistry contract
     */
    function getModuleRegistry() external view returns (address);

    /**
     * @notice Gives the address for the PortalRegistry contract
     * @return The current address of the PortalRegistry contract
     */
    function getPortalRegistry() external view returns (address);

    /**
     * @notice Gives the address for the SchemaRegistry contract
     * @return The current address of the SchemaRegistry contract
     */
    function getSchemaRegistry() external view returns (address);
}

// SPDX-License-Identifier: SEE LICENSE IN LICENSE
pragma solidity 0.8.19;

import {IERC1155} from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";

/**
 * @title IRubyscore_Certificates
 * @dev IRubyscore_Certificates is an interface for Rubyscore_Certificates contract
 */
interface IRubyscore_Certificates is IERC1155 {
    /**
     * @notice Emitted when the base URI for token metadata is updated.
     * @param newBaseURI The new base URI that will be used to construct token metadata URIs.
     * @dev This event is triggered when the contract operator updates the base URI
     * for retrieving metadata associated with tokens. The 'newBaseURI' parameter represents
     * the updated base URI.
     */
    event BaseURISet(string indexed newBaseURI);

    /**
     * @notice Emitted when NFTs are minted for a user.
     * @param userAddress The address of the user receiving the NFTs.
     * @param nftId NFT IDs that were minted.
     * @dev This event is emitted when new NFTs are created and assigned to a user.
     * @dev It includes the user's address, and the ID of the minted NFT for transparency.
     */
    event Minted(address indexed userAddress, uint256 nftId);

    /**
     * @notice Emitted when NFTs are minted for a user.
     * @param userAddress The address of the user receiving the NFTs.
     * @param nftIds NFT IDs that were minted.
     * @dev This event is emitted when new NFTs are created and assigned to a user.
     * @dev It includes the user's address and the IDs of the minted NFTs for transparency.
     */
    event BatchMinted(address indexed userAddress, uint256[] nftIds);

    /**
     * @notice Emitted when the URI for a specific token is updated.
     * @param tokenId The ID of the token for which the URI is updated.
     * @param newTokenURI The new URI assigned to the token.
     * @dev This event is emitted when the URI for a token is modified, providing transparency
     * when metadata URIs are changed for specific tokens.
     */
    event TokenURISet(uint256 indexed tokenId, string indexed newTokenURI);

    /**
     * @notice Get token name.
     * @return Token name.
     */
    function name() external view returns (string memory);

    /**
     * @notice Get token symbol.
     * @return Token symbol.
     */
    function symbol() external view returns (string memory);

    /**
     * @notice Get the URI of a token.
     * @param tokenId The ID of the token.
     * @return The URI of the token.
     */
    function uri(uint256 tokenId) external view returns (string memory);

    /**
     * @notice Get the token URI for a given tokenId.
     * @param tokenId The ID of the token.
     * @return The URI of the token.
     * @dev Diblicate for uri() method
     */
    function tokenURI(uint256 tokenId) external view returns (string memory);

    /**
     * @notice Set the URI for a token.
     * @param tokenId The ID of the token.
     * @param newTokenURI The new URI to set for the token.
     * @dev Requires the MINTER_ROLE.
     */
    function setTokenURI(uint256 tokenId, string memory newTokenURI) external;

    /**
     * @notice Set the URIs for multiple tokens in a batch.
     * @param tokenIds An array of token IDs to set URIs for.
     * @param newTokenURIs An array of new URIs to set for the tokens.
     * @dev Requires the MINTER_ROLE.
     * @dev Requires that the tokenIds and newTokenURIs arrays have the same length.
     */
    function setBatchTokenURI(uint256[] calldata tokenIds, string[] calldata newTokenURIs) external;

    /**
     * @notice Set the base URI for all tokens.
     * @param newBaseURI The new base URI to set.
     * @dev Requires the OPERATOR_ROLE.
     */
    function setBaseURI(string memory newBaseURI) external;

    /**
     * @notice Safely mints NFT for a user.
     * @param to The NFT recipient.
     * @param id The NFT id.
     */
    function safeMint(address to, uint256 id) external payable;

    /**
     * @notice Check if a given interface is supported by this contract.
     * @param interfaceId The interface identifier to check for support.
     * @return Whether the contract supports the specified interface.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

struct AttestationPayload {
    bytes32 schemaId; // The identifier of the schema this attestation adheres to.
    uint64 expirationDate; // The expiration date of the attestation.
    bytes subject; // The ID of the attestee, EVM address, DID, URL etc.
    bytes attestationData; // The attestation data.
}

struct Attestation {
    bytes32 attestationId; // The unique identifier of the attestation.
    bytes32 schemaId; // The identifier of the schema this attestation adheres to.
    bytes32 replacedBy; // Whether the attestation was replaced by a new one.
    address attester; // The address issuing the attestation to the subject.
    address portal; // The id of the portal that created the attestation.
    uint64 attestedDate; // The date the attestation is issued.
    uint64 expirationDate; // The expiration date of the attestation.
    uint64 revocationDate; // The date when the attestation was revoked.
    uint16 version; // Version of the registry when the attestation was created.
    bool revoked; // Whether the attestation is revoked or not.
    bytes subject; // The ID of the attestee, EVM address, DID, URL etc.
    bytes attestationData; // The attestation data.
}

struct Schema {
    string name; // The name of the schema.
    string description; // A description of the schema.
    string context; // The context of the schema.
    string schema; // The schema definition.
}

struct Portal {
    address id; // The unique identifier of the portal.
    address ownerAddress; // The address of the owner of this portal.
    address[] modules; // Addresses of modules implemented by the portal.
    bool isRevocable; // Whether attestations issued can be revoked.
    string name; // The name of the portal.
    string description; // A description of the portal.
    string ownerName; // The name of the owner of this portal.
}

struct Module {
    address moduleAddress; // The address of the module.
    string name; // The name of the module.
    string description; // A description of the module.
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import {AbstractPortal} from "./abstracts/AbstractPortal.sol";
import {AttestationPayload} from "./interfaces/Structs.sol";
import {Pausable} from "@openzeppelin/contracts/security/Pausable.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {IRubyscore_Certificates} from "./interfaces/IRubyscore_Certificates.sol";

/**
 * @title RubyScoreVeraxPortal
 * @dev RubyScoreVeraxPortal is a smart contract that handles the attestation process for RubyScore certificates.
 * It manages fees, signatures based on specific schemas.
 */
contract RubyScoreVeraxPortal is AbstractPortal, Ownable, Pausable {
    // State variables
    bool public bulkStatus = false;
    bool public feeStatus = true;

    // Storage
    mapping(bytes32 => bool) public certificates; // schemaId => certificateStatus
    mapping(bytes32 => uint256) public attestationFees; // schemaId => attestationFee

    // Errors
    error InvalidCertificateId();
    error ArrayLengthMismatch();
    error InvalidAttestationFee();
    error ZeroAddressCheck();
    error WithdrawFail();

    // Events
    event FeesSet(bytes32[] schemaIds, uint256[] attestationFees);

    /**
     * @dev Contract constructor.
     * @param modules List of modules to use for the portal.
     * @param router The Router's address.
     */
    constructor(address[] memory modules, address router) AbstractPortal(modules, router) {
        if (router == address(0)) revert ZeroAddressCheck();
        _transferOwnership(msg.sender);
    }

    function pause() public onlyOwner {
        _pause();
    }

    function unpause() public onlyOwner {
        _unpause();
    }

    /**
     * @dev Check if the provided value meets the attestation fee requirement.
     * @param schemaId The schemaId for which to check the fee.
     * @param _value The value sent for the attestation.
     */
    function checkFee(bytes32 schemaId, uint256 _value) public view {
        if (_value < attestationFees[schemaId]) revert InvalidAttestationFee();
    }

    /**
     * @dev Set the fee, signature, and issuance statuses.
     * @param fee Fee status.
     */
    function setCheckStatuses(bool fee, bool bulk) external onlyOwner {
        feeStatus = fee;
        bulkStatus = bulk;
    }

    /**
     * @dev Add a new module to the list of modules.
     * @param module The address of the new module.
     */
    function addModule(address module) external onlyOwner {
        modules.push(module);
    }

    /**
     * @dev Remove all modules from the list of modules.
     */
    function removeModules() external onlyOwner whenPaused {
        delete modules;
    }

    /**
     * @dev Set the fees for specific schemaIds.
     * @param schemaIds The schemaIds to set the fee for.
     * @param _attestationFees The fees required to attest.
     */
    function setFees(bytes32[] memory schemaIds, uint256[] memory _attestationFees) public onlyOwner {
        if (schemaIds.length != _attestationFees.length) revert ArrayLengthMismatch();
        for (uint256 i = 0; i < schemaIds.length; i++) {
            attestationFees[schemaIds[i]] = _attestationFees[i];
        }
        emit FeesSet(schemaIds, _attestationFees);
    }

    /**
     * @dev Set up certificate mappings for schemaIds.
     * @param schemaIds The schemaIds for which to set up certificates.
     * @param certificateStatuses The corresponding certificate statuses.
     */
    function setUpCertificates(bytes32[] calldata schemaIds, bool[] calldata certificateStatuses) public onlyOwner {
        if (schemaIds.length != certificateStatuses.length) revert ArrayLengthMismatch();
        for (uint256 i = 0; i < schemaIds.length; i++) {
            certificates[schemaIds[i]] = certificateStatuses[i];
        }
    }

    /**
     * @dev Attest a score with a given attestation payload and validation payloads.
     * @param attestationPayload The payload of the attestation.
     * @param validationPayload The validation payload required for the module.
     */
    function attestRubyscore(
        AttestationPayload memory attestationPayload,
        bytes[] memory validationPayload
    ) external payable {
        super.attest(attestationPayload, validationPayload);
    }

    /**
     * @dev Withdraw ETH from the contract.
     * @param to The address to which the ETH will be withdrawn.
     * @param amount The amount of ETH to withdraw.
     */
    function withdraw(address payable to, uint256 amount) external override onlyOwner {
        (bool status, ) = to.call{value: amount}("");
        if (!status) revert WithdrawFail();
    }

    /**
     * @notice Optional method run before a payload is attested
     * @param attestationPayload the attestation payload supposed to be attested
     * @param attester the address of the attester
     * @param value the value sent with the attestation
     */
    function _onAttest(
        AttestationPayload memory attestationPayload,
        address attester,
        uint256 value
    ) internal override whenNotPaused {
        if (!certificates[attestationPayload.schemaId]) revert InvalidCertificateId();
        if (feeStatus) checkFee(attestationPayload.schemaId, value);
        super._onAttest(attestationPayload, attester, value);
    }

    /**
     * @notice Optional method run when attesting a batch of payloads
     */
    function _onBulkAttest(
        AttestationPayload[] memory attestationsPayloads,
        bytes[][] memory validationPayloads
    ) internal override whenNotPaused {
        if (!bulkStatus) revert("Only single attest");
        for (uint256 i = 0; i < attestationsPayloads.length; i++) {
            if (!certificates[attestationsPayloads[i].schemaId]) revert InvalidCertificateId();
        }
        super._onBulkAttest(attestationsPayloads, validationPayloads);
    }

    /**
     * @notice Optional method run when an attestation is replaced
     * @param attestationId the ID of the attestation being replaced
     * @param attestationPayload the attestation payload to create attestation and register it
     * @param attester the address of the attester
     * @param value the value sent with the attestation
     */
    function _onReplace(
        bytes32 attestationId,
        AttestationPayload memory attestationPayload,
        address attester,
        uint256 value
    ) internal override whenNotPaused {
        if (!certificates[attestationPayload.schemaId]) revert InvalidCertificateId();
        if (feeStatus) checkFee(attestationPayload.schemaId, value);
        super._onReplace(attestationId, attestationPayload, attester, value);
    }

    function _onBulkReplace(
        bytes32[] memory attestationIds,
        AttestationPayload[] memory attestationsPayloads,
        bytes[][] memory validationPayloads
    ) internal override whenNotPaused {
        if (!bulkStatus) revert("Only single replace");
        for (uint256 i = 0; i < attestationsPayloads.length; i++) {
            if (!certificates[attestationsPayloads[i].schemaId]) revert InvalidCertificateId();
        }
        super._onBulkReplace(attestationIds, attestationsPayloads, validationPayloads);
    }
}

Please enter a contract address above to load the contract details and source code.

Context size (optional):