ClaimsDBV3_1

Description:

Proxy contract enabling upgradeable smart contract patterns. Delegates calls to an implementation contract.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "claims.sol": {
      "content": "// tesnet 0x7010996c5638C3b557cA1B7f69AD18991821eA82 (v1)\r
// tesnet v2 0xAb9F4f36897d108ffc89aaDDc4B06928edAf1c75 (v2)\r
// tesnet v3 0x21952de9a37BA2fD014E36f553C42Df208db1818 (v3)\r
// testnet v3.1 0x81bE3f271eF26CE80835A5B335a3aAA6C84a7418 (v3.1)\r
// mainnet 0xCBED2362c00587720aC216C37E4b62bCAB2F53E1\r
\r
// SPDX-License-Identifier: MIT\r
pragma solidity ^0.8.24;\r
\r
abstract contract UUPSUpgradeable {\r
    bytes32 private constant IMPLEMENTATION_SLOT =\r
        0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\r
\r
    function upgradeTo(address newImplementation) external virtual {\r
        _authorizeUpgrade(newImplementation);\r
        _setImplementation(newImplementation);\r
    }\r
\r
    function _setImplementation(address newImpl) internal {\r
        require(newImpl != address(0), "bad impl");\r
        bytes32 slot = IMPLEMENTATION_SLOT;\r
        assembly {\r
            sstore(slot, newImpl)\r
        }\r
    }\r
\r
    function _authorizeUpgrade(address newImplementation) internal virtual;\r
}\r
\r
    // --- Minimal ERC20 interface ---\r
    interface IERC20 {\r
        function decimals() external view returns (uint8);\r
        function balanceOf(address) external view returns (uint256);\r
        function allowance(address owner, address spender) external view returns (uint256);\r
        function transfer(address to, uint256 value) external returns (bool);\r
        function transferFrom(address from, address to, uint256 value) external returns (bool);\r
    }\r
\r
/// @title ClaimsDB V2 — ERC20 fee (default 10 tokens) instead of 1 ETH (UUPS)\r
/// @notice Mirrors v1 features but collects an ERC-20 token as the creation fee.\r
/// @dev Hardened for fee-on-transfer tokens (balance-delta), tolerant ERC-20 calls, and reentrancy-guarded.\r
///      `initializeDefault` derives the default fee from token decimals (falls back to 18).\r
/*\r
 * @changelog\r
 * - v2: ERC20 fee (10 tokens by default not 1 ether) + Slashing (UUPS)\r
 *\r
 * - v3: encrypts safe address\r
 */\r
contract ClaimsDBV3_1 is UUPSUpgradeable {\r
\r
\r
    // --- Data model (same as v1) ---\r
    enum Status { Pending, Approved, Rejected, Cancelled }\r
\r
    struct Claim {\r
        address claimer;         // who created the claim (payer)\r
        string  encryptedSafe;   // encrypted safe identifier (replaces address safe)\r
        address attestor;        // designated attestor\r
        string  encryptedPhone;  // encrypted phone blob (e.g., ciphertext)\r
        uint64  createdAt;       // timestamp at creation\r
        Status  status;          // current status\r
    }\r
\r
    // --- Config / admin ---\r
    address public treasury;               // admin/withdrawer (same role as v1)\r
    IERC20  public feeToken;               // ERC-20 used for fee (e.g., MRS)\r
    uint256 public registerFee;            // fee in token units (e.g., 10 * 10**decimals)\r
    bool    private _initialized;\r
\r
    // --- Storage ---\r
    uint256 public nextId;                 // auto-incremented claim id\r
    mapping(uint256 => Claim) private claims;\r
    uint256[] public ids;                  // optional enumeration\r
\r
    // --- Reentrancy guard ---\r
    uint256 private _entered;              // 0 = unlocked, 1 = locked\r
    modifier nonReentrant() {\r
        require(_entered == 0, "reentrancy");\r
        _entered = 1;\r
        _;\r
        _entered = 0;\r
    }\r
\r
    modifier whenInitialized() {\r
        require(_initialized, "not initialized");\r
        _;\r
    }\r
\r
    modifier onlyTreasury() {\r
        require(_initialized, "not initialized");\r
        require(msg.sender == treasury, "not treasury");\r
        _;\r
    }\r
\r
    // --- Events (aligned with v1 updated events) ---\r
    event ClaimCreated(\r
        uint256 indexed id,\r
        address indexed claimer,\r
        string encryptedSafe,\r
        address attestor,\r
        string encryptedPhone,\r
        uint64 createdAt\r
    );\r
    event StatusChanged(uint256 indexed id, Status fromStatus, Status toStatus);\r
    event PhoneUpdated(uint256 indexed id, string oldEncryptedPhone, string newEncryptedPhone);\r
    event AttestorUpdated(uint256 indexed id, address oldAttestor, address newAttestor);\r
    event Withdrawn(address indexed to, uint256 amount);\r
    event TreasuryChanged(address indexed oldTreasury, address indexed newTreasury);\r
    event RegisterFeeUpdated(uint256 oldFee, uint256 newFee);\r
    event FeeReceived(address indexed payer, uint256 amount);\r
\r
    // --- Constructor ---\r
    constructor() {\r
        _initialized = true; // lock the implementation\r
    }\r
\r
    // --- Initializers ---\r
    /// @notice Initialize with explicit fee value (token units)\r
    function initialize(address _treasury, address _feeToken, uint256 _fee) external {\r
        _initialize(_treasury, _feeToken, _fee);\r
    }\r
\r
    /// @notice Initialize with default fee of "10 tokens", respecting token decimals (fallback = 18)\r
    function initializeDefault(address _treasury, address _feeToken) external {\r
        uint256 fee;\r
        // Best-effort decimals read; default to 18 on failure\r
        try IERC20(_feeToken).decimals() returns (uint8 dec) {\r
            fee = 10 * (10 ** dec);\r
        } catch {\r
            fee = 10 * 1e18;\r
        }\r
        _initialize(_treasury, _feeToken, fee);\r
    }\r
\r
    function _initialize(address _treasury, address _feeToken, uint256 _fee) internal {\r
        require(!_initialized, "already initialized");\r
        require(_treasury != address(0), "treasury=0");\r
        require(_feeToken != address(0), "token=0");\r
        treasury = _treasury;\r
        feeToken = IERC20(_feeToken);\r
        registerFee = _fee;\r
        _entered = 0;\r
        _initialized = true;\r
    }\r
\r
    // --- Core: create a claim by paying token fee ---\r
    /// @param encryptedSafe Encrypted safe identifier (required)\r
    /// @param attestor Designated attestor (required)\r
    /// @param encryptedPhone Opaque encrypted blob\r
    /// @param amount Amount of tokens to attempt to pay (must result in received >= registerFee)\r
    function createClaim(\r
        string calldata encryptedSafe,\r
        address attestor,\r
        string calldata encryptedPhone,\r
        uint256 amount\r
    ) external whenInitialized nonReentrant returns (uint256 id) {\r
        require(amount > 0, "amount=0");\r
        //require(bytes(encryptedSafe).length > 0, "encryptedSafe=empty");\r
        require(attestor != address(0), "attestor=0");\r
\r
        // Pull tokens; verify actual amount received against registerFee (handles fee-on-transfer)\r
        uint256 received = _pullReceived(feeToken, msg.sender, amount);\r
        require(received >= registerFee, "fee too low");\r
\r
        unchecked { id = ++nextId; }\r
        Claim storage c = claims[id];\r
        c.claimer = msg.sender;\r
        c.encryptedSafe = encryptedSafe;    \r
        c.attestor = attestor;\r
        c.encryptedPhone = encryptedPhone;\r
        c.createdAt = uint64(block.timestamp);\r
        c.status = Status.Pending;\r
\r
        ids.push(id);\r
\r
        emit ClaimCreated(id, msg.sender, encryptedSafe, attestor, encryptedPhone, c.createdAt);\r
        emit FeeReceived(msg.sender, received);\r
    }\r
\r
    // --- Admin (treasury) can change status ---\r
    function setStatus(uint256 id, Status newStatus) external onlyTreasury {\r
        Claim storage c = _mustGet(id);\r
        Status old = c.status;\r
        if (old != newStatus) {\r
            c.status = newStatus;\r
            emit StatusChanged(id, old, newStatus);\r
        }\r
    }\r
\r
    /// @notice Change the treasury address. Only current treasury may call.\r
    function setTreasury(address newTreasury) external onlyTreasury {\r
        require(newTreasury != address(0), "treasury=0");\r
        address old = treasury;\r
        treasury = newTreasury;\r
        emit TreasuryChanged(old, newTreasury);\r
    }\r
\r
    /// @notice Update the register fee amount (token units). Only treasury may call.\r
    function setRegisterFee(uint256 newFee) external onlyTreasury {\r
        uint256 old = registerFee;\r
        registerFee = newFee;\r
        emit RegisterFeeUpdated(old, newFee);\r
    }\r
\r
    // --- Claimer can update encrypted phone & attestor while Pending ---\r
    function updateEncryptedPhone(uint256 id, string calldata newEncryptedPhone) external whenInitialized {\r
        Claim storage c = _mustGet(id);\r
        require(msg.sender == c.claimer, "not claimer");\r
        require(c.status == Status.Pending, "locked");\r
        string memory old = c.encryptedPhone;\r
        c.encryptedPhone = newEncryptedPhone;\r
        emit PhoneUpdated(id, old, newEncryptedPhone);\r
    }\r
\r
    function updateAttestor(uint256 id, address newAttestor) external whenInitialized {\r
        require(newAttestor != address(0), "attestor=0");\r
        Claim storage c = _mustGet(id);\r
        require(msg.sender == c.claimer, "not claimer");\r
        require(c.status == Status.Pending, "locked");\r
        address old = c.attestor;\r
        c.attestor = newAttestor;\r
        emit AttestorUpdated(id, old, newAttestor);\r
    }\r
\r
    // --- Views ---\r
\r
function getClaimsByAttester(address _attestor)\r
    external\r
    view\r
    whenInitialized\r
    returns (\r
        uint256[] memory outIds,\r
        address[] memory claimers,\r
        string[] memory encryptedSafes,\r
        address[] memory attestors,\r
        string[] memory encryptedPhones,\r
        uint64[] memory createdAts,\r
        Status[] memory statuses\r
    )\r
{\r
    // First pass: count matches\r
    uint256 count = 0;\r
    for (uint256 i = 0; i < ids.length; i++) {\r
        if (claims[ids[i]].attestor == _attestor) {\r
            unchecked { count++; }\r
        }\r
    }\r
\r
    // Allocate outputs\r
    outIds = new uint256[](count);\r
    claimers = new address[](count);\r
    encryptedSafes = new string[](count);\r
    attestors = new address[](count);\r
    encryptedPhones = new string[](count);\r
    createdAts = new uint64[](count);\r
    statuses = new Status[](count);\r
\r
    if (count == 0) {\r
        return (outIds, claimers, encryptedSafes, attestors, encryptedPhones, createdAts, statuses);\r
    }\r
\r
    // Second pass: fill arrays (newest first)\r
    uint256 idx = 0;\r
    for (uint256 i = ids.length; i > 0; i--) {\r
        uint256 id = ids[i - 1];\r
        Claim storage c = claims[id];\r
        if (c.attestor == _attestor) {\r
            outIds[idx] = id;\r
            claimers[idx] = c.claimer;\r
            encryptedSafes[idx] = c.encryptedSafe;\r
            attestors[idx] = c.attestor;\r
            encryptedPhones[idx] = c.encryptedPhone;\r
            createdAts[idx] = c.createdAt;\r
            statuses[idx] = c.status;\r
            unchecked { idx++; }\r
            if (idx == count) break;\r
        }\r
    }\r
\r
    return (outIds, claimers, encryptedSafes, attestors, encryptedPhones, createdAts, statuses);\r
}\r
\r
    function idsLength() external view whenInitialized returns (uint256) {\r
        return ids.length;\r
    }\r
\r
    // --- Treasury-only withdrawals of collected fee tokens ---\r
    function withdrawTokens(uint256 amount) external onlyTreasury nonReentrant {\r
        require(amount > 0, "amount=0");\r
        require(feeToken.balanceOf(address(this)) >= amount, "insufficient balance");\r
        require(_safeTransfer(feeToken, treasury, amount), "withdraw failed");\r
        emit Withdrawn(treasury, amount);\r
    }\r
\r
    function withdrawAllTokens() external onlyTreasury nonReentrant {\r
        uint256 bal = feeToken.balanceOf(address(this));\r
        if (bal == 0) return;\r
        require(_safeTransfer(feeToken, treasury, bal), "withdraw failed");\r
        emit Withdrawn(treasury, bal);\r
    }\r
\r
    // --- internal ---\r
    function _authorizeUpgrade(address) internal override onlyTreasury {}\r
\r
    function _mustGet(uint256 id) internal view returns (Claim storage c) {\r
        c = claims[id];\r
        require(c.createdAt != 0, "claim not found");\r
    }\r
\r
    // --- Internal helpers ---\r
    // Accept both no-return and bool-return ERC-20s; bubble up reverts.\r
    function _safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {\r
        (bool ok, bytes memory data) = address(token).call(\r
            abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value)\r
        );\r
        require(ok, "transferFrom revert");\r
        return (data.length == 0) || abi.decode(data, (bool));\r
    }\r
\r
    function _safeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {\r
        (bool ok, bytes memory data) = address(token).call(\r
            abi.encodeWithSelector(IERC20.transfer.selector, to, value)\r
        );\r
        require(ok, "transfer revert");\r
        return (data.length == 0) || abi.decode(data, (bool));\r
    }\r
\r
    /// @notice Pull tokens and return the actual amount received (handles fee-on-transfer).\r
    function _pullReceived(IERC20 token, address from, uint256 requested) internal returns (uint256 received) {\r
        uint256 beforeBal = token.balanceOf(address(this));\r
        require(_safeTransferFrom(token, from, address(this), requested), "transferFrom failed");\r
        unchecked {\r
            received = token.balanceOf(address(this)) - beforeBal;\r
        }\r
        require(received > 0, "nothing received");\r
    }\r
}\r
"
    }
  },
  "settings": {
    "optimizer": {
      "enabled": true,
      "runs": 200
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "remappings": []
  }
}}

Tags:
Proxy, Upgradeable, Factory|addr:0x5765e649f65945abce706e56788c68a7652cd8aa|verified:true|block:23687754|tx:0x12898647a9867a67ca1e0a5cf9bd029551b7c07dfdbf53c6da159cf6afb50060|first_check:1761825031

Submitted on: 2025-10-30 12:50:34

Comments

Log in to comment.

No comments yet.