Skip to content

Commit bf909b2

Browse files
authored
feat: add ERC7540 and ERC7575 interfaces (#644)
This adds the interfaces for the 2 finalized extensions to ERC4626, [ERC7540](https://eips.ethereum.org/EIPS/eip-7540) and [ERC7575](https://eips.ethereum.org/EIPS/eip-7575). See https://ethereum.org/en/developers/docs/standards/tokens/erc-4626/#introduction for details on these extensions. Adding these would be helpful for repositories that rely on the interfaces in `forge-std`. ERC7540 interfaces are split by async deposit, async redeem, and fully async vaults, per the ERC specification. This also ensures the ERC-165 ID matches for each vault type. The ERC7575 interface specifies all ERC4626 methods, rather than extending `IERC4626.sol`, because: 1. ERC20 methods need to be excluded for ERC7575. 2. This ensures `IERC7575.interfaceId` is the expected ID as specified in https://eips.ethereum.org/EIPS/eip-7575#erc-165-support, since `.interfaceID` does not account for inherited interfaces.
1 parent 3b20d60 commit bf909b2

File tree

2 files changed

+391
-0
lines changed

2 files changed

+391
-0
lines changed

src/interfaces/IERC7540.sol

+150
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity >=0.6.2;
3+
4+
import "./IERC7575.sol";
5+
6+
/// @dev Interface of the base operator logic of ERC7540, as defined in
7+
/// https://eips.ethereum.org/EIPS/eip-7540
8+
interface IERC7540Operator {
9+
/**
10+
* @dev The event emitted when an operator is set.
11+
*
12+
* @param controller The address of the controller.
13+
* @param operator The address of the operator.
14+
* @param approved The approval status.
15+
*/
16+
event OperatorSet(address indexed controller, address indexed operator, bool approved);
17+
18+
/**
19+
* @dev Sets or removes an operator for the caller.
20+
*
21+
* @param operator The address of the operator.
22+
* @param approved The approval status.
23+
* @return Whether the call was executed successfully or not
24+
*/
25+
function setOperator(address operator, bool approved) external returns (bool);
26+
27+
/**
28+
* @dev Returns `true` if the `operator` is approved as an operator for an `controller`.
29+
*
30+
* @param controller The address of the controller.
31+
* @param operator The address of the operator.
32+
* @return status The approval status
33+
*/
34+
function isOperator(address controller, address operator) external view returns (bool status);
35+
}
36+
37+
/// @dev Interface of the asynchronous deposit Vault interface of ERC7540, as defined in
38+
/// https://eips.ethereum.org/EIPS/eip-7540
39+
interface IERC7540Deposit is IERC7540Operator {
40+
event DepositRequest(
41+
address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets
42+
);
43+
/**
44+
* @dev Transfers assets from sender into the Vault and submits a Request for asynchronous deposit.
45+
*
46+
* - MUST support ERC-20 approve / transferFrom on asset as a deposit Request flow.
47+
* - MUST revert if all of assets cannot be requested for deposit.
48+
* - owner MUST be msg.sender unless some unspecified explicit approval is given by the caller,
49+
* approval of ERC-20 tokens from owner to sender is NOT enough.
50+
*
51+
* @param assets the amount of deposit assets to transfer from owner
52+
* @param controller the controller of the request who will be able to operate the request
53+
* @param owner the source of the deposit assets
54+
*
55+
* NOTE: most implementations will require pre-approval of the Vault with the Vault's underlying asset token.
56+
*/
57+
58+
function requestDeposit(uint256 assets, address controller, address owner) external returns (uint256 requestId);
59+
60+
/**
61+
* @dev Returns the amount of requested assets in Pending state.
62+
*
63+
* - MUST NOT include any assets in Claimable state for deposit or mint.
64+
* - MUST NOT show any variations depending on the caller.
65+
* - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.
66+
*/
67+
function pendingDepositRequest(uint256 requestId, address controller)
68+
external
69+
view
70+
returns (uint256 pendingAssets);
71+
72+
/**
73+
* @dev Returns the amount of requested assets in Claimable state for the controller to deposit or mint.
74+
*
75+
* - MUST NOT include any assets in Pending state.
76+
* - MUST NOT show any variations depending on the caller.
77+
* - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.
78+
*/
79+
function claimableDepositRequest(uint256 requestId, address controller)
80+
external
81+
view
82+
returns (uint256 claimableAssets);
83+
84+
/**
85+
* @dev Mints shares Vault shares to receiver by claiming the Request of the controller.
86+
*
87+
* - MUST emit the Deposit event.
88+
* - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator.
89+
*/
90+
function deposit(uint256 assets, address receiver, address controller) external returns (uint256 shares);
91+
92+
/**
93+
* @dev Mints exactly shares Vault shares to receiver by claiming the Request of the controller.
94+
*
95+
* - MUST emit the Deposit event.
96+
* - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator.
97+
*/
98+
function mint(uint256 shares, address receiver, address controller) external returns (uint256 assets);
99+
}
100+
101+
/// @dev Interface of the asynchronous deposit Vault interface of ERC7540, as defined in
102+
/// https://eips.ethereum.org/EIPS/eip-7540
103+
interface IERC7540Redeem is IERC7540Operator {
104+
event RedeemRequest(
105+
address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets
106+
);
107+
108+
/**
109+
* @dev Assumes control of shares from sender into the Vault and submits a Request for asynchronous redeem.
110+
*
111+
* - MUST support a redeem Request flow where the control of shares is taken from sender directly
112+
* where msg.sender has ERC-20 approval over the shares of owner.
113+
* - MUST revert if all of shares cannot be requested for redeem.
114+
*
115+
* @param shares the amount of shares to be redeemed to transfer from owner
116+
* @param controller the controller of the request who will be able to operate the request
117+
* @param owner the source of the shares to be redeemed
118+
*
119+
* NOTE: most implementations will require pre-approval of the Vault with the Vault's share token.
120+
*/
121+
function requestRedeem(uint256 shares, address controller, address owner) external returns (uint256 requestId);
122+
123+
/**
124+
* @dev Returns the amount of requested shares in Pending state.
125+
*
126+
* - MUST NOT include any shares in Claimable state for redeem or withdraw.
127+
* - MUST NOT show any variations depending on the caller.
128+
* - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.
129+
*/
130+
function pendingRedeemRequest(uint256 requestId, address controller)
131+
external
132+
view
133+
returns (uint256 pendingShares);
134+
135+
/**
136+
* @dev Returns the amount of requested shares in Claimable state for the controller to redeem or withdraw.
137+
*
138+
* - MUST NOT include any shares in Pending state for redeem or withdraw.
139+
* - MUST NOT show any variations depending on the caller.
140+
* - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.
141+
*/
142+
function claimableRedeemRequest(uint256 requestId, address controller)
143+
external
144+
view
145+
returns (uint256 claimableShares);
146+
}
147+
148+
/// @dev Interface of the fully asynchronous Vault interface of ERC7540, as defined in
149+
/// https://eips.ethereum.org/EIPS/eip-7540
150+
interface IERC7540 is IERC7540Deposit, IERC7540Redeem, IERC7575 {}

src/interfaces/IERC7575.sol

+241
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity >=0.6.2;
3+
4+
import "./IERC165.sol";
5+
6+
/// @dev Interface of the ERC7575 "Multi-Asset ERC-4626 Vaults", as defined in
7+
/// https://eips.ethereum.org/EIPS/eip-7575
8+
interface IERC7575 is IERC165 {
9+
event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
10+
event Withdraw(
11+
address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares
12+
);
13+
14+
/**
15+
* @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
16+
*
17+
* - MUST be an ERC-20 token contract.
18+
* - MUST NOT revert.
19+
*/
20+
function asset() external view returns (address assetTokenAddress);
21+
22+
/**
23+
* @dev Returns the address of the share token
24+
*
25+
* - MUST be an ERC-20 token contract.
26+
* - MUST NOT revert.
27+
*/
28+
function share() external view returns (address shareTokenAddress);
29+
30+
/**
31+
* @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
32+
* scenario where all the conditions are met.
33+
*
34+
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
35+
* - MUST NOT show any variations depending on the caller.
36+
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
37+
* - MUST NOT revert.
38+
*
39+
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
40+
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
41+
* from.
42+
*/
43+
function convertToShares(uint256 assets) external view returns (uint256 shares);
44+
45+
/**
46+
* @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
47+
* scenario where all the conditions are met.
48+
*
49+
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
50+
* - MUST NOT show any variations depending on the caller.
51+
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
52+
* - MUST NOT revert.
53+
*
54+
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
55+
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
56+
* from.
57+
*/
58+
function convertToAssets(uint256 shares) external view returns (uint256 assets);
59+
60+
/**
61+
* @dev Returns the total amount of the underlying asset that is “managed” by Vault.
62+
*
63+
* - SHOULD include any compounding that occurs from yield.
64+
* - MUST be inclusive of any fees that are charged against assets in the Vault.
65+
* - MUST NOT revert.
66+
*/
67+
function totalAssets() external view returns (uint256 totalManagedAssets);
68+
69+
/**
70+
* @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
71+
* through a deposit call.
72+
*
73+
* - MUST return a limited value if receiver is subject to some deposit limit.
74+
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
75+
* - MUST NOT revert.
76+
*/
77+
function maxDeposit(address receiver) external view returns (uint256 maxAssets);
78+
79+
/**
80+
* @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
81+
* current on-chain conditions.
82+
*
83+
* - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
84+
* call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
85+
* in the same transaction.
86+
* - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
87+
* deposit would be accepted, regardless if the user has enough tokens approved, etc.
88+
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
89+
* - MUST NOT revert.
90+
*
91+
* NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
92+
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
93+
*/
94+
function previewDeposit(uint256 assets) external view returns (uint256 shares);
95+
96+
/**
97+
* @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
98+
*
99+
* - MUST emit the Deposit event.
100+
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
101+
* deposit execution, and are accounted for during deposit.
102+
* - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
103+
* approving enough underlying tokens to the Vault contract, etc).
104+
*
105+
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
106+
*/
107+
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
108+
109+
/**
110+
* @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
111+
* - MUST return a limited value if receiver is subject to some mint limit.
112+
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
113+
* - MUST NOT revert.
114+
*/
115+
function maxMint(address receiver) external view returns (uint256 maxShares);
116+
117+
/**
118+
* @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
119+
* current on-chain conditions.
120+
*
121+
* - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
122+
* in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
123+
* same transaction.
124+
* - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
125+
* would be accepted, regardless if the user has enough tokens approved, etc.
126+
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
127+
* - MUST NOT revert.
128+
*
129+
* NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
130+
* share price or some other type of condition, meaning the depositor will lose assets by minting.
131+
*/
132+
function previewMint(uint256 shares) external view returns (uint256 assets);
133+
134+
/**
135+
* @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
136+
*
137+
* - MUST emit the Deposit event.
138+
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
139+
* execution, and are accounted for during mint.
140+
* - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
141+
* approving enough underlying tokens to the Vault contract, etc).
142+
*
143+
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
144+
*/
145+
function mint(uint256 shares, address receiver) external returns (uint256 assets);
146+
147+
/**
148+
* @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
149+
* Vault, through a withdraw call.
150+
*
151+
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
152+
* - MUST NOT revert.
153+
*/
154+
function maxWithdraw(address owner) external view returns (uint256 maxAssets);
155+
156+
/**
157+
* @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
158+
* given current on-chain conditions.
159+
*
160+
* - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
161+
* call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
162+
* called
163+
* in the same transaction.
164+
* - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
165+
* the withdrawal would be accepted, regardless if the user has enough shares, etc.
166+
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
167+
* - MUST NOT revert.
168+
*
169+
* NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
170+
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
171+
*/
172+
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
173+
174+
/**
175+
* @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
176+
*
177+
* - MUST emit the Withdraw event.
178+
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
179+
* withdraw execution, and are accounted for during withdraw.
180+
* - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
181+
* not having enough shares, etc).
182+
*
183+
* Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
184+
* Those methods should be performed separately.
185+
*/
186+
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
187+
188+
/**
189+
* @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
190+
* through a redeem call.
191+
*
192+
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
193+
* - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
194+
* - MUST NOT revert.
195+
*/
196+
function maxRedeem(address owner) external view returns (uint256 maxShares);
197+
198+
/**
199+
* @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
200+
* given current on-chain conditions.
201+
*
202+
* - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
203+
* in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
204+
* same transaction.
205+
* - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
206+
* redemption would be accepted, regardless if the user has enough shares, etc.
207+
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
208+
* - MUST NOT revert.
209+
*
210+
* NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
211+
* share price or some other type of condition, meaning the depositor will lose assets by redeeming.
212+
*/
213+
function previewRedeem(uint256 shares) external view returns (uint256 assets);
214+
215+
/**
216+
* @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
217+
*
218+
* - MUST emit the Withdraw event.
219+
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
220+
* redeem execution, and are accounted for during redeem.
221+
* - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
222+
* not having enough shares, etc).
223+
*
224+
* NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
225+
* Those methods should be performed separately.
226+
*/
227+
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
228+
}
229+
230+
/// @dev Interface of the ERC20 share token, as defined in
231+
/// https://eips.ethereum.org/EIPS/eip-7575
232+
interface IERC7575Share is IERC165 {
233+
event VaultUpdate(address indexed asset, address vault);
234+
235+
/**
236+
* @dev Returns the address of the Vault for the given asset.
237+
*
238+
* @param asset the ERC-20 token to deposit with into the Vault
239+
*/
240+
function vault(address asset) external view returns (address);
241+
}

0 commit comments

Comments
 (0)