Implement recommendations from 5.0 audit Phase 1A (#4398)
Co-authored-by: Francisco Giordano <fg@frang.io> Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
This commit is contained in:
@ -427,8 +427,9 @@ contract TimelockController is AccessControl, ERC721Holder, ERC1155Holder {
|
||||
* an operation where the timelock is the target and the data is the ABI-encoded call to this function.
|
||||
*/
|
||||
function updateDelay(uint256 newDelay) external virtual {
|
||||
if (msg.sender != address(this)) {
|
||||
revert TimelockUnauthorizedCaller(msg.sender);
|
||||
address sender = _msgSender();
|
||||
if (sender != address(this)) {
|
||||
revert TimelockUnauthorizedCaller(sender);
|
||||
}
|
||||
emit MinDelayChange(_minDelay, newDelay);
|
||||
_minDelay = newDelay;
|
||||
|
||||
@ -19,9 +19,9 @@ interface IVotes {
|
||||
event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
|
||||
|
||||
/**
|
||||
* @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of votes.
|
||||
* @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of voting units.
|
||||
*/
|
||||
event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance);
|
||||
event DelegateVotesChanged(address indexed delegate, uint256 previousVotes, uint256 newVotes);
|
||||
|
||||
/**
|
||||
* @dev Returns the current amount of votes that `account` has.
|
||||
|
||||
@ -118,6 +118,7 @@ interface IERC1155Errors {
|
||||
* @param sender Address whose tokens are being transferred.
|
||||
* @param balance Current balance for the interacting account.
|
||||
* @param needed Minimum amount required to perform a transfer.
|
||||
* @param tokenId Identifier number of a token.
|
||||
*/
|
||||
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
|
||||
|
||||
|
||||
@ -58,16 +58,12 @@ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IER
|
||||
* Clients calling this function must replace the `\{id\}` substring with the
|
||||
* actual token type ID.
|
||||
*/
|
||||
function uri(uint256) public view virtual returns (string memory) {
|
||||
function uri(uint256 /* id */) public view virtual returns (string memory) {
|
||||
return _uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev See {IERC1155-balanceOf}.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `account` cannot be the zero address.
|
||||
*/
|
||||
function balanceOf(address account, uint256 id) public view virtual returns (uint256) {
|
||||
return _balances[id][account];
|
||||
@ -114,11 +110,12 @@ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IER
|
||||
/**
|
||||
* @dev See {IERC1155-safeTransferFrom}.
|
||||
*/
|
||||
function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes memory data) public virtual {
|
||||
if (from != _msgSender() && !isApprovedForAll(from, _msgSender())) {
|
||||
revert ERC1155MissingApprovalForAll(_msgSender(), from);
|
||||
function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) public virtual {
|
||||
address sender = _msgSender();
|
||||
if (from != sender && !isApprovedForAll(from, sender)) {
|
||||
revert ERC1155MissingApprovalForAll(sender, from);
|
||||
}
|
||||
_safeTransferFrom(from, to, id, amount, data);
|
||||
_safeTransferFrom(from, to, id, value, data);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -128,17 +125,18 @@ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IER
|
||||
address from,
|
||||
address to,
|
||||
uint256[] memory ids,
|
||||
uint256[] memory amounts,
|
||||
uint256[] memory values,
|
||||
bytes memory data
|
||||
) public virtual {
|
||||
if (from != _msgSender() && !isApprovedForAll(from, _msgSender())) {
|
||||
revert ERC1155MissingApprovalForAll(_msgSender(), from);
|
||||
address sender = _msgSender();
|
||||
if (from != sender && !isApprovedForAll(from, sender)) {
|
||||
revert ERC1155MissingApprovalForAll(sender, from);
|
||||
}
|
||||
_safeBatchTransferFrom(from, to, ids, amounts, data);
|
||||
_safeBatchTransferFrom(from, to, ids, values, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`. Will mint (or burn) if `from` (or `to`) is the zero address.
|
||||
* @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`. Will mint (or burn) if `from` (or `to`) is the zero address.
|
||||
*
|
||||
* Emits a {TransferSingle} event if the arrays contain one element, and {TransferBatch} otherwise.
|
||||
*
|
||||
@ -146,75 +144,96 @@ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IER
|
||||
*
|
||||
* - If `to` refers to a smart contract, it must implement either {IERC1155Receiver-onERC1155Received}
|
||||
* or {IERC1155Receiver-onERC1155BatchReceived} and return the acceptance magic value.
|
||||
* - `ids` and `values` must have the same length.
|
||||
*
|
||||
* NOTE: The ERC-1155 acceptance check is not performed in this function. See {_updateWithAcceptanceCheck} instead.
|
||||
*/
|
||||
function _update(
|
||||
address from,
|
||||
address to,
|
||||
uint256[] memory ids,
|
||||
uint256[] memory amounts,
|
||||
bytes memory data
|
||||
) internal virtual {
|
||||
if (ids.length != amounts.length) {
|
||||
revert ERC1155InvalidArrayLength(ids.length, amounts.length);
|
||||
function _update(address from, address to, uint256[] memory ids, uint256[] memory values) internal virtual {
|
||||
if (ids.length != values.length) {
|
||||
revert ERC1155InvalidArrayLength(ids.length, values.length);
|
||||
}
|
||||
|
||||
address operator = _msgSender();
|
||||
|
||||
for (uint256 i = 0; i < ids.length; ++i) {
|
||||
uint256 id = ids.unsafeMemoryAccess(i);
|
||||
uint256 amount = amounts.unsafeMemoryAccess(i);
|
||||
uint256 value = values.unsafeMemoryAccess(i);
|
||||
|
||||
if (from != address(0)) {
|
||||
uint256 fromBalance = _balances[id][from];
|
||||
if (fromBalance < amount) {
|
||||
revert ERC1155InsufficientBalance(from, fromBalance, amount, id);
|
||||
if (fromBalance < value) {
|
||||
revert ERC1155InsufficientBalance(from, fromBalance, value, id);
|
||||
}
|
||||
unchecked {
|
||||
_balances[id][from] = fromBalance - amount;
|
||||
// Overflow not possible: value <= fromBalance
|
||||
_balances[id][from] = fromBalance - value;
|
||||
}
|
||||
}
|
||||
|
||||
if (to != address(0)) {
|
||||
_balances[id][to] += amount;
|
||||
_balances[id][to] += value;
|
||||
}
|
||||
}
|
||||
|
||||
if (ids.length == 1) {
|
||||
uint256 id = ids.unsafeMemoryAccess(0);
|
||||
uint256 amount = amounts.unsafeMemoryAccess(0);
|
||||
emit TransferSingle(operator, from, to, id, amount);
|
||||
if (to != address(0)) {
|
||||
_doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
|
||||
}
|
||||
uint256 value = values.unsafeMemoryAccess(0);
|
||||
emit TransferSingle(operator, from, to, id, value);
|
||||
} else {
|
||||
emit TransferBatch(operator, from, to, ids, amounts);
|
||||
if (to != address(0)) {
|
||||
_doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);
|
||||
emit TransferBatch(operator, from, to, ids, values);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Version of {_update} that performs the token acceptance check by calling {IERC1155Receiver-onERC1155Received}
|
||||
* or {IERC1155Receiver-onERC1155BatchReceived} on the receiver address if it contains code (eg. is a smart contract
|
||||
* at the moment of execution).
|
||||
*
|
||||
* IMPORTANT: Overriding this function is discouraged because it poses a reentrancy risk from the receiver. So any
|
||||
* update to the contract state after this function would break the check-effect-interaction pattern. Consider
|
||||
* overriding {_update} instead.
|
||||
*/
|
||||
function _updateWithAcceptanceCheck(
|
||||
address from,
|
||||
address to,
|
||||
uint256[] memory ids,
|
||||
uint256[] memory values,
|
||||
bytes memory data
|
||||
) internal virtual {
|
||||
_update(from, to, ids, values);
|
||||
if (to != address(0)) {
|
||||
address operator = _msgSender();
|
||||
if (ids.length == 1) {
|
||||
uint256 id = ids.unsafeMemoryAccess(0);
|
||||
uint256 value = values.unsafeMemoryAccess(0);
|
||||
_doSafeTransferAcceptanceCheck(operator, from, to, id, value, data);
|
||||
} else {
|
||||
_doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, values, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
|
||||
* @dev Transfers a `value` tokens of token type `id` from `from` to `to`.
|
||||
*
|
||||
* Emits a {TransferSingle} event.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `to` cannot be the zero address.
|
||||
* - `from` must have a balance of tokens of type `id` of at least `amount`.
|
||||
* - `from` must have a balance of tokens of type `id` of at least `value` amount.
|
||||
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
|
||||
* acceptance magic value.
|
||||
*/
|
||||
function _safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes memory data) internal {
|
||||
function _safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) internal {
|
||||
if (to == address(0)) {
|
||||
revert ERC1155InvalidReceiver(address(0));
|
||||
}
|
||||
if (from == address(0)) {
|
||||
revert ERC1155InvalidSender(address(0));
|
||||
}
|
||||
(uint256[] memory ids, uint256[] memory amounts) = _asSingletonArrays(id, amount);
|
||||
_update(from, to, ids, amounts, data);
|
||||
(uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
|
||||
_updateWithAcceptanceCheck(from, to, ids, values, data);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -226,12 +245,13 @@ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IER
|
||||
*
|
||||
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
|
||||
* acceptance magic value.
|
||||
* - `ids` and `values` must have the same length.
|
||||
*/
|
||||
function _safeBatchTransferFrom(
|
||||
address from,
|
||||
address to,
|
||||
uint256[] memory ids,
|
||||
uint256[] memory amounts,
|
||||
uint256[] memory values,
|
||||
bytes memory data
|
||||
) internal {
|
||||
if (to == address(0)) {
|
||||
@ -240,7 +260,7 @@ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IER
|
||||
if (from == address(0)) {
|
||||
revert ERC1155InvalidSender(address(0));
|
||||
}
|
||||
_update(from, to, ids, amounts, data);
|
||||
_updateWithAcceptanceCheck(from, to, ids, values, data);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -249,7 +269,7 @@ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IER
|
||||
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
|
||||
*
|
||||
* By this mechanism, any occurrence of the `\{id\}` substring in either the
|
||||
* URI or any of the amounts in the JSON file at said URI will be replaced by
|
||||
* URI or any of the values in the JSON file at said URI will be replaced by
|
||||
* clients with the token type ID.
|
||||
*
|
||||
* For example, the `https://token-cdn-domain/\{id\}.json` URI would be
|
||||
@ -267,7 +287,7 @@ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IER
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.
|
||||
* @dev Creates a `value` amount of tokens of type `id`, and assigns them to `to`.
|
||||
*
|
||||
* Emits a {TransferSingle} event.
|
||||
*
|
||||
@ -277,12 +297,12 @@ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IER
|
||||
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
|
||||
* acceptance magic value.
|
||||
*/
|
||||
function _mint(address to, uint256 id, uint256 amount, bytes memory data) internal {
|
||||
function _mint(address to, uint256 id, uint256 value, bytes memory data) internal {
|
||||
if (to == address(0)) {
|
||||
revert ERC1155InvalidReceiver(address(0));
|
||||
}
|
||||
(uint256[] memory ids, uint256[] memory amounts) = _asSingletonArrays(id, amount);
|
||||
_update(address(0), to, ids, amounts, data);
|
||||
(uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
|
||||
_updateWithAcceptanceCheck(address(0), to, ids, values, data);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -292,33 +312,34 @@ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IER
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `ids` and `amounts` must have the same length.
|
||||
* - `ids` and `values` must have the same length.
|
||||
* - `to` cannot be the zero address.
|
||||
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
|
||||
* acceptance magic value.
|
||||
*/
|
||||
function _mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) internal {
|
||||
function _mintBatch(address to, uint256[] memory ids, uint256[] memory values, bytes memory data) internal {
|
||||
if (to == address(0)) {
|
||||
revert ERC1155InvalidReceiver(address(0));
|
||||
}
|
||||
_update(address(0), to, ids, amounts, data);
|
||||
_updateWithAcceptanceCheck(address(0), to, ids, values, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Destroys `amount` tokens of token type `id` from `from`
|
||||
* @dev Destroys a `value` amount of tokens of type `id` from `from`
|
||||
*
|
||||
* Emits a {TransferSingle} event.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `from` cannot be the zero address.
|
||||
* - `from` must have at least `amount` tokens of token type `id`.
|
||||
* - `from` must have at least `value` amount of tokens of type `id`.
|
||||
*/
|
||||
function _burn(address from, uint256 id, uint256 amount) internal {
|
||||
function _burn(address from, uint256 id, uint256 value) internal {
|
||||
if (from == address(0)) {
|
||||
revert ERC1155InvalidSender(address(0));
|
||||
}
|
||||
(uint256[] memory ids, uint256[] memory amounts) = _asSingletonArrays(id, amount);
|
||||
_update(from, address(0), ids, amounts, "");
|
||||
(uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
|
||||
_updateWithAcceptanceCheck(from, address(0), ids, values, "");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -328,38 +349,48 @@ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IER
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `ids` and `amounts` must have the same length.
|
||||
* - `from` cannot be the zero address.
|
||||
* - `from` must have at least `value` amount of tokens of type `id`.
|
||||
* - `ids` and `values` must have the same length.
|
||||
*/
|
||||
function _burnBatch(address from, uint256[] memory ids, uint256[] memory amounts) internal {
|
||||
function _burnBatch(address from, uint256[] memory ids, uint256[] memory values) internal {
|
||||
if (from == address(0)) {
|
||||
revert ERC1155InvalidSender(address(0));
|
||||
}
|
||||
_update(from, address(0), ids, amounts, "");
|
||||
_updateWithAcceptanceCheck(from, address(0), ids, values, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Approve `operator` to operate on all of `owner` tokens
|
||||
*
|
||||
* Emits an {ApprovalForAll} event.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `operator` cannot be the zero address.
|
||||
*/
|
||||
function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {
|
||||
if (owner == operator) {
|
||||
revert ERC1155InvalidOperator(operator);
|
||||
if (operator == address(0)) {
|
||||
revert ERC1155InvalidOperator(address(0));
|
||||
}
|
||||
_operatorApprovals[owner][operator] = approved;
|
||||
emit ApprovalForAll(owner, operator, approved);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Performs an acceptance check by calling {IERC1155-onERC1155Received} on the `to` address
|
||||
* if it contains code at the moment of execution.
|
||||
*/
|
||||
function _doSafeTransferAcceptanceCheck(
|
||||
address operator,
|
||||
address from,
|
||||
address to,
|
||||
uint256 id,
|
||||
uint256 amount,
|
||||
uint256 value,
|
||||
bytes memory data
|
||||
) private {
|
||||
if (to.code.length > 0) {
|
||||
try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {
|
||||
try IERC1155Receiver(to).onERC1155Received(operator, from, id, value, data) returns (bytes4 response) {
|
||||
if (response != IERC1155Receiver.onERC1155Received.selector) {
|
||||
// Tokens rejected
|
||||
revert ERC1155InvalidReceiver(to);
|
||||
@ -378,16 +409,20 @@ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IER
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Performs a batch acceptance check by calling {IERC1155-onERC1155BatchReceived} on the `to` address
|
||||
* if it contains code at the moment of execution.
|
||||
*/
|
||||
function _doSafeBatchTransferAcceptanceCheck(
|
||||
address operator,
|
||||
address from,
|
||||
address to,
|
||||
uint256[] memory ids,
|
||||
uint256[] memory amounts,
|
||||
uint256[] memory values,
|
||||
bytes memory data
|
||||
) private {
|
||||
if (to.code.length > 0) {
|
||||
try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (
|
||||
try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, values, data) returns (
|
||||
bytes4 response
|
||||
) {
|
||||
if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
|
||||
@ -408,20 +443,28 @@ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IER
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Creates an array in memory with only one value for each of the elements provided.
|
||||
*/
|
||||
function _asSingletonArrays(
|
||||
uint256 element1,
|
||||
uint256 element2
|
||||
) private pure returns (uint256[] memory array1, uint256[] memory array2) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
// Load the free memory pointer
|
||||
array1 := mload(0x40)
|
||||
// Set array length to 1
|
||||
mstore(array1, 1)
|
||||
// Store the single element at the next word after the length (where content starts)
|
||||
mstore(add(array1, 0x20), element1)
|
||||
|
||||
// Repeat for next array locating it right after the first array
|
||||
array2 := add(array1, 0x40)
|
||||
mstore(array2, 1)
|
||||
mstore(add(array2, 0x20), element2)
|
||||
|
||||
// Update the free memory pointer by pointing after the second array
|
||||
mstore(0x40, add(array2, 0x40))
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ import {IERC165} from "../../utils/introspection/IERC165.sol";
|
||||
*/
|
||||
interface IERC1155 is IERC165 {
|
||||
/**
|
||||
* @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
|
||||
* @dev Emitted when `value` amount of tokens of type `id` are transferred from `from` to `to` by `operator`.
|
||||
*/
|
||||
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
|
||||
|
||||
@ -45,7 +45,7 @@ interface IERC1155 is IERC165 {
|
||||
event URI(string value, uint256 indexed id);
|
||||
|
||||
/**
|
||||
* @dev Returns the amount of tokens of token type `id` owned by `account`.
|
||||
* @dev Returns the value of tokens of token type `id` owned by `account`.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
@ -84,7 +84,7 @@ interface IERC1155 is IERC165 {
|
||||
function isApprovedForAll(address account, address operator) external view returns (bool);
|
||||
|
||||
/**
|
||||
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
|
||||
* @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`.
|
||||
*
|
||||
* WARNING: This function can potentially allow a reentrancy attack when transferring tokens
|
||||
* to an untrusted contract, when invoking {onERC1155Received} on the receiver.
|
||||
@ -97,11 +97,11 @@ interface IERC1155 is IERC165 {
|
||||
*
|
||||
* - `to` cannot be the zero address.
|
||||
* - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
|
||||
* - `from` must have a balance of tokens of type `id` of at least `amount`.
|
||||
* - `from` must have a balance of tokens of type `id` of at least `value` amount.
|
||||
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
|
||||
* acceptance magic value.
|
||||
*/
|
||||
function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;
|
||||
function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes calldata data) external;
|
||||
|
||||
/**
|
||||
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
|
||||
@ -116,7 +116,7 @@ interface IERC1155 is IERC165 {
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `ids` and `amounts` must have the same length.
|
||||
* - `ids` and `values` must have the same length.
|
||||
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
|
||||
* acceptance magic value.
|
||||
*/
|
||||
@ -124,7 +124,7 @@ interface IERC1155 is IERC165 {
|
||||
address from,
|
||||
address to,
|
||||
uint256[] calldata ids,
|
||||
uint256[] calldata amounts,
|
||||
uint256[] calldata values,
|
||||
bytes calldata data
|
||||
) external;
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ import {Pausable} from "../../../security/Pausable.sol";
|
||||
* addition to inheriting this contract, you must define both functions, invoking the
|
||||
* {Pausable-_pause} and {Pausable-_unpause} internal functions, with appropriate
|
||||
* access control, e.g. using {AccessControl} or {Ownable}. Not doing so will
|
||||
* make the contract unpausable.
|
||||
* make the contract pause mechanism of the contract unreachable, and thus unusable.
|
||||
*
|
||||
* _Available since v3.1._
|
||||
*/
|
||||
@ -33,9 +33,8 @@ abstract contract ERC1155Pausable is ERC1155, Pausable {
|
||||
address from,
|
||||
address to,
|
||||
uint256[] memory ids,
|
||||
uint256[] memory amounts,
|
||||
bytes memory data
|
||||
uint256[] memory values
|
||||
) internal virtual override whenNotPaused {
|
||||
super._update(from, to, ids, amounts, data);
|
||||
super._update(from, to, ids, values);
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,20 +15,22 @@ import {ERC1155} from "../ERC1155.sol";
|
||||
*
|
||||
* NOTE: This contract implies a global limit of 2**256 - 1 to the number of tokens
|
||||
* that can be minted.
|
||||
*
|
||||
* CAUTION: This extension should not be added in an upgrade to an already deployed contract.
|
||||
*/
|
||||
abstract contract ERC1155Supply is ERC1155 {
|
||||
mapping(uint256 => uint256) private _totalSupply;
|
||||
uint256 private _totalSupplyAll;
|
||||
|
||||
/**
|
||||
* @dev Total amount of tokens in with a given id.
|
||||
* @dev Total value of tokens in with a given id.
|
||||
*/
|
||||
function totalSupply(uint256 id) public view virtual returns (uint256) {
|
||||
return _totalSupply[id];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Total amount of tokens.
|
||||
* @dev Total value of tokens.
|
||||
*/
|
||||
function totalSupply() public view virtual returns (uint256) {
|
||||
return _totalSupplyAll;
|
||||
@ -48,35 +50,38 @@ abstract contract ERC1155Supply is ERC1155 {
|
||||
address from,
|
||||
address to,
|
||||
uint256[] memory ids,
|
||||
uint256[] memory amounts,
|
||||
bytes memory data
|
||||
uint256[] memory values
|
||||
) internal virtual override {
|
||||
super._update(from, to, ids, values);
|
||||
|
||||
if (from == address(0)) {
|
||||
uint256 totalMintAmount = 0;
|
||||
uint256 totalMintValue = 0;
|
||||
for (uint256 i = 0; i < ids.length; ++i) {
|
||||
uint256 amount = amounts[i];
|
||||
_totalSupply[ids[i]] += amount;
|
||||
totalMintAmount += amount;
|
||||
uint256 value = values[i];
|
||||
// Overflow check required: The rest of the code assumes that totalSupply never overflows
|
||||
_totalSupply[ids[i]] += value;
|
||||
totalMintValue += value;
|
||||
}
|
||||
_totalSupplyAll += totalMintAmount;
|
||||
// Overflow check required: The rest of the code assumes that totalSupplyAll never overflows
|
||||
_totalSupplyAll += totalMintValue;
|
||||
}
|
||||
|
||||
if (to == address(0)) {
|
||||
uint256 totalBurnAmount = 0;
|
||||
uint256 totalBurnValue = 0;
|
||||
for (uint256 i = 0; i < ids.length; ++i) {
|
||||
uint256 id = ids[i];
|
||||
uint256 amount = amounts[i];
|
||||
_totalSupply[id] -= amount;
|
||||
uint256 value = values[i];
|
||||
|
||||
unchecked {
|
||||
// Overflow not possible: sum(amounts[i]) <= sum(totalSupply(i)) <= totalSupplyAll
|
||||
totalBurnAmount += amount;
|
||||
// Overflow not possible: values[i] <= balanceOf(from, ids[i]) <= totalSupply(ids[i])
|
||||
_totalSupply[ids[i]] -= value;
|
||||
// Overflow not possible: sum_i(values[i]) <= sum_i(totalSupply(ids[i])) <= totalSupplyAll
|
||||
totalBurnValue += value;
|
||||
}
|
||||
}
|
||||
unchecked {
|
||||
// Overflow not possible: totalBurnAmount = sum(amounts[i]) <= sum(totalSupply(i)) <= totalSupplyAll
|
||||
_totalSupplyAll -= totalBurnAmount;
|
||||
// Overflow not possible: totalBurnValue = sum_i(values[i]) <= sum_i(totalSupply(ids[i])) <= totalSupplyAll
|
||||
_totalSupplyAll -= totalBurnValue;
|
||||
}
|
||||
}
|
||||
super._update(from, to, ids, amounts, data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -113,11 +113,11 @@ abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
|
||||
* Requirements:
|
||||
*
|
||||
* - `to` cannot be the zero address.
|
||||
* - the caller must have a balance of at least `amount`.
|
||||
* - the caller must have a balance of at least `value`.
|
||||
*/
|
||||
function transfer(address to, uint256 amount) public virtual returns (bool) {
|
||||
function transfer(address to, uint256 value) public virtual returns (bool) {
|
||||
address owner = _msgSender();
|
||||
_transfer(owner, to, amount);
|
||||
_transfer(owner, to, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -131,16 +131,16 @@ abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
|
||||
/**
|
||||
* @dev See {IERC20-approve}.
|
||||
*
|
||||
* NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
|
||||
* NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
|
||||
* `transferFrom`. This is semantically equivalent to an infinite approval.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `spender` cannot be the zero address.
|
||||
*/
|
||||
function approve(address spender, uint256 amount) public virtual returns (bool) {
|
||||
function approve(address spender, uint256 value) public virtual returns (bool) {
|
||||
address owner = _msgSender();
|
||||
_approve(owner, spender, amount);
|
||||
_approve(owner, spender, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -156,14 +156,14 @@ abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
|
||||
* Requirements:
|
||||
*
|
||||
* - `from` and `to` cannot be the zero address.
|
||||
* - `from` must have a balance of at least `amount`.
|
||||
* - `from` must have a balance of at least `value`.
|
||||
* - the caller must have allowance for ``from``'s tokens of at least
|
||||
* `amount`.
|
||||
* `value`.
|
||||
*/
|
||||
function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) {
|
||||
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
|
||||
address spender = _msgSender();
|
||||
_spendAllowance(from, spender, amount);
|
||||
_transfer(from, to, amount);
|
||||
_spendAllowance(from, spender, value);
|
||||
_transfer(from, to, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -198,6 +198,9 @@ abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
|
||||
* - `spender` cannot be the zero address.
|
||||
* - `spender` must have allowance for the caller of at least
|
||||
* `requestedDecrease`.
|
||||
*
|
||||
* NOTE: Although this function is designed to avoid double spending with {approval},
|
||||
* it can still be frontrunned, preventing any attempt of allowance reduction.
|
||||
*/
|
||||
function decreaseAllowance(address spender, uint256 requestedDecrease) public virtual returns (bool) {
|
||||
address owner = _msgSender();
|
||||
@ -213,7 +216,7 @@ abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Moves `amount` of tokens from `from` to `to`.
|
||||
* @dev Moves a `value` amount of tokens from `from` to `to`.
|
||||
*
|
||||
* This internal function is equivalent to {transfer}, and can be used to
|
||||
* e.g. implement automatic token fees, slashing mechanisms, etc.
|
||||
@ -222,83 +225,84 @@ abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
|
||||
*
|
||||
* NOTE: This function is not virtual, {_update} should be overridden instead.
|
||||
*/
|
||||
function _transfer(address from, address to, uint256 amount) internal {
|
||||
function _transfer(address from, address to, uint256 value) internal {
|
||||
if (from == address(0)) {
|
||||
revert ERC20InvalidSender(address(0));
|
||||
}
|
||||
if (to == address(0)) {
|
||||
revert ERC20InvalidReceiver(address(0));
|
||||
}
|
||||
_update(from, to, amount);
|
||||
_update(from, to, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Transfers `amount` of tokens from `from` to `to`, or alternatively mints (or burns) if `from` (or `to`) is
|
||||
* @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` (or `to`) is
|
||||
* the zero address. All customizations to transfers, mints, and burns should be done by overriding this function.
|
||||
*
|
||||
* Emits a {Transfer} event.
|
||||
*/
|
||||
function _update(address from, address to, uint256 amount) internal virtual {
|
||||
function _update(address from, address to, uint256 value) internal virtual {
|
||||
if (from == address(0)) {
|
||||
_totalSupply += amount;
|
||||
// Overflow check required: The rest of the code assumes that totalSupply never overflows
|
||||
_totalSupply += value;
|
||||
} else {
|
||||
uint256 fromBalance = _balances[from];
|
||||
if (fromBalance < amount) {
|
||||
revert ERC20InsufficientBalance(from, fromBalance, amount);
|
||||
if (fromBalance < value) {
|
||||
revert ERC20InsufficientBalance(from, fromBalance, value);
|
||||
}
|
||||
unchecked {
|
||||
// Overflow not possible: amount <= fromBalance <= totalSupply.
|
||||
_balances[from] = fromBalance - amount;
|
||||
// Overflow not possible: value <= fromBalance <= totalSupply.
|
||||
_balances[from] = fromBalance - value;
|
||||
}
|
||||
}
|
||||
|
||||
if (to == address(0)) {
|
||||
unchecked {
|
||||
// Overflow not possible: amount <= totalSupply or amount <= fromBalance <= totalSupply.
|
||||
_totalSupply -= amount;
|
||||
// Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
|
||||
_totalSupply -= value;
|
||||
}
|
||||
} else {
|
||||
unchecked {
|
||||
// Overflow not possible: balance + amount is at most totalSupply, which we know fits into a uint256.
|
||||
_balances[to] += amount;
|
||||
// Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
|
||||
_balances[to] += value;
|
||||
}
|
||||
}
|
||||
|
||||
emit Transfer(from, to, amount);
|
||||
emit Transfer(from, to, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Creates `amount` tokens and assigns them to `account`, by transferring it from address(0).
|
||||
* @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
|
||||
* Relies on the `_update` mechanism
|
||||
*
|
||||
* Emits a {Transfer} event with `from` set to the zero address.
|
||||
*
|
||||
* NOTE: This function is not virtual, {_update} should be overridden instead.
|
||||
*/
|
||||
function _mint(address account, uint256 amount) internal {
|
||||
function _mint(address account, uint256 value) internal {
|
||||
if (account == address(0)) {
|
||||
revert ERC20InvalidReceiver(address(0));
|
||||
}
|
||||
_update(address(0), account, amount);
|
||||
_update(address(0), account, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Destroys `amount` tokens from `account`, by transferring it to address(0).
|
||||
* @dev Destroys a `value` amount of tokens from `account`, by transferring it to address(0).
|
||||
* Relies on the `_update` mechanism.
|
||||
*
|
||||
* Emits a {Transfer} event with `to` set to the zero address.
|
||||
*
|
||||
* NOTE: This function is not virtual, {_update} should be overridden instead
|
||||
*/
|
||||
function _burn(address account, uint256 amount) internal {
|
||||
function _burn(address account, uint256 value) internal {
|
||||
if (account == address(0)) {
|
||||
revert ERC20InvalidSender(address(0));
|
||||
}
|
||||
_update(account, address(0), amount);
|
||||
_update(account, address(0), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
|
||||
* @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
|
||||
*
|
||||
* This internal function is equivalent to `approve`, and can be used to
|
||||
* e.g. set automatic allowances for certain subsystems, etc.
|
||||
@ -310,8 +314,8 @@ abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
|
||||
* - `owner` cannot be the zero address.
|
||||
* - `spender` cannot be the zero address.
|
||||
*/
|
||||
function _approve(address owner, address spender, uint256 amount) internal virtual {
|
||||
_approve(owner, spender, amount, true);
|
||||
function _approve(address owner, address spender, uint256 value) internal virtual {
|
||||
_approve(owner, spender, value, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -324,42 +328,42 @@ abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
|
||||
* Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to true
|
||||
* using the following override:
|
||||
* ```
|
||||
* function _approve(address owner, address spender, uint256 amount, bool) internal virtual override {
|
||||
* super._approve(owner, spender, amount, true);
|
||||
* function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
|
||||
* super._approve(owner, spender, value, true);
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Requirements are the same as {_approve}.
|
||||
*/
|
||||
function _approve(address owner, address spender, uint256 amount, bool emitEvent) internal virtual {
|
||||
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
|
||||
if (owner == address(0)) {
|
||||
revert ERC20InvalidApprover(address(0));
|
||||
}
|
||||
if (spender == address(0)) {
|
||||
revert ERC20InvalidSpender(address(0));
|
||||
}
|
||||
_allowances[owner][spender] = amount;
|
||||
_allowances[owner][spender] = value;
|
||||
if (emitEvent) {
|
||||
emit Approval(owner, spender, amount);
|
||||
emit Approval(owner, spender, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Updates `owner` s allowance for `spender` based on spent `amount`.
|
||||
* @dev Updates `owner` s allowance for `spender` based on spent `value`.
|
||||
*
|
||||
* Does not update the allowance amount in case of infinite allowance.
|
||||
* Does not update the allowance value in case of infinite allowance.
|
||||
* Revert if not enough allowance is available.
|
||||
*
|
||||
* Might emit an {Approval} event.
|
||||
*/
|
||||
function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
|
||||
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
|
||||
uint256 currentAllowance = allowance(owner, spender);
|
||||
if (currentAllowance != type(uint256).max) {
|
||||
if (currentAllowance < amount) {
|
||||
revert ERC20InsufficientAllowance(spender, currentAllowance, amount);
|
||||
if (currentAllowance < value) {
|
||||
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
|
||||
}
|
||||
unchecked {
|
||||
_approve(owner, spender, currentAllowance - amount, false);
|
||||
_approve(owner, spender, currentAllowance - value, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,23 +22,23 @@ interface IERC20 {
|
||||
event Approval(address indexed owner, address indexed spender, uint256 value);
|
||||
|
||||
/**
|
||||
* @dev Returns the amount of tokens in existence.
|
||||
* @dev Returns the value of tokens in existence.
|
||||
*/
|
||||
function totalSupply() external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @dev Returns the amount of tokens owned by `account`.
|
||||
* @dev Returns the value of tokens owned by `account`.
|
||||
*/
|
||||
function balanceOf(address account) external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @dev Moves `amount` tokens from the caller's account to `to`.
|
||||
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
|
||||
*
|
||||
* Returns a boolean value indicating whether the operation succeeded.
|
||||
*
|
||||
* Emits a {Transfer} event.
|
||||
*/
|
||||
function transfer(address to, uint256 amount) external returns (bool);
|
||||
function transfer(address to, uint256 value) external returns (bool);
|
||||
|
||||
/**
|
||||
* @dev Returns the remaining number of tokens that `spender` will be
|
||||
@ -50,7 +50,8 @@ interface IERC20 {
|
||||
function allowance(address owner, address spender) external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
|
||||
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
|
||||
* caller's tokens.
|
||||
*
|
||||
* Returns a boolean value indicating whether the operation succeeded.
|
||||
*
|
||||
@ -63,16 +64,16 @@ interface IERC20 {
|
||||
*
|
||||
* Emits an {Approval} event.
|
||||
*/
|
||||
function approve(address spender, uint256 amount) external returns (bool);
|
||||
function approve(address spender, uint256 value) external returns (bool);
|
||||
|
||||
/**
|
||||
* @dev Moves `amount` tokens from `from` to `to` using the
|
||||
* allowance mechanism. `amount` is then deducted from the caller's
|
||||
* @dev Moves a `value` amount of tokens from `from` to `to` using the
|
||||
* allowance mechanism. `value` is then deducted from the caller's
|
||||
* allowance.
|
||||
*
|
||||
* Returns a boolean value indicating whether the operation succeeded.
|
||||
*
|
||||
* Emits a {Transfer} event.
|
||||
*/
|
||||
function transferFrom(address from, address to, uint256 amount) external returns (bool);
|
||||
function transferFrom(address from, address to, uint256 value) external returns (bool);
|
||||
}
|
||||
|
||||
@ -13,27 +13,27 @@ import {Context} from "../../../utils/Context.sol";
|
||||
*/
|
||||
abstract contract ERC20Burnable is Context, ERC20 {
|
||||
/**
|
||||
* @dev Destroys `amount` tokens from the caller.
|
||||
* @dev Destroys a `value` amount of tokens from the caller.
|
||||
*
|
||||
* See {ERC20-_burn}.
|
||||
*/
|
||||
function burn(uint256 amount) public virtual {
|
||||
_burn(_msgSender(), amount);
|
||||
function burn(uint256 value) public virtual {
|
||||
_burn(_msgSender(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Destroys `amount` tokens from `account`, deducting from the caller's
|
||||
* allowance.
|
||||
* @dev Destroys a `value` amount of tokens from `account`, deducting from
|
||||
* the caller's allowance.
|
||||
*
|
||||
* See {ERC20-_burn} and {ERC20-allowance}.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - the caller must have allowance for ``accounts``'s tokens of at least
|
||||
* `amount`.
|
||||
* `value`.
|
||||
*/
|
||||
function burnFrom(address account, uint256 amount) public virtual {
|
||||
_spendAllowance(account, _msgSender(), amount);
|
||||
_burn(account, amount);
|
||||
function burnFrom(address account, uint256 value) public virtual {
|
||||
_spendAllowance(account, _msgSender(), value);
|
||||
_burn(account, value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,8 +42,8 @@ abstract contract ERC20Capped is ERC20 {
|
||||
/**
|
||||
* @dev See {ERC20-_update}.
|
||||
*/
|
||||
function _update(address from, address to, uint256 amount) internal virtual override {
|
||||
super._update(from, to, amount);
|
||||
function _update(address from, address to, uint256 value) internal virtual override {
|
||||
super._update(from, to, value);
|
||||
|
||||
if (from == address(0)) {
|
||||
uint256 maxSupply = cap();
|
||||
|
||||
@ -14,6 +14,10 @@ import {ERC20} from "../ERC20.sol";
|
||||
* Adds the {flashLoan} method, which provides flash loan support at the token
|
||||
* level. By default there is no fee, but this can be changed by overriding {flashFee}.
|
||||
*
|
||||
* NOTE: When this extension is used along with the {ERC20Capped} or {ERC20Votes} extensions,
|
||||
* {maxFlashLoan} will not correctly reflect the maximum that can be flash minted. We recommend
|
||||
* overriding {maxFlashLoan} so that it correctly reflects the supply cap.
|
||||
*
|
||||
* _Available since v4.1._
|
||||
*/
|
||||
abstract contract ERC20FlashMint is ERC20, IERC3156FlashLender {
|
||||
@ -25,7 +29,7 @@ abstract contract ERC20FlashMint is ERC20, IERC3156FlashLender {
|
||||
error ERC3156UnsupportedToken(address token);
|
||||
|
||||
/**
|
||||
* @dev The requested loan exceeds the max loan amount for `token`.
|
||||
* @dev The requested loan exceeds the max loan value for `token`.
|
||||
*/
|
||||
error ERC3156ExceededMaxLoan(uint256 maxLoan);
|
||||
|
||||
@ -38,6 +42,10 @@ abstract contract ERC20FlashMint is ERC20, IERC3156FlashLender {
|
||||
* @dev Returns the maximum amount of tokens available for loan.
|
||||
* @param token The address of the token that is requested.
|
||||
* @return The amount of token that can be loaned.
|
||||
*
|
||||
* NOTE: This function does not consider any form of supply cap, so in case
|
||||
* it's used in a token with a cap like {ERC20Capped}, make sure to override this
|
||||
* function to integrate the cap instead of `type(uint256).max`.
|
||||
*/
|
||||
function maxFlashLoan(address token) public view virtual returns (uint256) {
|
||||
return token == address(this) ? type(uint256).max - totalSupply() : 0;
|
||||
@ -48,14 +56,14 @@ abstract contract ERC20FlashMint is ERC20, IERC3156FlashLender {
|
||||
* the {_flashFee} function which returns the fee applied when doing flash
|
||||
* loans.
|
||||
* @param token The token to be flash loaned.
|
||||
* @param amount The amount of tokens to be loaned.
|
||||
* @param value The amount of tokens to be loaned.
|
||||
* @return The fees applied to the corresponding flash loan.
|
||||
*/
|
||||
function flashFee(address token, uint256 amount) public view virtual returns (uint256) {
|
||||
function flashFee(address token, uint256 value) public view virtual returns (uint256) {
|
||||
if (token != address(this)) {
|
||||
revert ERC3156UnsupportedToken(token);
|
||||
}
|
||||
return _flashFee(token, amount);
|
||||
return _flashFee(token, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -63,13 +71,13 @@ abstract contract ERC20FlashMint is ERC20, IERC3156FlashLender {
|
||||
* implementation has 0 fees. This function can be overloaded to make
|
||||
* the flash loan mechanism deflationary.
|
||||
* @param token The token to be flash loaned.
|
||||
* @param amount The amount of tokens to be loaned.
|
||||
* @param value The amount of tokens to be loaned.
|
||||
* @return The fees applied to the corresponding flash loan.
|
||||
*/
|
||||
function _flashFee(address token, uint256 amount) internal view virtual returns (uint256) {
|
||||
function _flashFee(address token, uint256 value) internal view virtual returns (uint256) {
|
||||
// silence warning about unused variable without the addition of bytecode.
|
||||
token;
|
||||
amount;
|
||||
value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -87,13 +95,13 @@ abstract contract ERC20FlashMint is ERC20, IERC3156FlashLender {
|
||||
* @dev Performs a flash loan. New tokens are minted and sent to the
|
||||
* `receiver`, who is required to implement the {IERC3156FlashBorrower}
|
||||
* interface. By the end of the flash loan, the receiver is expected to own
|
||||
* amount + fee tokens and have them approved back to the token contract itself so
|
||||
* value + fee tokens and have them approved back to the token contract itself so
|
||||
* they can be burned.
|
||||
* @param receiver The receiver of the flash loan. Should implement the
|
||||
* {IERC3156FlashBorrower-onFlashLoan} interface.
|
||||
* @param token The token to be flash loaned. Only `address(this)` is
|
||||
* supported.
|
||||
* @param amount The amount of tokens to be loaned.
|
||||
* @param value The amount of tokens to be loaned.
|
||||
* @param data An arbitrary datafield that is passed to the receiver.
|
||||
* @return `true` if the flash loan was successful.
|
||||
*/
|
||||
@ -103,24 +111,24 @@ abstract contract ERC20FlashMint is ERC20, IERC3156FlashLender {
|
||||
function flashLoan(
|
||||
IERC3156FlashBorrower receiver,
|
||||
address token,
|
||||
uint256 amount,
|
||||
uint256 value,
|
||||
bytes calldata data
|
||||
) public virtual returns (bool) {
|
||||
uint256 maxLoan = maxFlashLoan(token);
|
||||
if (amount > maxLoan) {
|
||||
if (value > maxLoan) {
|
||||
revert ERC3156ExceededMaxLoan(maxLoan);
|
||||
}
|
||||
uint256 fee = flashFee(token, amount);
|
||||
_mint(address(receiver), amount);
|
||||
if (receiver.onFlashLoan(msg.sender, token, amount, fee, data) != _RETURN_VALUE) {
|
||||
uint256 fee = flashFee(token, value);
|
||||
_mint(address(receiver), value);
|
||||
if (receiver.onFlashLoan(_msgSender(), token, value, fee, data) != _RETURN_VALUE) {
|
||||
revert ERC3156InvalidReceiver(address(receiver));
|
||||
}
|
||||
address flashFeeReceiver = _flashFeeReceiver();
|
||||
_spendAllowance(address(receiver), address(this), amount + fee);
|
||||
_spendAllowance(address(receiver), address(this), value + fee);
|
||||
if (fee == 0 || flashFeeReceiver == address(0)) {
|
||||
_burn(address(receiver), amount + fee);
|
||||
_burn(address(receiver), value + fee);
|
||||
} else {
|
||||
_burn(address(receiver), amount);
|
||||
_burn(address(receiver), value);
|
||||
_transfer(address(receiver), flashFeeReceiver, fee);
|
||||
}
|
||||
return true;
|
||||
|
||||
@ -17,7 +17,7 @@ import {Pausable} from "../../../security/Pausable.sol";
|
||||
* addition to inheriting this contract, you must define both functions, invoking the
|
||||
* {Pausable-_pause} and {Pausable-_unpause} internal functions, with appropriate
|
||||
* access control, e.g. using {AccessControl} or {Ownable}. Not doing so will
|
||||
* make the contract unpausable.
|
||||
* make the contract pause mechanism of the contract unreachable, and thus unusable.
|
||||
*/
|
||||
abstract contract ERC20Pausable is ERC20, Pausable {
|
||||
/**
|
||||
@ -27,7 +27,7 @@ abstract contract ERC20Pausable is ERC20, Pausable {
|
||||
*
|
||||
* - the contract must not be paused.
|
||||
*/
|
||||
function _update(address from, address to, uint256 amount) internal virtual override whenNotPaused {
|
||||
super._update(from, to, amount);
|
||||
function _update(address from, address to, uint256 value) internal virtual override whenNotPaused {
|
||||
super._update(from, to, value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,8 +41,8 @@ abstract contract ERC20Votes is ERC20, Votes {
|
||||
*
|
||||
* Emits a {IVotes-DelegateVotesChanged} event.
|
||||
*/
|
||||
function _update(address from, address to, uint256 amount) internal virtual override {
|
||||
super._update(from, to, amount);
|
||||
function _update(address from, address to, uint256 value) internal virtual override {
|
||||
super._update(from, to, value);
|
||||
if (from == address(0)) {
|
||||
uint256 supply = totalSupply();
|
||||
uint256 cap = _maxSupply();
|
||||
@ -50,11 +50,14 @@ abstract contract ERC20Votes is ERC20, Votes {
|
||||
revert ERC20ExceededSafeSupply(supply, cap);
|
||||
}
|
||||
}
|
||||
_transferVotingUnits(from, to, amount);
|
||||
_transferVotingUnits(from, to, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the balance of `account`.
|
||||
* @dev Returns the voting units of an `account`.
|
||||
*
|
||||
* WARNING: Overriding this function may compromise the internal vote accounting.
|
||||
* `ERC20Votes` assumes tokens map to voting units 1:1 and this is not easy to change.
|
||||
*/
|
||||
function _getVotingUnits(address account) internal view virtual override returns (uint256) {
|
||||
return balanceOf(account);
|
||||
|
||||
@ -51,22 +51,28 @@ abstract contract ERC20Wrapper is ERC20 {
|
||||
/**
|
||||
* @dev Allow a user to deposit underlying tokens and mint the corresponding number of wrapped tokens.
|
||||
*/
|
||||
function depositFor(address account, uint256 amount) public virtual returns (bool) {
|
||||
function depositFor(address account, uint256 value) public virtual returns (bool) {
|
||||
address sender = _msgSender();
|
||||
if (sender == address(this)) {
|
||||
revert ERC20InvalidSender(address(this));
|
||||
}
|
||||
SafeERC20.safeTransferFrom(_underlying, sender, address(this), amount);
|
||||
_mint(account, amount);
|
||||
if (account == address(this)) {
|
||||
revert ERC20InvalidReceiver(account);
|
||||
}
|
||||
SafeERC20.safeTransferFrom(_underlying, sender, address(this), value);
|
||||
_mint(account, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Allow a user to burn a number of wrapped tokens and withdraw the corresponding number of underlying tokens.
|
||||
*/
|
||||
function withdrawTo(address account, uint256 amount) public virtual returns (bool) {
|
||||
_burn(_msgSender(), amount);
|
||||
SafeERC20.safeTransfer(_underlying, account, amount);
|
||||
function withdrawTo(address account, uint256 value) public virtual returns (bool) {
|
||||
if (account == address(this)) {
|
||||
revert ERC20InvalidReceiver(account);
|
||||
}
|
||||
_burn(_msgSender(), value);
|
||||
SafeERC20.safeTransfer(_underlying, account, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -486,7 +486,7 @@ abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Er
|
||||
* that `ownerOf(tokenId)` is `a`.
|
||||
*/
|
||||
// solhint-disable-next-line func-name-mixedcase
|
||||
function __unsafe_increaseBalance(address account, uint256 amount) internal {
|
||||
_balances[account] += amount;
|
||||
function __unsafe_increaseBalance(address account, uint256 value) internal {
|
||||
_balances[account] += value;
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ import {Pausable} from "../../../security/Pausable.sol";
|
||||
* addition to inheriting this contract, you must define both functions, invoking the
|
||||
* {Pausable-_pause} and {Pausable-_unpause} internal functions, with appropriate
|
||||
* access control, e.g. using {AccessControl} or {Ownable}. Not doing so will
|
||||
* make the contract unpausable.
|
||||
* make the contract pause mechanism of the contract unreachable, and thus unusable.
|
||||
*/
|
||||
abstract contract ERC721Pausable is ERC721, Pausable {
|
||||
/**
|
||||
|
||||
@ -13,7 +13,7 @@ abstract contract Nonces {
|
||||
mapping(address => uint256) private _nonces;
|
||||
|
||||
/**
|
||||
* @dev Returns an address nonce.
|
||||
* @dev Returns an the next unused nonce for an address.
|
||||
*/
|
||||
function nonces(address owner) public view virtual returns (uint256) {
|
||||
return _nonces[owner];
|
||||
|
||||
@ -5,13 +5,12 @@
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import {Math} from "../math/Math.sol";
|
||||
import {SafeCast} from "../math/SafeCast.sol";
|
||||
|
||||
/**
|
||||
* @dev This library defines the `History` struct, for checkpointing values as they change at different points in
|
||||
* @dev This library defines the `Trace*` struct, for checkpointing values as they change at different points in
|
||||
* time, and later looking up past values by block number. See {Votes} as an example.
|
||||
*
|
||||
* To create a history of checkpoints define a variable type `Checkpoints.History` in your contract, and store a new
|
||||
* To create a history of checkpoints define a variable type `Checkpoints.Trace*` in your contract, and store a new
|
||||
* checkpoint for the current transaction block using the {push} function.
|
||||
*
|
||||
* _Available since v4.5._
|
||||
@ -35,6 +34,8 @@ library Checkpoints {
|
||||
* @dev Pushes a (`key`, `value`) pair into a Trace224 so that it is stored as the checkpoint.
|
||||
*
|
||||
* Returns previous value and new value.
|
||||
*
|
||||
* IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint32).max` key set will disable the library.
|
||||
*/
|
||||
function push(Trace224 storage self, uint32 key, uint224 value) internal returns (uint224, uint224) {
|
||||
return _insert(self._checkpoints, key, value);
|
||||
@ -220,6 +221,8 @@ library Checkpoints {
|
||||
* @dev Pushes a (`key`, `value`) pair into a Trace160 so that it is stored as the checkpoint.
|
||||
*
|
||||
* Returns previous value and new value.
|
||||
*
|
||||
* IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint96).max` key set will disable the library.
|
||||
*/
|
||||
function push(Trace160 storage self, uint96 key, uint160 value) internal returns (uint160, uint160) {
|
||||
return _insert(self._checkpoints, key, value);
|
||||
|
||||
Reference in New Issue
Block a user