ERC-8260: Dive Logs

,

Discussion topic for ERC-: Dive Log Standard

Update Log

2026-05-04: Initial draft, seeking community feedback.

2026-05-09: Moved from a two-contract Registry/Factory pattern to a universal sis. Added voidDive (supersede) and attestDive (cryptographic verification) mechanisms based on early feedback.

2026-05-10: PR created Dive-Logbook-PR

2026-05-11: The contract is now purely a dive ledger. Wallet-as-identity is the right call, it avoids the PII trap entirely. I reviewed but ultimately kept the dual unit system. Since each dive declares its own UnitSystem, the data is self-describing and auditable. No silent conversion errors, and we won’t require divers to try and convert dive data before logging.

2026-05-15: Refactor: update dive log schema with coordinates, nonce tracking, and refined data types.

Summary

This ERC defines a standard interface for storing, retrieving, and verifying dive log data on EVM-compatible blockchains. Rather than dictating how contracts are deployed (e.g., via a central registry or factory), this standard defines a universal IDiveLogBook interface. This ensures that whether a logbook is deployed by a major certification agency (PADI, NAUI), a military unit, or an independent diver, the resulting records are fully interoperable and easily verified across any platform.

The data model is derived from U.S. military diving log standards (DD Form 2544, ENG Form 4615) and covers commercial, military, scientific, and recreational diving operations, including full decompression planning, breathing gas mixtures, and environmental conditions.

Motivation for ERC

Dive logs are safety-critical records that track decompression history, demonstrate qualifications, and provide evidence of experience. Current storage methods (paper logbooks, centralized apps, institutional databases) are fragile, vendor-locked, and lack interoperability.
This standard provides:

  • Permanence — data survives any single point of failure
  • Ownership — divers control their records via wallet keys
  • Interoperability — a single schema any application can read/write
  • Verifiability — records are cryptographically signed and timestamped

Architecture

  • The Sovereign Interface: We standardize the book, not the bookstore. Any contract implementing IDiveLogBook is a valid logbook.
  • The Corrective Ledger (Void/Supersede): Dive logs are safety-critical and must be immutable. However, human error (typos) happens. Instead of deleting or editing records, we implement a professional accounting standard: a voidDive function that flags a record as invalid and optionally points to a supersededById containing the corrected data.
  • On-Chain Attestations: Dives can be cryptographically verified (attestDive) by a supervisor or buddy, eliminating “pencil-whipping” (faking logs) and establishing high-trust audit trails for commercial operations.
  • Unit-agnostic pressure fields: (cylinderPressureIn, cylinderPressureOut, gasConsumed) interpreted via the dive’s UnitSystem.
  • No PII on-chain: SSN, military IDs, names and other sensitive identifiers are deliberately excluded.

Specification Summary

// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.20;

import "./IDiveLogTypes.sol";
import "./IERC165.sol";

interface IDiveLog is IERC165 {
    event DiveLogged(uint256 indexed diveId, uint64 indexed diveDate);
    event DiveVoided(uint256 indexed diveId, uint256 indexed supersededById, address indexed voidedBy, string reason);
    event DiveAttested(uint256 indexed diveId, address indexed attester);

    error NotOwner();
    error InvalidDepth();
    error InvalidTimes();
    error DiveNotFound(uint256 diveId);
    error DiveAlreadyVoided(uint256 diveId);
    error InvalidSupersede(uint256 voidedId, uint256 supersededId);
    error AlreadyAttested(uint256 diveId, address attester);
    error InvalidSignature();
    error NonceMismatch(uint256 expected, uint256 provided);

    function logDive(DiveInput calldata input) external returns (uint256 diveId);

    function batchLogDives(DiveInput[] calldata inputs) external returns (uint256[] memory diveIds);

    function voidDive(
        uint256 diveId,
        uint256 supersededById,
        string calldata reason
    ) external;

    function attestDive(
        uint256 diveId,
        uint256 nonce,
        bytes calldata signature
    ) external;

    function getDive(uint256 diveId) external view returns (DiveLog memory);
    function getDivesByDate(uint64 date) external view returns (uint256[] memory);
    function getMultipleDives(uint256[] calldata diveIds) external view returns (DiveLog[] memory);
    function getAllDiveIds() external view returns (uint256[] memory);
    function getDiveCount() external view returns (uint256);
    function isDiveVoided(uint256 diveId) external view returns (bool);
    function getVoidInfo(uint256 diveId) external view returns (VoidInfo memory);
    function getAttestations(uint256 diveId) external view returns (Attestation[] memory);
    function attesterNonce(address attester) external view returns (uint256);
}

Reference Implementation:
Solidity (Foundry), 35 tests passing including fuzz tests:

Questions for Feedback

  1. Is the two-contract (registry + per-diver log book) architecture the right granularity, or would a single-contract with mapping-based storage be preferred for gas efficiency?
  2. Should the standard include a verification/attestation mechanism (e.g., a dive supervisor or buddy co-signing a dive record)?
  3. Are there additional dive modes or breathing gas types the community would want beyond SSA/SCUBA and the six defined gas types?
  4. Is the append-only constraint too restrictive, or is it appropriate given the safety-critical nature of dive logs?
    Full specifications
    Field reference

I ai’d a demo site for this. dive logbook creation and logging is live on avax. divechain.pro

onchain > on-chain

Why not get front ends to convert into a single unit system?

For privacy I’d recommend not putting any personal information onchain.

1 Like

Completely valid points, I was struggling with how much to abstract away while staying true to the regulations. I was worried that if I removed too many of the original log requirements, it couldn’t realistically function as a substitute, so I ended up including almost everything from the paper forms. I’m now thinking that since wallet ownership can be validated, linking a wallet to a name is a KYC process, not a contract responsibility.

Thanks for the suggestions!

1 Like

Why not publishes these using the existing Ethereum Attestation Service? This feels like the perfect use-case and EAS is already well supported and documented.

1 Like

EAS is “schema-agnostic,” meaning anyone can create a schema for anything. This leads to fragmentation, one of the key points of this proposal.

Doesn’t this still create fragmentation in the sense that anyone can create a logbook and publish attestations with no common format for attestation and verification? It’s not clear to me how to establish trust in any particular instance of a logbook.

It might be more useful to standardize the attestation schemes and verification for third parties to align on how to publish and verify attestations.

nope, purpose of an erc standard for interfaces. Attestation isn’t the purpose of this standard and can/will be used without one especially for recreational dives. IF supervisor signatures are required by the dive org then there is an option for it.

Okay, I’ll focus on the proposed interface and ask some questions. Looking through the data structures there are some things that aren’t clear to me:

struct DiveData {
    uint32 leaveSurfaceTime;     // Unix timestamp — diver descends from surface
    uint32 leaveBottomTime;      // Unix timestamp — diver leaves bottom
    uint32 reachSurfaceTime;     // Unix timestamp — diver reaches surface
    uint32 bottomTimeMinutes;    // Total bottom time in minutes
    uint32 maxDepth;              // Maximum depth attained (positive = below surface)
    int32 averageDepth;          // Average depth (OPTIONAL, 0 = not recorded)
    DiveMode mode;               // Dive mode
    DivePurpose purpose;         // Purpose of the dive
    SuitType suit;               // Exposure suit type
}

Should averageDepth be uint32?

struct Environment {
    int32 airTemp;               // Air temperature (unit per dive's UnitSystem)
    int32 waterTemp;             // Water temperature (unit per dive's UnitSystem)
    int16 currentKnots;          // Current speed in knots
    string location;             // Human-readable dive location
    string bottomType;           // Bottom composition (e.g., "Mud", "Coral", "Concrete")
    string weatherConditions;    // Weather description
}

Should bottomType be an enum? Same for weatherConditions?

How do you normalize location if UIs want to display them in rich interfaces (for example, and interactive map)?

struct GasData {
    BreathingGas gasType;
    uint16 o2Percent;
    uint16 hePercent;
    uint16 n2Percent;
    uint32 cylinderPressureIn;
    uint32 cylinderPressureOut;
    uint32 gasConsumed;
    uint32 bailoutPressure;
}

How are percent values encoded? Are they whole numbers or fixed precision? What is the unit on gasConsumed?

struct DiveLog {
    uint256 id;
    uint64 diveDate;
    UnitSystem units;
    DiveData data;
    Environment env;
    Decompression decomp;
    GasData gas;
    string remarks;
}

The diveDate is stored as uint64 but DiveData time values are stored as uint32. Should these used the same type and store all time values as unix timestamps? DiveLog also stores diveDate as uint64.

struct Attestation {
    address attester;
    uint64 attestedAt;
}

Should the Attestation struct be updated to include the nonce? The nonce is included in the type hash so I think it is supposed to be in the struct declaration.

1 Like

Thanks for the questions, I’ll try and speed run them.

Depth is a scalar value, so switching it to a uint32 makes way more sense and keeps it consistent with the max depth field.

Bottom type can for sure benefit from an enum. For weather, I’m thinking there are too many options to be useful as an enum, but maybe a simplified one with optional notes. Since 99/100 I write something like clear or cloudy, I’ll start looking at options.

For the location mapping, a string alone won’t really work for an interactive interface, so I’m going to add a coordinates struct with latitude and longitude. Even though it’s not in the original dive standards, I agree it’s a good add.

The timestamp mismatch was a solid find too. It’s definitely better to standardize everything to uint64 across the board to avoid an overflow chance.

On the gas percentages, I’m going to use basis points (so 3250 for 32.5%) for better precision. Gas consumed will just be the pressure delta based on the unit system selected.

Lastly, you’re right on the attestation nonce. It’s already in the type hash, so I’ll add it to the struct declaration so the data actually matches the signature.

1 Like