You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
200 lines
6.6 KiB
200 lines
6.6 KiB
4 years ago
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||
|
pragma solidity >=0.6.11;
|
||
|
|
||
3 years ago
|
// ============ Internal Imports ============
|
||
|
import {IBridgeToken} from "../../interfaces/bridge/IBridgeToken.sol";
|
||
3 years ago
|
import {ERC20} from "./vendored/OZERC20.sol";
|
||
3 years ago
|
// ============ External Imports ============
|
||
3 years ago
|
import {Version0} from "@abacus-network/abacus-sol/contracts/Version0.sol";
|
||
|
import {TypeCasts} from "@abacus-network/abacus-sol/contracts/XAppConnectionManager.sol";
|
||
3 years ago
|
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
||
4 years ago
|
|
||
3 years ago
|
contract BridgeToken is Version0, IBridgeToken, OwnableUpgradeable, ERC20 {
|
||
3 years ago
|
// ============ Immutables ============
|
||
|
|
||
3 years ago
|
// Immutables used in EIP 712 structured data hashing & signing
|
||
|
// https://eips.ethereum.org/EIPS/eip-712
|
||
|
bytes32 public immutable _PERMIT_TYPEHASH =
|
||
|
keccak256(
|
||
|
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
|
||
|
);
|
||
3 years ago
|
bytes32 private immutable _EIP712_STRUCTURED_DATA_VERSION =
|
||
|
keccak256(bytes("1"));
|
||
3 years ago
|
uint16 private immutable _EIP712_PREFIX_AND_VERSION = uint16(0x1901);
|
||
|
|
||
3 years ago
|
// ============ Public Storage ============
|
||
|
|
||
3 years ago
|
mapping(address => uint256) public nonces;
|
||
3 years ago
|
|
||
|
// ============ Upgrade Gap ============
|
||
|
|
||
3 years ago
|
uint256[49] private __GAP; // gap for upgrade safety
|
||
3 years ago
|
|
||
3 years ago
|
// ============ Initializer ============
|
||
|
|
||
3 years ago
|
function initialize() public override initializer {
|
||
|
__Ownable_init();
|
||
|
}
|
||
|
|
||
3 years ago
|
// ============ External Functions ============
|
||
3 years ago
|
|
||
4 years ago
|
/**
|
||
|
* @notice Destroys `_amnt` tokens from `_from`, reducing the
|
||
|
* total supply.
|
||
|
* @dev Emits a {Transfer} event with `to` set to the zero address.
|
||
|
* Requirements:
|
||
|
* - `_from` cannot be the zero address.
|
||
|
* - `_from` must have at least `_amnt` tokens.
|
||
|
* @param _from The address from which to destroy the tokens
|
||
|
* @param _amnt The amount of tokens to be destroyed
|
||
|
*/
|
||
4 years ago
|
function burn(address _from, uint256 _amnt) external override onlyOwner {
|
||
|
_burn(_from, _amnt);
|
||
4 years ago
|
}
|
||
|
|
||
4 years ago
|
/** @notice Creates `_amnt` tokens and assigns them to `_to`, increasing
|
||
|
* the total supply.
|
||
|
* @dev Emits a {Transfer} event with `from` set to the zero address.
|
||
|
* Requirements:
|
||
|
* - `to` cannot be the zero address.
|
||
|
* @param _to The destination address
|
||
|
* @param _amnt The amount of tokens to be minted
|
||
|
*/
|
||
4 years ago
|
function mint(address _to, uint256 _amnt) external override onlyOwner {
|
||
|
_mint(_to, _amnt);
|
||
4 years ago
|
}
|
||
|
|
||
4 years ago
|
/**
|
||
|
* @notice Set the details of a token
|
||
|
* @param _newName The new name
|
||
|
* @param _newSymbol The new symbol
|
||
|
* @param _newDecimals The new decimals
|
||
|
*/
|
||
4 years ago
|
function setDetails(
|
||
3 years ago
|
string calldata _newName,
|
||
|
string calldata _newSymbol,
|
||
4 years ago
|
uint8 _newDecimals
|
||
|
) external override onlyOwner {
|
||
|
// careful with naming convention change here
|
||
3 years ago
|
token.name = _newName;
|
||
|
token.symbol = _newSymbol;
|
||
4 years ago
|
token.decimals = _newDecimals;
|
||
4 years ago
|
}
|
||
|
|
||
3 years ago
|
/**
|
||
|
* @notice Sets approval from owner to spender to value
|
||
|
* as long as deadline has not passed
|
||
|
* by submitting a valid signature from owner
|
||
|
* Uses EIP 712 structured data hashing & signing
|
||
|
* https://eips.ethereum.org/EIPS/eip-712
|
||
|
* @param _owner The account setting approval & signing the message
|
||
|
* @param _spender The account receiving approval to spend owner's tokens
|
||
|
* @param _value The amount to set approval for
|
||
|
* @param _deadline The timestamp before which the signature must be submitted
|
||
|
* @param _v ECDSA signature v
|
||
|
* @param _r ECDSA signature r
|
||
|
* @param _s ECDSA signature s
|
||
|
*/
|
||
|
function permit(
|
||
|
address _owner,
|
||
|
address _spender,
|
||
|
uint256 _value,
|
||
|
uint256 _deadline,
|
||
|
uint8 _v,
|
||
|
bytes32 _r,
|
||
|
bytes32 _s
|
||
|
) external {
|
||
|
require(block.timestamp <= _deadline, "ERC20Permit: expired deadline");
|
||
|
require(_owner != address(0), "ERC20Permit: owner zero address");
|
||
|
uint256 _nonce = nonces[_owner];
|
||
|
bytes32 _hashStruct = keccak256(
|
||
3 years ago
|
abi.encode(
|
||
|
_PERMIT_TYPEHASH,
|
||
|
_owner,
|
||
|
_spender,
|
||
|
_value,
|
||
|
_nonce,
|
||
|
_deadline
|
||
|
)
|
||
3 years ago
|
);
|
||
|
bytes32 _digest = keccak256(
|
||
3 years ago
|
abi.encodePacked(
|
||
|
_EIP712_PREFIX_AND_VERSION,
|
||
|
domainSeparator(),
|
||
|
_hashStruct
|
||
|
)
|
||
3 years ago
|
);
|
||
|
address _signer = ecrecover(_digest, _v, _r, _s);
|
||
|
require(_signer == _owner, "ERC20Permit: invalid signature");
|
||
|
nonces[_owner] = _nonce + 1;
|
||
|
_approve(_owner, _spender, _value);
|
||
|
}
|
||
|
|
||
3 years ago
|
// ============ Public Functions ============
|
||
|
|
||
|
/**
|
||
|
* @dev silence the compiler being dumb
|
||
|
*/
|
||
|
function balanceOf(address _account)
|
||
|
public
|
||
|
view
|
||
|
override(IBridgeToken, ERC20)
|
||
|
returns (uint256)
|
||
|
{
|
||
|
return ERC20.balanceOf(_account);
|
||
|
}
|
||
|
|
||
4 years ago
|
/**
|
||
|
* @dev Returns the name of the token.
|
||
|
*/
|
||
|
function name() public view override returns (string memory) {
|
||
4 years ago
|
return token.name;
|
||
4 years ago
|
}
|
||
|
|
||
|
/**
|
||
|
* @dev Returns the symbol of the token, usually a shorter version of the
|
||
|
* name.
|
||
|
*/
|
||
|
function symbol() public view override returns (string memory) {
|
||
4 years ago
|
return token.symbol;
|
||
4 years ago
|
}
|
||
|
|
||
|
/**
|
||
|
* @dev Returns the number of decimals used to get its user representation.
|
||
|
* For example, if `decimals` equals `2`, a balance of `505` tokens should
|
||
|
* be displayed to a user as `5,05` (`505 / 10 ** 2`).
|
||
|
* Tokens usually opt for a value of 18, imitating the relationship between
|
||
|
* Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
|
||
|
* called.
|
||
|
* NOTE: This information is only used for _display_ purposes: it in
|
||
|
* no way affects any of the arithmetic of the contract, including
|
||
|
* {IERC20-balanceOf} and {IERC20-transfer}.
|
||
|
*/
|
||
|
function decimals() public view override returns (uint8) {
|
||
4 years ago
|
return token.decimals;
|
||
4 years ago
|
}
|
||
3 years ago
|
|
||
3 years ago
|
/**
|
||
|
* @dev This is ALWAYS calculated at runtime
|
||
|
* because the token name may change
|
||
|
*/
|
||
3 years ago
|
function domainSeparator() public view returns (bytes32) {
|
||
|
uint256 _chainId;
|
||
|
assembly {
|
||
|
_chainId := chainid()
|
||
|
}
|
||
|
return
|
||
|
keccak256(
|
||
|
abi.encode(
|
||
|
keccak256(
|
||
|
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
|
||
|
),
|
||
|
keccak256(bytes(token.name)),
|
||
|
_EIP712_STRUCTURED_DATA_VERSION,
|
||
|
_chainId,
|
||
|
address(this)
|
||
|
)
|
||
|
);
|
||
|
}
|
||
4 years ago
|
}
|