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

import { ISemver } from "src/universal/interfaces/ISemver.sol";

/// @title AttestationStation
/// @author Optimism Collective
/// @author Gitcoin
/// @notice Where attestations live.
contract AttestationStation is ISemver {
    /// @notice Struct representing data that is being attested.
    /// @custom:field about Address for which the attestation is about.
    /// @custom:field key   A bytes32 key for the attestation.
    /// @custom:field val   The attestation as arbitrary bytes.
    struct AttestationData {
        address about;
        bytes32 key;
        bytes val;
    }

    /// @notice Maps addresses to attestations. Creator => About => Key => Value.
    mapping(address => mapping(address => mapping(bytes32 => bytes))) public attestations;

    /// @notice Emitted when Attestation is created.
    /// @param creator Address that made the attestation.
    /// @param about   Address attestation is about.
    /// @param key     Key of the attestation.
    /// @param val     Value of the attestation.
    event AttestationCreated(address indexed creator, address indexed about, bytes32 indexed key, bytes val);

    /// @notice Semantic version.
    /// @custom:semver 1.2.1-beta.1
    string public constant version = "1.2.1-beta.1";

    /// @notice Allows anyone to create an attestation.
    /// @param _about Address that the attestation is about.
    /// @param _key   A key used to namespace the attestation.
    /// @param _val   An arbitrary value stored as part of the attestation.
    function attest(address _about, bytes32 _key, bytes memory _val) public {
        attestations[msg.sender][_about][_key] = _val;

        emit AttestationCreated(msg.sender, _about, _key, _val);
    }

    /// @notice Allows anyone to create attestations.
    /// @param _attestations An array of AttestationData structs.
    function attest(AttestationData[] calldata _attestations) external {
        uint256 length = _attestations.length;
        for (uint256 i = 0; i < length;) {
            AttestationData memory attestation = _attestations[i];

            attest(attestation.about, attestation.key, attestation.val);

            unchecked {
                ++i;
            }
        }
    }
}
