npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

consumable-contracts

v1.0.0

Published

Consumable project contracts

Downloads

9

Readme

Consumable

Introduction

Consumables are a new way to interact with Smart Contracts. They enable the creation of on-chain one-time secrets that are resistant to front-running and can be consumed against any EVM function, in a secure and privacy-enhancing manner.

Motivation

Protecting smart contract function executions with secure passwords unlocks many different and new use cases, like linking secrets to physical products for claiming originality certificates (NFTS) , giving away vouchers for expending tokens, and even anonymous voting.

The use of cryptographic secure passwords to protect smart contract function executions unlocks various new use cases, including:

  • Linking one-time claiming secrets to physical products via QR's for originality certificates (NFTs).
  • Distributing vouchers for one-time payments.
  • Enabling anonymous voting mechanisms by delivering one-time voting vouchers.

Consumable Smart Contract Standard

The Consumable.sol contract is an abstract, inheritable contract inspired by OpenZeppelin's Ownable.sol. It provides utilities for managing valid cryptographic consumers with consumable secrets.

Key Features:

  • merkleRoot state
  • onlyConsumer modifier
  • isValidConsumer function
  • consumerHasNotExceededTotalUses function

Contract Interface:

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

import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";

abstract contract Consumable {
  bytes32 public merkleRoot;
  uint256 public totalUsesPerConsumer;
  mapping(address => uint256) public userConsumptions;

  constructor(bytes32 _merkleRoot, uint256 _totalUsesPerConsumer) {
    merkleRoot = _merkleRoot;
    totalUsesPerConsumer = _totalUsesPerConsumer;
  }

  modifier onlyConsumer(bytes32[] calldata _merkleProof) {
    _checkConsumer(_merkleProof);
    _;
  }

  function _checkConsumer(bytes32[] calldata _merkleProof) internal virtual {
    require(isValidConsumer(_merkleProof), "Not a valid consumer");
    require(
      consumerHasNotExceededTotalUses(),
      "Consumer has exceeded total uses"
    );
    _incrementConsumerComsumptions();
  }

  function isValidConsumer(
    bytes32[] calldata _merkleProof
  ) public view returns (bool) {
    bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(msg.sender))));
    return MerkleProof.verify(_merkleProof, merkleRoot, leaf);
  }

  function consumerHasNotExceededTotalUses() public view returns (bool) {
    return userConsumptions[msg.sender] < totalUsesPerConsumer;
  }

  function _incrementConsumerComsumptions() internal {
    userConsumptions[msg.sender]++;
  }
}

Example Scenario:

A user could generate withdrawal secrets before going on a travel, allowing limited token withdrawals just in case he faces an emergency and needs some money, but without exposing their private key. If in the worst-case the secret gets compromised, the user would only lose the amount tied to that secret, and it can only be consumed once.

Vault Contract Example:

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

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "../Consumable.sol";

/* My Vault holds 1000 tokens, and each one-time secret can withdraw 100 tokens (value set at constructor) */
contract Vault is Ownable, Consumable {
  address public tokenAddress;
  uint256 public voucherValue;

  constructor(
    bytes32 _merkleRoot,
    uint256 _totalUsesPerConsumer,
    address _tokenAddress,
    uint256 _voucherValue
  ) Consumable(_merkleRoot, _totalUsesPerConsumer) Ownable(msg.sender) {
    tokenAddress = _tokenAddress;
    voucherValue = _voucherValue;
  }

  function ownerWithdraw(address _token, uint256 _amount) external onlyOwner {
    IERC20(_token).transfer(msg.sender, _amount);
  }

  function consumeSecret(
    bytes32[] calldata _merkleProof,
    address receiver
  ) external onlyConsumer(_merkleProof) {
    IERC20(tokenAddress).transfer(receiver, voucherValue);
  }
}

Secret Structure and Workflow

A typical transaction consists of the sender, parameters, and transaction configuration (e.g., gas settings). However, sending secrets or even their hashes directly as parameters is vulnerable to front-running on a public mempool.

Solution

To address this, our solution generates secrets as funded and ready-to-use private keys. In addition, to facilitate use, we include "Secrets Metadata", which includes useful data such as the contract address and function to be called, so any frontend can execute and consume in one click.

  • First 20 bytes: The secret itself.
  • Followed by Secret Metadata: Chain ID, Contract Address, Function Signature, and Merkle Proof.

Proof of Concept

Related Repositories

License

This project is licensed under the MIT License.