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);
}
}