Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/ALMProxy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ contract ALMProxy is IALMProxy, AccessControl {
/**********************************************************************************************/

function doCall(address target, bytes memory data)
external payable override onlyRole(CONTROLLER) returns (bytes memory result)
external override onlyRole(CONTROLLER) returns (bytes memory result)
{
result = target.functionCallWithValue(data, msg.value);
result = target.functionCall(data);
}

function doCallWithValue(address target, bytes memory data, uint256 value)
Expand All @@ -42,7 +42,7 @@ contract ALMProxy is IALMProxy, AccessControl {
}

function doDelegateCall(address target, bytes memory data)
external payable override onlyRole(CONTROLLER) returns (bytes memory result)
external override onlyRole(CONTROLLER) returns (bytes memory result)
{
result = target.functionDelegateCall(data);
}
Expand Down
28 changes: 14 additions & 14 deletions src/ForeignController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,17 @@ contract ForeignController is AccessControl {
bytes32 public constant FREEZER = keccak256("FREEZER");
bytes32 public constant RELAYER = keccak256("RELAYER");

bytes32 public constant LIMIT_PSM_DEPOSIT = keccak256("LIMIT_PSM_DEPOSIT");
bytes32 public constant LIMIT_PSM_WITHDRAW = keccak256("LIMIT_PSM_WITHDRAW");
bytes32 public constant LIMIT_USDC_TO_CCTP = keccak256("LIMIT_USDC_TO_CCTP");
bytes32 public constant LIMIT_PSM_DEPOSIT = keccak256("LIMIT_PSM_DEPOSIT");
bytes32 public constant LIMIT_PSM_WITHDRAW = keccak256("LIMIT_PSM_WITHDRAW");
bytes32 public constant LIMIT_USDC_TO_CCTP = keccak256("LIMIT_USDC_TO_CCTP");
bytes32 public constant LIMIT_USDC_TO_DOMAIN = keccak256("LIMIT_USDC_TO_DOMAIN");

IALMProxy public immutable proxy;
ICCTPLike public immutable cctp;
IPSM3 public immutable psm;
IRateLimits public immutable rateLimits;

IERC20 public immutable usds;
IERC20 public immutable usdc;
IERC20 public immutable susds;

bool public active;

Expand All @@ -60,22 +59,16 @@ contract ForeignController is AccessControl {
address proxy_,
address rateLimits_,
address psm_,
address usds_,
address usdc_,
address susds_,
address cctp_
) {
_grantRole(DEFAULT_ADMIN_ROLE, admin_);

proxy = IALMProxy(proxy_);
rateLimits = IRateLimits(rateLimits_);
psm = IPSM3(psm_);

usds = IERC20(usds_);
usdc = IERC20(usdc_);
susds = IERC20(susds_);

cctp = ICCTPLike(cctp_);
usdc = IERC20(usdc_);
cctp = ICCTPLike(cctp_);

active = true;
}
Expand Down Expand Up @@ -179,7 +172,14 @@ contract ForeignController is AccessControl {
/**********************************************************************************************/

function transferUSDCToCCTP(uint256 usdcAmount, uint32 destinationDomain)
external onlyRole(RELAYER) isActive rateLimited(LIMIT_USDC_TO_CCTP, usdcAmount)
external
onlyRole(RELAYER)
isActive
rateLimited(LIMIT_USDC_TO_CCTP, usdcAmount)
rateLimited(
RateLimitHelpers.makeDomainKey(LIMIT_USDC_TO_DOMAIN, destinationDomain),
usdcAmount
)
{
bytes32 mintRecipient = mintRecipients[destinationDomain];

Expand Down
32 changes: 24 additions & 8 deletions src/MainnetController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { IALMProxy } from "src/interfaces/IALMProxy.sol";
import { ICCTPLike } from "src/interfaces/CCTPInterfaces.sol";
import { IRateLimits } from "src/interfaces/IRateLimits.sol";

import { RateLimitHelpers } from "src/RateLimitHelpers.sol";

interface IDaiUsdsLike {
function dai() external view returns(address);
function daiToUsds(address usr, uint256 wad) external;
Expand Down Expand Up @@ -53,9 +55,10 @@ contract MainnetController is AccessControl {
bytes32 public constant FREEZER = keccak256("FREEZER");
bytes32 public constant RELAYER = keccak256("RELAYER");

bytes32 public constant LIMIT_USDC_TO_CCTP = keccak256("LIMIT_USDC_TO_CCTP");
bytes32 public constant LIMIT_USDS_MINT = keccak256("LIMIT_USDS_MINT");
bytes32 public constant LIMIT_USDS_TO_USDC = keccak256("LIMIT_USDS_TO_USDC");
bytes32 public constant LIMIT_USDC_TO_CCTP = keccak256("LIMIT_USDC_TO_CCTP");
bytes32 public constant LIMIT_USDC_TO_DOMAIN = keccak256("LIMIT_USDC_TO_DOMAIN");
bytes32 public constant LIMIT_USDS_MINT = keccak256("LIMIT_USDS_MINT");
bytes32 public constant LIMIT_USDS_TO_USDC = keccak256("LIMIT_USDS_TO_USDC");

address public immutable buffer;

Expand All @@ -71,6 +74,8 @@ contract MainnetController is AccessControl {
IERC20 public immutable usdc;
ISUSDSLike public immutable susds;

uint256 public immutable psmTo18ConversionFactor;

bool public active;

mapping(uint32 destinationDomain => bytes32 mintRecipient) public mintRecipients;
Expand Down Expand Up @@ -105,6 +110,8 @@ contract MainnetController is AccessControl {
usdc = IERC20(psm.gem());
usds = IERC20(susds.usds());

psmTo18ConversionFactor = psm.to18ConversionFactor();

active = true;
}

Expand Down Expand Up @@ -240,10 +247,12 @@ contract MainnetController is AccessControl {
/*** Relayer PSM functions ***/
/**********************************************************************************************/

// NOTE: The param `usdcAmount` is denominated in 1e6 precision to match how PSM uses
// USDC precision for both `buyGemNoFee` and `sellGemNoFee`
function swapUSDSToUSDC(uint256 usdcAmount)
external onlyRole(RELAYER) isActive rateLimited(LIMIT_USDS_TO_USDC, usdcAmount)
{
uint256 usdsAmount = usdcAmount * psm.to18ConversionFactor();
uint256 usdsAmount = usdcAmount * psmTo18ConversionFactor;

// Approve USDS to DaiUsds migrator from the proxy (assumes the proxy has enough USDS)
proxy.doCall(
Expand All @@ -257,7 +266,7 @@ contract MainnetController is AccessControl {
abi.encodeCall(daiUsds.usdsToDai, (address(proxy), usdsAmount))
);

// Approve DAI to PSM from the proxy (assumes the proxy has enough DAI)
// Approve DAI to PSM from the proxy because conversion from USDS to DAI was 1:1
proxy.doCall(
address(dai),
abi.encodeCall(dai.approve, (address(psm), usdsAmount))
Expand All @@ -273,15 +282,15 @@ contract MainnetController is AccessControl {
function swapUSDCToUSDS(uint256 usdcAmount)
external onlyRole(RELAYER) isActive cancelRateLimit(LIMIT_USDS_TO_USDC, usdcAmount)
{
uint256 usdsAmount = usdcAmount * psm.to18ConversionFactor();
uint256 usdsAmount = usdcAmount * psmTo18ConversionFactor;

// Approve USDC to PSM from the proxy (assumes the proxy has enough USDC)
proxy.doCall(
address(usdc),
abi.encodeCall(usdc.approve, (address(psm), usdcAmount))
);

// Swap USDC to DAI through the PSM
// Swap USDC to DAI through the PSM (1:1 since sellGemNoFee is used)
proxy.doCall(
address(psm),
abi.encodeCall(psm.sellGemNoFee, (address(proxy), usdcAmount))
Expand All @@ -305,7 +314,14 @@ contract MainnetController is AccessControl {
/**********************************************************************************************/

function transferUSDCToCCTP(uint256 usdcAmount, uint32 destinationDomain)
external onlyRole(RELAYER) isActive rateLimited(LIMIT_USDC_TO_CCTP, usdcAmount)
external
onlyRole(RELAYER)
isActive
rateLimited(LIMIT_USDC_TO_CCTP, usdcAmount)
rateLimited(
RateLimitHelpers.makeDomainKey(LIMIT_USDC_TO_DOMAIN, destinationDomain),
usdcAmount
)
{
bytes32 mintRecipient = mintRecipients[destinationDomain];

Expand Down
4 changes: 4 additions & 0 deletions src/RateLimitHelpers.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,8 @@ library RateLimitHelpers {
return keccak256(abi.encode(key, asset));
}

function makeDomainKey(bytes32 key, uint32 domain) internal pure returns (bytes32) {
return keccak256(abi.encode(key, domain));
}

}
2 changes: 1 addition & 1 deletion src/RateLimits.sol
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ contract RateLimits is IRateLimits, AccessControl {
emit RateLimitDataSet(key, maxAmount, slope, lastAmount, lastUpdated);
}

function setRateLimitData(bytes32 key,uint256 maxAmount,uint256 slope) external override {
function setRateLimitData(bytes32 key, uint256 maxAmount, uint256 slope) external override {
setRateLimitData(key, maxAmount, slope, maxAmount, block.timestamp);
}

Expand Down
8 changes: 2 additions & 6 deletions src/interfaces/IALMProxy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,22 @@ pragma solidity >=0.8.0;
interface IALMProxy {

/**
* @notice Returns the controller identifier
* @dev This function retrieves a constant `bytes32` value that represents the controller.
* @return The `bytes32` identifier of the controller.
*/
function CONTROLLER() external view returns (bytes32);

/**
* @notice Executes a low-level call to a target contract
* @dev Performs a standard call to the specified `target` with the given `data`.
* Reverts if the call fails.
* @param target The address of the target contract to call.
* @param data The calldata that will be sent to the target contract.
* @return result The returned data from the call.
*/
function doCall(address target, bytes calldata data)
external payable returns (bytes memory result);
external returns (bytes memory result);

/**
* @notice Executes a low-level call with value transfer to a target contract
* @dev This function allows for transferring `value` (ether) along with the call to the target contract.
* Reverts if the call fails.
* @param target The address of the target contract to call.
Expand All @@ -34,14 +31,13 @@ interface IALMProxy {
external payable returns (bytes memory result);

/**
* @notice Executes a low-level delegate call to a target contract
* @dev This function performs a delegate call to the specified `target`
* with the given `data`. Reverts if the call fails.
* @param target The address of the target contract to delegate call.
* @param data The calldata that will be sent to the target contract.
* @return result The returned data from the delegate call.
*/
function doDelegateCall(address target, bytes calldata data)
external payable returns (bytes memory result);
external returns (bytes memory result);

}
6 changes: 4 additions & 2 deletions src/interfaces/IRateLimits.sol
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ interface IRateLimits {
) external;

/**
* @dev Sets rate limit data for a specific key.
* @dev Sets rate limit data for a specific key with
* `lastAmount == maxAmount` and `lastUpdated == block.timestamp`.
* @param key The identifier for the rate limit.
* @param maxAmount The maximum allowed amount for the rate limit.
* @param slope The slope value used in the rate limit calculation.
Expand Down Expand Up @@ -149,7 +150,8 @@ interface IRateLimits {
external returns (uint256 newLimit);

/**
* @dev Increases the rate limit for a given key up to the maxAmount.
* @dev Increases the rate limit for a given key up to the maxAmount. Does not revert if
* the new rate limit exceeds the maxAmount.
* @param key The identifier for the rate limit.
* @param amountToIncrease The amount to increase from the current rate limit.
* @return newLimit The updated rate limit after the addition.
Expand Down
2 changes: 0 additions & 2 deletions test/base-fork/ForkTestBase.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,7 @@ contract ForkTestBase is Test {
proxy_ : address(almProxy),
rateLimits_ : address(rateLimits),
psm_ : address(psmBase),
usds_ : address(usdsBase),
usdc_ : USDC_BASE,
susds_ : address(susdsBase),
cctp_ : CCTP_MESSENGER_BASE
});

Expand Down
Loading
Loading