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
- rAuth: Primary authorized user
- rOwner: Owner of the Reserve
Interface
// SPDX-License-Identifier: CC0-1.0
pragmasolidity^0.8.0;import"./ERC4626.sol";interfaceTokenReserveisERC4626{/**
* @dev Event emitted after a new proposal is created
*/eventproposals(addressindexedtoken,uint256indexedproposalNum,uint256indexedamount,addressrecipient);/**
* @dev Event emitted after a new deposit is made by the owner
*/eventdepositR(addressindexedtoken,uint256indexedamount,uint256indexedtime,uint256count);/**
* @dev Get time of a deposit made to reserve with depositReserve()
* @param count Number matching deposit
* @return block.timestamp format
*/functiondepositTime(uint256count)externalviewreturns(uint256);/**
* @dev Get amount deposited to reserve with depositReserve()
* @param count Number of deposit
* @return uint256 number of any asset that were deposited
*/functionownerDeposit(uint256count)externalviewreturns(uint256);/**
* @dev Token type deposited to reserve with depositReserve()
* - MUST be an address of ERC20 token
* @param count Number of deposit
*/functiontokenDeposit(uint256count)externalviewreturns(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
*/functionuserDeposit(addressuser,uint256proposal)externalviewreturns(uint256);/**
* @dev Token used for given proposal
* - MUST be ERC20 address
* @param proposal number for requested token
* @return token address
*/functionproposalToken(uint256proposal)externalviewreturns(address);/**
* @dev Amount withdrawn for given opened proposal
*/functionproposalWithdrew(uint256proposal)externalviewreturns(uint256);/**
* @dev Amount received for given closed proposal
*/functionproposalDeposited(uint256proposal)externalviewreturns(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
*/functionproposalDeposit(uint256assets,addressreceiver,uint256proposal)externalvirtualreturns(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
*/functionproposalWithdraw(uint256assets,addressreceiver,addressowner,uint256proposal)externalvirtualreturns(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
*/functionproposalOpen(addresstoken,uint256amount,addressreceiver)externalvirtualreturns(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
*/functionproposalClose(addresstoken,uint256proposal,uint256amount,boolclose)externalvirtualreturns(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
*/functiondepositReserve(addresstoken,addresssender,uint256amount)externalvirtual;}
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.