Last active
January 24, 2024 18:31
-
-
Save martinvol/1061f25b61cf28915a7e0d3539bf4165 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: 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