-
Notifications
You must be signed in to change notification settings - Fork 64
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
18 changed files
with
4,064 additions
and
158 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,298 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.7; | ||
import "../../zevm/Interfaces.sol"; | ||
|
||
/** | ||
* @dev Custom errors for ZRC20 | ||
*/ | ||
interface ZRC20Errors { | ||
// @dev: Error thrown when caller is not the fungible module | ||
error CallerIsNotFungibleModule(); | ||
error InvalidSender(); | ||
error GasFeeTransferFailed(); | ||
error ZeroGasCoin(); | ||
error ZeroGasPrice(); | ||
error LowAllowance(); | ||
error LowBalance(); | ||
error ZeroAddress(); | ||
} | ||
|
||
// NOTE: this is exactly the same as ZRC20, except gateway contract address is set at deployment | ||
// and used to allow deposit. This is first version, it might change in the future. | ||
contract ZRC20New is IZRC20, IZRC20Metadata, ZRC20Errors { | ||
/// @notice Fungible address is always the same, maintained at the protocol level | ||
address public constant FUNGIBLE_MODULE_ADDRESS = 0x735b14BB79463307AAcBED86DAf3322B1e6226aB; | ||
/// @notice Chain id.abi | ||
uint256 public immutable CHAIN_ID; | ||
/// @notice Coin type, checkout Interfaces.sol. | ||
CoinType public immutable COIN_TYPE; | ||
/// @notice System contract address. | ||
address public SYSTEM_CONTRACT_ADDRESS; | ||
/// @notice Gateway contract address. | ||
address public GATEWAY_CONTRACT_ADDRESS; | ||
/// @notice Gas limit. | ||
uint256 public GAS_LIMIT; | ||
/// @notice Protocol flat fee. | ||
uint256 public PROTOCOL_FLAT_FEE; | ||
|
||
mapping(address => uint256) private _balances; | ||
mapping(address => mapping(address => uint256)) private _allowances; | ||
uint256 private _totalSupply; | ||
string private _name; | ||
string private _symbol; | ||
uint8 private _decimals; | ||
|
||
function _msgSender() internal view virtual returns (address) { | ||
return msg.sender; | ||
} | ||
|
||
function _msgData() internal view virtual returns (bytes calldata) { | ||
return msg.data; | ||
} | ||
|
||
/** | ||
* @dev Only fungible module modifier. | ||
*/ | ||
modifier onlyFungible() { | ||
if (msg.sender != FUNGIBLE_MODULE_ADDRESS) revert CallerIsNotFungibleModule(); | ||
_; | ||
} | ||
|
||
/** | ||
* @dev The only one allowed to deploy new ZRC20 is fungible address. | ||
*/ | ||
constructor( | ||
string memory name_, | ||
string memory symbol_, | ||
uint8 decimals_, | ||
uint256 chainid_, | ||
CoinType coinType_, | ||
uint256 gasLimit_, | ||
address systemContractAddress_, | ||
address gatewayContractAddress_ | ||
) { | ||
if (msg.sender != FUNGIBLE_MODULE_ADDRESS) revert CallerIsNotFungibleModule(); | ||
_name = name_; | ||
_symbol = symbol_; | ||
_decimals = decimals_; | ||
CHAIN_ID = chainid_; | ||
COIN_TYPE = coinType_; | ||
GAS_LIMIT = gasLimit_; | ||
SYSTEM_CONTRACT_ADDRESS = systemContractAddress_; | ||
GATEWAY_CONTRACT_ADDRESS = gatewayContractAddress_; | ||
} | ||
|
||
/** | ||
* @dev ZRC20 name | ||
* @return name as string | ||
*/ | ||
function name() public view virtual override returns (string memory) { | ||
return _name; | ||
} | ||
|
||
/** | ||
* @dev ZRC20 symbol. | ||
* @return symbol as string. | ||
*/ | ||
function symbol() public view virtual override returns (string memory) { | ||
return _symbol; | ||
} | ||
|
||
/** | ||
* @dev ZRC20 decimals. | ||
* @return returns uint8 decimals. | ||
*/ | ||
function decimals() public view virtual override returns (uint8) { | ||
return _decimals; | ||
} | ||
|
||
/** | ||
* @dev ZRC20 total supply. | ||
* @return returns uint256 total supply. | ||
*/ | ||
function totalSupply() public view virtual override returns (uint256) { | ||
return _totalSupply; | ||
} | ||
|
||
/** | ||
* @dev Returns ZRC20 balance of an account. | ||
* @param account, account address for which balance is requested. | ||
* @return uint256 account balance. | ||
*/ | ||
function balanceOf(address account) public view virtual override returns (uint256) { | ||
return _balances[account]; | ||
} | ||
|
||
/** | ||
* @dev Returns ZRC20 balance of an account. | ||
* @param recipient, recipiuent address to which transfer is done. | ||
* @return true/false if transfer succeeded/failed. | ||
*/ | ||
function transfer(address recipient, uint256 amount) public virtual override returns (bool) { | ||
_transfer(_msgSender(), recipient, amount); | ||
return true; | ||
} | ||
|
||
/** | ||
* @dev Returns token allowance from owner to spender. | ||
* @param owner, owner address. | ||
* @return uint256 allowance. | ||
*/ | ||
function allowance(address owner, address spender) public view virtual override returns (uint256) { | ||
return _allowances[owner][spender]; | ||
} | ||
|
||
/** | ||
* @dev Approves amount transferFrom for spender. | ||
* @param spender, spender address. | ||
* @param amount, amount to approve. | ||
* @return true/false if succeeded/failed. | ||
*/ | ||
function approve(address spender, uint256 amount) public virtual override returns (bool) { | ||
_approve(_msgSender(), spender, amount); | ||
return true; | ||
} | ||
|
||
/** | ||
* @dev Transfers tokens from sender to recipient. | ||
* @param sender, sender address. | ||
* @param recipient, recipient address. | ||
* @param amount, amount to transfer. | ||
* @return true/false if succeeded/failed. | ||
*/ | ||
function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { | ||
_transfer(sender, recipient, amount); | ||
|
||
uint256 currentAllowance = _allowances[sender][_msgSender()]; | ||
if (currentAllowance < amount) revert LowAllowance(); | ||
|
||
_approve(sender, _msgSender(), currentAllowance - amount); | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* @dev Burns an amount of tokens. | ||
* @param amount, amount to burn. | ||
* @return true/false if succeeded/failed. | ||
*/ | ||
function burn(uint256 amount) external returns (bool) { | ||
_burn(msg.sender, amount); | ||
return true; | ||
} | ||
|
||
function _transfer(address sender, address recipient, uint256 amount) internal virtual { | ||
if (sender == address(0)) revert ZeroAddress(); | ||
if (recipient == address(0)) revert ZeroAddress(); | ||
|
||
uint256 senderBalance = _balances[sender]; | ||
if (senderBalance < amount) revert LowBalance(); | ||
|
||
_balances[sender] = senderBalance - amount; | ||
_balances[recipient] += amount; | ||
|
||
emit Transfer(sender, recipient, amount); | ||
} | ||
|
||
function _mint(address account, uint256 amount) internal virtual { | ||
if (account == address(0)) revert ZeroAddress(); | ||
|
||
_totalSupply += amount; | ||
_balances[account] += amount; | ||
emit Transfer(address(0), account, amount); | ||
} | ||
|
||
function _burn(address account, uint256 amount) internal virtual { | ||
if (account == address(0)) revert ZeroAddress(); | ||
|
||
uint256 accountBalance = _balances[account]; | ||
if (accountBalance < amount) revert LowBalance(); | ||
|
||
_balances[account] = accountBalance - amount; | ||
_totalSupply -= amount; | ||
|
||
emit Transfer(account, address(0), amount); | ||
} | ||
|
||
function _approve(address owner, address spender, uint256 amount) internal virtual { | ||
if (owner == address(0)) revert ZeroAddress(); | ||
if (spender == address(0)) revert ZeroAddress(); | ||
|
||
_allowances[owner][spender] = amount; | ||
emit Approval(owner, spender, amount); | ||
} | ||
|
||
/** | ||
* @dev Deposits corresponding tokens from external chain, only callable by Fungible module. | ||
* @param to, recipient address. | ||
* @param amount, amount to deposit. | ||
* @return true/false if succeeded/failed. | ||
*/ | ||
function deposit(address to, uint256 amount) external override returns (bool) { | ||
if (msg.sender != FUNGIBLE_MODULE_ADDRESS && msg.sender != SYSTEM_CONTRACT_ADDRESS && msg.sender != GATEWAY_CONTRACT_ADDRESS) revert InvalidSender(); | ||
_mint(to, amount); | ||
emit Deposit(abi.encodePacked(FUNGIBLE_MODULE_ADDRESS), to, amount); | ||
return true; | ||
} | ||
|
||
/** | ||
* @dev Withdraws gas fees. | ||
* @return returns the ZRC20 address for gas on the same chain of this ZRC20, and calculates the gas fee for withdraw() | ||
*/ | ||
function withdrawGasFee() public view override returns (address, uint256) { | ||
address gasZRC20 = ISystem(SYSTEM_CONTRACT_ADDRESS).gasCoinZRC20ByChainId(CHAIN_ID); | ||
if (gasZRC20 == address(0)) { | ||
revert ZeroGasCoin(); | ||
} | ||
uint256 gasPrice = ISystem(SYSTEM_CONTRACT_ADDRESS).gasPriceByChainId(CHAIN_ID); | ||
if (gasPrice == 0) { | ||
revert ZeroGasPrice(); | ||
} | ||
uint256 gasFee = gasPrice * GAS_LIMIT + PROTOCOL_FLAT_FEE; | ||
return (gasZRC20, gasFee); | ||
} | ||
|
||
/** | ||
* @dev Withraws ZRC20 tokens to external chains, this function causes cctx module to send out outbound tx to the outbound chain | ||
* this contract should be given enough allowance of the gas ZRC20 to pay for outbound tx gas fee. | ||
* @param to, recipient address. | ||
* @param amount, amount to deposit. | ||
* @return true/false if succeeded/failed. | ||
*/ | ||
function withdraw(bytes memory to, uint256 amount) external override returns (bool) { | ||
(address gasZRC20, uint256 gasFee) = withdrawGasFee(); | ||
if (!IZRC20(gasZRC20).transferFrom(msg.sender, FUNGIBLE_MODULE_ADDRESS, gasFee)) { | ||
revert GasFeeTransferFailed(); | ||
} | ||
_burn(msg.sender, amount); | ||
emit Withdrawal(msg.sender, to, amount, gasFee, PROTOCOL_FLAT_FEE); | ||
return true; | ||
} | ||
|
||
/** | ||
* @dev Updates system contract address. Can only be updated by the fungible module. | ||
* @param addr, new system contract address. | ||
*/ | ||
function updateSystemContractAddress(address addr) external onlyFungible { | ||
SYSTEM_CONTRACT_ADDRESS = addr; | ||
emit UpdatedSystemContract(addr); | ||
} | ||
|
||
/** | ||
* @dev Updates gas limit. Can only be updated by the fungible module. | ||
* @param gasLimit, new gas limit. | ||
*/ | ||
function updateGasLimit(uint256 gasLimit) external onlyFungible { | ||
GAS_LIMIT = gasLimit; | ||
emit UpdatedGasLimit(gasLimit); | ||
} | ||
|
||
/** | ||
* @dev Updates protocol flat fee. Can only be updated by the fungible module. | ||
* @param protocolFlatFee, new protocol flat fee. | ||
*/ | ||
function updateProtocolFlatFee(uint256 protocolFlatFee) external onlyFungible { | ||
PROTOCOL_FLAT_FEE = protocolFlatFee; | ||
emit UpdatedProtocolFlatFee(protocolFlatFee); | ||
} | ||
} |
This file contains 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
Oops, something went wrong.