Description:
ERC20 token contract with Factory capabilities. Standard implementation for fungible tokens on Ethereum.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"src/adapters/ethereum/LidoAdapter.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.19;
import "../BaseAdapter.sol";
interface ILido {
function submit(address _referral) external payable returns (uint256);
}
/// @title LidoAdapter
/// @notice Adapter for depositing ETH to Lido to get stETH
contract LidoAdapter is BaseAdapter {
address public immutable LIDO;
/// @notice Initialize the adapter with Lido contract address
/// @param _lidoAddress Address of the Lido stETH contract
constructor(address _lidoAddress) {
require(_lidoAddress != address(0), "Invalid Lido address");
LIDO = _lidoAddress;
}
event LidoDeposit(address indexed executor, address indexed recipient, uint256 ethAmount, uint256 stEthAmount);
/// @notice Deposit ETH to Lido and get stETH for a recipient
/// @param recipient Address that should receive resulting stETH
/// @return stEthAmount The amount of stETH received
function depositETH(address recipient) external payable validAmount(msg.value) returns (uint256 stEthAmount) {
address targetRecipient = _getTargetRecipient(recipient);
// Deposit ETH to Lido to get stETH
stEthAmount = ILido(LIDO).submit{value: msg.value}(address(0));
emit LidoDeposit(msg.sender, targetRecipient, msg.value, stEthAmount);
// Transfer stETH to recipient
_safeTransfer(LIDO, targetRecipient, stEthAmount);
return stEthAmount;
}
}
"
},
"src/adapters/BaseAdapter.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.19;
import "../interfaces/IERC20.sol";
/// @title BaseAdapter
/// @notice Base contract for all protocol adapters with common functionality
abstract contract BaseAdapter {
/// @notice Validates that an amount is greater than zero
/// @param amount The amount to validate
modifier validAmount(uint256 amount) {
require(amount > 0, "Invalid amount: must be greater than zero");
_;
}
/// @notice Validates that an address is not zero
/// @param addr The address to validate
modifier validAddress(address addr) {
require(addr != address(0), "Invalid address: cannot be zero");
_;
}
/// @notice Returns the target recipient, defaulting to msg.sender if recipient is zero
/// @param recipient The intended recipient address
/// @return The actual recipient address to use
function _getTargetRecipient(address recipient) internal view returns (address) {
return recipient == address(0) ? msg.sender : recipient;
}
/// @notice Returns the actual user address (supports UniExecutor pattern)
/// @return The user address (tx.origin for UniExecutor calls, msg.sender otherwise)
function _getUser() internal view returns (address) {
// Use tx.origin when called through UniExecutor (msg.sender would be the executor)
// This assumes UniExecutor is a trusted intermediary
return tx.origin != msg.sender ? tx.origin : msg.sender;
}
/// @notice Safely transfers tokens from the adapter to a recipient
/// @param token The token address
/// @param recipient The recipient address
/// @param amount The amount to transfer
function _safeTransfer(address token, address recipient, uint256 amount) internal {
require(amount > 0, "Transfer amount must be greater than zero");
require(recipient != address(0), "Cannot transfer to zero address");
bool success = IERC20(token).transfer(recipient, amount);
require(success, "Token transfer failed");
}
/// @notice Safely transfers tokens from one address to another
/// @param token The token address
/// @param from The sender address
/// @param to The recipient address
/// @param amount The amount to transfer
function _safeTransferFrom(address token, address from, address to, uint256 amount) internal {
require(amount > 0, "Transfer amount must be greater than zero");
require(from != address(0), "Cannot transfer from zero address");
require(to != address(0), "Cannot transfer to zero address");
bool success = IERC20(token).transferFrom(from, to, amount);
require(success, "Token transferFrom failed");
}
/// @notice Safely approves token spending
/// @param token The token address
/// @param spender The spender address
/// @param amount The amount to approve
function _safeApprove(address token, address spender, uint256 amount) internal {
require(spender != address(0), "Cannot approve zero address");
// Reset approval to 0 first to handle tokens that require it
if (IERC20(token).allowance(address(this), spender) > 0) {
bool resetSuccess = IERC20(token).approve(spender, 0);
require(resetSuccess, "Failed to reset approval");
}
bool approveSuccess = IERC20(token).approve(spender, amount);
require(approveSuccess, "Token approval failed");
}
/// @notice Gets the balance of a token for an address
/// @param token The token address
/// @param account The account address
/// @return The token balance
function _getBalance(address token, address account) internal view returns (uint256) {
return IERC20(token).balanceOf(account);
}
/// @notice Handles token balance management for adapters
/// @param token The token address
/// @param requiredAmount The required amount
/// @param user The user address to pull tokens from if needed
/// @return actualAmount The actual amount available after transfers
function _ensureBalance(address token, uint256 requiredAmount, address user)
internal
returns (uint256 actualAmount)
{
uint256 adapterBalance = _getBalance(token, address(this));
if (adapterBalance >= requiredAmount) {
return requiredAmount;
}
uint256 shortfall = requiredAmount - adapterBalance;
uint256 userBalance = _getBalance(token, user);
if (userBalance < shortfall) {
// Use all available tokens (adapter + user)
if (userBalance > 0) {
_safeTransferFrom(token, user, address(this), userBalance);
}
return adapterBalance + userBalance;
} else {
// Pull exact shortfall from user
_safeTransferFrom(token, user, address(this), shortfall);
return requiredAmount;
}
}
}
"
},
"src/interfaces/IERC20.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.19;
interface IERC20 {
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
}
"
}
},
"settings": {
"remappings": [
"forge-std/=lib/forge-std/src/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "prague",
"viaIR": true
}
}}
Submitted on: 2025-10-26 09:47:17
Comments
Log in to comment.
No comments yet.