Last active
March 5, 2024 06:30
-
-
Save sarvagnakadiya/11ac24ee7be59ab0cd89e2acb0207c56 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.20; | |
import "https://github.com/ethereum-attestation-service/eas-contracts/blob/master/contracts/resolver/SchemaResolver.sol"; | |
import "https://github.com/ethereum-attestation-service/eas-contracts/blob/master/contracts/IEAS.sol"; | |
import "@openzeppelin/contracts/access/Ownable.sol"; | |
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; | |
import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | |
/// @title AttesterResolver | |
/// @notice Attestation resolver contract that checks whether the attestation is from a specific attester. | |
contract AttesterResolver is SchemaResolver, Ownable, ReentrancyGuard { | |
/// @notice Default receive function that allows the contract to accept incoming Ether | |
receive() external payable override {} | |
/// @notice Fallback function to handle Ether sent to the contract without a specific function call | |
fallback() external payable {} | |
/// @notice Constructs the contract. | |
/// @param eas The instance of the Ethereum Attestation Service. | |
/// @param _targetAttester The address of the target attester. | |
/// @param _fees The fees required for attestation. | |
/// @param _initialOwner The address of the initial owner. | |
constructor( | |
IEAS eas, | |
address _targetAttester, | |
uint256 _fees, | |
address _initialOwner | |
) SchemaResolver(eas) Ownable(_initialOwner) { | |
targetAttester = _targetAttester; | |
fees = _fees; // 10000000000000 | |
} | |
// -------------------------------------------------------------------------- MODIFIERS | |
modifier nonZero(uint256 _amount) { | |
require(_amount != 0, "Amount must be non-zero"); | |
_; | |
} | |
modifier notZeroAddress(address _address) { | |
require(_address != address(0), "Address cannot be the zero address"); | |
_; | |
} | |
// -------------------------------------------------------------------------- EVENTS | |
/// @dev Emitted when the resolver address is changed. | |
event AttesterChanged(address newResolver); | |
/// @dev Emitted when the fees are changed. | |
event FeesChanged(uint256 newFees); | |
/// @dev Emitted when ETH is staked. | |
event ETHStaked(address staker, uint256 amount); | |
/// @dev Emitted when ETH is unstaked. | |
event ETHUnstaked(address staker, uint256 amount); | |
/// @notice Event emitted when _amount of ETH is withdrawn from the contract. | |
event EtherWithdrawn(address indexed recipient, uint256 amount); | |
/// @dev Emitted when ERC20 tokens are withdrawn. | |
event ERC20Withdrawn(address tokenAddress, address to, uint256 amount); | |
// -------------------------------------------------------------------------- MAPPINGS | |
mapping(address => uint256) public stakedAmounts; | |
// -------------------------------------------------------------------------- STORAGE VARIABLES | |
address public targetAttester; | |
uint256 public fees; | |
uint256 public gasBurnt; | |
/// @notice Stakes ETH for attestation. | |
/// @dev Ether sent along with the call is staked. | |
function stakeETH() external payable nonReentrant nonZero(msg.value) { | |
require(msg.value >= fees, "Atleast stake more than fees required"); | |
stakedAmounts[msg.sender] += msg.value; | |
emit ETHStaked(msg.sender, msg.value); | |
} | |
/// @notice Unstakes previously staked ETH. | |
/// @param _amount The amount of ETH to unstake. | |
function unstakeETH(uint256 _amount) | |
external | |
nonReentrant | |
nonZero(_amount) | |
{ | |
require(_amount <= stakedAmounts[msg.sender], "Invalid amount"); | |
require( | |
address(this).balance >= _amount, | |
"Insufficient funds in the contract balance" | |
); | |
stakedAmounts[msg.sender] -= _amount; | |
(bool sent, ) = msg.sender.call{value: _amount}(""); | |
require(sent, "Failed to send Ether"); | |
emit ETHUnstaked(msg.sender, _amount); | |
} | |
/// @notice Handles attestation callback when a new attestation is received. | |
/// @dev This function is called internally when a new attestation is received. | |
/// @param attestation The attestation data containing information about the attestation. | |
/// @param /*value*/ | |
/// @return A boolean indicating whether the attestation was successfully processed. | |
function onAttest( | |
Attestation calldata attestation, | |
uint256 /*value*/ | |
) internal override returns (bool) { | |
require( | |
stakedAmounts[attestation.recipient] >= fees, | |
"You do not have adequate fees, stakeETH first" | |
); | |
require( | |
attestation.attester == targetAttester, | |
"Only Issuer can issue" | |
); | |
if (stakedAmounts[attestation.recipient] >= fees) { | |
stakedAmounts[attestation.recipient] -= fees; | |
gasBurnt += fees; | |
return true; | |
} else { | |
return false; | |
} | |
} | |
/// @notice Handles revocation callback when an attestation is revoked. | |
/// @dev This function is called internally when an attestation is revoked. | |
/// @param /*attestation*/ | |
/// @param /*value*/ | |
/// @return A boolean indicating whether the revocation was successfully processed. | |
/// (but kept as false to not allow attestation to be revoked) | |
function onRevoke( | |
Attestation calldata, /*attestation*/ | |
uint256 /*value*/ | |
) internal pure override returns (bool) { | |
return false; | |
} | |
// -------------------------------------------------------------------------- ONLY OWNER FUNCTIONS | |
/// @notice Withdraws _amount of ETH from the contract. | |
/// @dev Only callable by the owner. | |
/// @param _address The address to send the ETH to. | |
/// @param _amount of ETH to withdraw. | |
function withdraw(address payable _address, uint256 _amount) | |
public | |
onlyOwner | |
nonReentrant | |
nonZero(_amount) | |
{ | |
require(address(this).balance > 0, "No funds to withdraw"); | |
require( | |
_amount <= gasBurnt, | |
"Withdrawal amount exceeds gas burnt for attestation" | |
); | |
(bool sent, ) = _address.call{value: _amount}(""); | |
require(sent, "Failed to send Ether"); | |
gasBurnt -= _amount; | |
emit EtherWithdrawn(_address, _amount); | |
} | |
/// @notice Withdraws ERC20 tokens from the contract. | |
/// @dev Only callable by the owner. | |
/// @param _tokenAddress The address of the ERC20 token contract. | |
/// @param _to The address to which the ERC20 tokens will be sent. | |
/// @param _amount The amount of ERC20 tokens to withdraw. | |
function withdrawERC20( | |
address _tokenAddress, | |
address _to, | |
uint256 _amount | |
) | |
external | |
onlyOwner | |
nonReentrant | |
nonZero(_amount) | |
notZeroAddress(_tokenAddress) | |
{ | |
IERC20 token = IERC20(_tokenAddress); | |
require( | |
token.balanceOf(address(this)) >= _amount, | |
"Insufficient token balance" | |
); | |
require(token.transfer(_to, _amount), "Transfer failed"); | |
emit ERC20Withdrawn(_tokenAddress, _to, _amount); | |
} | |
/// @notice Changes the target Attester. | |
/// @dev Only callable by the owner. | |
/// @param _newAddress The new resolver address. | |
function changeTargetAttester(address _newAddress) | |
public | |
onlyOwner | |
notZeroAddress(_newAddress) | |
{ | |
targetAttester = _newAddress; | |
emit AttesterChanged(_newAddress); | |
} | |
/// @notice Changes the attestation fees. | |
/// @dev Only callable by the owner. | |
/// @param _newAmount The new attestation fees. | |
function changefees(uint256 _newAmount) public onlyOwner { | |
fees = _newAmount; | |
emit FeesChanged(_newAmount); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment