From dc8e38e94c3b83ed38d5ef29eaffd0a6e7074a09 Mon Sep 17 00:00:00 2001 From: John Date: Sun, 14 Jul 2024 15:08:27 +0200 Subject: [PATCH 1/3] chore: Add documentation for the remaining methods --- src/interfaces/ICentrifugeRouter.sol | 129 +++++++++++++++++++++++---- 1 file changed, 114 insertions(+), 15 deletions(-) diff --git a/src/interfaces/ICentrifugeRouter.sol b/src/interfaces/ICentrifugeRouter.sol index 936ee1fa..b063ae1b 100644 --- a/src/interfaces/ICentrifugeRouter.sol +++ b/src/interfaces/ICentrifugeRouter.sol @@ -12,7 +12,8 @@ interface ICentrifugeRouter is IRecoverable { event UnlockDepositRequest(address indexed vault, address indexed controller, address indexed receiver); event ExecuteLockedDepositRequest(address indexed vault, address indexed controller, address sender); - /// @notice TODO + /// @notice Check how much of the `vault`'s asset is locked for the current `controller`. + /// @dev This is a getter method function lockedRequests(address controller, address vault) external view returns (uint256 amount); // --- Deposit --- @@ -29,19 +30,64 @@ interface ICentrifugeRouter is IRecoverable { external payable; - /// @notice TODO + /// @notice Locks `amount` of `vault`'s asset in an escrow before actually sending a deposit LockDepositRequest + /// There are users that would like to interact with the protocol but haven't passed KYC yet. They can + /// lock the funds they would like to deposit beforehand. Once the KYC is passed, anyone can deposit on + /// their behalf + /// by calling `executeLockedDepositRequest`. + /// + /// + /// Example: DAO with onchain governance, that wants to invest their treasury (aka a Prime user) + /// The process that doesn't include calling this method is as follows: + /// + /// 1. The DAO signs the legal agreements for the pool => no onchain action, + /// but only after this the issuer can call update_member to add them as a whitelisted investor + /// 2. Call `requestDeposit` to lock funds + /// 3. After the pool has fulfilled their request, call `deposit` to claim their tranche tokens + /// + /// + /// With the new router function the steps are as follows: + /// + /// 1. DAO signs the legal agreement + calls `lockDepositRequest` in 1 governance proposal + /// + /// 2. Issuer then whitelists them, then calls `executeLockDepositFunds` for them, + /// then fulfills the request, then calls `claimDeposit` for them + /// + /// @dev For initial interaction better use `openLockDepositRequest` which includes some of the message calls + /// that the caller + /// must do execute before calling `lockDepositRequest` + /// + /// @param vault The address of the vault to invest in + /// @param amount Amount to invest + /// @param controller Address of the owner of the position + /// @param owner Where the funds to be deposited will be take from function lockDepositRequest(address vault, uint256 amount, address controller, address owner) external payable; - /// @notice Helper method to lock a deposit request, and enable permissionless claiming of that vault in 1 call + /// @notice Helper method to lock a deposit request, and enable permissionless claiming of that vault in 1 call. + /// @dev It starts interaction with the vault by calling `open`. + /// If `vault`'s underlying asset is a wrapped one, there is a `wrap` message call on the deposited asset + /// beforehand. + /// @param vault Address of the vault + /// @param amount Amount to be deposited function openLockDepositRequest(address vault, uint256 amount) external payable; - /// @notice TODO + /// @notice Unlocks all deposited assets of the current caller for a given vault + /// + /// @param vault Address of the vault for which funds were locked + /// @param receiver Address of the received of the unlocked funds function unlockDepositRequest(address vault, address receiver) external payable; - /// @notice TODO + /// @notice After the controller being KYC approved, anyone can call this method and + /// actually request a deposit with the locked funds on the behalf of the `controller` + /// @param vault The vault for which funds are locked + /// @param controller Owner of the deposit position + /// @param topUpAmount Amount that covers all costs outside EVM function executeLockedDepositRequest(address vault, address controller, uint256 topUpAmount) external payable; - /// @notice TODO + /// @notice Check IERC7540Deposit.mint + /// @param vault Address of the vault + /// @param receiver Check IERC7540Deposit.mint.receiver + /// @param controller Check IERC7540Deposit.mint.owner function claimDeposit(address vault, address receiver, address controller) external payable; // --- Redeem --- @@ -53,7 +99,11 @@ interface ICentrifugeRouter is IRecoverable { /// @param topUpAmount Amount that covers all costs outside EVM function cancelDepositRequest(address vault, uint256 topUpAmount) external payable; - /// @notice TODO + /// @notice Check IERC7540CancelDeposit.claimCancelDepositRequest + /// + /// @param vault Address of the vault + /// @param receiver Check IERC7540CancelDeposit.claimCancelDepositRequest.receiver + /// @param controller Check IERC7540CancelDeposit.claimCancelDepositRequest.controller function claimCancelDepositRequest(address vault, address receiver, address controller) external payable; // --- Redeem --- @@ -70,7 +120,13 @@ interface ICentrifugeRouter is IRecoverable { external payable; - /// @notice TODO + /// @notice Check IERC7575.withdraw + /// @dev If the underlying vault asset is a wrapped one, + /// `CentrifugeRouter.unwrap` is called and the unwrapped + /// asset is sent to the receiver + /// @param vault Address of the vault + /// @param receiver Check IERC7575.withdraw.receiver + /// @param controller Check IERC7575.withdraw.owner function claimRedeem(address vault, address receiver, address controller) external payable; // --- Manage permissionless claiming --- @@ -88,6 +144,11 @@ interface ICentrifugeRouter is IRecoverable { /// @param topUpAmount Amount that covers all costs outside EVM function cancelRedeemRequest(address vault, uint256 topUpAmount) external payable; + /// @notice Check IERC7540CancelRedeem.claimableCancelRedeemRequest + /// + /// @param vault Address of the vault + /// @param receiver Check IERC7540CancelRedeem.claimCancelRedeemRequest.receiver + /// @param controller Check IERC7540CancelRedeem.claimCancelRedeemRequest.controller function claimCancelRedeemRequest(address vault, address receiver, address controller) external payable; // --- Transfer --- @@ -125,7 +186,7 @@ interface ICentrifugeRouter is IRecoverable { ) external payable; /// @notice This is a more friendly version where the recipient is and EVM address - /// @dev the recipient address is padded to 32 bytes internally + /// @dev The recipient address is padded to 32 bytes internally function transferTrancheTokens( address vault, Domain domain, @@ -136,26 +197,64 @@ interface ICentrifugeRouter is IRecoverable { ) external payable; // --- ERC20 permit --- - /// @notice TODO + /// @notice Check IERC20.permit function permit(address asset, address spender, uint256 assets, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external payable; // --- ERC20 wrapping --- - /// @notice TODO + /// @notice There are vault which underlying asset is actuall a wrapped one. + /// + /// @param wrapper The address of the wrapper + /// @param amount Amount to be wrapped + /// @param receiver Receiver of the wrapped tokens + /// @param owner The address from which `amount` is taken from function wrap(address wrapper, uint256 amount, address receiver, address owner) external payable; - /// @notice TODO + /// @notice There are vault which underlying asset is actuall a wrapped one. + /// @dev Currently only wrapped tokens where CentrifugeRouter is the owner can be unwrapped + /// No unwrapping for 3rd parties is supported. + /// @param wrapper The address of the wrapper + /// @param amount Amount to be wrapped + /// @param receiver Receiver of the unwrapped tokens function unwrap(address wrapper, uint256 amount, address receiver) external payable; // --- Batching --- - /// @notice TODO + /// @notice Allows caller to execute multiple ( batched ) messages calls in one transaction. + /// @dev Messages calls that can be executed are only part of the CentrifugeRouter itself. + /// No reentrat execution is allowed. + /// In order to provide the correct value for functions that require top up, + /// the caller must estimate separate, in advance, how much each of the message call will cost. + /// The `msg.value` when calling this method must be the sum of all estimates. + /// + /// Example: An investor would like to make 2 consequetive deposit requests in a single batch. + /// address investor = // Investor's address + /// address vault = // Vault's address + /// uint256 amount1 = 100 * 10 ** 18 + /// uint256 amount2 = 50 * 10 ** 18 + /// uint256 requestDepositCost = 10 gwei + /// + /// address router = // CentrifugeRouter's address + /// + /// bytes[] memory calls = new bytes[](2); + /// calls[0] = abi.encodeWithSelector( + /// router.requestDeposit.selector, vault, amount1, investor, investor, requestDepositCost + /// }; + /// calls[1] = abi.encodeWithSelector( + /// router.requestDeposit.selector, vault, amount2, investor, investor, requestDepositCost + /// }; + /// uint256 msgValue = 2 * requestDepositCost; + + /// router.multical{value: msgValue}(calls); + /// + /// The `msg.value` MUST be at least 20 gwei. `multicall{value: 20 gwei}()` + /// @param data An array of all encoded messages calls and their arguments function multicall(bytes[] memory data) external payable; // --- View Methods --- - /// @notice TODO + /// @notice Check IPoolManager.getVault function getVault(uint64 poolId, bytes16 trancheId, address asset) external view returns (address); - /// @notice TODO + /// @notice Check IGateway.estimate function estimate(bytes calldata payload) external view returns (uint256 amount); } From 206f1ad37e2c81ab7e3920e23eb10455b8deeeeb Mon Sep 17 00:00:00 2001 From: John Date: Sun, 14 Jul 2024 15:24:16 +0200 Subject: [PATCH 2/3] chore: Improve wording and format --- src/interfaces/ICentrifugeRouter.sol | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/interfaces/ICentrifugeRouter.sol b/src/interfaces/ICentrifugeRouter.sol index b063ae1b..46411ed3 100644 --- a/src/interfaces/ICentrifugeRouter.sol +++ b/src/interfaces/ICentrifugeRouter.sol @@ -31,13 +31,12 @@ interface ICentrifugeRouter is IRecoverable { payable; /// @notice Locks `amount` of `vault`'s asset in an escrow before actually sending a deposit LockDepositRequest - /// There are users that would like to interact with the protocol but haven't passed KYC yet. They can - /// lock the funds they would like to deposit beforehand. Once the KYC is passed, anyone can deposit on - /// their behalf - /// by calling `executeLockedDepositRequest`. + /// There are users that would like to interact with the protocol but don't have permissions yet. They can + /// lock the funds they would like to deposit beforehand. Once permissions are granted, anyone can deposit on + /// their behalf by calling `executeLockedDepositRequest`. /// /// - /// Example: DAO with onchain governance, that wants to invest their treasury (aka a Prime user) + /// Example: DAO with onchain governance, that wants to invest their treasury /// The process that doesn't include calling this method is as follows: /// /// 1. The DAO signs the legal agreements for the pool => no onchain action, @@ -48,14 +47,13 @@ interface ICentrifugeRouter is IRecoverable { /// /// With the new router function the steps are as follows: /// - /// 1. DAO signs the legal agreement + calls `lockDepositRequest` in 1 governance proposal + /// 1. DAO signs the legal agreement + calls `openLockDepositRequest` in 1 governance proposal /// - /// 2. Issuer then whitelists them, then calls `executeLockDepositFunds` for them, + /// 2. Issuer then gives them permissions, then calls `executeLockDepositFunds` for them, /// then fulfills the request, then calls `claimDeposit` for them /// /// @dev For initial interaction better use `openLockDepositRequest` which includes some of the message calls - /// that the caller - /// must do execute before calling `lockDepositRequest` + /// that the caller must do execute before calling `lockDepositRequest` /// /// @param vault The address of the vault to invest in /// @param amount Amount to invest @@ -77,7 +75,7 @@ interface ICentrifugeRouter is IRecoverable { /// @param receiver Address of the received of the unlocked funds function unlockDepositRequest(address vault, address receiver) external payable; - /// @notice After the controller being KYC approved, anyone can call this method and + /// @notice After the controller is given permissions, anyone can call this method and /// actually request a deposit with the locked funds on the behalf of the `controller` /// @param vault The vault for which funds are locked /// @param controller Owner of the deposit position @@ -212,8 +210,7 @@ interface ICentrifugeRouter is IRecoverable { function wrap(address wrapper, uint256 amount, address receiver, address owner) external payable; /// @notice There are vault which underlying asset is actuall a wrapped one. - /// @dev Currently only wrapped tokens where CentrifugeRouter is the owner can be unwrapped - /// No unwrapping for 3rd parties is supported. + /// @dev Wrapped tokens need to be held by the CentrifugeRouter to be unwrapped. /// @param wrapper The address of the wrapper /// @param amount Amount to be wrapped /// @param receiver Receiver of the unwrapped tokens @@ -222,12 +219,12 @@ interface ICentrifugeRouter is IRecoverable { // --- Batching --- /// @notice Allows caller to execute multiple ( batched ) messages calls in one transaction. /// @dev Messages calls that can be executed are only part of the CentrifugeRouter itself. - /// No reentrat execution is allowed. + /// No reentrant execution is allowed. /// In order to provide the correct value for functions that require top up, /// the caller must estimate separate, in advance, how much each of the message call will cost. /// The `msg.value` when calling this method must be the sum of all estimates. /// - /// Example: An investor would like to make 2 consequetive deposit requests in a single batch. + /// Example: An investor would like to make 2 consecutive deposit requests in a single batch. /// address investor = // Investor's address /// address vault = // Vault's address /// uint256 amount1 = 100 * 10 ** 18 From 5caf5a80b234f05395b94ca722be5ef7e2a1912b Mon Sep 17 00:00:00 2001 From: John Date: Sun, 14 Jul 2024 15:29:31 +0200 Subject: [PATCH 3/3] chore: Fix formatting issue --- src/interfaces/ICentrifugeRouter.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/interfaces/ICentrifugeRouter.sol b/src/interfaces/ICentrifugeRouter.sol index 46411ed3..054731d8 100644 --- a/src/interfaces/ICentrifugeRouter.sol +++ b/src/interfaces/ICentrifugeRouter.sol @@ -32,10 +32,10 @@ interface ICentrifugeRouter is IRecoverable { /// @notice Locks `amount` of `vault`'s asset in an escrow before actually sending a deposit LockDepositRequest /// There are users that would like to interact with the protocol but don't have permissions yet. They can - /// lock the funds they would like to deposit beforehand. Once permissions are granted, anyone can deposit on + /// lock the funds they would like to deposit beforehand. + /// Once permissions are granted, anyone can deposit on /// their behalf by calling `executeLockedDepositRequest`. /// - /// /// Example: DAO with onchain governance, that wants to invest their treasury /// The process that doesn't include calling this method is as follows: ///