Description:
Proxy contract enabling upgradeable smart contract patterns. Delegates calls to an implementation contract.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"contracts/upgradeability/draft-IERC1822.sol": {
"content": "// SPDX-License-Identifier: MIT\r
// OpenZeppelin Contracts v4.x.0 (proxy/ERC1822/IProxiable.sol)\r
\r
pragma solidity 0.8.11;\r
\r
/**\r
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified\r
* proxy whose upgrades are fully controlled by the current implementation.\r
*/\r
interface IERC1822Proxiable {\r
/**\r
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation\r
* address.\r
*\r
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\r
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\r
* function revert if invoked through a proxy.\r
*/\r
function proxiableUUID() external view returns (bytes32);\r
}"
},
"contracts/upgradeability/ERC1967Upgrade.sol": {
"content": "// SPDX-License-Identifier: MIT\r
// OpenZeppelin Contracts v4.4.1 (proxy/ERC1967/ERC1967Upgrade.sol)\r
\r
pragma solidity 0.8.11;\r
\r
import "./draft-IERC1822.sol";\r
import "../util/Address.sol";\r
import "../util/StorageSlot.sol";\r
\r
/**\r
* @dev This abstract contract provides getters and event emitting update functions for\r
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.\r
*\r
* _Available since v4.1._\r
*\r
* @custom:oz-upgrades-unsafe-allow delegatecall\r
*/\r
abstract contract ERC1967Upgrade {\r
// This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1\r
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;\r
\r
/**\r
* @dev Storage slot with the address of the current implementation.\r
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is\r
* validated in the constructor.\r
*/\r
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\r
\r
/**\r
* @dev Emitted when the implementation is upgraded.\r
*/\r
event Upgraded(address indexed implementation);\r
\r
/**\r
* @dev Returns the current implementation address.\r
*/\r
function _getImplementation() internal view returns (address) {\r
return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\r
}\r
\r
/**\r
* @dev Stores a new address in the EIP1967 implementation slot.\r
*/\r
function _setImplementation(address newImplementation) private {\r
require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");\r
StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\r
}\r
\r
/**\r
* @dev Perform implementation upgrade\r
*\r
* Emits an {Upgraded} event.\r
*/\r
function _upgradeTo(address newImplementation) internal {\r
_setImplementation(newImplementation);\r
emit Upgraded(newImplementation);\r
}\r
\r
/**\r
* @dev Perform implementation upgrade with additional setup call.\r
*\r
* Emits an {Upgraded} event.\r
*/\r
function _upgradeToAndCall(\r
address newImplementation,\r
bytes memory data,\r
bool forceCall\r
) internal {\r
_upgradeTo(newImplementation);\r
if (data.length > 0 || forceCall) {\r
Address.functionDelegateCall(newImplementation, data);\r
}\r
}\r
\r
/**\r
* @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.\r
*\r
* Emits an {Upgraded} event.\r
*/\r
function _upgradeToAndCallUUPS(\r
address newImplementation,\r
bytes memory data,\r
bool forceCall\r
) internal {\r
// Upgrades from old implementations will perform a rollback test. This test requires the new\r
// implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing\r
// this special case will break upgrade paths from old UUPS implementation to new ones.\r
if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {\r
_setImplementation(newImplementation);\r
} else {\r
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {\r
require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");\r
} catch {\r
revert("ERC1967Upgrade: new implementation is not UUPS");\r
}\r
_upgradeToAndCall(newImplementation, data, forceCall);\r
}\r
}\r
\r
uint256[50] private _gap;\r
}"
},
"contracts/upgradeability/UUPSUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT\r
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/UUPSUpgradeable.sol)\r
\r
pragma solidity 0.8.11;\r
\r
import "./draft-IERC1822.sol";\r
import "./ERC1967Upgrade.sol";\r
\r
/**\r
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an\r
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.\r
*\r
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is\r
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing\r
* `UUPSUpgradeable` with a custom implementation of upgrades.\r
*\r
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.\r
*\r
* _Available since v4.1._\r
*/\r
abstract contract UUPSUpgradeable is IERC1822Proxiable, ERC1967Upgrade {\r
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment\r
address private immutable __self = address(this);\r
\r
/**\r
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is\r
* a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case\r
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a\r
* function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to\r
* fail.\r
*/\r
modifier onlyProxy() {\r
require(\r
address(this) != __self,\r
"Function must be called through delegatecall"\r
);\r
require(\r
_getImplementation() == __self,\r
"Function must be called through active proxy"\r
);\r
_;\r
}\r
\r
/**\r
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be\r
* callable on the implementing contract but not through proxies.\r
*/\r
modifier notDelegated() {\r
require(\r
address(this) == __self,\r
"UUPSUpgradeable: must not be called through delegatecall"\r
);\r
_;\r
}\r
\r
/**\r
* @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the\r
* implementation. It is used to validate that the this implementation remains valid after an upgrade.\r
*\r
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\r
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\r
* function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.\r
*/\r
function proxiableUUID()\r
external\r
view\r
virtual\r
override\r
notDelegated\r
returns (bytes32)\r
{\r
return _IMPLEMENTATION_SLOT;\r
}\r
\r
/**\r
* @dev Upgrade the implementation of the proxy to `newImplementation`.\r
*\r
* Calls {_authorizeUpgrade}.\r
*\r
* Emits an {Upgraded} event.\r
*/\r
function upgradeTo(address newImplementation) external virtual onlyProxy {\r
_authorizeUpgrade(newImplementation);\r
_upgradeToAndCallUUPS(newImplementation, new bytes(0), false);\r
}\r
\r
/**\r
* @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call\r
* encoded in `data`.\r
*\r
* Calls {_authorizeUpgrade}.\r
*\r
* Emits an {Upgraded} event.\r
*/\r
function upgradeToAndCall(address newImplementation, bytes memory data)\r
external\r
payable\r
virtual\r
onlyProxy\r
{\r
_authorizeUpgrade(newImplementation);\r
_upgradeToAndCallUUPS(newImplementation, data, true);\r
}\r
\r
/**\r
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by\r
* {upgradeTo} and {upgradeToAndCall}.\r
*\r
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.\r
*\r
* ```solidity\r
* function _authorizeUpgrade(address) internal override onlyOwner {}\r
* ```\r
*/\r
function _authorizeUpgrade(address newImplementation) internal virtual;\r
\r
uint256[50] private _gap;\r
}\r
"
},
"contracts/util/Address.sol": {
"content": "// SPDX-License-Identifier: MIT\r
// OpenZeppelin Contracts v4.4.0 (utils/Address.sol)\r
\r
pragma solidity 0.8.11;\r
\r
/**\r
* @dev Collection of functions related to the address type\r
*/\r
library Address {\r
/**\r
* @dev Returns true if `account` is a contract.\r
* @dev Forked from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/4961a51cc736c7d4aa9bd2e11e4cbbaff73efee9/contracts/utils/Context.sol\r
* Modifications:\r
* 1. Change solidity version to 0.8.11\r
*\r
* [IMPORTANT]\r
* ====\r
* It is unsafe to assume that an address for which this function returns\r
* false is an externally-owned account (EOA) and not a contract.\r
*\r
* Among others, `isContract` will return false for the following\r
* types of addresses:\r
*\r
* - an externally-owned account\r
* - a contract in construction\r
* - an address where a contract will be created\r
* - an address where a contract lived, but was destroyed\r
* ====\r
*/\r
function isContract(address account) internal view returns (bool) {\r
// This method relies on extcodesize, which returns 0 for contracts in\r
// construction, since the code is only stored at the end of the\r
// constructor execution.\r
\r
uint256 size;\r
assembly {\r
size := extcodesize(account)\r
}\r
return size > 0;\r
}\r
\r
/**\r
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to\r
* `recipient`, forwarding all available gas and reverting on errors.\r
*\r
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\r
* of certain opcodes, possibly making contracts go over the 2300 gas limit\r
* imposed by `transfer`, making them unable to receive funds via\r
* `transfer`. {sendValue} removes this limitation.\r
*\r
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\r
*\r
* IMPORTANT: because control is transferred to `recipient`, care must be\r
* taken to not create reentrancy vulnerabilities. Consider using\r
* {ReentrancyGuard} or the\r
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\r
*/\r
function sendValue(address payable recipient, uint256 amount) internal {\r
require(address(this).balance >= amount, "Address: insufficient balance");\r
\r
(bool success, ) = recipient.call{value: amount}("");\r
require(success, "Address: unable to send value, recipient may have reverted");\r
}\r
\r
/**\r
* @dev Performs a Solidity function call using a low level `call`. A\r
* plain `call` is an unsafe replacement for a function call: use this\r
* function instead.\r
*\r
* If `target` reverts with a revert reason, it is bubbled up by this\r
* function (like regular Solidity function calls).\r
*\r
* Returns the raw returned data. To convert to the expected return value,\r
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\r
*\r
* Requirements:\r
*\r
* - `target` must be a contract.\r
* - calling `target` with `data` must not revert.\r
*\r
* _Available since v3.1._\r
*/\r
function functionCall(address target, bytes memory data) internal returns (bytes memory) {\r
return functionCall(target, data, "Address: low-level call failed");\r
}\r
\r
/**\r
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\r
* `errorMessage` as a fallback revert reason when `target` reverts.\r
*\r
* _Available since v3.1._\r
*/\r
function functionCall(\r
address target,\r
bytes memory data,\r
string memory errorMessage\r
) internal returns (bytes memory) {\r
return functionCallWithValue(target, data, 0, errorMessage);\r
}\r
\r
/**\r
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\r
* but also transferring `value` wei to `target`.\r
*\r
* Requirements:\r
*\r
* - the calling contract must have an ETH balance of at least `value`.\r
* - the called Solidity function must be `payable`.\r
*\r
* _Available since v3.1._\r
*/\r
function functionCallWithValue(\r
address target,\r
bytes memory data,\r
uint256 value\r
) internal returns (bytes memory) {\r
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");\r
}\r
\r
/**\r
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\r
* with `errorMessage` as a fallback revert reason when `target` reverts.\r
*\r
* _Available since v3.1._\r
*/\r
function functionCallWithValue(\r
address target,\r
bytes memory data,\r
uint256 value,\r
string memory errorMessage\r
) internal returns (bytes memory) {\r
require(address(this).balance >= value, "Address: insufficient balance for call");\r
require(isContract(target), "Address: call to non-contract");\r
\r
(bool success, bytes memory returndata) = target.call{value: value}(data);\r
return verifyCallResult(success, returndata, errorMessage);\r
}\r
\r
/**\r
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\r
* but performing a static call.\r
*\r
* _Available since v3.3._\r
*/\r
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\r
return functionStaticCall(target, data, "Address: low-level static call failed");\r
}\r
\r
/**\r
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\r
* but performing a static call.\r
*\r
* _Available since v3.3._\r
*/\r
function functionStaticCall(\r
address target,\r
bytes memory data,\r
string memory errorMessage\r
) internal view returns (bytes memory) {\r
require(isContract(target), "Address: static call to non-contract");\r
\r
(bool success, bytes memory returndata) = target.staticcall(data);\r
return verifyCallResult(success, returndata, errorMessage);\r
}\r
\r
/**\r
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\r
* but performing a delegate call.\r
*\r
* _Available since v3.4._\r
*/\r
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\r
return functionDelegateCall(target, data, "Address: low-level delegate call failed");\r
}\r
\r
/**\r
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\r
* but performing a delegate call.\r
*\r
* _Available since v3.4._\r
*/\r
function functionDelegateCall(\r
address target,\r
bytes memory data,\r
string memory errorMessage\r
) internal returns (bytes memory) {\r
require(isContract(target), "Address: delegate call to non-contract");\r
\r
(bool success, bytes memory returndata) = target.delegatecall(data);\r
return verifyCallResult(success, returndata, errorMessage);\r
}\r
\r
/**\r
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\r
* revert reason using the provided one.\r
*\r
* _Available since v4.3._\r
*/\r
function verifyCallResult(\r
bool success,\r
bytes memory returndata,\r
string memory errorMessage\r
) internal pure returns (bytes memory) {\r
if (success) {\r
return returndata;\r
} else {\r
// Look for revert reason and bubble it up if present\r
if (returndata.length > 0) {\r
// The easiest way to bubble the revert reason is using memory via assembly\r
\r
assembly {\r
let returndata_size := mload(returndata)\r
revert(add(32, returndata), returndata_size)\r
}\r
} else {\r
revert(errorMessage);\r
}\r
}\r
}\r
}"
},
"contracts/util/ECRecover.sol": {
"content": "/**\r
* SPDX-License-Identifier: MIT\r
*\r
* Copyright (c) 2016-2019 zOS Global Limited\r
* Copyright (c) 2018-2020 CENTRE SECZ\r
*\r
* Permission is hereby granted, free of charge, to any person obtaining a copy\r
* of this software and associated documentation files (the "Software"), to deal\r
* in the Software without restriction, including without limitation the rights\r
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
* copies of the Software, and to permit persons to whom the Software is\r
* furnished to do so, subject to the following conditions:\r
*\r
* The above copyright notice and this permission notice shall be included in\r
* copies or substantial portions of the Software.\r
*\r
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
* SOFTWARE.\r
*/\r
\r
pragma solidity 0.8.11;\r
\r
/**\r
* @dev Forked from https://github.com/centrehq/centre-tokens/blob/37039f00534d3e5148269adf98bd2d42ea9fcfd7/contracts/util/ECRecover.sol\r
* Modifications:\r
* 1. Change solidity version to 0.8.11\r
*/\r
/**\r
* @title ECRecover\r
* @notice A library that provides a safe ECDSA recovery function\r
*/\r
library ECRecover {\r
/**\r
* @notice Recover signer's address from a signed message\r
* @dev Adapted from: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/65e4ffde586ec89af3b7e9140bdc9235d1254853/contracts/cryptography/ECDSA.sol\r
* Modifications: Accept v, r, and s as separate arguments\r
* @param digest Keccak-256 hash digest of the signed message\r
* @param v v of the signature\r
* @param r r of the signature\r
* @param s s of the signature\r
* @return Signer address\r
*/\r
function recover(\r
bytes32 digest,\r
uint8 v,\r
bytes32 r,\r
bytes32 s\r
) internal pure returns (address) {\r
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\r
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\r
// the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most\r
// signatures from current libraries generate a unique signature with an s-value in the lower half order.\r
//\r
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\r
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\r
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\r
// these malleable signatures as well.\r
if (\r
uint256(s) >\r
0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0\r
) {\r
revert("ECRecover: invalid signature 's' value");\r
}\r
\r
if (v != 27 && v != 28) {\r
revert("ECRecover: invalid signature 'v' value");\r
}\r
\r
// If the signature is valid (and not malleable), return the signer address\r
address signer = ecrecover(digest, v, r, s);\r
require(signer != address(0), "ECRecover: invalid signature");\r
\r
return signer;\r
}\r
}"
},
"contracts/util/EIP712.sol": {
"content": "/**\r
* SPDX-License-Identifier: MIT\r
*\r
* Copyright (c) 2018-2020 CENTRE SECZ\r
*\r
* Permission is hereby granted, free of charge, to any person obtaining a copy\r
* of this software and associated documentation files (the "Software"), to deal\r
* in the Software without restriction, including without limitation the rights\r
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
* copies of the Software, and to permit persons to whom the Software is\r
* furnished to do so, subject to the following conditions:\r
*\r
* The above copyright notice and this permission notice shall be included in\r
* copies or substantial portions of the Software.\r
*\r
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
* SOFTWARE.\r
*/\r
\r
pragma solidity 0.8.11;\r
\r
import "./ECRecover.sol";\r
\r
/**\r
* @title EIP712\r
* @notice A library that provides EIP712 helper functions\r
*/\r
library EIP712 {\r
/**\r
* @notice Make EIP712 domain separator\r
* @param name Contract name\r
* @param version Contract version\r
* @return Domain separator\r
*/\r
function makeDomainSeparator(string memory name, string memory version)\r
internal\r
view\r
returns (bytes32)\r
{\r
uint256 chainId;\r
assembly {\r
chainId := chainid()\r
}\r
return\r
keccak256(\r
abi.encode(\r
// keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")\r
0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f,\r
keccak256(bytes(name)),\r
keccak256(bytes(version)),\r
chainId,\r
address(this)\r
)\r
);\r
}\r
\r
/**\r
* @notice Recover signer's address from a EIP712 signature\r
* @param domainSeparator Domain separator\r
* @param v v of the signature\r
* @param r r of the signature\r
* @param s s of the signature\r
* @param typeHashAndData Type hash concatenated with data\r
* @return Signer's address\r
*/\r
function recover(\r
bytes32 domainSeparator,\r
uint8 v,\r
bytes32 r,\r
bytes32 s,\r
bytes memory typeHashAndData\r
) internal pure returns (address) {\r
bytes32 digest = keccak256(\r
abi.encodePacked(\r
"\x19\x01",\r
domainSeparator,\r
keccak256(typeHashAndData)\r
)\r
);\r
return ECRecover.recover(digest, v, r, s);\r
}\r
}"
},
"contracts/util/IERC20.sol": {
"content": "// SPDX-License-Identifier: MIT\r
// OpenZeppelin Contracts v4.4.0 (token/ERC20/IERC20.sol)\r
\r
pragma solidity 0.8.11;\r
\r
/**\r
* @dev Forked from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/4961a51cc736c7d4aa9bd2e11e4cbbaff73efee9/contracts/token/ERC20/IERC20.sol\r
* Modifications:\r
* 1. Change solidity version to 0.8.11\r
*/\r
/**\r
* @dev Interface of the ERC20 standard as defined in the EIP.\r
*/\r
interface IERC20 {\r
/**\r
* @dev Returns the amount of tokens in existence.\r
*/\r
function totalSupply() external view returns (uint256);\r
\r
/**\r
* @dev Returns the amount of tokens owned by `account`.\r
*/\r
function balanceOf(address account) external view returns (uint256);\r
\r
/**\r
* @dev Moves `amount` tokens from the caller's account to `recipient`.\r
*\r
* Returns a boolean value indicating whether the operation succeeded.\r
*\r
* Emits a {Transfer} event.\r
*/\r
function transfer(address recipient, uint256 amount) external returns (bool);\r
\r
/**\r
* @dev Returns the remaining number of tokens that `spender` will be\r
* allowed to spend on behalf of `owner` through {transferFrom}. This is\r
* zero by default.\r
*\r
* This value changes when {approve} or {transferFrom} are called.\r
*/\r
function allowance(address owner, address spender) external view returns (uint256);\r
\r
/**\r
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\r
*\r
* Returns a boolean value indicating whether the operation succeeded.\r
*\r
* IMPORTANT: Beware that changing an allowance with this method brings the risk\r
* that someone may use both the old and the new allowance by unfortunate\r
* transaction ordering. One possible solution to mitigate this race\r
* condition is to first reduce the spender's allowance to 0 and set the\r
* desired value afterwards:\r
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\r
*\r
* Emits an {Approval} event.\r
*/\r
function approve(address spender, uint256 amount) external returns (bool);\r
\r
/**\r
* @dev Moves `amount` tokens from `sender` to `recipient` using the\r
* allowance mechanism. `amount` is then deducted from the caller's\r
* allowance.\r
*\r
* Returns a boolean value indicating whether the operation succeeded.\r
*\r
* Emits a {Transfer} event.\r
*/\r
function transferFrom(\r
address sender,\r
address recipient,\r
uint256 amount\r
) external returns (bool);\r
\r
/**\r
* @dev Emitted when `value` tokens are moved from one account (`from`) to\r
* another (`to`).\r
*\r
* Note that `value` may be zero.\r
*/\r
event Transfer(address indexed from, address indexed to, uint256 value);\r
\r
/**\r
* @dev Emitted when the allowance of a `spender` for an `owner` is set by\r
* a call to {approve}. `value` is the new allowance.\r
*/\r
event Approval(address indexed owner, address indexed spender, uint256 value);\r
}"
},
"contracts/util/StorageSlot.sol": {
"content": "// SPDX-License-Identifier: MIT\r
\r
pragma solidity 0.8.11;\r
\r
/**\r
* @dev Forked from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/4961a51cc736c7d4aa9bd2e11e4cbbaff73efee9/contracts/utils/StorageSlot.sol\r
* Modifications:\r
* 1. Change solidity version to 0.8.11\r
*/\r
/**\r
* @dev Library for reading and writing primitive types to specific storage slots.\r
*\r
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\r
* This library helps with reading and writing to such slots without the need for inline assembly.\r
*\r
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\r
*\r
* Example usage to set ERC1967 implementation slot:\r
* ```\r
* contract ERC1967 {\r
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\r
*\r
* function _getImplementation() internal view returns (address) {\r
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\r
* }\r
*\r
* function _setImplementation(address newImplementation) internal {\r
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");\r
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\r
* }\r
* }\r
* ```\r
*\r
* _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._\r
*/\r
library StorageSlot {\r
struct AddressSlot {\r
address value;\r
}\r
\r
struct BooleanSlot {\r
bool value;\r
}\r
\r
struct Bytes32Slot {\r
bytes32 value;\r
}\r
\r
struct Uint256Slot {\r
uint256 value;\r
}\r
\r
/**\r
* @dev Returns an `AddressSlot` with member `value` located at `slot`.\r
*/\r
function getAddressSlot(bytes32 slot)\r
internal\r
pure\r
returns (AddressSlot storage r)\r
{\r
assembly {\r
r.slot := slot\r
}\r
}\r
\r
/**\r
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.\r
*/\r
function getBooleanSlot(bytes32 slot)\r
internal\r
pure\r
returns (BooleanSlot storage r)\r
{\r
assembly {\r
r.slot := slot\r
}\r
}\r
\r
/**\r
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.\r
*/\r
function getBytes32Slot(bytes32 slot)\r
internal\r
pure\r
returns (Bytes32Slot storage r)\r
{\r
assembly {\r
r.slot := slot\r
}\r
}\r
\r
/**\r
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.\r
*/\r
function getUint256Slot(bytes32 slot)\r
internal\r
pure\r
returns (Uint256Slot storage r)\r
{\r
assembly {\r
r.slot := slot\r
}\r
}\r
}\r
"
},
"contracts/v1/AbstractFiatTokenV1.sol": {
"content": "/**\r
* SPDX-License-Identifier: MIT\r
*\r
* Copyright (c) 2018-2020 CENTRE SECZ\r
* Copyright (c) 2022 JPYC\r
*\r
* Permission is hereby granted, free of charge, to any person obtaining a copy\r
* of this software and associated documentation files (the "Software"), to deal\r
* in the Software without restriction, including without limitation the rights\r
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
* copies of the Software, and to permit persons to whom the Software is\r
* furnished to do so, subject to the following conditions:\r
*\r
* The above copyright notice and this permission notice shall be included in\r
* copies or substantial portions of the Software.\r
*\r
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
* SOFTWARE.\r
*/\r
\r
pragma solidity 0.8.11;\r
\r
import "../util/IERC20.sol";\r
\r
/**\r
* @notice base abstract contract to inherit IERC20\r
* @dev Forked from https://github.com/centrehq/centre-tokens/blob/37039f00534d3e5148269adf98bd2d42ea9fcfd7/contracts/v1/AbstractFiatTokenV1.sol\r
* Modifications:\r
* 1. Change solidity version to 0.8.11\r
* 2. Add gap\r
* 3. Add functions: _increaseAllowance & _decreaseAllowance\r
*/\r
\r
abstract contract AbstractFiatTokenV1 is IERC20 {\r
function _approve(\r
address owner,\r
address spender,\r
uint256 value\r
) internal virtual;\r
\r
function _transfer(\r
address from,\r
address to,\r
uint256 value\r
) internal virtual;\r
\r
function _increaseAllowance(\r
address owner,\r
address spender,\r
uint256 increment\r
) internal virtual;\r
\r
function _decreaseAllowance(\r
address owner,\r
address spender,\r
uint256 decrement\r
) internal virtual;\r
\r
uint256[50] private __gap;\r
}"
},
"contracts/v1/Blocklistable.sol": {
"content": "/**\r
* SPDX-License-Identifier: MIT\r
*\r
* Copyright (c) 2018-2020 CENTRE SECZ\r
* Copyright (c) 2022 JPYC\r
*\r
* Permission is hereby granted, free of charge, to any person obtaining a copy\r
* of this software and associated documentation files (the "Software"), to deal\r
* in the Software without restriction, including without limitation the rights\r
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
* copies of the Software, and to permit persons to whom the Software is\r
* furnished to do so, subject to the following conditions:\r
*\r
* The above copyright notice and this permission notice shall be included in\r
* copies or substantial portions of the Software.\r
*\r
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
* SOFTWARE.\r
*/\r
\r
pragma solidity 0.8.11;\r
\r
import "./Ownable.sol";\r
\r
/**\r
* @dev Forked from https://github.com/centrehq/centre-tokens/blob/37039f00534d3e5148269adf98bd2d42ea9fcfd7/contracts/v1/Blacklistable.sol\r
* Modifications:\r
* 1. Change solidity version to 0.8.11\r
* 2. Change bool -> uint256 for gas optimization\r
* 3. Change blacklist -> blocklist\r
* 4. Add gap\r
*/\r
/**\r
* @title Blocklistable Token\r
* @dev Allows accounts to be blocklisted by a "blocklister" role\r
*/\r
contract Blocklistable is Ownable {\r
address public blocklister;\r
mapping(address => uint256) internal blocklisted;\r
\r
event Blocklisted(address indexed _account);\r
event UnBlocklisted(address indexed _account);\r
event BlocklisterChanged(address indexed newBlocklister);\r
\r
/**\r
* @dev Throws if called by any account other than the blocklister\r
*/\r
modifier onlyBlocklister() {\r
require(\r
msg.sender == blocklister,\r
"Blocklistable: caller is not the blocklister"\r
);\r
_;\r
}\r
\r
/**\r
* @dev Throws if argument account is blocklisted\r
* @param _account The address to check\r
*/\r
modifier notBlocklisted(address _account) {\r
require(\r
blocklisted[_account] == 0,\r
"Blocklistable: account is blocklisted"\r
);\r
_;\r
}\r
\r
/**\r
* @dev Checks if account is blocklisted\r
* @param _account The address to check\r
* @return True if account is blocklisted\r
*/\r
function isBlocklisted(address _account) external view returns (bool) {\r
return blocklisted[_account] == 1;\r
}\r
\r
/**\r
* @dev Adds account to blocklist\r
* @param _account The address to blocklist\r
*/\r
function blocklist(address _account) external onlyBlocklister {\r
blocklisted[_account] = 1;\r
emit Blocklisted(_account);\r
}\r
\r
/**\r
* @dev Removes account from blocklist\r
* @param _account The address to remove from the blocklist\r
*/\r
function unBlocklist(address _account) external onlyBlocklister {\r
blocklisted[_account] = 0;\r
emit UnBlocklisted(_account);\r
}\r
\r
function updateBlocklister(address _newBlocklister) external onlyOwner {\r
require(\r
_newBlocklister != address(0),\r
"Blocklistable: new blocklister is the zero address"\r
);\r
blocklister = _newBlocklister;\r
emit BlocklisterChanged(blocklister);\r
}\r
\r
uint256[50] private __gap;\r
}"
},
"contracts/v1/EIP2612.sol": {
"content": "/**\r
* SPDX-License-Identifier: MIT\r
*\r
* Copyright (c) 2018-2020 CENTRE SECZ\r
* Copyright (c) 2022 JPYC\r
*\r
* Permission is hereby granted, free of charge, to any person obtaining a copy\r
* of this software and associated documentation files (the "Software"), to deal\r
* in the Software without restriction, including without limitation the rights\r
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
* copies of the Software, and to permit persons to whom the Software is\r
* furnished to do so, subject to the following conditions:\r
*\r
* The above copyright notice and this permission notice shall be included in\r
* copies or substantial portions of the Software.\r
*\r
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
* SOFTWARE.\r
*/\r
\r
pragma solidity 0.8.11;\r
\r
import "./AbstractFiatTokenV1.sol";\r
import "./EIP712Domain.sol";\r
import "../util/EIP712.sol";\r
\r
/**\r
* @dev Forked from https://github.com/centrehq/centre-tokens/blob/37039f00534d3e5148269adf98bd2d42ea9fcfd7/contracts/v2/EIP2612.sol\r
* Modifications:\r
* 1. Change solidity version to 0.8.11\r
* 2. Make domain separator dynamic by adding function: domainSeparatorV4\r
* 3. Add gap\r
* 4. Change now to block.timestamp\r
*/\r
\r
/**\r
* @title EIP-2612\r
* @notice Provide internal implementation for gas-abstracted approvals\r
*/\r
abstract contract EIP2612 is AbstractFiatTokenV1, EIP712Domain {\r
// keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)")\r
bytes32 public constant PERMIT_TYPEHASH =\r
0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;\r
\r
mapping(address => uint256) private _permitNonces;\r
\r
/**\r
* @notice Nonces for permit\r
* @param owner Token owner's address (Authorizer)\r
* @return Next nonce\r
*/\r
function nonces(address owner) external view returns (uint256) {\r
return _permitNonces[owner];\r
}\r
\r
/**\r
* @notice Verify a signed approval permit and execute if valid\r
* @param owner Token owner's address (Authorizer)\r
* @param spender Spender's address\r
* @param value Amount of allowance\r
* @param deadline The time at which this expires (unix time)\r
* @param v v of the signature\r
* @param r r of the signature\r
* @param s s of the signature\r
*/\r
function _permit(\r
address owner,\r
address spender,\r
uint256 value,\r
uint256 deadline,\r
uint8 v,\r
bytes32 r,\r
bytes32 s\r
) internal {\r
require(deadline >= block.timestamp, "EIP2612: permit is expired");\r
\r
bytes memory data = abi.encode(\r
PERMIT_TYPEHASH,\r
owner,\r
spender,\r
value,\r
_permitNonces[owner]++,\r
deadline\r
);\r
require(\r
EIP712.recover(_domainSeparatorV4(), v, r, s, data) == owner,\r
"EIP2612: invalid signature"\r
);\r
\r
_approve(owner, spender, value);\r
}\r
\r
uint256[50] private __gap;\r
}\r
"
},
"contracts/v1/EIP3009.sol": {
"content": "/**\r
* SPDX-License-Identifier: MIT\r
*\r
* Copyright (c) 2018-2020 CENTRE SECZ\r
* Copyright (c) 2022 JPYC\r
*\r
* Permission is hereby granted, free of charge, to any person obtaining a copy\r
* of this software and associated documentation files (the "Software"), to deal\r
* in the Software without restriction, including without limitation the rights\r
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
* copies of the Software, and to permit persons to whom the Software is\r
* furnished to do so, subject to the following conditions:\r
*\r
* The above copyright notice and this permission notice shall be included in\r
* copies or substantial portions of the Software.\r
*\r
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
* SOFTWARE.\r
*/\r
\r
pragma solidity 0.8.11;\r
\r
import "./AbstractFiatTokenV1.sol";\r
import "./EIP712Domain.sol";\r
import "../util/EIP712.sol";\r
\r
/**\r
* @dev Forked from https://github.com/centrehq/centre-tokens/blob/37039f00534d3e5148269adf98bd2d42ea9fcfd7/contracts/v2/EIP3009.sol\r
* Modifications:\r
* 1. Change solidity version to 0.8.11\r
* 2. Make domain separator dynamic by adding function: domainSeparatorV4\r
* 3. Change _authorizationStates to uint256 for gas optimization\r
* 4. Change now to block.timestamp\r
* 5. Add gap\r
*/\r
\r
/**\r
* @title EIP-3009\r
* @notice Provide internal implementation for gas-abstracted transfers\r
* @dev Contracts that inherit from this must wrap these with publicly\r
* accessible functions, optionally adding modifiers where necessary\r
*/\r
abstract contract EIP3009 is AbstractFiatTokenV1, EIP712Domain {\r
// keccak256("TransferWithAuthorization(address from,address to,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)")\r
bytes32 public constant TRANSFER_WITH_AUTHORIZATION_TYPEHASH =\r
0x7c7c6cdb67a18743f49ec6fa9b35f50d52ed05cbed4cc592e13b44501c1a2267;\r
\r
// keccak256("ReceiveWithAuthorization(address from,address to,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)")\r
bytes32 public constant RECEIVE_WITH_AUTHORIZATION_TYPEHASH =\r
0xd099cc98ef71107a616c4f0f941f04c322d8e254fe26b3c6668db87aae413de8;\r
\r
// keccak256("CancelAuthorization(address authorizer,bytes32 nonce)")\r
bytes32 public constant CANCEL_AUTHORIZATION_TYPEHASH =\r
0x158b0a9edf7a828aad02f63cd515c68ef2f50ba807396f6d12842833a1597429;\r
\r
/**\r
* @dev authorizer address => nonce => bool (true if nonce is used)\r
*/\r
mapping(address => mapping(bytes32 => uint256)) private _authorizationStates;\r
\r
event AuthorizationUsed(address indexed authorizer, bytes32 indexed nonce);\r
event AuthorizationCanceled(\r
address indexed authorizer,\r
bytes32 indexed nonce\r
);\r
\r
/**\r
* @notice Returns the state of an authorization\r
* @dev Nonces are randomly generated 32-byte data unique to the\r
* authorizer's address\r
* @param authorizer Authorizer's address\r
* @param nonce Nonce of the authorization\r
* @return True if the nonce is used\r
*/\r
function authorizationState(address authorizer, bytes32 nonce)\r
external\r
view\r
returns (bool)\r
{\r
return _authorizationStates[authorizer][nonce] == 1;\r
}\r
\r
/**\r
* @notice Execute a transfer with a signed authorization\r
* @param from Payer's address (Authorizer)\r
* @param to Payee's address\r
* @param value Amount to be transferred\r
* @param validAfter The time after which this is valid (unix time)\r
* @param validBefore The time before which this is valid (unix time)\r
* @param nonce Unique nonce\r
* @param v v of the signature\r
* @param r r of the signature\r
* @param s s of the signature\r
*/\r
function _transferWithAuthorization(\r
address from,\r
address to,\r
uint256 value,\r
uint256 validAfter,\r
uint256 validBefore,\r
bytes32 nonce,\r
uint8 v,\r
bytes32 r,\r
bytes32 s\r
) internal {\r
_requireValidAuthorization(from, nonce, validAfter, validBefore);\r
\r
bytes memory data = abi.encode(\r
TRANSFER_WITH_AUTHORIZATION_TYPEHASH,\r
from,\r
to,\r
value,\r
validAfter,\r
validBefore,\r
nonce\r
);\r
require(\r
EIP712.recover(_domainSeparatorV4(), v, r, s, data) == from,\r
"EIP3009: invalid signature"\r
);\r
\r
_markAuthorizationAsUsed(from, nonce);\r
_transfer(from, to, value);\r
}\r
\r
/**\r
* @notice Receive a transfer with a signed authorization from the payer\r
* @dev This has an additional check to ensure that the payee's address\r
* matches the caller of this function to prevent front-running attacks.\r
* @param from Payer's address (Authorizer)\r
* @param to Payee's address\r
* @param value Amount to be transferred\r
* @param validAfter The time after which this is valid (unix time)\r
* @param validBefore The time before which this is valid (unix time)\r
* @param nonce Unique nonce\r
* @param v v of the signature\r
* @param r r of the signature\r
* @param s s of the signature\r
*/\r
function _receiveWithAuthorization(\r
address from,\r
address to,\r
uint256 value,\r
uint256 validAfter,\r
uint256 validBefore,\r
bytes32 nonce,\r
uint8 v,\r
bytes32 r,\r
bytes32 s\r
) internal {\r
require(to == msg.sender, "EIP3009: caller must be the payee");\r
_requireValidAuthorization(from, nonce, validAfter, validBefore);\r
\r
bytes memory data = abi.encode(\r
RECEIVE_WITH_AUTHORIZATION_TYPEHASH,\r
from,\r
to,\r
value,\r
validAfter,\r
validBefore,\r
nonce\r
);\r
require(\r
EIP712.recover(_domainSeparatorV4(), v, r, s, data) == from,\r
"EIP3009: invalid signature"\r
);\r
\r
_markAuthorizationAsUsed(from, nonce);\r
_transfer(from, to, value);\r
}\r
\r
/**\r
* @notice Attempt to cancel an authorization\r
* @param authorizer Authorizer's address\r
* @param nonce Nonce of the authorization\r
* @param v v of the signature\r
* @param r r of the signature\r
* @param s s of the signature\r
*/\r
function _cancelAuthorization(\r
address authorizer,\r
bytes32 nonce,\r
uint8 v,\r
bytes32 r,\r
bytes32 s\r
) internal {\r
_requireUnusedAuthorization(authorizer, nonce);\r
\r
bytes memory data = abi.encode(\r
CANCEL_AUTHORIZATION_TYPEHASH,\r
authorizer,\r
nonce\r
);\r
require(\r
EIP712.recover(_domainSeparatorV4(), v, r, s, data) == authorizer,\r
"EIP3009: invalid signature"\r
);\r
\r
_authorizationStates[authorizer][nonce] = 1;\r
emit AuthorizationCanceled(authorizer, nonce);\r
}\r
\r
/**\r
* @notice Check that an authorization is unused\r
* @param authorizer Authorizer's address\r
* @param nonce Nonce of the authorization\r
*/\r
function _requireUnusedAuthorization(address authorizer, bytes32 nonce)\r
private\r
view\r
{\r
require(\r
_authorizationStates[authorizer][nonce] == 0,\r
"EIP3009: authorization is used or canceled"\r
);\r
}\r
\r
/**\r
* @notice Check that authorization is valid\r
* @param authorizer Authorizer's address\r
* @param nonce Nonce of the authorization\r
* @param validAfter The time after which this is valid (unix time)\r
* @param validBefore The time before which this is valid (unix time)\r
*/\r
function _requireValidAuthorization(\r
address authorizer,\r
bytes32 nonce,\r
uint256 validAfter,\r
uint256 validBefore\r
) private view {\r
require(\r
block.timestamp > validAfter,\r
"EIP3009: authorization is not yet valid"\r
);\r
require(\r
block.timestamp < validBefore,\r
"EIP3009: authorization is expired"\r
);\r
_requireUnusedAuthorization(authorizer, nonce);\r
}\r
\r
/**\r
* @notice Mark an authorization as used\r
* @param authorizer Authorizer's address\r
* @param nonce Nonce of the authorization\r
*/\r
function _markAuthorizationAsUsed(address authorizer, bytes32 nonce)\r
private\r
{\r
_authorizationStates[authorizer][nonce] = 1;\r
emit AuthorizationUsed(authorizer, nonce);\r
}\r
\r
uint256[50] private __gap;\r
}\r
"
},
"contracts/v1/EIP712Domain.sol": {
"content": "/**\r
* SPDX-License-Identifier: MIT\r
*\r
* Copyright (c) 2018-2020 CENTRE SECZ\r
*\r
* Permission is hereby granted, free of charge, to any person obtaining a copy\r
* of this software and associated documentation files (the "Software"), to deal\r
* in the Software without restriction, including without limitation the rights\r
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
* copies of the Software, and to permit persons to whom the Software is\r
* furnished to do so, subject to the following conditions:\r
*\r
* The above copyright notice and this permission notice shall be included in\r
* copies or substantial portions of the Software.\r
*\r
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
* SOFTWARE.\r
*/\r
\r
pragma solidity 0.8.11;\r
\r
import "../util/EIP712.sol";\r
\r
/**\r
* @dev Forked from https://github.com/centrehq/centre-tokens/blob/37039f00534d3e5148269adf98bd2d42ea9fcfd7/contracts/v2/EIP712Domain.sol\r
* Modifications:\r
* 1. Change solidity version to 0.8.11\r
* 2. Add 4 new state variables: DOMAIN_SEPARATOR, CHAIN_ID, NAME, VERSION\r
* 3. Add new function _domainSeparatorV4\r
* 4. Add gap\r
*/\r
\r
/**\r
* @title EIP712 Domain\r
*/\r
contract EIP712Domain {\r
/**\r
* @dev EIP712 Domain Separator\r
*/\r
bytes32 internal DOMAIN_SEPARATOR;\r
uint256 internal CHAIN_ID;\r
string internal NAME;\r
string internal VERSION;\r
\r
/**\r
* @dev Returns the domain separator for the current chain.\r
*/\r
function _domainSeparatorV4() public view returns (bytes32) {\r
if(block.chainid == CHAIN_ID) {\r
return DOMAIN_SEPARATOR;\r
} else {\r
return EIP712.makeDomainSeparator(NAME, VERSION);\r
}\r
}\r
\r
uint256[50] private __gap;\r
}"
},
"contracts/v1/FiatTokenV1.sol": {
"content": "/**\r
* SPDX-License-Identifier: MIT\r
*\r
* Copyright (c) 2018-2020 CENTRE SECZ\r
* Copyright (c) 2022 JPYC\r
*\r
* Permission is hereby granted, free of charge, to any person obtaining a copy\r
* of this software and associated documentation files (the "Software"), to deal\r
* in the Software without restriction, including without limitation the rights\r
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
* copies of the Software, and to permit persons to whom the Software is\r
* furnished to do so, subject to the following conditions:\r
*\r
* The above copyright notice and this permission notice shall be included in\r
* copies or substantial portions of the Software.\r
*\r
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
* SOFTWARE.\r
*/\r
\r
pragma solidity 0.8.11;\r
\r
import "./Ownable.sol";\r
import "./Pausable.sol";\r
import "./Blocklistable.sol";\r
import "../util/EIP712.sol";\r
import "./Rescuable.sol";\r
import "./EIP3009.sol";\r
import "./EIP2612.sol";\r
import "../upgradeability/UUPSUpgradeable.sol";\r
\r
/**\r
* @dev ERC20 Token backed by fiat reserves. Forked from\r
* https://github.com/centrehq/centre-tokens/blob/37039f00534d3e5148269adf98bd2d42ea9fcfd7/contracts/v1/FiatTokenV1.sol,\r
* https://github.com/centrehq/centre-tokens/blob/37039f00534d3e5148269adf98bd2d42ea9fcfd7/contracts/v1.1/FiatTokenV1_1.sol,\r
* https://github.com/centrehq/centre-tokens/blob/37039f00534d3e5148269adf98bd2d42ea9fcfd7/contracts/v2/FiatTokenV2.sol,\r
* https://github.com/centrehq/centre-tokens/blob/37039f00534d3e5148269adf98bd2d42ea9fcfd7/contracts/v2/FiatTokenV2_1.sol\r
* Modifications:\r
* 1. Change solidity version to 0.8.11\r
* 2. Use cashe for gas optimization\r
* 3. Let initialize function initialize a rescuer\r
* 4. Change materMinter -> minterAdmin\r
* 5. Use initializedVersion to manage the version\r
* 6. Check if the approved amount is max amount for gas optimization\r
*/\r
\r
/**\r
* @title FiatToken\r
* @dev ERC20 Token backed by fiat reserves\r
*/\r
contract FiatTokenV1 is\r
Ownable,\r
Pausable,\r
Blocklistable,\r
Rescuable,\r
EIP3009,\r
EIP2612,\r
UUPSUpgradeable\r
{\r
string public name;\r
string public symbol;\r
string public currency;\r
uint256 internal totalSupply_;\r
address public minterAdmin;\r
uint8 public decimals;\r
uint8 internal initializedVersion;\r
\r
mapping(address => uint256) internal balances;\r
mapping(address => mapping(address => uint256)) internal allowed;\r
mapping(address => bool) internal minters;\r
mapping(address => uint256) internal minterAllowed;\r
\r
event Mint(address indexed minter, address indexed to, uint256 amount);\r
event Burn(address indexed burner, uint256 amount);\r
event MinterConfigured(address indexed minter, uint256 minterAllowedAmount);\r
event MinterRemoved(address indexed oldMinter);\r
event MinterAdminChanged(address indexed newMinterAdmin);\r
\r
function initialize(\r
string memory tokenName,\r
string memory tokenSymbol,\r
string memory tokenCurrency,\r
uint8 tokenDecimals,\r
address newMinterAdmin,\r
address newPauser,\r
address newBlocklister,\r
address newRescuer,\r
address newOwner\r
) public {\r
require(\r
initializedVersion == 0,\r
"FiatToken: contract is already initialized"\r
);\r
require(\r
newMinterAdmin != address(0),\r
"FiatToken: new minterAdmin is the zero address"\r
);\r
require(\r
newPauser != address(0),\r
"FiatToken: new pauser is the zero address"\r
);\r
require(\r
newBlocklister != address(0),\r
"FiatToken: new blocklister is the zero address"\r
);\r
require(\r
newRescuer != address(0),\r
"FiatToken: new rescuer is the zero address"\r
);\r
require(\r
newOwner != address(0),\r
"FiatToken: new owner is the zero address"\r
);\r
\r
name = tokenName;\r
symbol = tokenSymbol;\r
currency = tokenCurrency;\r
decimals = tokenDecimals;\r
minterAdmin = newMinterAdmin;\r
pauser = newPauser;\r
blocklister = newBlocklister;\r
rescuer = newRescuer;\r
_transferOwnership(newOwner);\r
blocklisted[address(this)] = 1;\r
DOMAIN_SEPARATOR = EIP712.makeDomainSeparator(tokenName, "1");\r
CHAIN_ID = block.chainid;\r
NAME = tokenName;\r
VERSION = "1";\r
initializedVersion = 1;\r
}\r
\r
/**\r
* @dev Throws if called by any account other than a minter\r
*/\r
modifier onlyMinters() {\r
require(minters[msg.sender], "FiatToken: caller is not a minter");\r
_;\r
}\r
\r
/**\r
* @dev Function to mint tokens\r
* @param _to The address that will receive the minted tokens.\r
* @param _amount The amount of tokens to mint. Must be less than or equal\r
* to the minterAllowance of the caller.\r
* @return A boolean that indicates if the operation was successful.\r
*/\r
function mint(address _to, uint256 _amount)\r
external\r
whenNotPaused\r
onlyMinters\r
notBlocklisted(msg.sender)\r
notBlocklisted(_to)\r
returns (bool)\r
{\r
require(_to != address(0), "FiatToken: mint to the zero address");\r
require(_amount > 0, "FiatToken: mint amount not greater than 0");\r
\r
uint256 mintingAllowedAmount = minterAllowed[msg.sender];\r
require(\r
_amount <= mintingAllowedAmount,\r
"FiatToken: mint amount exceeds minterAllowance"\r
);\r
\r
totalSupply_ = totalSupply_ + _amount;\r
balances[_to] = balances[_to] + _amount;\r
minterAllowed[msg.sender] = mintingAllowedAmount - _amount;\r
emit Mint(msg.sender, _to, _amount);\r
emit Transfer(address(0), _to, _amount);\r
return true;\r
}\r
\r
/**\r
* @dev Throws if called by any account other than the minterAdmin\r
*/\r
modifier onlyMinterAdmin() {\r
require(\r
msg.sender == minterAdmin,\r
"FiatToken: caller is not the minterAdmin"\r
);\r
_;\r
}\r
\r
/**\r
* @dev Get minter allowance for an account\r
* @param minter The address of the minter\r
* @return Allowance of the minter can mint\r
*/\r
function minterAllowance(address minter) external view returns (uint256) {\r
return minterAllowed[minter];\r
}\r
\r
/**\r
* @dev Checks if account is a minter\r
* @param account The address to check\r
* @return True if account is a minter\r
*/\r
function isMinter(address account) external view returns (bool) {\r
return minters[account];\r
}\r
\r
/**\r
* @notice Amount of remaining tokens spender is allowed to transfer on\r
* behalf of the token owner\r
* @param owner Token owner's address\r
* @param spender Spender's address\r
* @return Allowance amount\r
*/\r
function allowance(address owner, address spender)\r
external\r
view\r
override\r
returns (uint256)\r
{\r
return allowed[owner][spender];\r
}\r
\r
/**\r
* @dev Get totalSupply of token\r
* @return TotalSupply\r
*/\r
function totalSupply() external view override returns (uint256) {\r
return totalSupply_;\r
}\r
\r
/**\r
* @dev Get token balance of an account\r
* @param account address The account\r
* @return Balance amount of the account\r
*/\r
function balanceOf(address account)\r
external\r
view\r
override\r
returns (uint256)\r
{\r
return balances[account];\r
}\r
\r
/**\r
* @notice Set spender's allowance over the caller's tokens to be a given\r
* value.\r
* @param spender Spender's address\r
* @param value Allowance amount\r
* @return True if successful\r
*/\r
function approve(address spender, uint256 value)\r
external\r
override\r
whenNotPaused\r
notBlocklisted(msg.sender)\r
notBlocklisted(spender)\r
returns (bool)\r
{\r
_approve(msg.sender, spender, value);\r
return true;\r
}\r
\r
/**\r
* @dev Internal function to set allowance\r
* @param owner Token owner's address\r
* @param spender Spender's address\r
* @param value Allowance amount\r
*/\r
function _approve(\r
address owner,\r
address spender,\r
uint256 value\r
) internal override {\r
require(owner != address(0), "FiatToken: approve from the zero address");\r
require(spender != address(0), "FiatToken: approve to the zero address");\r
allowed[owner][spender] = value;\r
emit Approval(owner, spender, value);\r
}\r
\r
/**\r
* @notice Transfer tokens by spending allowance\r
* @param from Payer's address\r
* @param to Payee's address\r
* @param value Transfer amount\r
* @return True if successful\r
*/\r
function transferFrom(\r
address from,\r
address to,\r
uint256 value\r
)\r
external\r
override\r
whenNotPaused\r
notBlocklisted(msg.
Submitted on: 2025-09-17 12:45:56
Comments
Log in to comment.
No comments yet.