Skip to content

Commit 9d84fe6

Browse files
barrutkolucas-manuelhieronxsupercontractshacker-DOM
authored
Add Centrifuge integration to ForeignController (#8)
* feat: Add and rename audits (#96) * feat: add cantina * fix: change all names * feat: Refactor staging deployments scripting to work for full deployment on Base and Arbitrum (#97) * feat: do initial refactor * feat: initial deploy script working * feat: update with working script * feat: staging deployment working locally * fix: cleanup * feat: update to add full input files * feat: add arbitrum test coverage * feat: add more testing and update arbitrum file * fix: update to remove deps from output, updagte lib * feat: add live staging contracts * fix: update sub and blocks * feat: add release jsons * fix: add mainnet staing * fix: arb filename * feat: Add audits (#26) * feat: add audits * fix: update file * fix: update staging test * fix: Update Centrifuge tests (#25) * Adapt to latest vault address * Update block number * Remove unused setUp --------- Co-authored-by: Lucas Manuel <lucasmanuel.tech@gmail.com> * feat: Refactor to use internal functions and modifiers (#24) * feat: refactor to use internal functions and modifiers * fix: use view * fix: move helpers * fix: rm todo * feat: Add DaiUsds swaps (SC-940) (#22) * feat: add dai usds swaps * fix: rm rate limits * feat: Add Curve support, remove Morpho allocator logic (SC-938) (#23) * feat: add basic curve deposit/withdraw * feat: Refactor to use internal functions and modifiers (#24) * feat: refactor to use internal functions and modifiers * fix: use view * fix: move helpers * fix: rm todo * feat: Add DaiUsds swaps (SC-940) (#22) * feat: add dai usds swaps * fix: rm rate limits * test: add testing for failure modes * feat: tests all passing * fix: update broken staging test * test: add invalid order coverage, cleanup * fix: rm morpho functionality * fix: rm morpho * feat: tests passing * fix: rm console * feat: refactor to use rlusd pool * feat: refactor to use new slippages, remove tokens params * feat: add remove liquidity working * feat: tests passing * fix: rm console * fix: update remaining fixes * fix: reorder some code, add zero slippage test coverage * fix: update test names * feat: add simplified calculation * fix: rm unused function * fix: formatting * fix: update slippage * fix: comment * fix: cache param * fix: update spacing * feat: Update to round up for rate limits and minimums (SC-955) (#31) * feat: Use `get_virtual_price` (SC-959) (#29) * feat: add comments * feat: add virtual price * feat: add stress test * feat: add starting fuzz tests * fix: delete fuzz test * fix: add comments * fix: update comments * fix: Add line about transferAsset (#33) * feat: Add swap rate limiting in `addLiquidityCurve` (SC-952) (#30) * feat: add initial structure * feat: add rate limit for swap * feat: tests passing * fix: ordering and test * fix: update optimizer runs * fix: update comment * feat: Add index input validation (SC-960) (#34) * feat: add index input validation * feat: update to add testing * ifx: update to use n coins * fix: Update swap rate limit calculation (#94) * feat: Add audits (#26) * feat: add audits * fix: update file * fix: update staging test * fix: Update Centrifuge tests (#25) * Adapt to latest vault address * Update block number * Remove unused setUp --------- Co-authored-by: Lucas Manuel <lucasmanuel.tech@gmail.com> * feat: Refactor to use internal functions and modifiers (#24) * feat: refactor to use internal functions and modifiers * fix: use view * fix: move helpers * fix: rm todo * feat: Add DaiUsds swaps (SC-940) (#22) * feat: add dai usds swaps * fix: rm rate limits * feat: Add Curve support, remove Morpho allocator logic (SC-938) (#23) * feat: add basic curve deposit/withdraw * feat: Refactor to use internal functions and modifiers (#24) * feat: refactor to use internal functions and modifiers * fix: use view * fix: move helpers * fix: rm todo * feat: Add DaiUsds swaps (SC-940) (#22) * feat: add dai usds swaps * fix: rm rate limits * test: add testing for failure modes * feat: tests all passing * fix: update broken staging test * test: add invalid order coverage, cleanup * fix: rm morpho functionality * fix: rm morpho * feat: tests passing * fix: rm console * feat: refactor to use rlusd pool * feat: refactor to use new slippages, remove tokens params * feat: add remove liquidity working * feat: tests passing * fix: rm console * fix: update remaining fixes * fix: reorder some code, add zero slippage test coverage * fix: update test names * feat: add simplified calculation * fix: rm unused function * fix: formatting * fix: update slippage * fix: comment * fix: cache param * fix: update spacing * feat: Update to round up for rate limits and minimums (SC-955) (#31) * feat: Use `get_virtual_price` (SC-959) (#29) * feat: add comments * feat: add virtual price * feat: add stress test * feat: add starting fuzz tests * fix: delete fuzz test * fix: add comments * fix: update comments * fix: Add line about transferAsset (#33) * feat: Add swap rate limiting in `addLiquidityCurve` (SC-952) (#30) * feat: add initial structure * feat: add rate limit for swap * feat: tests passing * fix: ordering and test * fix: update optimizer runs * fix: update comment * feat: Add index input validation (SC-960) (#34) * feat: add index input validation * feat: update to add testing * ifx: update to use n coins * feat: initial logic working * feat: update to add testing * fix: cleanup --------- Co-authored-by: Jeroen <1748621+hieronx@users.noreply.github.com> * feat: Update staging PSM addresses, fix morpho usdc staging address (#98) * feat: update addresses * fix: logs * fix: rm unconfigured psms * feat: Add v1.4.0 audits (#99) * fix: rm redundant audits, add chainsecurity * feat: add cantina audit * feat: Deploy v1.4.0 staging (#103) * feat: deploy v1.4.0 staging * fix: newlines * fix: update testing * feat: Update testing to use USDT pools, focus on USDT approval functionality (#101) * fix: rm redundant audits, add chainsecurity * feat: add cantina audit * fix: refactor tests * test: add allowance assertions * test: add coverage for swap rate limits * fix: update to use higher swaps * refactor: Remove `setRateLimitData` from RateLimitHelpers (SC-962) (sparkdotfi#108) * refactor: Split out Curve and PSM logic into libraries (SC-971) (#104) * refactor: Init library to take multiple relayers (SC 961) (sparkdotfi#109) * refactor: Spin out logic of CCTP into a library (SC-970) (#105) * feat: Adds forceApprove logic (SC-978) (sparkdotfi#110) * feat: Deploy Unichain (SC-992) * cleanup: Remove BUIDL redeem facility (SC 994) * chore: Change `CENTRIFUGE_REQUEST_ID` var to constant (sparkdotfi#118) * chore: change var to constant * use internal * feat: Add LayerZero integration (SC-982) (sparkdotfi#119) * feat: layerzero integration * fix review * change note * fix followup review * add success tests * fix review * add gas cost test * chore: linting * add tests for setter functions * chore: linting * chore: linting * fix: Update README (sparkdotfi#121) * fix: Order params consistently (sparkdotfi#122) * fix: interface (sparkdotfi#124) * fix: Use more robust `_approve` (SC-1036) (sparkdotfi#126) * feat: add requires * fix: add full test coverage * feat: Gas optimize `approve` (SC-1037) (sparkdotfi#128) * feat: add requires * fix: add full test coverage * feat: reuse `approveData` in (Mainnet|Foreign)Controller._approve. * fix: typo (causing compilation error). --------- Co-authored-by: Lucas Manuel <lucasmanuel.tech@gmail.com> * Minor issues (#14 from audit) (SC-1032) (sparkdotfi#130) * chore: rm `IMetaMorpho` imports in MainnetController.sol. * chore: rm `AccessControl` import in CurveLib.sol. * chore: rm `RateLimitHelpers` import in PSMLib.sol. * fix: `multiplied` spelling. * chore: change IERC(20|4626) to openzeppelin. * chore: rm import from ForeignController.sol. * fix: alphabetical ordering. * fix: re-order imports. --------- Co-authored-by: Lucas Manuel <lucasmanuel.tech@gmail.com> * fix: Make `transferTokenLayerZero` payable (SC-1039) (sparkdotfi#127) * fix: make transfer function payable * fix: review --------- Co-authored-by: Lucas Manuel <lucasmanuel.tech@gmail.com> * feat: Set LayerZero recipients in deploy (SC-1038) (sparkdotfi#129) * feat: setLayerzeroRecipients in deploy * fix: review * fix: build * fix: align --------- Co-authored-by: Lucas Manuel <lucasmanuel.tech@gmail.com> * fix: Add missing approval (SC-1035) (sparkdotfi#123) * fix: add missing approval * add comments * fix: comments * fix: comments * fix: comment --------- Co-authored-by: Lucas Manuel <lucasmanuel.tech@gmail.com> * fix: Reuse approveData in CurveLib (sparkdotfi#131) * update * remove script * update * chore: remove irrelevant deployments * test: skip arbitrum deployment tests * adjust deployment inputs * reorg * change staging psm address * feat: add Centrifuge functions to ForeignController * test: add ForeignController tests on fake Avalanche (ETH Mainnet) * refactor: add minor fixes * remove transfer --------- Co-authored-by: Lucas Manuel <lucasmanuel.tech@gmail.com> Co-authored-by: Jeroen <1748621+hieronx@users.noreply.github.com> Co-authored-by: supercontracts <bonjour.tabish@gmail.com> Co-authored-by: Dom <18601956+hacker-DOM@users.noreply.github.com>
1 parent c119510 commit 9d84fe6

File tree

3 files changed

+1218
-1
lines changed

3 files changed

+1218
-1
lines changed

src/ForeignController.sol

Lines changed: 148 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ pragma solidity ^0.8.21;
44
import { IAToken } from "aave-v3-origin/src/core/contracts/interfaces/IAToken.sol";
55
import { IPool as IAavePool } from "aave-v3-origin/src/core/contracts/interfaces/IPool.sol";
66

7+
// This interface has been reviewed, and is compliant with the specs: https://eips.ethereum.org/EIPS/eip-7540
8+
import { IERC7540 } from "forge-std/interfaces/IERC7540.sol";
9+
710
import { IMetaMorpho, Id, MarketAllocation } from "metamorpho/interfaces/IMetaMorpho.sol";
811

912
import { AccessControl } from "openzeppelin-contracts/contracts/access/AccessControl.sol";
@@ -27,6 +30,15 @@ interface IATokenWithPool is IAToken {
2730
function POOL() external view returns(address);
2831
}
2932

33+
interface ICentrifugeToken is IERC7540 {
34+
function cancelDepositRequest(uint256 requestId, address controller) external;
35+
function cancelRedeemRequest(uint256 requestId, address controller) external;
36+
function claimCancelDepositRequest(uint256 requestId, address receiver, address controller)
37+
external returns (uint256 assets);
38+
function claimCancelRedeemRequest(uint256 requestId, address receiver, address controller)
39+
external returns (uint256 shares);
40+
}
41+
3042
contract ForeignController is AccessControl {
3143

3244
using OptionsBuilder for bytes;
@@ -58,14 +70,19 @@ contract ForeignController is AccessControl {
5870

5971
bytes32 public constant LIMIT_4626_DEPOSIT = keccak256("LIMIT_4626_DEPOSIT");
6072
bytes32 public constant LIMIT_4626_WITHDRAW = keccak256("LIMIT_4626_WITHDRAW");
73+
bytes32 public constant LIMIT_7540_DEPOSIT = keccak256("LIMIT_7540_DEPOSIT");
74+
bytes32 public constant LIMIT_7540_REDEEM = keccak256("LIMIT_7540_REDEEM");
6175
bytes32 public constant LIMIT_AAVE_DEPOSIT = keccak256("LIMIT_AAVE_DEPOSIT");
6276
bytes32 public constant LIMIT_AAVE_WITHDRAW = keccak256("LIMIT_AAVE_WITHDRAW");
77+
bytes32 public constant LIMIT_ASSET_TRANSFER = keccak256("LIMIT_ASSET_TRANSFER");
6378
bytes32 public constant LIMIT_LAYERZERO_TRANSFER = keccak256("LIMIT_LAYERZERO_TRANSFER");
6479
bytes32 public constant LIMIT_PSM_DEPOSIT = keccak256("LIMIT_PSM_DEPOSIT");
6580
bytes32 public constant LIMIT_PSM_WITHDRAW = keccak256("LIMIT_PSM_WITHDRAW");
6681
bytes32 public constant LIMIT_USDC_TO_CCTP = keccak256("LIMIT_USDC_TO_CCTP");
6782
bytes32 public constant LIMIT_USDC_TO_DOMAIN = keccak256("LIMIT_USDC_TO_DOMAIN");
6883

84+
uint256 internal constant CENTRIFUGE_REQUEST_ID = 0;
85+
6986
IALMProxy public immutable proxy;
7087
ICCTPLike public immutable cctp;
7188
IPSM3 public immutable psm;
@@ -250,7 +267,7 @@ contract ForeignController is AccessControl {
250267
);
251268

252269
// NOTE: Full integration testing of this logic is not possible without OFTs with
253-
// approvalRequired == true. Add integration testing for this case before
270+
// approvalRequired == true. Add integration testing for this case before
254271
// using in production.
255272
if (ILayerZero(oftAddress).approvalRequired()) {
256273
_approve(ILayerZero(oftAddress).token(), oftAddress, amount);
@@ -346,6 +363,136 @@ contract ForeignController is AccessControl {
346363
);
347364
}
348365

366+
/**********************************************************************************************/
367+
/*** Relayer ERC7540 functions ***/
368+
/**********************************************************************************************/
369+
370+
function requestDepositERC7540(address token, uint256 amount)
371+
external
372+
onlyRole(RELAYER)
373+
rateLimitedAsset(LIMIT_7540_DEPOSIT, token, amount)
374+
{
375+
// Note that whitelist is done by rate limits
376+
IERC20 asset = IERC20(IERC7540(token).asset());
377+
378+
// Approve asset to vault from the proxy (assumes the proxy has enough of the asset).
379+
_approve(address(asset), token, amount);
380+
381+
// Submit deposit request by transferring assets
382+
proxy.doCall(
383+
token,
384+
abi.encodeCall(IERC7540(token).requestDeposit, (amount, address(proxy), address(proxy)))
385+
);
386+
}
387+
388+
function claimDepositERC7540(address token)
389+
external
390+
onlyRole(RELAYER)
391+
rateLimitExists(RateLimitHelpers.makeAssetKey(LIMIT_7540_DEPOSIT, token))
392+
{
393+
uint256 shares = IERC7540(token).maxMint(address(proxy));
394+
395+
// Claim shares from the vault to the proxy
396+
proxy.doCall(
397+
token,
398+
abi.encodeCall(IERC4626(token).mint, (shares, address(proxy)))
399+
);
400+
}
401+
402+
function requestRedeemERC7540(address token, uint256 shares)
403+
external
404+
onlyRole(RELAYER)
405+
rateLimitedAsset(LIMIT_7540_REDEEM, token, IERC7540(token).convertToAssets(shares))
406+
{
407+
// Submit redeem request by transferring shares
408+
proxy.doCall(
409+
token,
410+
abi.encodeCall(IERC7540(token).requestRedeem, (shares, address(proxy), address(proxy)))
411+
);
412+
}
413+
414+
function claimRedeemERC7540(address token)
415+
external
416+
onlyRole(RELAYER)
417+
rateLimitExists(RateLimitHelpers.makeAssetKey(LIMIT_7540_REDEEM, token))
418+
{
419+
uint256 assets = IERC7540(token).maxWithdraw(address(proxy));
420+
421+
// Claim assets from the vault to the proxy
422+
proxy.doCall(
423+
token,
424+
abi.encodeCall(IERC7540(token).withdraw, (assets, address(proxy), address(proxy)))
425+
);
426+
}
427+
428+
/**********************************************************************************************/
429+
/*** Relayer Centrifuge functions ***/
430+
/**********************************************************************************************/
431+
432+
// NOTE: These cancelation methods are compatible with ERC-7887
433+
434+
function cancelCentrifugeDepositRequest(address token)
435+
external
436+
onlyRole(RELAYER)
437+
rateLimitExists(RateLimitHelpers.makeAssetKey(LIMIT_7540_DEPOSIT, token))
438+
{
439+
440+
// NOTE: While the cancelation is pending, no new deposit request can be submitted
441+
proxy.doCall(
442+
token,
443+
abi.encodeCall(
444+
ICentrifugeToken(token).cancelDepositRequest,
445+
(CENTRIFUGE_REQUEST_ID, address(proxy))
446+
)
447+
);
448+
}
449+
450+
function claimCentrifugeCancelDepositRequest(address token)
451+
external
452+
onlyRole(RELAYER)
453+
rateLimitExists(RateLimitHelpers.makeAssetKey(LIMIT_7540_DEPOSIT, token))
454+
{
455+
456+
proxy.doCall(
457+
token,
458+
abi.encodeCall(
459+
ICentrifugeToken(token).claimCancelDepositRequest,
460+
(CENTRIFUGE_REQUEST_ID, address(proxy), address(proxy))
461+
)
462+
);
463+
}
464+
465+
function cancelCentrifugeRedeemRequest(address token)
466+
external
467+
onlyRole(RELAYER)
468+
rateLimitExists(RateLimitHelpers.makeAssetKey(LIMIT_7540_REDEEM, token))
469+
{
470+
471+
// NOTE: While the cancelation is pending, no new redeem request can be submitted
472+
proxy.doCall(
473+
token,
474+
abi.encodeCall(
475+
ICentrifugeToken(token).cancelRedeemRequest,
476+
(CENTRIFUGE_REQUEST_ID, address(proxy))
477+
)
478+
);
479+
}
480+
481+
function claimCentrifugeCancelRedeemRequest(address token)
482+
external
483+
onlyRole(RELAYER)
484+
rateLimitExists(RateLimitHelpers.makeAssetKey(LIMIT_7540_REDEEM, token))
485+
{
486+
487+
proxy.doCall(
488+
token,
489+
abi.encodeCall(
490+
ICentrifugeToken(token).claimCancelRedeemRequest,
491+
(CENTRIFUGE_REQUEST_ID, address(proxy), address(proxy))
492+
)
493+
);
494+
}
495+
349496
/**********************************************************************************************/
350497
/*** Relayer Aave functions ***/
351498
/**********************************************************************************************/

0 commit comments

Comments
 (0)