Skip to content

Instantly share code, notes, and snippets.

@rizzytwizzy
Created December 17, 2023 02:20
Show Gist options
  • Save rizzytwizzy/396d6e210630f73a956ec9f4aa80848d to your computer and use it in GitHub Desktop.
Save rizzytwizzy/396d6e210630f73a956ec9f4aa80848d to your computer and use it in GitHub Desktop.
ERC20Permit token transfer with gas fees in ERC20
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
interface IERC20Permit {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
contract GaslessTokenTransfer {
AggregatorV3Interface internal priceFeed;
uint256 private possibleMaxGasETH = 0.02 ether;
// Initialize the Chainlink price feed in the constructor
constructor(address _priceFeedAddress) {
priceFeed = AggregatorV3Interface(_priceFeedAddress);
}
// Function to get the current ETH to ERC20 rate from the Chainlink Oracle
function getEthToErc20Rate() public view returns (uint256) {
(, int256 price, , , ) = priceFeed.latestRoundData();
require(price > 0, "Invalid price data");
return uint256(price);
}
function send(
address token,
address sender,
address receiver,
uint256 amount,
uint256 fee,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external {
uint256 initialGas = gasleft();
// Get the current rate from the Chainlink Oracle
uint256 ethToErc20Rate = getEthToErc20Rate();
uint256 additionalFee;
additionalFee = fee + possibleMaxGasETH * ethToErc20Rate / 1 ether;
// Permit
IERC20Permit(token).permit(sender, address(this), amount + additionalFee, deadline, v, r, s);
// Send amount to receiver
IERC20Permit(token).transferFrom(sender, receiver, amount);
// Take fee - send fee to msg.sender
IERC20Permit(token).transferFrom(sender, msg.sender, fee);
// Calculate the gas fee in ERC20
uint256 gasUsed = initialGas - gasleft();
uint256 transactionFeeETH = gasUsed * tx.gasprice;
uint256 gasFeeInERC20 = transactionFeeETH * ethToErc20Rate / 1 ether;
// Transfer the total fee to the msg.sender (sponsor)
IERC20Permit(token).transferFrom(sender, msg.sender, gasFeeInERC20);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment