Skip to content

Instantly share code, notes, and snippets.

@sarvagnakadiya
Last active March 5, 2024 06:30
Show Gist options
  • Save sarvagnakadiya/11ac24ee7be59ab0cd89e2acb0207c56 to your computer and use it in GitHub Desktop.
Save sarvagnakadiya/11ac24ee7be59ab0cd89e2acb0207c56 to your computer and use it in GitHub Desktop.
// 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