Ethereum Smart Contract Notary

Published on June 23, 2025

Create a permanent, queryable, and structured proof-of-existence for any file by storing its hash in a dedicated smart contract using the Foundry toolkit.

This guide covers an advanced method for developers. For a simpler approach using just MetaMask, see our Ethereum Notary Guide.

While embedding data in a transaction's input field is simple and effective, a more robust and extensible method is to store the data in a smart contract's state. This approach creates structured, on-chain records that can be easily read and integrated into other decentralized applications.

This guide provides an advanced walkthrough using Foundry, a leading toolkit for Ethereum application development, to deploy and interact with a dedicated Notary contract.


Step 1: The Notary Smart Contract

First, we need a smart contract that can receive, store, and expose notarization records. This simple Notary.sol contract stores the data hash, the sender's address, and a timestamp for each entry.

Create a file named src/Notary.sol in your Foundry project:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract Notary {
    struct Record {
        address sender;
        uint256 timestamp;
        bytes32 data;
    }

    Record[] public notarizations;

    function notarize(bytes32 _data) public {
        notarizations.push(Record({
            sender: msg.sender,
            timestamp: block.timestamp,
            data: _data
        }));
    }

    function getNotarizationCount() public view returns (uint256) {
        return notarizations.length;
    }
}

Step 2: Deploy the Contract with `forge create`

With the contract code ready, use Foundry's forge tool to compile and deploy it to a test network like Sepolia. This command broadcasts the creation transaction.

forge create --rpc-url YOUR_SEPOLIA_RPC_URL \
--private-key YOUR_PRIVATE_KEY \
src/Notary.sol:Notary --broadcast

Command Breakdown:

Forge will output the address of your newly deployed Notary contract. Save this address for the next steps.


Step 3: Notarize a File Hash with `cast send`

Now, you can call the notarize function on your live contract. First, get the SHA-256 hash of your document using the tool in our Bitcoin Notary Guide.

Use Foundry's cast tool to send the transaction that calls the function, passing your document's hash as the argument.

cast send YOUR_CONTRACT_ADDRESS \
  "notarize(bytes32)" \
  YOUR_DOCUMENT_HASH \
  --rpc-url YOUR_SEPOLIA_RPC_URL \
  --private-key YOUR_PRIVATE_KEY

This transaction will create a new Record in the contract's notarizations array, permanently storing your hash alongside your address and the block's timestamp.


Step 4: Verify the On-Chain Data with `cast call`

Since the notarized data is stored in the contract's public state, you can read it back at any time without needing a private key or paying for gas. Use cast call to read the record at a specific index (e.g., 0 for the first record).

cast call YOUR_CONTRACT_ADDRESS \
"notarizations(uint256)" 0 \
--rpc-url YOUR_SEPOLIA_RPC_URL

The command will return the raw, 32-byte-aligned data for the struct, which you can then decode.


A More Robust Foundation

Using a smart contract for notarization provides a powerful, extensible foundation. The stored data is structured, machine-readable, and can be used as a trusted oracle by other smart contracts, opening up possibilities for automated verification, royalty systems, and more.

Nanar Consulting specializes in developing these robust, on-chain solutions. If you need to integrate blockchain notarization into your business workflow or protect high-value intellectual property, contact us for a full consultation and custom software development services.