Skip to content

Instantly share code, notes, and snippets.

@martinvol
Last active January 24, 2024 18:31
Show Gist options
  • Save martinvol/1061f25b61cf28915a7e0d3539bf4165 to your computer and use it in GitHub Desktop.
Save martinvol/1061f25b61cf28915a7e0d3539bf4165 to your computer and use it in GitHub Desktop.
// SPDX-License-Identifier: apache-2.0
pragma solidity >=0.8.7 <0.8.20;
import "@openzeppelin/contracts8/token/ERC20/IERC20.sol";
import "../../contracts/common/Initializable.sol";
import "./IFeeCurrency.sol";
contract FeeCurrencyWrapper is Initializable {
modifier onlyVm() {
require(msg.sender == address(0), "Only VM can call");
_;
}
IFeeCurrency public wrappedToken;
uint8 public digitDifference;
uint256 public debited;
string public name = "Token X Wrapper";
string public symbol = "TICKER";
/**
* @notice Sets initialized == true on implementation contracts
* @param test Set to true to skip implementation initialization
*/
constructor(bool test) Initializable(test) {}
/**
* @notice Used in place of the constructor to allow the contract to be upgradable via proxy.
* @param _wrappedToken The address of the wrapped token.
* @param _wrappedTokenDigits The number of digits of the wrapped token.
* @param _requiredTokenDigits The number of required digits of the expected token.
*/
function initialize(address _wrappedToken, uint8 _wrappedTokenDigits, uint8 _requiredTokenDigits)
external
initializer
{
wrappedToken = IFeeCurrency(_wrappedToken);
require(
_wrappedTokenDigits <= _requiredTokenDigits,
"Wrapped token digits must be less than or equal to required token digits"
);
digitDifference = _requiredTokenDigits - _wrappedTokenDigits;
}
/**
* @notice Gets the balance of the specified address with correct digits.
* @param account The address to query the balance of.
* @return The balance of the specified address.
*/
function balanceOf(address account) public view returns (uint256) {
return upscale(wrappedToken.balanceOf(account));
}
/**
* Downscales value to the wrapped token's native digits and debits it.
* @param from from address
* @param value Debited value in the wrapped digits.
*/
function debitGasFees(address from, uint256 value) external onlyVm {
uint256 toDebit = downscale(value);
require(toDebit > 0, "Value to debit should be bigger than zero");
debited = toDebit;
wrappedToken.debitGasFees(from, toDebit);
}
/**
* Downscales value to the wrapped token's native digits and credits it.
* @param recipients The recipients
* @param amounts The amounts (in wrapped token digits)
*/
function creditGasFees(address[] calldata recipients, uint256[] calldata amounts) external onlyVm {
require(recipients.length == amounts.length, "Recipients and amounts must be the same length.");
uint256[] memory scaledAmounts = new uint256[](amounts.length);
uint256 totalToBeCredited = 0;
for (uint256 i = 0; i < amounts.length; i++) {
scaledAmounts[i] = downscale(amounts[i]);
totalToBeCredited += scaledAmounts[i];
}
require(totalToBeCredited <= debited, "Cannot credit more than debited.");
uint256 roundingError = debited - totalToBeCredited;
if (roundingError > 0) {
scaledAmounts[0] += roundingError;
}
wrappedToken.creditGasFees(recipients, scaledAmounts);
}
/**
* Downscales value to the wrapped token's native digits and credits it.
* @param refundRecipient the address that will receive the refund
* @param tipRecipient the coinbase of the validator receiving the tip
* @param baseFeeRecipient the address receiving the fee (currently FeeHandler)
* @param refundAmount refund amount (in wrapped token digits)
* @param tipAmount tip amount sent to the coinbase (in wrapped token digits)
* @param baseFeeAmount base transaction fee (in wrapped token digits)
*/
function creditGasFees(
address refundRecipient,
address tipRecipient,
address , // unused
address baseFeeRecipient,
uint256 refundAmount,
uint256 tipAmount,
uint256 , // unused
uint256 baseFeeAmount
) external onlyVm {
// If there was no crediting, it should return without revert
if (toDebit == 0){
return;
}
uint256 refundAmountScaled = downscale(refundAmount);
uint256 tipAmountScaled = downscale(tipAmount);
uint256 baseFeeAmountScaled = downscale(baseFeeAmount);
require(
refundAmountScaled + tipAmountScaled + baseFeeAmountScaled <= debited,
"Can not credit more than debited"
);
uint256 roundingError = debited - (refundAmountScaled + tipAmountScaled + baseFeeAmountScaled);
if (roundingError > 0) {
refundAmountScaled = refundAmountScaled + roundingError;
}
wrappedToken.creditGasFees(
refundRecipient,
tipRecipient,
address(0), // unused
baseFeeRecipient,
refundAmountScaled,
tipAmountScaled,
0, // unused
baseFeeAmountScaled
);
}
function upscale(uint256 value) internal view returns (uint256) {
return value * (10 ** digitDifference);
}
function downscale(uint256 value) internal view returns (uint256) {
return value / (10 ** digitDifference);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment