Skip to content

Commit

Permalink
feat(IXERC20/MintAllowance): duplicating minting allowance to enable …
Browse files Browse the repository at this point in the history
…burn allowance. Implement IXERC20 interface in token. there are still some function un-coded
  • Loading branch information
KristenPire committed Jun 27, 2024
1 parent aceed5e commit 34cc1bf
Show file tree
Hide file tree
Showing 3 changed files with 326 additions and 28 deletions.
119 changes: 98 additions & 21 deletions src/MintAllowanceUpgradeable.sol
Original file line number Diff line number Diff line change
@@ -1,25 +1,43 @@
pragma solidity ^0.8.20;

contract MintAllowanceUpgradeable {
struct MintAllowanceStorage {
mapping(address => uint256) _mintAllowance;
uint256 _maxMintAllowance;
struct Allowance {
uint256 max;
mapping(address => uint256) allowances;
}

struct AllowanceStorage {
Allowance _mint;
Allowance _burn;
}

//keccak256("Monerium.MintAllowanceStorage")
bytes32 private constant MintAllowanceStorageLocation =
0xb337526095403ef89c7becef1792605e55dadf16cfa1d0df874fad9581a6937d;
bytes32 private constant AllowanceStorageLocation =
0x7dfa07e9bc075623c605ec9614e9976bbce827d371ce2ecdb28aa7ae3f76de54;

function _getMintAllowanceStorage()
function _getAllowanceStorage()
private
pure
returns (MintAllowanceStorage storage $)
returns (AllowanceStorage storage $)
{
assembly {
$.slot := MintAllowanceStorageLocation
$.slot := AllowanceStorageLocation
}
}

/**
* @dev Emitted when allowance is set.
* @param account The address of the account.
* @param amount The amount of allowance.
*/
event BurnAllowance(address indexed account, uint256 amount);

/**
* @dev Emitted when max allowance is set.
* @param amount The amount of allowance.
*/
event MaxBurnAllowance(uint256 amount);

/**
* @dev Emitted when allowance is set.
* @param account The address of the account.
Expand All @@ -33,46 +51,105 @@ contract MintAllowanceUpgradeable {
*/
event MaxMintAllowance(uint256 amount);

///////////// Burn
function getBurnAllowance(address account) public view returns (uint256) {
Allowance storage b = _getAllowanceStorage()._burn;
return b.allowances[account];
}

function _setBurnAllowance(address account, uint256 amount) internal {
Allowance storage b = _getAllowanceStorage()._burn;

require(
amount <= b.max,
"BurnAllowance: cannot set allowance higher than max"
);

b.allowances[account] = amount;

emit BurnAllowance(account, amount);
}

function _setBurnAllowance(address account, uint256 amount) internal {
Allowance storage b = _getAllowanceStorage()._burn;

require(
amount <= b.max,
"BurnAllowance: cannot set allowance higher than max"
);

b.allowances[account] = amount;

emit BurnAllowance(account, amount);
}

function getMaxBurnAllowance() public view returns (uint256) {
Allowance storage b = _getAllowanceStorage()._burn;
return b.max;
}

function _setMaxBurnAllowance(uint256 amount) internal {
Allowance storage b = _getAllowanceStorage()._burn;

b.max = amount;

emit MaxBurnAllowance(amount);
}

function _useBurnAllowance(address account, uint256 amount) internal {
Allowance storage b = _getAllowanceStorage()._burn;

require(
b.allowances[account] >= amount,
"BurnAllowance: not allowed to burn more than allowed"
);

b.allowances[account] -= amount;

emit BurnAllowance(account, b.allowances[account]);
}

///////////// Mint
function getMintAllowance(address account) public view returns (uint256) {
MintAllowanceStorage storage s = _getMintAllowanceStorage();
return s._mintAllowance[account];
Allowance storage m = _getAllowanceStorage()._mint;
return m.allowances[account];
}

function _setMintAllowance(address account, uint256 amount) internal {
MintAllowanceStorage storage s = _getMintAllowanceStorage();
Allowance storage m = _getAllowanceStorage()._mint;

require(
amount <= s._maxMintAllowance,
amount <= m.max,
"MintAllowance: cannot set allowance higher than max"
);

s._mintAllowance[account] = amount;
m.allowances[account] = amount;

emit MintAllowance(account, amount);
}

function _useMintAllowance(address account, uint256 amount) internal {
MintAllowanceStorage storage s = _getMintAllowanceStorage();
Allowance storage m = _getAllowanceStorage()._mint;

require(
s._mintAllowance[account] >= amount,
m.allowances[account] >= amount,
"MintAllowance: not allowed to mint more than allowed"
);

s._mintAllowance[account] -= amount;
m.allowances[account] -= amount;

emit MintAllowance(account, s._mintAllowance[account]);
emit MintAllowance(account, m.allowances[account]);
}

function getMaxMintAllowance() public view returns (uint256) {
MintAllowanceStorage storage s = _getMintAllowanceStorage();
return s._maxMintAllowance;
Allowance storage m = _getAllowanceStorage()._mint;
return m.max;
}

function _setMaxMintAllowance(uint256 amount) internal {
MintAllowanceStorage storage s = _getMintAllowanceStorage();
Allowance storage m = _getAllowanceStorage()._mint;

s._maxMintAllowance = amount;
m.max = amount;

emit MaxMintAllowance(amount);
}
Expand Down
85 changes: 78 additions & 7 deletions src/Token.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import "./MintAllowanceUpgradeable.sol";
import "./SystemRoleUpgradeable.sol";
import "./IValidator.sol";

import "./interfaces/IXERC20.sol";

/**
* @dev Token contract with upgradeable patterns, mint allowance, and system roles.
*/
Expand All @@ -22,7 +24,8 @@ contract Token is
ERC20PermitUpgradeable,
UUPSUpgradeable,
MintAllowanceUpgradeable,
SystemRoleUpgradeable
SystemRoleUpgradeable,
IXERC20
{
// Subsequent contract versions must retain this variable to avoid storage conflicts with the proxy.
IValidator public validator;
Expand Down Expand Up @@ -56,7 +59,10 @@ contract Token is
__UUPSUpgradeable_init();
__SystemRole_init();
validator = IValidator(_validator);
require(validator.CONTRACT_ID() == keccak256("monerium.validator"), "Not Monerium Validator Contract");
require(
validator.CONTRACT_ID() == keccak256("monerium.validator"),
"Not Monerium Validator Contract"
);
}

// _authorizeUpgrade is a crucial part of the UUPS upgrade pattern in OpenZeppelin.
Expand All @@ -71,14 +77,20 @@ contract Token is
_mint(to, amount);
}

/**
* @dev Burns tokens from a specified address. This function is reserved for internal use by Monerium's infrastructure.
*/
function burn(
address from,
uint256 amount,
bytes32 ,
bytes32,
bytes memory signature
) public onlySystemAccounts {
require(
from.isValidSignatureNow(0xb77c35c892a1b24b10a2ce49b424e578472333ee8d2456234fff90626332c50f, signature),
from.isValidSignatureNow(
0xb77c35c892a1b24b10a2ce49b424e578472333ee8d2456234fff90626332c50f,
signature
),
"signature/hash does not match"
);
_burn(from, amount);
Expand All @@ -87,7 +99,7 @@ contract Token is
function recover(
address from,
address to,
bytes32 ,
bytes32,
uint8 v,
bytes32 r,
bytes32 s
Expand All @@ -97,7 +109,10 @@ contract Token is
signature = abi.encodePacked(r, s, v);
}
require(
from.isValidSignatureNow(0xb77c35c892a1b24b10a2ce49b424e578472333ee8d2456234fff90626332c50f, signature),
from.isValidSignatureNow(
0xb77c35c892a1b24b10a2ce49b424e578472333ee8d2456234fff90626332c50f,
signature
),
"signature/hash does not match"
);
uint256 amount = balanceOf(from);
Expand All @@ -110,7 +125,10 @@ contract Token is
// Function to set the validator, restricted to owner
function setValidator(address _validator) public onlyOwner {
validator = IValidator(_validator);
require(validator.CONTRACT_ID() == keccak256("monerium.validator"), "Not Monerium Validator Contract");
require(
validator.CONTRACT_ID() == keccak256("monerium.validator"),
"Not Monerium Validator Contract"
);
}

// Override transfer function to invoke validator
Expand Down Expand Up @@ -177,6 +195,59 @@ contract Token is
);
}

//--> IXERC20 functions
function setLockbox(address) external view onlyOwner {
revert("not implemented"); // todo : return error
}

function burn(address user, uint256 amount) external onlySystemAccounts {
//#1 spend allowance
_burn(user, amount);
}

function setLimits(
address bridge,
uint256 mintingLimit,
uint256 burningLimit
) external onlyAdminAccounts {
if (
mintingLimit > (type(uint256).max / 2) ||
burningLimit > (type(uint256).max / 2)
) {
revert IXERC20_LimitsTooHigh();
}

_setMaxMintAllowance(mintingLimit);
_setMintAllowance(bridge, mintingLimit);

_setMaxBurnAllowance(bridge, )
// burnAllowance?
emit BridgeLimitsSet(mintingLimit, burningLimit, bridge);
}

function burningCurrentLimitOf(
address bridge
) external view returns (uint256 limit) {
return 0;
}

function burningMaxLimitOf(
address bridge
) external view returns (uint256 limit) {
return 0;
}

function mintingCurrentLimitOf(
address minter
) external view returns (uint256 limit) {
return 0;
}

function mintingMaxLimitOf(
address minter
) external view returns (uint256 limit) {
return 0;
}

}

Loading

0 comments on commit 34cc1bf

Please sign in to comment.