Alert Source Discuss
⚠️ Draft Standards Track: ERC

ERC-7425: Tokenized Reserve

Transparent reserve fund on-chain with stakeholder participation.

Authors Jimmy Debe (@jimstir)
Created 2023-06-30
Discussion Link https://ethereum-magicians.org/t/eip-7425-tokenized-reserve/15297
Requires EIP-20, EIP-4626

Abstract

A proposal for a tokenized reserve mechanism. The reserve allows an audit of on-chain actions of the owner. Using ERC-4626, stakeholders can create shares to show support for actions in the reserve.

Motivation

Tokenized reserves are an extension of tokenized vaults. The goal is to create a reserve similar to a real world reserve an entity has as a backup in case regular funds run low. In the real world, an entity will have to meet certain criteria before accessing reserve funds. In a decentralized environment, an entity can incorporate stakeholders into their criteria. This will help entities who participate in decentralized environments to be transparent with stakeholders.

Specification

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119 and RFC 8174.

Definitions:

- owner: The creator of the reserve
- user: Stakeholders of specific proposals
- reserve: The tokenized reserve contract
- proposal: Occurs when the owner wants a withdrawal from contract

Constructor:

- name: ERC-20 token name - ticker: ERC-20 ticker - asset: ERC-4626 underlying ERC-20 address
- rAuth: Primary authorized user
- rOwner: Owner of the Reserve

Interface

// SPDX-License-Identifier: CC0-1.0

pragma solidity ^0.8.0;
import "./ERC4626.sol";
    
interface TokenReserve is ERC4626{
	/**
	* @dev Event emitted after a new proposal is created
	*/
	event proposals(
	    	address indexed token,
	    	uint256 indexed proposalNum,
	    	uint256 indexed amount,
		address recipient
	);
	/**
	* @dev Event emitted after a new deposit is made by the owner
	*/
	event depositR(
		address indexed token,
	    	uint256 indexed amount,
	    	uint256 indexed time,
	    	uint256 count
	);
	/** 
	* @dev Get time of a deposit made to reserve with depositReserve()
	* @param count Number matching deposit
	* @return block.timestamp format
	*/
	function depositTime(uint256 count) external view returns (uint256);
	/** 
	* @dev Get amount deposited to reserve with depositReserve() 
	* @param count Number of deposit
	* @return uint256 number of any asset that were deposited
	*/
	function ownerDeposit(uint256 count) external view returns(uint256);
	/**
	* @dev Token type deposited to reserve with depositReserve()
	* - MUST be an address of ERC20 token
	* @param count Number of deposit
	*/
	function tokenDeposit(uint256 count) external view returns(address);
	/**
	* @dev Amount deposited for shares of proposal by the user
	* - MUST be an ERC20 address
	* @param user address of user
	* @param proposal number of the proposal the user deposited
	*/
	function userDeposit(address user, uint256 proposal) external view returns(uint256);
	/**
	* @dev Token used for given proposal
	* - MUST be ERC20 address
	* @param proposal number for requested token
	* @return token address
	*/
	function proposalToken(uint256 proposal) external view returns(address);
	/**
	* @dev Amount withdrawn for given opened proposal
	*/
	function proposalWithdrew(uint256 proposal) external view returns(uint256);
	/**
	* @dev Amount received for given closed proposal
	*/
	function proposalDeposited(uint256 proposal) external view returns(uint256);
	/**
	* @dev Make a deposit to a proposal creating new shares with deposit function from ERC-4626
	* - MUST be opened proposal
	* - MUST NOT be opened proposal that was closed
	* NOTE: using the deposit() will cause assets to not be accounted for in a proposal
	* @param assets Amount being deposited
	* @param receiver Address of depositor
	* @param proposal Number associated proposal
	*/
	function proposalDeposit(uint256 assets, address receiver, uint256 proposal) external virtual returns(uint256);
	/**
	* @dev Burn shares, receive 1 to 1 value of shares
	* - MUST have closed proposalNumber
	* - MUST have userDeposit greater than or equal to userWithdrawal
	* @param assets Amount being deposited
	* @param receiver Address of receiver
	* @param owner Address of token owner
	* @param proposal Number associated proposal
	*/
	function proposalWithdraw(uint256 assets, address receiver, address owner, uint256 proposal)external virtual returns(uint256);
	/**
	* @dev Issue new proposal
	* - MUST create new proposal number
	* - MUST account for amount withdrawn
	* - MUST emit proposals event
	* @param token Address of ERC-20 token
	* @param amount Token amount being withdrawn
	* @param receiver Address of token recipient
	*/
	function proposalOpen(address token, uint256 amount, address receiver) external virtual returns (uint256);
	/**
	* @dev Make deposit and/or choose to close an opened proposal
	* - MUST account for amount received
	* - MUST be a proposal that is less than or equal to current proposal
	* - MUST emit proposals event
	* @param token Address of ERC-20 token
	* @param proposal Number of desired proposal
	* @param amount Token amount being deposited to the reserve
	* @param close Choose to close the proposal
	*/
	function proposalClose(address token, uint256 proposal, uint256 amount, bool close) external virtual returns (bool);
	/**
	* @dev Optional accounting for tokens deposited by owner
	* - MUST be reserve owner
	* - MUST emit depositR event
	* NOTE: No shares are issued, funds can not be redeemed. Only withdrawn from proposalOpen
	* @param token Address of ERC-20 token
	* @param sender Address of where tokens from
	* @param amount Token amount being deposited
	*/
	function depositReserve(address token, address sender, uint256 amount) external virtual;
}
    

Rationale

This proposal is designed to be a basic implementation of a reserve fund interface. Other non specified conditions should be addressed on a case by case basis. Each reserve uses ERC-20 standard for shares, and ERC-4626 for the creation of shares. The reserve token can be the underlying token in ERC-4626 or the shares that are created when the underlying token is deposited in the vault. ERC-4626 is implemented to the reserve to account for user participation. There needs to be a representation for users participating in a proposal within a reserve. With vaults, the implementor could decide how to treat participation based on users entering the vault. For example, a user could be forced not to use the same tokens in multiple proposals to allow shares to be created fairly. Once the underlying token is deposited into the vault for an open proposal those tokens could not be accessible until the proposal is closed. It is not explicitly enforced that deposited tokens that create shares cannot be withdrawn by the owner of the reserve. On a case by case basis there can be implementions to ensure those tokens are accounted for if needed.

Backwards Compatibility

Tokenized reserves are made compatible with ERC-20 and ERC-4626.

Security Considerations

Needs discussion.

Copyright and related rights waived via CC0.

Citation

Please cite this document as:

Jimmy Debe (@jimstir), "ERC-7425: Tokenized Reserve [DRAFT]," Ethereum Improvement Proposals, no. 7425, June 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7425.