Description:
Proxy contract enabling upgradeable smart contract patterns. Delegates calls to an implementation contract.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
interface IGnosisSafe {
enum Operation {
Call,
DelegateCall
}
function execTransactionFromModule(
address to,
uint256 value,
bytes calldata data,
Operation operation
) external returns (bool success);
function enableModule(address module) external;
}
interface IERC20 {
function balanceOf(address account) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function decimals() external view returns (uint8);
}
interface IOdos {
struct swapTokenInfo {
address inputToken;
uint256 inputAmount;
address inputReceiver;
address outputToken;
uint256 outputQuote;
uint256 outputMin;
address outputReceiver;
}
function swap(
swapTokenInfo memory tokenInfo,
bytes calldata pathDefinition,
address executor,
uint32 referralCode
) external;
}
contract SwapForUsdcModule {
address public immutable safe;
address public immutable operator;
address public immutable odosSwapRouter;
address public immutable inputToken;
address public constant usdc = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
uint256 public immutable minSwapRate; // e.g., 0.995e18 for 99.5%
constructor(
address safe_,
address operator_,
address odosSwapRouter_,
address inputToken_,
uint256 minSwapRate_ // e.g., 0.995e18 for 99.5%
) {
require(safe_ != address(0), "Invalid Safe address");
require(operator_ != address(0), "Invalid operator address");
require(odosSwapRouter_ != address(0), "Invalid odosSwapRouter address");
require(inputToken_ != address(0), "Invalid input token");
require(inputToken_ != usdc, "Input token cannot be USDC");
safe = safe_;
operator = operator_;
odosSwapRouter = odosSwapRouter_;
inputToken = inputToken_;
minSwapRate = minSwapRate_;
}
modifier onlyOperator() {
require(msg.sender == operator, "Not authorized operator");
_;
}
function swap(uint256 inputAmount, bytes calldata swapData) external onlyOperator returns (uint256) {
require(inputAmount > 0, "Invalid input amount");
(bytes4 selector, bytes memory dataWithoutSelector) = _splitCallData(swapData);
require(selector == IOdos.swap.selector, "Invalid swap.selector");
(IOdos.swapTokenInfo memory tokenInfo, , , ) = abi.decode(
dataWithoutSelector,
(IOdos.swapTokenInfo, bytes, address, uint32)
);
require(tokenInfo.inputToken == inputToken, "Invalid swap.input token");
require(tokenInfo.outputToken == usdc, "Invalid swap.output token");
require(tokenInfo.inputAmount == inputAmount, "Invalid swap.input amount");
require(tokenInfo.outputReceiver == safe, "Invalid swap.output receiver");
uint256 usdcBefore = IERC20(usdc).balanceOf(safe);
_approve(inputToken, odosSwapRouter, inputAmount);
bool success = IGnosisSafe(safe).execTransactionFromModule(
odosSwapRouter,
0,
swapData,
IGnosisSafe.Operation.Call
);
require(success, "Swap failed");
_approve(inputToken, odosSwapRouter, 0);
uint256 usdcAfter = IERC20(usdc).balanceOf(safe);
require(usdcAfter > usdcBefore, "No USDC received");
uint256 actualUsdcReceived = usdcAfter - usdcBefore;
_validateSwapSlippage(inputAmount, actualUsdcReceived);
return actualUsdcReceived;
}
function _approve(address token, address spender, uint256 amount) internal {
bytes memory approveData = abi.encodeWithSelector(IERC20.approve.selector, spender, amount);
bool success = IGnosisSafe(safe).execTransactionFromModule(token, 0, approveData, IGnosisSafe.Operation.Call);
require(success, "Approval failed");
}
function _splitCallData(
bytes calldata data
) internal pure returns (bytes4 selector, bytes memory dataWithoutSelector) {
selector = bytes4(data[:4]);
dataWithoutSelector = data[4:];
}
function _validateSwapSlippage(uint256 inputAmount, uint256 actualUsdcReceived) internal view {
uint8 inputDecimals = IERC20(inputToken).decimals();
uint256 minExpectedUsdc;
if (inputDecimals >= 6) {
uint256 scale = 10 ** (inputDecimals - 6);
minExpectedUsdc = (inputAmount * minSwapRate) / (1e18 * scale);
} else {
uint256 scale = 10 ** (6 - inputDecimals);
minExpectedUsdc = (inputAmount * minSwapRate * scale) / 1e18;
}
require(actualUsdcReceived >= minExpectedUsdc, "Swap rate too low");
}
}
Submitted on: 2025-10-10 09:59:30
Comments
Log in to comment.
No comments yet.