Skip to content
This repository has been archived by the owner on Dec 3, 2024. It is now read-only.

Commit

Permalink
namespace storage for remotes
Browse files Browse the repository at this point in the history
  • Loading branch information
Matthew Lam committed Jul 10, 2024
1 parent 82d5d12 commit 7fb63df
Show file tree
Hide file tree
Showing 6 changed files with 293 additions and 151 deletions.
38 changes: 35 additions & 3 deletions contracts/src/TokenRemote/ERC20TokenRemote.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,24 @@ import {CallUtils} from "../utils/CallUtils.sol";
* @custom:security-contact https://github.com/ava-labs/avalanche-interchain-token-transfer/blob/main/SECURITY.md
*/
contract ERC20TokenRemote is IERC20TokenTransferrer, ERC20Upgradeable, TokenRemote {
uint8 private _decimals;
/// @custom:storage-location erc7201:avalanche-ictt.storage.ERC20TokenRemote
struct ERC20TokenRemoteStorage {
uint8 _decimals;
}

// keccak256(abi.encode(uint256(keccak256("avalanche-ictt.storage.ERC20TokenRemote")) - 1)) & ~bytes32(uint256(0xff));
bytes32 private constant ERC20TokenRemoteStorageLocation =
0x69a5f7616543528c4fbe43f410b1034bd6da4ba06c25bedf04617268014cf500;

function _getERC20TokenRemoteStorage()
private
pure
returns (ERC20TokenRemoteStorage storage $)
{
assembly {
$.slot := ERC20TokenRemoteStorageLocation
}
}

/**
* @notice Initializes this token TokenRemote instance to receive tokens from the specified TokenHome instance,
Expand All @@ -43,9 +60,23 @@ contract ERC20TokenRemote is IERC20TokenTransferrer, ERC20Upgradeable, TokenRemo
string memory tokenSymbol,
uint8 tokenDecimals_
) public initializer {
__ERC20TokenRemote_init(settings, tokenName, tokenSymbol, tokenDecimals_);
}

function __ERC20TokenRemote_init(
TokenRemoteSettings memory settings,
string memory tokenName,
string memory tokenSymbol,
uint8 tokenDecimals_
) internal onlyInitializing {
__ERC20_init(tokenName, tokenSymbol);
__TokenRemote_init(settings, 0, tokenDecimals_);
_decimals = tokenDecimals;
__ERC20TokenRemote_init_unchained(tokenDecimals_);
}

function __ERC20TokenRemote_init_unchained(uint8 tokenDecimals_) internal {
ERC20TokenRemoteStorage storage $ = _getERC20TokenRemoteStorage();
$._decimals = tokenDecimals_;
}

/**
Expand All @@ -70,7 +101,8 @@ contract ERC20TokenRemote is IERC20TokenTransferrer, ERC20Upgradeable, TokenRemo
* @dev See {ERC20-decimals}
*/
function decimals() public view override returns (uint8) {
return _decimals;
ERC20TokenRemoteStorage storage $ = _getERC20TokenRemoteStorage();
return $._decimals;
}

/**
Expand Down
102 changes: 74 additions & 28 deletions contracts/src/TokenRemote/NativeTokenRemote.sol
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,37 @@ contract NativeTokenRemote is
{
using Address for address payable;

/// @custom:storage-location erc7201:avalanche-ictt.storage.NativeTokenRemote
struct NativeTokenRemoteStorage {
/**
* @notice Percentage of burned transaction fees that will be rewarded to a relayer delivering
* the message created by calling calling reportBurnedTxFees().
*/
uint256 _burnedFeesReportingRewardPercentage;
/**
* @notice Total number of tokens minted by this contract through the native minter precompile.
*/
uint256 _totalMinted;
/**
* @notice The balance of BURNED_TX_FEES_ADDRESS the last time burned fees were reported to the TokenHome instance.
*/
uint256 _lastestBurnedFeesReported;
}

// keccak256(abi.encode(uint256(keccak256("avalanche-ictt.storage.NativeTokenRemote")) - 1)) & ~bytes32(uint256(0xff));
bytes32 private constant NativeTokenRemoteStorageLocation =
0x914a9547f6c3ddce1d5efbd9e687708f0d1d408ce129e8e1a88bce4f40e29500;

function _getNativeTokenRemoteStorage()
private
pure
returns (NativeTokenRemoteStorage storage $)
{
assembly {
$.slot := NativeTokenRemoteStorageLocation
}
}

/**
* @notice The address where the burned transaction fees are credited.
*
Expand Down Expand Up @@ -77,28 +108,12 @@ contract NativeTokenRemote is
INativeMinter public constant NATIVE_MINTER =
INativeMinter(0x0200000000000000000000000000000000000001);

/**
* @notice Percentage of burned transaction fees that will be rewarded to a relayer delivering
* the message created by calling calling reportBurnedTxFees().
*/
uint256 public burnedFeesReportingRewardPercentage;

/**
* @notice Total number of tokens minted by this contract through the native minter precompile.
*/
uint256 public totalMinted;

/**
* @notice The balance of BURNED_TX_FEES_ADDRESS the last time burned fees were reported to the TokenHome instance.
*/
uint256 public lastestBurnedFeesReported;

/**
* @dev When modifier is used, the function can only be called after the contract is fully collelateralized,
* accounting for the initialReserveImbalance.
*/
modifier onlyWhenCollateralized() {
require(isCollateralized, "NativeTokenRemote: contract undercollateralized");
require(getIsCollateralized(), "NativeTokenRemote: contract undercollateralized");
_;
}

Expand All @@ -117,11 +132,33 @@ contract NativeTokenRemote is
uint256 initialReserveImbalance,
uint256 burnedFeesReportingRewardPercentage_
) public initializer {
__NativeTokenRemote_init(
settings,
nativeAssetSymbol,
initialReserveImbalance,
burnedFeesReportingRewardPercentage_
);
}

function __NativeTokenRemote_init(
TokenRemoteSettings memory settings,
string memory nativeAssetSymbol,
uint256 initialReserveImbalance,
uint256 burnedFeesReportingRewardPercentage_
) internal onlyInitializing {
require(initialReserveImbalance != 0, "NativeTokenRemote: zero initial reserve imbalance");
__ERC20_init(nativeAssetSymbol, nativeAssetSymbol);
__TokenRemote_init(settings, initialReserveImbalance, 18);
require(initialReserveImbalance != 0, "NativeTokenRemote: zero initial reserve imbalance");
__NativeTokenRemote_init_unchained(burnedFeesReportingRewardPercentage_);
}

function __NativeTokenRemote_init_unchained(uint256 burnedFeesReportingRewardPercentage_)
internal
onlyInitializing
{
NativeTokenRemoteStorage storage $ = _getNativeTokenRemoteStorage();
require(burnedFeesReportingRewardPercentage_ < 100, "NativeTokenRemote: invalid percentage");
burnedFeesReportingRewardPercentage = burnedFeesReportingRewardPercentage_;
$._burnedFeesReportingRewardPercentage = burnedFeesReportingRewardPercentage_;
}

/**
Expand Down Expand Up @@ -158,16 +195,17 @@ contract NativeTokenRemote is
* @dev See {INativeTokenRemote-reportBurnedTxFees}.
*/
function reportBurnedTxFees(uint256 requiredGasLimit) external sendNonReentrant {
NativeTokenRemoteStorage storage $ = _getNativeTokenRemoteStorage();
uint256 burnAddressBalance = BURNED_TX_FEES_ADDRESS.balance;
require(
burnAddressBalance > lastestBurnedFeesReported,
burnAddressBalance > $._lastestBurnedFeesReported,
"NativeTokenRemote: burn address balance not greater than last report"
);

uint256 burnedDifference = burnAddressBalance - lastestBurnedFeesReported;
uint256 reward = (burnedDifference * burnedFeesReportingRewardPercentage) / 100;
uint256 burnedDifference = burnAddressBalance - $._lastestBurnedFeesReported;
uint256 reward = (burnedDifference * $._burnedFeesReportingRewardPercentage) / 100;
uint256 burnedTxFees = burnedDifference - reward;
lastestBurnedFeesReported = burnAddressBalance;
$._lastestBurnedFeesReported = burnAddressBalance;

if (reward > 0) {
// Re-mint the native tokens to this contract, and then deposit them to be the wrapped
Expand All @@ -179,7 +217,9 @@ contract NativeTokenRemote is

// Check that the scaled amount on the TokenHome instance will be non-zero.
require(
TokenScalingUtils.removeTokenScale(tokenMultiplier, multiplyOnRemote, burnedTxFees) > 0,
TokenScalingUtils.removeTokenScale(
getTokenMultiplier(), getMultiplyOnRemote(), burnedTxFees
) > 0,
"NativeTokenRemote: zero scaled amount to report burn"
);

Expand All @@ -193,8 +233,8 @@ contract NativeTokenRemote is

bytes32 messageID = _sendTeleporterMessage(
TeleporterMessageInput({
destinationBlockchainID: tokenHomeBlockchainID,
destinationAddress: tokenHomeAddress,
destinationBlockchainID: getTokenHomeBlockchainID(),
destinationAddress: getTokenHomeAddress(),
feeInfo: TeleporterFeeInfo({feeTokenAddress: address(this), amount: reward}),
requiredGasLimit: requiredGasLimit,
allowedRelayerAddresses: new address[](0),
Expand Down Expand Up @@ -244,11 +284,16 @@ contract NativeTokenRemote is
* that is represented as an ERC20.
*/
function totalNativeAssetSupply() public view returns (uint256) {
NativeTokenRemoteStorage storage $ = _getNativeTokenRemoteStorage();
uint256 burned = BURNED_TX_FEES_ADDRESS.balance + BURNED_FOR_TRANSFER_ADDRESS.balance;
uint256 created = totalMinted + initialReserveImbalance;
uint256 created = $._totalMinted + getInitialReserveImbalance();
return created - burned;
}

function getTotalMinted() external view returns (uint256) {
return _getNativeTokenRemoteStorage()._totalMinted;
}

/**
* @dev See {TokenRemote-_withdraw}
*/
Expand Down Expand Up @@ -340,7 +385,8 @@ contract NativeTokenRemote is
* @dev Mints coins to the recipient through the NativeMinter precompile.
*/
function _mintNativeCoin(address recipient, uint256 amount) private {
totalMinted += amount;
NativeTokenRemoteStorage storage $ = _getNativeTokenRemoteStorage();
$._totalMinted += amount;
// Calls NativeMinter precompile through INativeMinter interface.
NATIVE_MINTER.mintNativeCoin(recipient, amount);
}
Expand Down
Loading

0 comments on commit 7fb63df

Please sign in to comment.