// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol)pragmasolidity ^0.8.0;import"./IAccessControl.sol";
import"../utils/Context.sol";
import"../utils/Strings.sol";
import"../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it.
*/abstractcontractAccessControlisContext, IAccessControl, ERC165{
structRoleData {
mapping(address=>bool) members;
bytes32 adminRole;
}
mapping(bytes32=> RoleData) private _roles;
bytes32publicconstant DEFAULT_ADMIN_ROLE =0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*
* _Available since v4.1._
*/modifieronlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverridereturns (bool) {
return interfaceId ==type(IAccessControl).interfaceId||super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/functionhasRole(bytes32 role, address account) publicviewvirtualoverridereturns (bool) {
return _roles[role].members[account];
}
/**
* @dev Revert with a standard message if `_msgSender()` is missing `role`.
* Overriding this function changes the behavior of the {onlyRole} modifier.
*
* Format of the revert message is described in {_checkRole}.
*
* _Available since v4.6._
*/function_checkRole(bytes32 role) internalviewvirtual{
_checkRole(role, _msgSender());
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/function_checkRole(bytes32 role, address account) internalviewvirtual{
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(account),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/functiongetRoleAdmin(bytes32 role) publicviewvirtualoverridereturns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/functiongrantRole(bytes32 role, address account) publicvirtualoverrideonlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/functionrevokeRole(bytes32 role, address account) publicvirtualoverrideonlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*
* May emit a {RoleRevoked} event.
*/functionrenounceRole(bytes32 role, address account) publicvirtualoverride{
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event. Note that unlike {grantRole}, this function doesn't perform any
* checks on the calling account.
*
* May emit a {RoleGranted} event.
*
* [WARNING]
* ====
* This function should only be called from the constructor when setting
* up the initial roles for the system.
*
* Using this function in any other way is effectively circumventing the admin
* system imposed by {AccessControl}.
* ====
*
* NOTE: This function is deprecated in favor of {_grantRole}.
*/function_setupRole(bytes32 role, address account) internalvirtual{
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/function_setRoleAdmin(bytes32 role, bytes32 adminRole) internalvirtual{
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/function_grantRole(bytes32 role, address account) internalvirtual{
if (!hasRole(role, account)) {
_roles[role].members[account] =true;
emit RoleGranted(role, account, _msgSender());
}
}
/**
* @dev Revokes `role` from `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/function_revokeRole(bytes32 role, address account) internalvirtual{
if (hasRole(role, account)) {
_roles[role].members[account] =false;
emit RoleRevoked(role, account, _msgSender());
}
}
}
Contract Source Code
File 2 of 41: Address.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)pragmasolidity ^0.8.1;/**
* @dev Collection of functions related to the address type
*/libraryAddress{
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/functionisContract(address account) internalviewreturns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0// for contracts in construction, since the code is only stored at the end// of the constructor execution.return account.code.length>0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/functionsendValue(addresspayable recipient, uint256 amount) internal{
require(address(this).balance>= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/functionfunctionCall(address target, bytesmemory data) internalreturns (bytesmemory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/functionfunctionCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalreturns (bytesmemory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/functionfunctionCallWithValue(address target,
bytesmemory data,
uint256 value
) internalreturns (bytesmemory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/functionfunctionCallWithValue(address target,
bytesmemory data,
uint256 value,
stringmemory errorMessage
) internalreturns (bytesmemory) {
require(address(this).balance>= value, "Address: insufficient balance for call");
(bool success, bytesmemory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/functionfunctionStaticCall(address target, bytesmemory data) internalviewreturns (bytesmemory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/functionfunctionStaticCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalviewreturns (bytesmemory) {
(bool success, bytesmemory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/functionfunctionDelegateCall(address target, bytesmemory data) internalreturns (bytesmemory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/functionfunctionDelegateCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalreturns (bytesmemory) {
(bool success, bytesmemory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/functionverifyCallResultFromTarget(address target,
bool success,
bytesmemory returndata,
stringmemory errorMessage
) internalviewreturns (bytesmemory) {
if (success) {
if (returndata.length==0) {
// only check isContract if the call was successful and the return data is empty// otherwise we already know that it was a contractrequire(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/functionverifyCallResult(bool success,
bytesmemory returndata,
stringmemory errorMessage
) internalpurereturns (bytesmemory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function_revert(bytesmemory returndata, stringmemory errorMessage) privatepure{
// Look for revert reason and bubble it up if presentif (returndata.length>0) {
// The easiest way to bubble the revert reason is using memory via assembly/// @solidity memory-safe-assemblyassembly {
let returndata_size :=mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
Contract Source Code
File 3 of 41: BytesLib.sol
// SPDX-License-Identifier: Unlicense/*
* @title Solidity Bytes Arrays Utils
* @author Gonçalo Sá <goncalo.sa@consensys.net>
*
* @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.
* The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.
*/pragmasolidity >=0.8.0 <0.9.0;libraryBytesLib{
functionconcat(bytesmemory _preBytes,
bytesmemory _postBytes
)
internalpurereturns (bytesmemory)
{
bytesmemory tempBytes;
assembly {
// Get a location of some free memory and store it in tempBytes as// Solidity does for memory variables.
tempBytes :=mload(0x40)
// Store the length of the first bytes array at the beginning of// the memory for tempBytes.let length :=mload(_preBytes)
mstore(tempBytes, length)
// Maintain a memory counter for the current write location in the// temp bytes array by adding the 32 bytes for the array length to// the starting location.let mc :=add(tempBytes, 0x20)
// Stop copying when the memory counter reaches the length of the// first bytes array.let end :=add(mc, length)
for {
// Initialize a copy counter to the start of the _preBytes data,// 32 bytes into its memory.let cc :=add(_preBytes, 0x20)
} lt(mc, end) {
// Increase both counters by 32 bytes each iteration.
mc :=add(mc, 0x20)
cc :=add(cc, 0x20)
} {
// Write the _preBytes data into the tempBytes memory 32 bytes// at a time.mstore(mc, mload(cc))
}
// Add the length of _postBytes to the current length of tempBytes// and store it as the new length in the first 32 bytes of the// tempBytes memory.
length :=mload(_postBytes)
mstore(tempBytes, add(length, mload(tempBytes)))
// Move the memory counter back from a multiple of 0x20 to the// actual end of the _preBytes data.
mc := end
// Stop copying when the memory counter reaches the new combined// length of the arrays.
end :=add(mc, length)
for {
let cc :=add(_postBytes, 0x20)
} lt(mc, end) {
mc :=add(mc, 0x20)
cc :=add(cc, 0x20)
} {
mstore(mc, mload(cc))
}
// Update the free-memory pointer by padding our last write location// to 32 bytes: add 31 bytes to the end of tempBytes to move to the// next 32 byte block, then round down to the nearest multiple of// 32. If the sum of the length of the two arrays is zero then add// one before rounding down to leave a blank 32 bytes (the length block with 0).mstore(0x40, and(
add(add(end, iszero(add(length, mload(_preBytes)))), 31),
not(31) // Round down to the nearest 32 bytes.
))
}
return tempBytes;
}
functionconcatStorage(bytesstorage _preBytes, bytesmemory _postBytes) internal{
assembly {
// Read the first 32 bytes of _preBytes storage, which is the length// of the array. (We don't need to use the offset into the slot// because arrays use the entire slot.)let fslot :=sload(_preBytes.slot)
// Arrays of 31 bytes or less have an even value in their slot,// while longer arrays have an odd value. The actual length is// the slot divided by two for odd values, and the lowest order// byte divided by two for even values.// If the slot is even, bitwise and the slot with 255 and divide by// two to get the length. If the slot is odd, bitwise and the slot// with -1 and divide by two.let slength :=div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
let mlength :=mload(_postBytes)
let newlength :=add(slength, mlength)
// slength can contain both the length and contents of the array// if length < 32 bytes so let's prepare for that// v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storageswitchadd(lt(slength, 32), lt(newlength, 32))
case2 {
// Since the new array still fits in the slot, we just need to// update the contents of the slot.// uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_lengthsstore(
_preBytes.slot,
// all the modifications to the slot are inside this// next blockadd(
// we can just add to the slot contents because the// bytes we want to change are the LSBs
fslot,
add(
mul(
div(
// load the bytes from memorymload(add(_postBytes, 0x20)),
// zero all bytes to the rightexp(0x100, sub(32, mlength))
),
// and now shift left the number of bytes to// leave space for the length in the slotexp(0x100, sub(32, newlength))
),
// increase length by the double of the memory// bytes lengthmul(mlength, 2)
)
)
)
}
case1 {
// The stored value fits in the slot, but the combined value// will exceed it.// get the keccak hash to get the contents of the arraymstore(0x0, _preBytes.slot)
let sc :=add(keccak256(0x0, 0x20), div(slength, 32))
// save new lengthsstore(_preBytes.slot, add(mul(newlength, 2), 1))
// The contents of the _postBytes array start 32 bytes into// the structure. Our first read should obtain the `submod`// bytes that can fit into the unused space in the last word// of the stored array. To get this, we read 32 bytes starting// from `submod`, so the data we read overlaps with the array// contents by `submod` bytes. Masking the lowest-order// `submod` bytes allows us to add that value directly to the// stored value.let submod :=sub(32, slength)
let mc :=add(_postBytes, submod)
let end :=add(_postBytes, mlength)
let mask :=sub(exp(0x100, submod), 1)
sstore(
sc,
add(
and(
fslot,
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00
),
and(mload(mc), mask)
)
)
for {
mc :=add(mc, 0x20)
sc :=add(sc, 1)
} lt(mc, end) {
sc :=add(sc, 1)
mc :=add(mc, 0x20)
} {
sstore(sc, mload(mc))
}
mask :=exp(0x100, sub(mc, end))
sstore(sc, mul(div(mload(mc), mask), mask))
}
default {
// get the keccak hash to get the contents of the arraymstore(0x0, _preBytes.slot)
// Start copying to the last used word of the stored array.let sc :=add(keccak256(0x0, 0x20), div(slength, 32))
// save new lengthsstore(_preBytes.slot, add(mul(newlength, 2), 1))
// Copy over the first `submod` bytes of the new data as in// case 1 above.let slengthmod :=mod(slength, 32)
let mlengthmod :=mod(mlength, 32)
let submod :=sub(32, slengthmod)
let mc :=add(_postBytes, submod)
let end :=add(_postBytes, mlength)
let mask :=sub(exp(0x100, submod), 1)
sstore(sc, add(sload(sc), and(mload(mc), mask)))
for {
sc :=add(sc, 1)
mc :=add(mc, 0x20)
} lt(mc, end) {
sc :=add(sc, 1)
mc :=add(mc, 0x20)
} {
sstore(sc, mload(mc))
}
mask :=exp(0x100, sub(mc, end))
sstore(sc, mul(div(mload(mc), mask), mask))
}
}
}
functionslice(bytesmemory _bytes,
uint256 _start,
uint256 _length
)
internalpurereturns (bytesmemory)
{
require(_length +31>= _length, "slice_overflow");
require(_bytes.length>= _start + _length, "slice_outOfBounds");
bytesmemory tempBytes;
assembly {
switchiszero(_length)
case0 {
// Get a location of some free memory and store it in tempBytes as// Solidity does for memory variables.
tempBytes :=mload(0x40)
// The first word of the slice result is potentially a partial// word read from the original array. To read it, we calculate// the length of that partial word and start copying that many// bytes into the array. The first word we copy will start with// data we don't care about, but the last `lengthmod` bytes will// land at the beginning of the contents of the new array. When// we're done copying, we overwrite the full first word with// the actual length of the slice.let lengthmod :=and(_length, 31)
// The multiplication in the next line is necessary// because when slicing multiples of 32 bytes (lengthmod == 0)// the following copy loop was copying the origin's length// and then ending prematurely not copying everything it should.let mc :=add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
let end :=add(mc, _length)
for {
// The multiplication in the next line has the same exact purpose// as the one above.let cc :=add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
} lt(mc, end) {
mc :=add(mc, 0x20)
cc :=add(cc, 0x20)
} {
mstore(mc, mload(cc))
}
mstore(tempBytes, _length)
//update free-memory pointer//allocating the array padded to 32 bytes like the compiler does nowmstore(0x40, and(add(mc, 31), not(31)))
}
//if we want a zero-length slice let's just return a zero-length arraydefault {
tempBytes :=mload(0x40)
//zero out the 32 bytes slice we are about to return//we need to do it because Solidity does not garbage collectmstore(tempBytes, 0)
mstore(0x40, add(tempBytes, 0x20))
}
}
return tempBytes;
}
functiontoAddress(bytesmemory _bytes, uint256 _start) internalpurereturns (address) {
require(_bytes.length>= _start +20, "toAddress_outOfBounds");
address tempAddress;
assembly {
tempAddress :=div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
}
return tempAddress;
}
functiontoUint8(bytesmemory _bytes, uint256 _start) internalpurereturns (uint8) {
require(_bytes.length>= _start +1 , "toUint8_outOfBounds");
uint8 tempUint;
assembly {
tempUint :=mload(add(add(_bytes, 0x1), _start))
}
return tempUint;
}
functiontoUint16(bytesmemory _bytes, uint256 _start) internalpurereturns (uint16) {
require(_bytes.length>= _start +2, "toUint16_outOfBounds");
uint16 tempUint;
assembly {
tempUint :=mload(add(add(_bytes, 0x2), _start))
}
return tempUint;
}
functiontoUint32(bytesmemory _bytes, uint256 _start) internalpurereturns (uint32) {
require(_bytes.length>= _start +4, "toUint32_outOfBounds");
uint32 tempUint;
assembly {
tempUint :=mload(add(add(_bytes, 0x4), _start))
}
return tempUint;
}
functiontoUint64(bytesmemory _bytes, uint256 _start) internalpurereturns (uint64) {
require(_bytes.length>= _start +8, "toUint64_outOfBounds");
uint64 tempUint;
assembly {
tempUint :=mload(add(add(_bytes, 0x8), _start))
}
return tempUint;
}
functiontoUint96(bytesmemory _bytes, uint256 _start) internalpurereturns (uint96) {
require(_bytes.length>= _start +12, "toUint96_outOfBounds");
uint96 tempUint;
assembly {
tempUint :=mload(add(add(_bytes, 0xc), _start))
}
return tempUint;
}
functiontoUint128(bytesmemory _bytes, uint256 _start) internalpurereturns (uint128) {
require(_bytes.length>= _start +16, "toUint128_outOfBounds");
uint128 tempUint;
assembly {
tempUint :=mload(add(add(_bytes, 0x10), _start))
}
return tempUint;
}
functiontoUint256(bytesmemory _bytes, uint256 _start) internalpurereturns (uint256) {
require(_bytes.length>= _start +32, "toUint256_outOfBounds");
uint256 tempUint;
assembly {
tempUint :=mload(add(add(_bytes, 0x20), _start))
}
return tempUint;
}
functiontoBytes32(bytesmemory _bytes, uint256 _start) internalpurereturns (bytes32) {
require(_bytes.length>= _start +32, "toBytes32_outOfBounds");
bytes32 tempBytes32;
assembly {
tempBytes32 :=mload(add(add(_bytes, 0x20), _start))
}
return tempBytes32;
}
functionequal(bytesmemory _preBytes, bytesmemory _postBytes) internalpurereturns (bool) {
bool success =true;
assembly {
let length :=mload(_preBytes)
// if lengths don't match the arrays are not equalswitcheq(length, mload(_postBytes))
case1 {
// cb is a circuit breaker in the for loop since there's// no said feature for inline assembly loops// cb = 1 - don't breaker// cb = 0 - breaklet cb :=1let mc :=add(_preBytes, 0x20)
let end :=add(mc, length)
for {
let cc :=add(_postBytes, 0x20)
// the next line is the loop condition:// while(uint256(mc < end) + cb == 2)
} eq(add(lt(mc, end), cb), 2) {
mc :=add(mc, 0x20)
cc :=add(cc, 0x20)
} {
// if any of these checks fails then arrays are not equalifiszero(eq(mload(mc), mload(cc))) {
// unsuccess:
success :=0
cb :=0
}
}
}
default {
// unsuccess:
success :=0
}
}
return success;
}
functionequalStorage(bytesstorage _preBytes,
bytesmemory _postBytes
)
internalviewreturns (bool)
{
bool success =true;
assembly {
// we know _preBytes_offset is 0let fslot :=sload(_preBytes.slot)
// Decode the length of the stored array like in concatStorage().let slength :=div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
let mlength :=mload(_postBytes)
// if lengths don't match the arrays are not equalswitcheq(slength, mlength)
case1 {
// slength can contain both the length and contents of the array// if length < 32 bytes so let's prepare for that// v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storageifiszero(iszero(slength)) {
switchlt(slength, 32)
case1 {
// blank the last byte which is the length
fslot :=mul(div(fslot, 0x100), 0x100)
ifiszero(eq(fslot, mload(add(_postBytes, 0x20)))) {
// unsuccess:
success :=0
}
}
default {
// cb is a circuit breaker in the for loop since there's// no said feature for inline assembly loops// cb = 1 - don't breaker// cb = 0 - breaklet cb :=1// get the keccak hash to get the contents of the arraymstore(0x0, _preBytes.slot)
let sc :=keccak256(0x0, 0x20)
let mc :=add(_postBytes, 0x20)
let end :=add(mc, mlength)
// the next line is the loop condition:// while(uint256(mc < end) + cb == 2)for {} eq(add(lt(mc, end), cb), 2) {
sc :=add(sc, 1)
mc :=add(mc, 0x20)
} {
ifiszero(eq(sload(sc), mload(mc))) {
// unsuccess:
success :=0
cb :=0
}
}
}
}
}
default {
// unsuccess:
success :=0
}
}
return success;
}
}
Contract Source Code
File 4 of 41: Context.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)pragmasolidity ^0.8.0;/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/abstractcontractContext{
function_msgSender() internalviewvirtualreturns (address) {
returnmsg.sender;
}
function_msgData() internalviewvirtualreturns (bytescalldata) {
returnmsg.data;
}
}
Contract Source Code
File 5 of 41: ECDSA.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)pragmasolidity ^0.8.0;import"../Strings.sol";
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/libraryECDSA{
enumRecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV // Deprecated in v4.8
}
function_throwError(RecoverError error) privatepure{
if (error == RecoverError.NoError) {
return; // no error: do nothing
} elseif (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} elseif (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} elseif (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature` or error string. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*
* _Available since v4.3._
*/functiontryRecover(bytes32 hash, bytesmemory signature) internalpurereturns (address, RecoverError) {
if (signature.length==65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them// currently is to use assembly./// @solidity memory-safe-assemblyassembly {
r :=mload(add(signature, 0x20))
s :=mload(add(signature, 0x40))
v :=byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/functionrecover(bytes32 hash, bytesmemory signature) internalpurereturns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*
* _Available since v4.3._
*/functiontryRecover(bytes32 hash,
bytes32 r,
bytes32 vs
) internalpurereturns (address, RecoverError) {
bytes32 s = vs &bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v =uint8((uint256(vs) >>255) +27);
return tryRecover(hash, v, r, s);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*
* _Available since v4.2._
*/functionrecover(bytes32 hash,
bytes32 r,
bytes32 vs
) internalpurereturns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*
* _Available since v4.3._
*/functiontryRecover(bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internalpurereturns (address, RecoverError) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most// signatures from current libraries generate a unique signature with an s-value in the lower half order.//// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept// these malleable signatures as well.if (uint256(s) >0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
// If the signature is valid (and not malleable), return the signer addressaddress signer =ecrecover(hash, v, r, s);
if (signer ==address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/functionrecover(bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internalpurereturns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/functiontoEthSignedMessageHash(bytes32 hash) internalpurereturns (bytes32) {
// 32 is the length in bytes of hash,// enforced by the type signature abovereturnkeccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
/**
* @dev Returns an Ethereum Signed Message, created from `s`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/functiontoEthSignedMessageHash(bytesmemory s) internalpurereturns (bytes32) {
returnkeccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/functiontoTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internalpurereturns (bytes32) {
returnkeccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
}
}
Contract Source Code
File 6 of 41: EIP712.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/EIP712.sol)pragmasolidity ^0.8.0;import"./ECDSA.sol";
/**
* @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
*
* The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
* thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
* they need in their contracts using a combination of `abi.encode` and `keccak256`.
*
* This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
* scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
* ({_hashTypedDataV4}).
*
* The implementation of the domain separator was designed to be as efficient as possible while still properly updating
* the chain id to protect against replay attacks on an eventual fork of the chain.
*
* NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
* https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
*
* _Available since v3.4._
*/abstractcontractEIP712{
/* solhint-disable var-name-mixedcase */// Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to// invalidate the cached domain separator if the chain id changes.bytes32privateimmutable _CACHED_DOMAIN_SEPARATOR;
uint256privateimmutable _CACHED_CHAIN_ID;
addressprivateimmutable _CACHED_THIS;
bytes32privateimmutable _HASHED_NAME;
bytes32privateimmutable _HASHED_VERSION;
bytes32privateimmutable _TYPE_HASH;
/* solhint-enable var-name-mixedcase *//**
* @dev Initializes the domain separator and parameter caches.
*
* The meaning of `name` and `version` is specified in
* https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
*
* - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
* - `version`: the current major version of the signing domain.
*
* NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
* contract upgrade].
*/constructor(stringmemory name, stringmemory version) {
bytes32 hashedName =keccak256(bytes(name));
bytes32 hashedVersion =keccak256(bytes(version));
bytes32 typeHash =keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
);
_HASHED_NAME = hashedName;
_HASHED_VERSION = hashedVersion;
_CACHED_CHAIN_ID =block.chainid;
_CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);
_CACHED_THIS =address(this);
_TYPE_HASH = typeHash;
}
/**
* @dev Returns the domain separator for the current chain.
*/function_domainSeparatorV4() internalviewreturns (bytes32) {
if (address(this) == _CACHED_THIS &&block.chainid== _CACHED_CHAIN_ID) {
return _CACHED_DOMAIN_SEPARATOR;
} else {
return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);
}
}
function_buildDomainSeparator(bytes32 typeHash,
bytes32 nameHash,
bytes32 versionHash
) privateviewreturns (bytes32) {
returnkeccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));
}
/**
* @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
* function returns the hash of the fully encoded EIP712 message for this domain.
*
* This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
*
* ```solidity
* bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
* keccak256("Mail(address to,string contents)"),
* mailTo,
* keccak256(bytes(mailContents))
* )));
* address signer = ECDSA.recover(digest, signature);
* ```
*/function_hashTypedDataV4(bytes32 structHash) internalviewvirtualreturns (bytes32) {
return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
}
}
Contract Source Code
File 7 of 41: ERC1155.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC1155/ERC1155.sol)pragmasolidity ^0.8.0;import"./IERC1155.sol";
import"./IERC1155Receiver.sol";
import"./extensions/IERC1155MetadataURI.sol";
import"../../utils/Address.sol";
import"../../utils/Context.sol";
import"../../utils/introspection/ERC165.sol";
/**
* @dev Implementation of the basic standard multi-token.
* See https://eips.ethereum.org/EIPS/eip-1155
* Originally based on code by Enjin: https://github.com/enjin/erc-1155
*
* _Available since v3.1._
*/contractERC1155isContext, ERC165, IERC1155, IERC1155MetadataURI{
usingAddressforaddress;
// Mapping from token ID to account balancesmapping(uint256=>mapping(address=>uint256)) private _balances;
// Mapping from account to operator approvalsmapping(address=>mapping(address=>bool)) private _operatorApprovals;
// Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.jsonstringprivate _uri;
/**
* @dev See {_setURI}.
*/constructor(stringmemory uri_) {
_setURI(uri_);
}
/**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverride(ERC165, IERC165) returns (bool) {
return
interfaceId ==type(IERC1155).interfaceId||
interfaceId ==type(IERC1155MetadataURI).interfaceId||super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC1155MetadataURI-uri}.
*
* This implementation returns the same URI for *all* token types. It relies
* on the token type ID substitution mechanism
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
*
* Clients calling this function must replace the `\{id\}` substring with the
* actual token type ID.
*/functionuri(uint256) publicviewvirtualoverridereturns (stringmemory) {
return _uri;
}
/**
* @dev See {IERC1155-balanceOf}.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/functionbalanceOf(address account, uint256 id) publicviewvirtualoverridereturns (uint256) {
require(account !=address(0), "ERC1155: address zero is not a valid owner");
return _balances[id][account];
}
/**
* @dev See {IERC1155-balanceOfBatch}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/functionbalanceOfBatch(address[] memory accounts, uint256[] memory ids)
publicviewvirtualoverridereturns (uint256[] memory)
{
require(accounts.length== ids.length, "ERC1155: accounts and ids length mismatch");
uint256[] memory batchBalances =newuint256[](accounts.length);
for (uint256 i =0; i < accounts.length; ++i) {
batchBalances[i] = balanceOf(accounts[i], ids[i]);
}
return batchBalances;
}
/**
* @dev See {IERC1155-setApprovalForAll}.
*/functionsetApprovalForAll(address operator, bool approved) publicvirtualoverride{
_setApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC1155-isApprovedForAll}.
*/functionisApprovedForAll(address account, address operator) publicviewvirtualoverridereturns (bool) {
return _operatorApprovals[account][operator];
}
/**
* @dev See {IERC1155-safeTransferFrom}.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 id,
uint256 amount,
bytesmemory data
) publicvirtualoverride{
require(
from== _msgSender() || isApprovedForAll(from, _msgSender()),
"ERC1155: caller is not token owner or approved"
);
_safeTransferFrom(from, to, id, amount, data);
}
/**
* @dev See {IERC1155-safeBatchTransferFrom}.
*/functionsafeBatchTransferFrom(addressfrom,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytesmemory data
) publicvirtualoverride{
require(
from== _msgSender() || isApprovedForAll(from, _msgSender()),
"ERC1155: caller is not token owner or approved"
);
_safeBatchTransferFrom(from, to, ids, amounts, data);
}
/**
* @dev Transfers `amount` 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`.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/function_safeTransferFrom(addressfrom,
address to,
uint256 id,
uint256 amount,
bytesmemory data
) internalvirtual{
require(to !=address(0), "ERC1155: transfer to the zero address");
address operator = _msgSender();
uint256[] memory ids = _asSingletonArray(id);
uint256[] memory amounts = _asSingletonArray(amount);
_beforeTokenTransfer(operator, from, to, ids, amounts, data);
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
unchecked {
_balances[id][from] = fromBalance - amount;
}
_balances[id][to] += amount;
emit TransferSingle(operator, from, to, id, amount);
_afterTokenTransfer(operator, from, to, ids, amounts, data);
_doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/function_safeBatchTransferFrom(addressfrom,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytesmemory data
) internalvirtual{
require(ids.length== amounts.length, "ERC1155: ids and amounts length mismatch");
require(to !=address(0), "ERC1155: transfer to the zero address");
address operator = _msgSender();
_beforeTokenTransfer(operator, from, to, ids, amounts, data);
for (uint256 i =0; i < ids.length; ++i) {
uint256 id = ids[i];
uint256 amount = amounts[i];
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
unchecked {
_balances[id][from] = fromBalance - amount;
}
_balances[id][to] += amount;
}
emit TransferBatch(operator, from, to, ids, amounts);
_afterTokenTransfer(operator, from, to, ids, amounts, data);
_doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);
}
/**
* @dev Sets a new URI for all token types, by relying on the token type ID
* substitution mechanism
* 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
* clients with the token type ID.
*
* For example, the `https://token-cdn-domain/\{id\}.json` URI would be
* interpreted by clients as
* `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
* for token type ID 0x4cce0.
*
* See {uri}.
*
* Because these URIs cannot be meaningfully represented by the {URI} event,
* this function emits no events.
*/function_setURI(stringmemory newuri) internalvirtual{
_uri = newuri;
}
/**
* @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - 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,
bytesmemory data
) internalvirtual{
require(to !=address(0), "ERC1155: mint to the zero address");
address operator = _msgSender();
uint256[] memory ids = _asSingletonArray(id);
uint256[] memory amounts = _asSingletonArray(amount);
_beforeTokenTransfer(operator, address(0), to, ids, amounts, data);
_balances[id][to] += amount;
emit TransferSingle(operator, address(0), to, id, amount);
_afterTokenTransfer(operator, address(0), to, ids, amounts, data);
_doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
* - 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,
bytesmemory data
) internalvirtual{
require(to !=address(0), "ERC1155: mint to the zero address");
require(ids.length== amounts.length, "ERC1155: ids and amounts length mismatch");
address operator = _msgSender();
_beforeTokenTransfer(operator, address(0), to, ids, amounts, data);
for (uint256 i =0; i < ids.length; i++) {
_balances[ids[i]][to] += amounts[i];
}
emit TransferBatch(operator, address(0), to, ids, amounts);
_afterTokenTransfer(operator, address(0), to, ids, amounts, data);
_doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);
}
/**
* @dev Destroys `amount` tokens of token 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`.
*/function_burn(addressfrom,
uint256 id,
uint256 amount
) internalvirtual{
require(from!=address(0), "ERC1155: burn from the zero address");
address operator = _msgSender();
uint256[] memory ids = _asSingletonArray(id);
uint256[] memory amounts = _asSingletonArray(amount);
_beforeTokenTransfer(operator, from, address(0), ids, amounts, "");
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
unchecked {
_balances[id][from] = fromBalance - amount;
}
emit TransferSingle(operator, from, address(0), id, amount);
_afterTokenTransfer(operator, from, address(0), ids, amounts, "");
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
*/function_burnBatch(addressfrom,
uint256[] memory ids,
uint256[] memory amounts
) internalvirtual{
require(from!=address(0), "ERC1155: burn from the zero address");
require(ids.length== amounts.length, "ERC1155: ids and amounts length mismatch");
address operator = _msgSender();
_beforeTokenTransfer(operator, from, address(0), ids, amounts, "");
for (uint256 i =0; i < ids.length; i++) {
uint256 id = ids[i];
uint256 amount = amounts[i];
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
unchecked {
_balances[id][from] = fromBalance - amount;
}
}
emit TransferBatch(operator, from, address(0), ids, amounts);
_afterTokenTransfer(operator, from, address(0), ids, amounts, "");
}
/**
* @dev Approve `operator` to operate on all of `owner` tokens
*
* Emits an {ApprovalForAll} event.
*/function_setApprovalForAll(address owner,
address operator,
bool approved
) internalvirtual{
require(owner != operator, "ERC1155: setting approval status for self");
_operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
/**
* @dev Hook that is called before any token transfer. This includes minting
* and burning, as well as batched variants.
*
* The same hook is called on both single and batched variants. For single
* transfers, the length of the `ids` and `amounts` arrays will be 1.
*
* Calling conditions (for each `id` and `amount` pair):
*
* - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* of token type `id` will be transferred to `to`.
* - When `from` is zero, `amount` tokens of token type `id` will be minted
* for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
* will be burned.
* - `from` and `to` are never both zero.
* - `ids` and `amounts` have the same, non-zero length.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/function_beforeTokenTransfer(address operator,
addressfrom,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytesmemory data
) internalvirtual{}
/**
* @dev Hook that is called after any token transfer. This includes minting
* and burning, as well as batched variants.
*
* The same hook is called on both single and batched variants. For single
* transfers, the length of the `id` and `amount` arrays will be 1.
*
* Calling conditions (for each `id` and `amount` pair):
*
* - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* of token type `id` will be transferred to `to`.
* - When `from` is zero, `amount` tokens of token type `id` will be minted
* for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
* will be burned.
* - `from` and `to` are never both zero.
* - `ids` and `amounts` have the same, non-zero length.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/function_afterTokenTransfer(address operator,
addressfrom,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytesmemory data
) internalvirtual{}
function_doSafeTransferAcceptanceCheck(address operator,
addressfrom,
address to,
uint256 id,
uint256 amount,
bytesmemory data
) private{
if (to.isContract()) {
try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {
if (response != IERC1155Receiver.onERC1155Received.selector) {
revert("ERC1155: ERC1155Receiver rejected tokens");
}
} catchError(stringmemory reason) {
revert(reason);
} catch {
revert("ERC1155: transfer to non-ERC1155Receiver implementer");
}
}
}
function_doSafeBatchTransferAcceptanceCheck(address operator,
addressfrom,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytesmemory data
) private{
if (to.isContract()) {
try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (
bytes4 response
) {
if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
revert("ERC1155: ERC1155Receiver rejected tokens");
}
} catchError(stringmemory reason) {
revert(reason);
} catch {
revert("ERC1155: transfer to non-ERC1155Receiver implementer");
}
}
}
function_asSingletonArray(uint256 element) privatepurereturns (uint256[] memory) {
uint256[] memory array =newuint256[](1);
array[0] = element;
return array;
}
}
Contract Source Code
File 8 of 41: ERC165.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)pragmasolidity ^0.8.0;import"./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/abstractcontractERC165isIERC165{
/**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverridereturns (bool) {
return interfaceId ==type(IERC165).interfaceId;
}
}
Contract Source Code
File 9 of 41: ERC2771Recipient.sol
// SPDX-License-Identifier: MIT// solhint-disable no-inline-assemblypragmasolidity >=0.6.9;import"./IERC2771Recipient.sol";
/**
* @title The ERC-2771 Recipient Base Abstract Class - Implementation
*
* @notice Note that this contract was called `BaseRelayRecipient` in the previous revision of the GSN.
*
* @notice A base contract to be inherited by any contract that want to receive relayed transactions.
*
* @notice A subclass must use `_msgSender()` instead of `msg.sender`.
*/abstractcontractERC2771RecipientisIERC2771Recipient{
/*
* Forwarder singleton we accept calls from
*/addressprivate _trustedForwarder;
constructor(address trustedForwarder) {
_trustedForwarder = trustedForwarder;
}
/**
* :warning: **Warning** :warning: The Forwarder can have a full control over your Recipient. Only trust verified Forwarder.
* @notice Method is not a required method to allow Recipients to trust multiple Forwarders. Not recommended yet.
* @return forwarder The address of the Forwarder contract that is being used.
*/functiongetTrustedForwarder()
publicviewvirtualreturns (address forwarder)
{
return _trustedForwarder;
}
function_setTrustedForwarder(address _forwarder) internal{
_trustedForwarder = _forwarder;
}
/// @inheritdoc IERC2771RecipientfunctionisTrustedForwarder(address forwarder
) publicviewvirtualoverridereturns (bool) {
return forwarder == _trustedForwarder;
}
/// @inheritdoc IERC2771Recipientfunction_msgSender() internalviewvirtualoverridereturns (address ret) {
if (msg.data.length >=20&& isTrustedForwarder(msg.sender)) {
// At this point we know that the sender is a trusted forwarder,// so we trust that the last bytes of msg.data are the verified sender address.// extract sender address from the end of msg.dataassembly {
ret :=shr(96, calldataload(sub(calldatasize(), 20)))
}
} else {
ret =msg.sender;
}
}
/// @inheritdoc IERC2771Recipientfunction_msgData()
internalviewvirtualoverridereturns (bytescalldata ret)
{
if (msg.data.length >=20&& isTrustedForwarder(msg.sender)) {
returnmsg.data[0:msg.data.length - 20];
} else {
returnmsg.data;
}
}
}
// SPDX-License-Identifier: MITpragmasolidity 0.8.17;import { Ownable } from"@openzeppelin/contracts/access/Ownable.sol";
import { SafeERC20, IERC20 } from"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { EIP712, ECDSA } from"@openzeppelin/contracts/utils/cryptography/EIP712.sol";
import { IEchoCardsHandler } from"./interfaces/IEchoCardsHandler.sol";
import { InvokeSpendHandler } from"./libraries/EchoCardsLib.sol";
import { EchoCardsPrice } from"./EchoCardsPrice.sol";
import { EchoCards } from"./EchoCards.sol";
contractEchoCardsHandlerisOwnable, IEchoCardsHandler, EIP712{
usingSafeERC20forIERC20;
/// @notice Prime token contract address
IERC20 public prime = IERC20(0xfA980cEd6895AC314E7dE34Ef1bFAE90a5AdD21b);
/// @notice Disabled state of the contractboolpublic isDisabled;
/// @notice Nonce to prevent signature from being reusedmapping(address=>uint256) public nonces;
/// @notice mapping of parallel alpha ids to echos idsmapping(uint256=>uint256) public parallelAlphaToEchos;
/// @notice Trusted signer from backend serveraddresspublic trustedSigner;
/// @notice Contract for price calculation
EchoCardsPrice public echoCardsPrice;
/// @notice Contract for Echo Cards
EchoCards public echoCards;
/// @notice Ability to change the echo cards price contractboolpublic echoCardPriceLocked;
// @notice EIP712("name", "version")constructor() EIP712("Echo Cards", "1.0.0") {}
/// @notice Updated PRIME contract address./// @param _prime New PRIME contract address.functionsetPrime(IERC20 _prime) externalonlyOwner{
prime = _prime;
emit PrimeAddressSet(address(_prime));
}
/// @notice Sets invoke to enabled/disabled./// @param _isDisabled New state of the invoke.functionsetDisabled(bool _isDisabled) externalonlyOwner{
isDisabled = _isDisabled;
emit IsDisabledSet(isDisabled);
}
/// @notice Sets the server trusted signer./// @param _trustedSigner New trusted signer.functionsetTrustedSigner(address _trustedSigner) externalonlyOwner{
trustedSigner = _trustedSigner;
emit TrustedSignerSet(_trustedSigner);
}
/** @notice Set Echo Cards price contract
* @param _echoCardsPrice Contract for price calculation
*/functionsetEchoCardsPrice(
EchoCardsPrice _echoCardsPrice
) externalonlyOwner{
if (echoCardPriceLocked) {
revert EchoCardsPriceLocked();
}
echoCardsPrice = _echoCardsPrice;
emit EchoCardsPriceSet(address(_echoCardsPrice));
}
/** @notice Set Echo Cards contract
* @param _echoCards New Echo Cards conctact
*/functionsetEchoCards(EchoCards _echoCards) externalonlyOwner{
echoCards = _echoCards;
emit EchoCardsSet(address(_echoCards));
}
/** @notice Lock the ability to set echo cards price contract
*/functionlockEchoCardsPrice() externalonlyOwner{
echoCardPriceLocked =true;
emit EchoCardsPriceLockedSet();
}
/// @notice update the mapping of parallel alpha to echos/// @param _parallelAlphaIds mapping from parallel alpha ids/// @param _echosIds mapping to echos idsfunctionsetParallelAlphaToEchos(uint256[] calldata _parallelAlphaIds,
uint256[] calldata _echosIds
) externalonlyOwner{
if (_parallelAlphaIds.length!= _echosIds.length)
revert InvalidLength();
for (uint256 i =0; i < _parallelAlphaIds.length; i++) {
parallelAlphaToEchos[_parallelAlphaIds[i]] = _echosIds[i];
}
emit ParallelAlphaToEchosSet(_parallelAlphaIds, _echosIds);
}
/**
* @notice Function invoked by the prime token contract to handle echo card minting
* @param _from The address of the original msg.sender
* @param _primeValue The amount of prime that was sent from the prime token contract
* @param _data Catch-all param to allow the caller to pass additional data to the handler, includes the amount of cards they want to purchase
*/functionhandleInvokeEchelon(address _from,
address,
address,
uint256,
uint256,
uint256 _primeValue,
bytesmemory _data
) publicpayable{
if (isDisabled) revert ContractDisabled();
if (_msgSender() !=address(prime)) {
revert InvalidPrimeAddress();
}
(
uint256[] memory _ids,
uint256[] memory _amounts,
bytesmemory _signature
) =abi.decode(_data, (uint256[], uint256[], bytes));
if (!_verify(_ids, _amounts, _from, _signature)) {
revert InvalidSig(_signature);
} else {
nonces[_from] +=1;
}
(
uint256[] memory _echosIds,
uint256[] memory _echosAmounts
) = getParallelAlphaToEchos(_ids, _amounts);
uint256 totalPrice;
for (uint256 i =0; i < _echosIds.length; i++) {
uint256 echosId = _echosIds[i];
uint256 echosAmount = _echosAmounts[i];
totalPrice +=
echoCardsPrice.getCardPrice(echosId, echosAmount) *
echosAmount;
}
if (totalPrice > _primeValue) {
revert InvalidPayment();
}
echoCards.mintBatchAdmin(_from, _echosIds, _echosAmounts, "");
emit EchoCardsPayment(
_from,
nonces[_from],
totalPrice,
_echosIds,
_echosAmounts,
_signature
);
}
/**
* @notice Verifies that the data was signed by the trusted signer
* @param _tokenIds TokenIds the user should own
* @param _amounts The amount of each tokenId the user should own
* @param _from Original caller
* @param _signature Signature of trusted signer
*/function_verify(uint256[] memory _tokenIds,
uint256[] memory _amounts,
address _from,
bytesmemory _signature
) internalviewreturns (bool) {
bytes32 digest = _hashTypedDataV4(
keccak256(
abi.encode(
keccak256(
"Message(address from,uint256[] tokenIds,uint256[] amounts,uint256 nonce)"
),
_from,
keccak256(abi.encodePacked(_tokenIds)),
keccak256(abi.encodePacked(_amounts)),
nonces[_from]
)
)
);
return ECDSA.recover(digest, _signature) == trustedSigner;
}
/**
* @notice View function to get the list of echo cards and amounts, as well as the price of the requested cards
* @param _ids The list of parallel alpha ids
* @param _amounts - The amount for each parallel alpha id
*/functiongetParallelAlphaToEchos(uint256[] memory _ids,
uint256[] memory _amounts
)
publicviewreturns (uint256[] memory _echosIds, uint256[] memory _echosAmounts)
{
if (_ids.length!= _amounts.length) revert InvalidLength();
_echosIds =newuint256[](_ids.length);
_echosAmounts =newuint256[](_amounts.length);
uint256 cutOffIndex =0;
for (uint256 i =0; i < _ids.length; i++) {
uint256 echosId = parallelAlphaToEchos[_ids[i]];
if (echosId ==0) revert InvalidId(_ids[i]);
uint256 echosAmount = _amounts[i];
bool found =false;
for (uint256 j =0; j < cutOffIndex; j++) {
if (_echosIds[j] == echosId) {
_echosAmounts[j] += echosAmount;
found =true;
break;
}
}
if (!found) {
_echosIds[cutOffIndex] = echosId;
_echosAmounts[cutOffIndex] = echosAmount;
cutOffIndex +=1;
}
}
uint256 reduceBy = _ids.length- cutOffIndex;
if (reduceBy >0) {
assembly {
mstore(_echosIds, sub(mload(_echosIds), reduceBy))
}
assembly {
mstore(_echosAmounts, sub(mload(_echosAmounts), reduceBy))
}
}
}
}
Contract Source Code
File 12 of 41: EchoCardsInvoke.sol
// SPDX-License-Identifier: MITpragmasolidity 0.8.17;import { ONFT1155 } from"@layerzerolabs/solidity-examples/contracts/token/onft/ONFT1155.sol";
import { AccessControl } from"@openzeppelin/contracts/access/AccessControl.sol";
import { SafeERC20, IERC20 } from"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { Strings } from"@openzeppelin/contracts/utils/Strings.sol";
import { ReentrancyGuard } from"@openzeppelin/contracts/security/ReentrancyGuard.sol";
import { Context } from"@openzeppelin/contracts/utils/Context.sol";
import { IEchoCards } from"./interfaces/IEchoCards.sol";
import { EchoCardsLib, InvokeSpendHandler } from"./libraries/EchoCardsLib.sol";
import { ERC2771Recipient } from"../metatx/ERC2771Recipient.sol";
contractEchoCardsInvokeisIEchoCards,
ONFT1155,
ERC2771Recipient,
AccessControl,
ReentrancyGuard{
usingSafeERC20forIERC20;
usingStringsforuint256;
/// @notice Address of the prime contract.
IERC20 public prime = IERC20(0xfA980cEd6895AC314E7dE34Ef1bFAE90a5AdD21b);
/// @notice A descriptive name for a collection of NFTs in this contractstringpublic name ="Echo";
/// @notice An abbreviated name for NFTs in this contractstringpublic symbol ="ECHO";
/// @notice a record of all SpendGatewaysmapping(uint256=> EchoCardsLib.SpendGateway) public spendGateways;
bytes32publicconstant MINTER_ROLE =keccak256("MINTER_ROLE");
/// @param _lzEndpoint Layer Zero endpoint/// @param _forwarder forwarder addressconstructor(address _lzEndpoint,
address _forwarder
)
ERC2771Recipient(_forwarder)
ONFT1155("https://nftdata.parallelnft.com/api/tokens/parallel-echos/ipfs/{id}",
_lzEndpoint
)
{
prime = IERC20(0xb23d80f5FefcDDaa212212F028021B41DEd428CF);
_grantRole(DEFAULT_ADMIN_ROLE, _msgSender());
_grantRole(MINTER_ROLE, _msgSender());
}
/**
* @notice Modifier used to check if sender is minter
* @dev Throws InsufficientPermissions if sender does not have MINTER_ROLE.
*/modifieronlyMinter() {
if (!hasRole(MINTER_ROLE, _msgSender())) {
revert InsufficientPermissions({
userAddress: _msgSender(),
requiredRole: MINTER_ROLE
});
}
_;
}
/**
* @notice Modifier used to check if sender is admin
* @dev Throws InsufficientPermissions if sender does not have ADMIN_ROLE.
*/modifieronlyAdmin() {
if (!hasRole(DEFAULT_ADMIN_ROLE, _msgSender())) {
revert InsufficientPermissions({
userAddress: _msgSender(),
requiredRole: DEFAULT_ADMIN_ROLE
});
}
_;
}
/**
* @dev Returns the URI for token type `id`.
*
* If the `\{id\}` substring is present in the URI, it must be replaced by
* clients with the actual token type ID.
*/functionuri(uint256 _tokenId
) publicviewvirtualoverridereturns (stringmemory) {
stringmemory baseURI =super.uri(_tokenId);
// Exit early if the baseURI is empty.if (bytes(baseURI).length==0) {
return"";
}
// Check if the last character in baseURI is a slash.if (bytes(baseURI)[bytes(baseURI).length-1] !=bytes("/")[0]) {
return baseURI;
}
returnstring.concat(baseURI, _tokenId.toString());
}
/**
* @dev Sets a new URI for all token types, by relying on the token type ID
* substitution mechanism
* 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
* clients with the token type ID.
*
* For example, the `https://token-cdn-domain/\{id\}.json` URI would be
* interpreted by clients as
* `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
* for token type ID 0x4cce0.
*
* See {uri}.
*
* Because these URIs cannot be meaningfully represented by the {URI} event,
* this function emits no events.
*/functionsetURI(stringmemory _uri) externalonlyAdmin{
_setURI(_uri);
}
/**
* @notice Updated trusted forwarder address.
* @param _forwarder New trusted forwarder address.
*/functionsetTrustedForwarder(address _forwarder) externalonlyAdmin{
_setTrustedForwarder(_forwarder);
emit TrustedForwarderSet(_forwarder);
}
/// @notice Updated PRIME contract address./// @param _prime New PRIME contract address.functionsetPrime(IERC20 _prime) externalonlyAdmin{
prime = _prime;
emit PrimeAddressSet(address(_prime));
}
/**
* @notice Allow the caller to send Echo Cards to the Parallel Ecosystem of smart
* contracts. Echo Cards are collected to the destination address,
* handler is invoked to trigger downstream logic and events
*
* @param _id An id of the gateway
* @param _tokenIds Token id of the Echo Cards that was sent
* @param _amounts The amount of an Echo Cards that was sent to the
* invokeSpend function (and was collected to gateway handler)
* @param _primeValue The amount of an PRIME that was sent to the
* invokeSpend function (and was collected to gateway handler)
* @param _data Catch-all param to allow the caller to pass additional
* data to the handler
*/functioninvokeSpend(uint256 _id,
uint256[] calldata _tokenIds,
uint256[] calldata _amounts,
uint256 _primeValue,
bytesmemory _data
) publicpayablenonReentrant{
EchoCardsLib.SpendGateway memory gateway = spendGateways[_id];
if (gateway.echoCardDestinationAddress ==address(0))
revert ZeroAddress("echoCardDestinationAddress");
// pull the native token to nativeTokenDestinationAddressif (msg.value!=0) {
(bool success, ) =payable(gateway.nativeTokenDestinationAddress)
.call{ value: msg.value }("");
if (!success) revert TransferError();
}
// pull the PRIME to primeDestinationAddressif (_primeValue !=0) {
prime.safeTransferFrom(
_msgSender(),
gateway.primeDestinationAddress,
_primeValue
);
}
// pull the Nfts to nftReceiverAddressif (_tokenIds.length!=0) {
_safeBatchTransferFrom(
_msgSender(),
gateway.echoCardDestinationAddress,
_tokenIds,
_amounts,
""
);
}
// invoke the handler function with all transaction data
InvokeSpendHandler(gateway.invokeSpendHandler).handleInvokeSpend(
_msgSender(),
gateway.echoCardDestinationAddress,
gateway.nativeTokenDestinationAddress,
gateway.primeDestinationAddress,
_id,
_tokenIds,
_amounts,
msg.value,
_primeValue,
_data
);
emit SpendInvoked(
_msgSender(),
gateway.echoCardDestinationAddress,
gateway.nativeTokenDestinationAddress,
gateway.primeDestinationAddress,
_id,
_tokenIds,
_amounts,
msg.value,
_primeValue,
_data
);
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - the caller must have the `MINTER_ROLE`.
* - `ids` and `amounts` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/functionmintBatchAdmin(address _to,
uint256[] memory _ids,
uint256[] memory _amounts,
bytesmemory _data
) externalonlyMinter{
_mintBatch(_to, _ids, _amounts, _data);
}
/**
* @notice Allow an address with admin role to add a handler contract for invoke
* @param _id - The id of the newly added handler contracts
* @param _echoCardDestinationAddress - The address to which the Echo Cards are collected
* @param _nativeTokenDestinationAddress - The address to which Native token is collected
* @param _primeDestinationAddress - The address to which PRIME is collected
* @param _invokeSpendHandler - The address of the new invoke handler contract to be registered
*/functionsetGateway(uint256 _id,
address _echoCardDestinationAddress,
address _nativeTokenDestinationAddress,
address _primeDestinationAddress,
address _invokeSpendHandler
) publiconlyAdmin{
if (_echoCardDestinationAddress ==address(0))
revert ZeroAddress("_echoCardDestinationAddress");
if (_nativeTokenDestinationAddress ==address(0))
revert ZeroAddress("_nativeTokenDestinationAddress");
if (_primeDestinationAddress ==address(0))
revert ZeroAddress("_primeDestinationAddress");
if (_invokeSpendHandler ==address(0))
revert ZeroAddress("_invokeSpendHandler");
EchoCardsLib.SpendGateway memory gateway;
gateway.echoCardDestinationAddress = _echoCardDestinationAddress;
gateway.nativeTokenDestinationAddress = _nativeTokenDestinationAddress;
gateway.primeDestinationAddress = _primeDestinationAddress;
gateway.invokeSpendHandler = InvokeSpendHandler(_invokeSpendHandler);
spendGateways[_id] = gateway;
emit SpendGatewayRegistered(
_id,
_invokeSpendHandler,
_echoCardDestinationAddress,
_nativeTokenDestinationAddress,
_primeDestinationAddress
);
}
/**
* @notice Overridden _msgSender to handle ERC2771
*/function_msgSender()
internalviewvirtualoverride(Context, ERC2771Recipient)
returns (address ret)
{
ret = ERC2771Recipient._msgSender();
}
/**
* @notice Overridden _msgData to handle ERC2771
*/function_msgData()
internalviewvirtualoverride(Context, ERC2771Recipient)
returns (bytescalldata)
{
return ERC2771Recipient._msgData();
}
/**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 _interfaceId
) publicviewvirtualoverride(AccessControl, ONFT1155) returns (bool) {
returnsuper.supportsInterface(_interfaceId);
}
}
// SPDX-License-Identifier: MITpragmasolidity 0.8.17;import { Ownable } from"@openzeppelin/contracts/access/Ownable.sol";
import { EchoCardsHandler } from"./EchoCardsHandler.sol";
import { IEchoCardsPrice } from"./interfaces/IEchoCardsPrice.sol";
import { EchoCardsPriceLib } from"./libraries/EchoCardsPriceLib.sol";
contractEchoCardsPriceisOwnable, IEchoCardsPrice{
mapping(uint256=> EchoCardsPriceLib.EchoCardsPriceInfo)
public echoCardsPriceInfo;
uint256publicconstant PRECISION =10000000000;
EchoCardsHandler public echoCardsHandler =
EchoCardsHandler(0x76BE3b62873462d2142405439777e971754E8E77);
/**
* @notice Calculates card price based on the card config
* @param _id Card id to get the price for
*/functioncalculatePrice(uint256 _id
) publicviewreturns (uint256 timeIntervals, uint256 newPrice) {
EchoCardsPriceLib.EchoCardsPriceInfo
memory echoCardsPrice = echoCardsPriceInfo[_id];
EchoCardsPriceLib.ConfigurableInfo
memory configurableInfo = echoCardsPrice.configurableInfo;
if (!echoCardsPrice.isInitialized) revert NotInitialized();
timeIntervals =
(block.timestamp- echoCardsPrice.lastTimestamp) /
configurableInfo.secondsPerDecrease;
if (timeIntervals >0&& echoCardsPrice.lastTimestamp !=0) {
uint256 linear = ((configurableInfo.linearDecreaseRate *
timeIntervals *1ether) / PRECISION);
newPrice = _getExpDecay(configurableInfo.price, timeIntervals, _id);
if (newPrice > linear) {
newPrice -= linear;
}
if (newPrice < configurableInfo.floorPrice) {
newPrice = configurableInfo.floorPrice;
}
} else {
uint256 numTicks = echoCardsPrice.countSinceLastPriceDecrease /
configurableInfo.numHitsPerIncrease;
uint256 exp = _getExpGrowth(configurableInfo.price, numTicks, _id);
uint256 linear = ((configurableInfo.linearIncreaseRate *
numTicks *1ether) / PRECISION);
if (exp + linear > configurableInfo.ceilingPrice) {
newPrice = configurableInfo.ceilingPrice;
} else {
newPrice = exp + linear;
}
}
}
/**
* @notice Returns card price based on the number of card being purchased and
the card config
* @param _id Card id to get the price for
* @param _cardCount Number of cards being purchased
*/functiongetCardPrice(uint256 _id,
uint256 _cardCount
) externalreturns (uint256) {
EchoCardsPriceLib.EchoCardsPriceInfo
storage echoCardsPrice = echoCardsPriceInfo[_id];
EchoCardsPriceLib.ConfigurableInfo
storage configurableInfo = echoCardsPrice.configurableInfo;
if (msg.sender!=address(echoCardsHandler)) {
revert InvalidGetPriceInvoker();
}
(uint256 timeIntervals, uint256 newPrice) = calculatePrice(_id);
if (timeIntervals >0&& echoCardsPrice.lastTimestamp !=0) {
echoCardsPrice.countSinceLastPriceDecrease = _cardCount;
echoCardsPrice.lastDecayPrice = newPrice;
} else {
echoCardsPrice.countSinceLastPriceDecrease += _cardCount;
echoCardsPrice.lastGrowthPrice = newPrice;
}
configurableInfo.price = newPrice;
echoCardsPrice.lastTimestamp =block.timestamp;
return configurableInfo.price;
}
/** @notice Set the echo cards handler address
* @param _echoCardsHandler echo cards handler address
*/functionsetEchoCardsHandler(
EchoCardsHandler _echoCardsHandler
) externalonlyOwner{
echoCardsHandler = _echoCardsHandler;
emit EchoCardsHandlerSet(address(_echoCardsHandler));
}
/** @notice Set the price of an echos card
* @param _tokenId token id to update variable for
* @param _price new price to set for tokenId
*/functionsetPrice(uint256 _tokenId, uint256 _price) externalonlyOwner{
echoCardsPriceInfo[_tokenId].configurableInfo.price = _price;
emit PriceSet(_tokenId, _price);
}
/** @notice Set the linear % each tick should increase by
* @param _tokenId token id to update variable for
* @param _linearIncreaseRate % to set that is relative to PRECISION
*/functionsetLinearIncreaseRate(uint256 _tokenId,
uint256 _linearIncreaseRate
) externalonlyOwner{
echoCardsPriceInfo[_tokenId]
.configurableInfo
.linearIncreaseRate = _linearIncreaseRate;
emit LinearIncreaseRateSet(_tokenId, _linearIncreaseRate);
}
/** @notice Set the linear % each timeIntervals should decrease by
* @param _tokenId token id to update variable for
* @param _linearDecreaseRate % to set that is relative to PRECISION
*/functionsetLinearDecreaseRate(uint256 _tokenId,
uint256 _linearDecreaseRate
) externalonlyOwner{
echoCardsPriceInfo[_tokenId]
.configurableInfo
.linearDecreaseRate = _linearDecreaseRate;
emit LinearDecreaseRateSet(_tokenId, _linearDecreaseRate);
}
/** @notice Set the growth double time
* @param _tokenId token id to update variable for
* @param _growthDoubleTime New growth double time
*/functionsetGrowthDoubleTime(uint256 _tokenId,
uint256 _growthDoubleTime
) externalonlyOwner{
echoCardsPriceInfo[_tokenId]
.configurableInfo
.growthDoublingTime = _growthDoubleTime;
emit GrowthDoubleTimeSet(_tokenId, _growthDoubleTime);
}
/** @notice Set the decay half life
* @param _tokenId token id to update variable for
* @param _decayHalfLife New decay half life
*/functionsetDecayHalfLife(uint256 _tokenId,
uint256 _decayHalfLife
) externalonlyOwner{
echoCardsPriceInfo[_tokenId]
.configurableInfo
.decayHalfLife = _decayHalfLife;
emit DecayHalfLifeSet(_tokenId, _decayHalfLife);
}
/** @notice Set the growth factor relative to exponential growth
* @param _tokenId token id to update variable for
* @param _growthFactor New growth factor
*/functionsetGrowthFactor(uint256 _tokenId,
uint256 _growthFactor
) externalonlyOwner{
echoCardsPriceInfo[_tokenId]
.configurableInfo
.growthFactor = _growthFactor;
emit GrowthFactorSet(_tokenId, _growthFactor);
}
/** @notice Set the decay factor relative to exponential decay
* @param _tokenId token id to update variable for
* @param _decayFactor New decay factor
*/functionsetDecayFactor(uint256 _tokenId,
uint256 _decayFactor
) externalonlyOwner{
echoCardsPriceInfo[_tokenId]
.configurableInfo
.decayFactor = _decayFactor;
emit DecayFactorSet(_tokenId, _decayFactor);
}
/** @notice The max price each card can be worth
* @param _ceilingPrice Ceiling price to set
*/functionsetCeilingPrice(uint256 _tokenId,
uint256 _ceilingPrice
) externalonlyOwner{
echoCardsPriceInfo[_tokenId]
.configurableInfo
.ceilingPrice = _ceilingPrice;
emit CeilingPriceSet(_tokenId, _ceilingPrice);
}
/** @notice Set minimum price each card can be worth
* @param _tokenId token id to update variable for
* @param _floorPrice Floor price to set
*/functionsetFloorPrice(uint256 _tokenId,
uint256 _floorPrice
) externalonlyOwner{
echoCardsPriceInfo[_tokenId].configurableInfo.floorPrice = _floorPrice;
emit FloorPriceSet(_tokenId, _floorPrice);
}
/** @notice Set how many hits it takes before price is increased
* @param _tokenId token id to update variable for
* @param _numHitsPerIncrease number of hits per increase
*/functionsetNumHitsPerIncrease(uint256 _tokenId,
uint256 _numHitsPerIncrease
) externalonlyOwner{
echoCardsPriceInfo[_tokenId]
.configurableInfo
.numHitsPerIncrease = _numHitsPerIncrease;
emit NumHitsPerIncreaseSet(_tokenId, _numHitsPerIncrease);
}
/** @notice Set how many seconds it takes before price is decreased
* @param _tokenId token id to update variable for
* @param _secondsPerDecrease number of seconds per decrease
*/functionsetSecondsPerDecrease(uint256 _tokenId,
uint256 _secondsPerDecrease
) externalonlyOwner{
echoCardsPriceInfo[_tokenId]
.configurableInfo
.secondsPerDecrease = _secondsPerDecrease;
emit SecondsPerDecreaseSet(_tokenId, _secondsPerDecrease);
}
/** @notice Set the inital price determine variables
* @param _tokenIds token ids to update variable for
* @param _configurableInfos initial configurable info of each token id
*/functionsetConfigurablePriceVariables(uint256[] calldata _tokenIds,
EchoCardsPriceLib.ConfigurableInfo[] calldata _configurableInfos
) publiconlyOwner{
if (_tokenIds.length!= _configurableInfos.length)
revert InvalidLength();
for (uint256 i =0; i < _tokenIds.length; i++) {
EchoCardsPriceLib.EchoCardsPriceInfo
storage echoCardsPrice = echoCardsPriceInfo[_tokenIds[i]];
if (!echoCardsPrice.isInitialized)
echoCardsPrice.isInitialized =true;
echoCardsPrice.configurableInfo = _configurableInfos[i];
}
emit ConfigurablePriceVariablesSet(_tokenIds, _configurableInfos);
}
/**
* @dev Helper function to approximate exp decay
* @param value To get exp decay for
* @param t Internal to get exp decay for
* @param id Card id to get the config for
*/function_getExpDecay(uint256 value,
uint256 t,
uint256 id
) internalviewreturns (uint256 exp) {
EchoCardsPriceLib.ConfigurableInfo
memory configurableInfo = echoCardsPriceInfo[id].configurableInfo;
value >>=
(configurableInfo.decayFactor * t) /
configurableInfo.decayHalfLife;
t %= configurableInfo.decayHalfLife;
exp =
value -
(value * configurableInfo.decayFactor * t) /
configurableInfo.decayHalfLife /2;
}
/**
* @dev Helper function to approximate exp growth
* @param value To get exp growth for
* @param t Internal to get exp growth for
* @param id Card id to get the config for
*/function_getExpGrowth(uint256 value,
uint256 t,
uint256 id
) internalviewreturns (uint256 exp) {
EchoCardsPriceLib.ConfigurableInfo
memory configurableInfo = echoCardsPriceInfo[id].configurableInfo;
value <<=
(configurableInfo.growthFactor * t) /
configurableInfo.growthDoublingTime;
t %= configurableInfo.growthDoublingTime;
exp =
value +
(value * configurableInfo.growthFactor * t) /
configurableInfo.growthDoublingTime /2;
}
}
// SPDX-License-Identifier: MIT OR Apache-2.0pragmasolidity >=0.7.6;libraryExcessivelySafeCall{
uint256constant LOW_28_MASK =0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
/// @notice Use when you _really_ really _really_ don't trust the called/// contract. This prevents the called contract from causing reversion of/// the caller in as many ways as we can./// @dev The main difference between this and a solidity low-level call is/// that we limit the number of bytes that the callee can cause to be/// copied to caller memory. This prevents stupid things like malicious/// contracts returning 10,000,000 bytes causing a local OOG when copying/// to memory./// @param _target The address to call/// @param _gas The amount of gas to forward to the remote contract/// @param _maxCopy The maximum number of bytes of returndata to copy/// to memory./// @param _calldata The data to send to the remote contract/// @return success and returndata, as `.call()`. Returndata is capped to/// `_maxCopy` bytes.functionexcessivelySafeCall(address _target,
uint256 _gas,
uint16 _maxCopy,
bytesmemory _calldata
) internalreturns (bool, bytesmemory) {
// set up for assembly calluint256 _toCopy;
bool _success;
bytesmemory _returnData =newbytes(_maxCopy);
// dispatch message to recipient// by assembly calling "handle" function// we call via assembly to avoid memcopying a very large returndata// returned by a malicious contractassembly {
_success :=call(
_gas, // gas
_target, // recipient0, // ether valueadd(_calldata, 0x20), // inlocmload(_calldata), // inlen0, // outloc0// outlen
)
// limit our copy to 256 bytes
_toCopy :=returndatasize()
ifgt(_toCopy, _maxCopy) {
_toCopy := _maxCopy
}
// Store the length of the copied bytesmstore(_returnData, _toCopy)
// copy the bytes from returndata[0:_toCopy]returndatacopy(add(_returnData, 0x20), 0, _toCopy)
}
return (_success, _returnData);
}
/// @notice Use when you _really_ really _really_ don't trust the called/// contract. This prevents the called contract from causing reversion of/// the caller in as many ways as we can./// @dev The main difference between this and a solidity low-level call is/// that we limit the number of bytes that the callee can cause to be/// copied to caller memory. This prevents stupid things like malicious/// contracts returning 10,000,000 bytes causing a local OOG when copying/// to memory./// @param _target The address to call/// @param _gas The amount of gas to forward to the remote contract/// @param _maxCopy The maximum number of bytes of returndata to copy/// to memory./// @param _calldata The data to send to the remote contract/// @return success and returndata, as `.call()`. Returndata is capped to/// `_maxCopy` bytes.functionexcessivelySafeStaticCall(address _target,
uint256 _gas,
uint16 _maxCopy,
bytesmemory _calldata
) internalviewreturns (bool, bytesmemory) {
// set up for assembly calluint256 _toCopy;
bool _success;
bytesmemory _returnData =newbytes(_maxCopy);
// dispatch message to recipient// by assembly calling "handle" function// we call via assembly to avoid memcopying a very large returndata// returned by a malicious contractassembly {
_success :=staticcall(
_gas, // gas
_target, // recipientadd(_calldata, 0x20), // inlocmload(_calldata), // inlen0, // outloc0// outlen
)
// limit our copy to 256 bytes
_toCopy :=returndatasize()
ifgt(_toCopy, _maxCopy) {
_toCopy := _maxCopy
}
// Store the length of the copied bytesmstore(_returnData, _toCopy)
// copy the bytes from returndata[0:_toCopy]returndatacopy(add(_returnData, 0x20), 0, _toCopy)
}
return (_success, _returnData);
}
/**
* @notice Swaps function selectors in encoded contract calls
* @dev Allows reuse of encoded calldata for functions with identical
* argument types but different names. It simply swaps out the first 4 bytes
* for the new selector. This function modifies memory in place, and should
* only be used with caution.
* @param _newSelector The new 4-byte selector
* @param _buf The encoded contract args
*/functionswapSelector(bytes4 _newSelector, bytesmemory _buf)
internalpure{
require(_buf.length>=4);
uint256 _mask = LOW_28_MASK;
assembly {
// load the first word oflet _word :=mload(add(_buf, 0x20))
// mask out the top 4 bytes// /x
_word :=and(_word, _mask)
_word :=or(_newSelector, _word)
mstore(add(_buf, 0x20), _word)
}
}
}
Contract Source Code
File 17 of 41: IAccessControl.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)pragmasolidity ^0.8.0;/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/interfaceIAccessControl{
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/eventRoleAdminChanged(bytes32indexed role, bytes32indexed previousAdminRole, bytes32indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/eventRoleGranted(bytes32indexed role, addressindexed account, addressindexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/eventRoleRevoked(bytes32indexed role, addressindexed account, addressindexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/functionhasRole(bytes32 role, address account) externalviewreturns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/functiongetRoleAdmin(bytes32 role) externalviewreturns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/functiongrantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/functionrevokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/functionrenounceRole(bytes32 role, address account) external;
}
Contract Source Code
File 18 of 41: IERC1155.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)pragmasolidity ^0.8.0;import"../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC1155 compliant contract, as defined in the
* https://eips.ethereum.org/EIPS/eip-1155[EIP].
*
* _Available since v3.1._
*/interfaceIERC1155isIERC165{
/**
* @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
*/eventTransferSingle(addressindexed operator, addressindexedfrom, addressindexed to, uint256 id, uint256 value);
/**
* @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
* transfers.
*/eventTransferBatch(addressindexed operator,
addressindexedfrom,
addressindexed to,
uint256[] ids,
uint256[] values
);
/**
* @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
* `approved`.
*/eventApprovalForAll(addressindexed account, addressindexed operator, bool approved);
/**
* @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
*
* If an {URI} event was emitted for `id`, the standard
* https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
* returned by {IERC1155MetadataURI-uri}.
*/eventURI(string value, uint256indexed id);
/**
* @dev Returns the amount of tokens of token type `id` owned by `account`.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/functionbalanceOf(address account, uint256 id) externalviewreturns (uint256);
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/functionbalanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
externalviewreturns (uint256[] memory);
/**
* @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
*
* Emits an {ApprovalForAll} event.
*
* Requirements:
*
* - `operator` cannot be the caller.
*/functionsetApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
*
* See {setApprovalForAll}.
*/functionisApprovedForAll(address account, address operator) externalviewreturns (bool);
/**
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `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`.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 id,
uint256 amount,
bytescalldata data
) external;
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/functionsafeBatchTransferFrom(addressfrom,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytescalldata data
) external;
}
Contract Source Code
File 19 of 41: IERC1155MetadataURI.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)pragmasolidity ^0.8.0;import"../IERC1155.sol";
/**
* @dev Interface of the optional ERC1155MetadataExtension interface, as defined
* in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
*
* _Available since v3.1._
*/interfaceIERC1155MetadataURIisIERC1155{
/**
* @dev Returns the URI for token type `id`.
*
* If the `\{id\}` substring is present in the URI, it must be replaced by
* clients with the actual token type ID.
*/functionuri(uint256 id) externalviewreturns (stringmemory);
}
Contract Source Code
File 20 of 41: IERC1155Receiver.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)pragmasolidity ^0.8.0;import"../../utils/introspection/IERC165.sol";
/**
* @dev _Available since v3.1._
*/interfaceIERC1155ReceiverisIERC165{
/**
* @dev Handles the receipt of a single ERC1155 token type. This function is
* called at the end of a `safeTransferFrom` after the balance has been updated.
*
* NOTE: To accept the transfer, this must return
* `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
* (i.e. 0xf23a6e61, or its own function selector).
*
* @param operator The address which initiated the transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param id The ID of the token being transferred
* @param value The amount of tokens being transferred
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
*/functiononERC1155Received(address operator,
addressfrom,
uint256 id,
uint256 value,
bytescalldata data
) externalreturns (bytes4);
/**
* @dev Handles the receipt of a multiple ERC1155 token types. This function
* is called at the end of a `safeBatchTransferFrom` after the balances have
* been updated.
*
* NOTE: To accept the transfer(s), this must return
* `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
* (i.e. 0xbc197c81, or its own function selector).
*
* @param operator The address which initiated the batch transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param ids An array containing ids of each token being transferred (order and length must match values array)
* @param values An array containing amounts of each token being transferred (order and length must match ids array)
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
*/functiononERC1155BatchReceived(address operator,
addressfrom,
uint256[] calldata ids,
uint256[] calldata values,
bytescalldata data
) externalreturns (bytes4);
}
Contract Source Code
File 21 of 41: IERC165.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)pragmasolidity ^0.8.0;/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/interfaceIERC165{
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/functionsupportsInterface(bytes4 interfaceId) externalviewreturns (bool);
}
Contract Source Code
File 22 of 41: IERC20.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)pragmasolidity ^0.8.0;/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/interfaceIERC20{
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/eventTransfer(addressindexedfrom, addressindexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/eventApproval(addressindexed owner, addressindexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/functiontotalSupply() externalviewreturns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/functionbalanceOf(address account) externalviewreturns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/functiontransfer(address to, uint256 amount) externalreturns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/functionallowance(address owner, address spender) externalviewreturns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/functionapprove(address spender, uint256 amount) externalreturns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/functiontransferFrom(addressfrom,
address to,
uint256 amount
) externalreturns (bool);
}
Contract Source Code
File 23 of 41: IERC2771Recipient.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/**
* @title The ERC-2771 Recipient Base Abstract Class - Declarations
*
* @notice A contract must implement this interface in order to support relayed transaction.
*
* @notice It is recommended that your contract inherits from the ERC2771Recipient contract.
*/abstractcontractIERC2771Recipient{
/**
* :warning: **Warning** :warning: The Forwarder can have a full control over your Recipient. Only trust verified Forwarder.
* @param forwarder The address of the Forwarder contract that is being used.
* @return isTrustedForwarder `true` if the Forwarder is trusted to forward relayed transactions by this Recipient.
*/functionisTrustedForwarder(address forwarder
) publicviewvirtualreturns (bool);
/**
* @notice Use this method the contract anywhere instead of msg.sender to support relayed transactions.
* @return sender The real sender of this call.
* For a call that came through the Forwarder the real sender is extracted from the last 20 bytes of the `msg.data`.
* Otherwise simply returns `msg.sender`.
*/function_msgSender() internalviewvirtualreturns (address);
/**
* @notice Use this method in the contract instead of `msg.data` when difference matters (hashing, signature, etc.)
* @return data The real `msg.data` of this call.
* For a call that came through the Forwarder, the real sender address was appended as the last 20 bytes
* of the `msg.data` - so this method will strip those 20 bytes off.
* Otherwise (if the call was made directly and not through the forwarder) simply returns `msg.data`.
*/function_msgData() internalviewvirtualreturns (bytescalldata);
}
Contract Source Code
File 24 of 41: IEchoCards.sol
// SPDX-License-Identifier: MITpragmasolidity 0.8.17;interfaceIEchoCards{
/**
* @dev Insufficient permissions for caller.
*
* @param userAddress user address.
* @param requiredRole the required role
*/errorInsufficientPermissions(address userAddress, bytes32 requiredRole);
/**
* @dev Invalid address of zero
*
* @param addressType Which address is incorrectly set
*/errorZeroAddress(string addressType);
/**
* @dev eth transfer failed
*/errorTransferError();
/**
* @dev Fired when a new gateway (i.e. spend handler contract) is registered
* @param id - The id of the gateway
* @param handler - The address of the newly registered invokeSpend handler contract
* @param echoCardDestinationAddress - The address to which Echo Cards was collected
* @param nativeTokenDestinationAddress - The address to which native token was collected
* @param primeDestinationAddress - The address to which PRIME was collected
*/eventSpendGatewayRegistered(uint256indexed id,
addressindexed handler,
address echoCardDestinationAddress,
address nativeTokenDestinationAddress,
address primeDestinationAddress
);
/**
* @dev Emitted when the new forwarder is set
* @param forwarder The address of the new forwarder
*/eventTrustedForwarderSet(address forwarder);
/**
* @dev Emit an event when the disabled state gets set.
*/eventIsDisabledSet(bool newDisabledState);
/**
* @dev Emit an event for prime address updates.
*
* @param newPrimeAddress the new prime address.
*/eventPrimeAddressSet(addressindexed newPrimeAddress);
/**
* @dev Fired when the handler is invoked
* @param from - The address of the invoker
* @param echoCardDestination - The address to which nfts was collected
* @param nativeDestination - The address to which ETH or whatever native token was collected
* @param primeDestination - The address to which PRIME was collected
* @param id - The arbitrary identifier used for tracking
* @param nativeValue - The amount of ETH or whatever native token that was sent
* @param primeValue - The amount of PRIME that was sent
* @param data - Additional data that was sent
*/eventSpendInvoked(addressindexedfrom,
address echoCardDestination,
address nativeDestination,
address primeDestination,
uint256 id,
uint256[] _tokenIds,
uint256[] _amounts,
uint256 nativeValue,
uint256 primeValue,
bytes data
);
}
Contract Source Code
File 25 of 41: IEchoCardsHandler.sol
// SPDX-License-Identifier: MITpragmasolidity 0.8.17;interfaceIEchoCardsHandler{
errorInvalidPrimeAddress();
errorContractDisabled();
errorEchoCardsPriceLocked();
errorInvalidSig(bytes _signature);
errorInvalidPayment();
/**
* @dev Emit an event when the disabled state gets set.
*/eventIsDisabledSet(bool newDisabledState);
/**
* @dev Emit an event for prime address updates.
*
* @param newPrimeAddress the new prime address.
*/eventPrimeAddressSet(addressindexed newPrimeAddress);
/**
* @dev Emit an event for trusted signer updates.
*
* @param newTrustedSigner the new trusted signer address.
*/eventTrustedSignerSet(addressindexed newTrustedSigner);
errorInvalidId(uint256 parallelAlphaId);
errorInvalidLength();
/**
* @dev Emit an event for echo cards payment.
*
* @param from address that is allowed to mint by the signature.
* @param nonce current nonce of from
* @param totalPrice cost of minting
* @param ids ids being minted
* @param amounts amounts being minted
* @param signature signature includes from, ids, amounts, and current nonce
*/eventEchoCardsPayment(addressindexedfrom,
uint256indexed nonce,
uint256 totalPrice,
uint256[] ids,
uint256[] amounts,
bytes signature
);
eventEchoCardsPriceLockedSet();
eventEchoCardsPriceSet(addressindexed echoCardsPrice);
eventEchoCardsSet(addressindexed echoCards);
eventParallelAlphaToEchosSet(uint256[] parallelAlphaIds,
uint256[] echosIds
);
}
// SPDX-License-Identifier: MITpragmasolidity >=0.5.0;import"./ILayerZeroUserApplicationConfig.sol";
interfaceILayerZeroEndpointisILayerZeroUserApplicationConfig{
// @notice send a LayerZero message to the specified address at a LayerZero endpoint.// @param _dstChainId - the destination chain identifier// @param _destination - the address on destination chain (in bytes). address length/format may vary by chains// @param _payload - a custom bytes payload to send to the destination contract// @param _refundAddress - if the source transaction is cheaper than the amount of value passed, refund the additional amount to this address// @param _zroPaymentAddress - the address of the ZRO token holder who would pay for the transaction// @param _adapterParams - parameters for custom functionality. e.g. receive airdropped native gas from the relayer on destinationfunctionsend(uint16 _dstChainId, bytescalldata _destination, bytescalldata _payload, addresspayable _refundAddress, address _zroPaymentAddress, bytescalldata _adapterParams) externalpayable;
// @notice used by the messaging library to publish verified payload// @param _srcChainId - the source chain identifier// @param _srcAddress - the source contract (as bytes) at the source chain// @param _dstAddress - the address on destination chain// @param _nonce - the unbound message ordering nonce// @param _gasLimit - the gas limit for external contract execution// @param _payload - verified payload to send to the destination contractfunctionreceivePayload(uint16 _srcChainId, bytescalldata _srcAddress, address _dstAddress, uint64 _nonce, uint _gasLimit, bytescalldata _payload) external;
// @notice get the inboundNonce of a lzApp from a source chain which could be EVM or non-EVM chain// @param _srcChainId - the source chain identifier// @param _srcAddress - the source chain contract addressfunctiongetInboundNonce(uint16 _srcChainId, bytescalldata _srcAddress) externalviewreturns (uint64);
// @notice get the outboundNonce from this source chain which, consequently, is always an EVM// @param _srcAddress - the source chain contract addressfunctiongetOutboundNonce(uint16 _dstChainId, address _srcAddress) externalviewreturns (uint64);
// @notice gets a quote in source native gas, for the amount that send() requires to pay for message delivery// @param _dstChainId - the destination chain identifier// @param _userApplication - the user app address on this EVM chain// @param _payload - the custom message to send over LayerZero// @param _payInZRO - if false, user app pays the protocol fee in native token// @param _adapterParam - parameters for the adapter service, e.g. send some dust native token to dstChainfunctionestimateFees(uint16 _dstChainId, address _userApplication, bytescalldata _payload, bool _payInZRO, bytescalldata _adapterParam) externalviewreturns (uint nativeFee, uint zroFee);
// @notice get this Endpoint's immutable source identifierfunctiongetChainId() externalviewreturns (uint16);
// @notice the interface to retry failed message on this Endpoint destination// @param _srcChainId - the source chain identifier// @param _srcAddress - the source chain contract address// @param _payload - the payload to be retriedfunctionretryPayload(uint16 _srcChainId, bytescalldata _srcAddress, bytescalldata _payload) external;
// @notice query if any STORED payload (message blocking) at the endpoint.// @param _srcChainId - the source chain identifier// @param _srcAddress - the source chain contract addressfunctionhasStoredPayload(uint16 _srcChainId, bytescalldata _srcAddress) externalviewreturns (bool);
// @notice query if the _libraryAddress is valid for sending msgs.// @param _userApplication - the user app address on this EVM chainfunctiongetSendLibraryAddress(address _userApplication) externalviewreturns (address);
// @notice query if the _libraryAddress is valid for receiving msgs.// @param _userApplication - the user app address on this EVM chainfunctiongetReceiveLibraryAddress(address _userApplication) externalviewreturns (address);
// @notice query if the non-reentrancy guard for send() is on// @return true if the guard is on. false otherwisefunctionisSendingPayload() externalviewreturns (bool);
// @notice query if the non-reentrancy guard for receive() is on// @return true if the guard is on. false otherwisefunctionisReceivingPayload() externalviewreturns (bool);
// @notice get the configuration of the LayerZero messaging library of the specified version// @param _version - messaging library version// @param _chainId - the chainId for the pending config change// @param _userApplication - the contract address of the user application// @param _configType - type of configuration. every messaging library has its own convention.functiongetConfig(uint16 _version, uint16 _chainId, address _userApplication, uint _configType) externalviewreturns (bytesmemory);
// @notice get the send() LayerZero messaging library version// @param _userApplication - the contract address of the user applicationfunctiongetSendVersion(address _userApplication) externalviewreturns (uint16);
// @notice get the lzReceive() LayerZero messaging library version// @param _userApplication - the contract address of the user applicationfunctiongetReceiveVersion(address _userApplication) externalviewreturns (uint16);
}
Contract Source Code
File 28 of 41: ILayerZeroReceiver.sol
// SPDX-License-Identifier: MITpragmasolidity >=0.5.0;interfaceILayerZeroReceiver{
// @notice LayerZero endpoint will invoke this function to deliver the message on the destination// @param _srcChainId - the source endpoint identifier// @param _srcAddress - the source sending contract address from the source chain// @param _nonce - the ordered message nonce// @param _payload - the signed payload is the UA bytes has encoded to be sentfunctionlzReceive(uint16 _srcChainId, bytescalldata _srcAddress, uint64 _nonce, bytescalldata _payload) external;
}
Contract Source Code
File 29 of 41: ILayerZeroUserApplicationConfig.sol
// SPDX-License-Identifier: MITpragmasolidity >=0.5.0;interfaceILayerZeroUserApplicationConfig{
// @notice set the configuration of the LayerZero messaging library of the specified version// @param _version - messaging library version// @param _chainId - the chainId for the pending config change// @param _configType - type of configuration. every messaging library has its own convention.// @param _config - configuration in the bytes. can encode arbitrary content.functionsetConfig(uint16 _version, uint16 _chainId, uint _configType, bytescalldata _config) external;
// @notice set the send() LayerZero messaging library version to _version// @param _version - new messaging library versionfunctionsetSendVersion(uint16 _version) external;
// @notice set the lzReceive() LayerZero messaging library version to _version// @param _version - new messaging library versionfunctionsetReceiveVersion(uint16 _version) external;
// @notice Only when the UA needs to resume the message flow in blocking mode and clear the stored payload// @param _srcChainId - the chainId of the source chain// @param _srcAddress - the contract address of the source contract at the source chainfunctionforceResumeReceive(uint16 _srcChainId, bytescalldata _srcAddress) external;
}
Contract Source Code
File 30 of 41: IONFT1155.sol
// SPDX-License-Identifier: MITpragmasolidity >=0.5.0;import"./IONFT1155Core.sol";
import"@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
/**
* @dev Interface of the ONFT standard
*/interfaceIONFT1155isIONFT1155Core, IERC1155{
}
Contract Source Code
File 31 of 41: IONFT1155Core.sol
// SPDX-License-Identifier: MITpragmasolidity >=0.5.0;import"@openzeppelin/contracts/utils/introspection/IERC165.sol";
/**
* @dev Interface of the ONFT Core standard
*/interfaceIONFT1155CoreisIERC165{
eventSendToChain(uint16indexed _dstChainId, addressindexed _from, bytesindexed _toAddress, uint _tokenId, uint _amount);
eventSendBatchToChain(uint16indexed _dstChainId, addressindexed _from, bytesindexed _toAddress, uint[] _tokenIds, uint[] _amounts);
eventReceiveFromChain(uint16indexed _srcChainId, bytesindexed _srcAddress, addressindexed _toAddress, uint _tokenId, uint _amount);
eventReceiveBatchFromChain(uint16indexed _srcChainId, bytesindexed _srcAddress, addressindexed _toAddress, uint[] _tokenIds, uint[] _amounts);
// _from - address where tokens should be deducted from on behalf of// _dstChainId - L0 defined chain id to send tokens too// _toAddress - dynamic bytes array which contains the address to whom you are sending tokens to on the dstChain// _tokenId - token Id to transfer// _amount - amount of the tokens to transfer// _refundAddress - address on src that will receive refund for any overpayment of L0 fees// _zroPaymentAddress - if paying in zro, pass the address to use. using 0x0 indicates not paying fees in zro// _adapterParams - flexible bytes array to indicate messaging adapter services in L0functionsendFrom(address _from, uint16 _dstChainId, bytescalldata _toAddress, uint _tokenId, uint _amount, addresspayable _refundAddress, address _zroPaymentAddress, bytescalldata _adapterParams) externalpayable;
// _from - address where tokens should be deducted from on behalf of// _dstChainId - L0 defined chain id to send tokens too// _toAddress - dynamic bytes array which contains the address to whom you are sending tokens to on the dstChain// _tokenIds - token Ids to transfer// _amounts - amounts of the tokens to transfer// _refundAddress - address on src that will receive refund for any overpayment of L0 fees// _zroPaymentAddress - if paying in zro, pass the address to use. using 0x0 indicates not paying fees in zro// _adapterParams - flexible bytes array to indicate messaging adapter services in L0functionsendBatchFrom(address _from, uint16 _dstChainId, bytescalldata _toAddress, uint[] calldata _tokenIds, uint[] calldata _amounts, addresspayable _refundAddress, address _zroPaymentAddress, bytescalldata _adapterParams) externalpayable;
// _dstChainId - L0 defined chain id to send tokens too// _toAddress - dynamic bytes array which contains the address to whom you are sending tokens to on the dstChain// _tokenId - token Id to transfer// _amount - amount of the tokens to transfer// _useZro - indicates to use zro to pay L0 fees// _adapterParams - flexible bytes array to indicate messaging adapter services in L0functionestimateSendFee(uint16 _dstChainId, bytescalldata _toAddress, uint _tokenId, uint _amount, bool _useZro, bytescalldata _adapterParams) externalviewreturns (uint nativeFee, uint zroFee);
// _dstChainId - L0 defined chain id to send tokens too// _toAddress - dynamic bytes array which contains the address to whom you are sending tokens to on the dstChain// _tokenIds - tokens Id to transfer// _amounts - amounts of the tokens to transfer// _useZro - indicates to use zro to pay L0 fees// _adapterParams - flexible bytes array to indicate messaging adapter services in L0functionestimateSendBatchFee(uint16 _dstChainId, bytescalldata _toAddress, uint[] calldata _tokenIds, uint[] calldata _amounts, bool _useZro, bytescalldata _adapterParams) externalviewreturns (uint nativeFee, uint zroFee);
}
Contract Source Code
File 32 of 41: LzApp.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import"@openzeppelin/contracts/access/Ownable.sol";
import"../interfaces/ILayerZeroReceiver.sol";
import"../interfaces/ILayerZeroUserApplicationConfig.sol";
import"../interfaces/ILayerZeroEndpoint.sol";
import"../util/BytesLib.sol";
/*
* a generic LzReceiver implementation
*/abstractcontractLzAppisOwnable, ILayerZeroReceiver, ILayerZeroUserApplicationConfig{
usingBytesLibforbytes;
// ua can not send payload larger than this by default, but it can be changed by the ua owneruintconstantpublic DEFAULT_PAYLOAD_SIZE_LIMIT =10000;
ILayerZeroEndpoint publicimmutable lzEndpoint;
mapping(uint16=>bytes) public trustedRemoteLookup;
mapping(uint16=>mapping(uint16=>uint)) public minDstGasLookup;
mapping(uint16=>uint) public payloadSizeLimitLookup;
addresspublic precrime;
eventSetPrecrime(address precrime);
eventSetTrustedRemote(uint16 _remoteChainId, bytes _path);
eventSetTrustedRemoteAddress(uint16 _remoteChainId, bytes _remoteAddress);
eventSetMinDstGas(uint16 _dstChainId, uint16 _type, uint _minDstGas);
constructor(address _endpoint) {
lzEndpoint = ILayerZeroEndpoint(_endpoint);
}
functionlzReceive(uint16 _srcChainId, bytescalldata _srcAddress, uint64 _nonce, bytescalldata _payload) publicvirtualoverride{
// lzReceive must be called by the endpoint for securityrequire(_msgSender() ==address(lzEndpoint), "LzApp: invalid endpoint caller");
bytesmemory trustedRemote = trustedRemoteLookup[_srcChainId];
// if will still block the message pathway from (srcChainId, srcAddress). should not receive message from untrusted remote.require(_srcAddress.length== trustedRemote.length&& trustedRemote.length>0&&keccak256(_srcAddress) ==keccak256(trustedRemote), "LzApp: invalid source sending contract");
_blockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload);
}
// abstract function - the default behaviour of LayerZero is blocking. See: NonblockingLzApp if you dont need to enforce ordered messagingfunction_blockingLzReceive(uint16 _srcChainId, bytesmemory _srcAddress, uint64 _nonce, bytesmemory _payload) internalvirtual;
function_lzSend(uint16 _dstChainId, bytesmemory _payload, addresspayable _refundAddress, address _zroPaymentAddress, bytesmemory _adapterParams, uint _nativeFee) internalvirtual{
bytesmemory trustedRemote = trustedRemoteLookup[_dstChainId];
require(trustedRemote.length!=0, "LzApp: destination chain is not a trusted source");
_checkPayloadSize(_dstChainId, _payload.length);
lzEndpoint.send{value: _nativeFee}(_dstChainId, trustedRemote, _payload, _refundAddress, _zroPaymentAddress, _adapterParams);
}
function_checkGasLimit(uint16 _dstChainId, uint16 _type, bytesmemory _adapterParams, uint _extraGas) internalviewvirtual{
uint providedGasLimit = _getGasLimit(_adapterParams);
uint minGasLimit = minDstGasLookup[_dstChainId][_type] + _extraGas;
require(minGasLimit >0, "LzApp: minGasLimit not set");
require(providedGasLimit >= minGasLimit, "LzApp: gas limit is too low");
}
function_getGasLimit(bytesmemory _adapterParams) internalpurevirtualreturns (uint gasLimit) {
require(_adapterParams.length>=34, "LzApp: invalid adapterParams");
assembly {
gasLimit :=mload(add(_adapterParams, 34))
}
}
function_checkPayloadSize(uint16 _dstChainId, uint _payloadSize) internalviewvirtual{
uint payloadSizeLimit = payloadSizeLimitLookup[_dstChainId];
if (payloadSizeLimit ==0) { // use default if not set
payloadSizeLimit = DEFAULT_PAYLOAD_SIZE_LIMIT;
}
require(_payloadSize <= payloadSizeLimit, "LzApp: payload size is too large");
}
//---------------------------UserApplication config----------------------------------------functiongetConfig(uint16 _version, uint16 _chainId, address, uint _configType) externalviewreturns (bytesmemory) {
return lzEndpoint.getConfig(_version, _chainId, address(this), _configType);
}
// generic config for LayerZero user ApplicationfunctionsetConfig(uint16 _version, uint16 _chainId, uint _configType, bytescalldata _config) externaloverrideonlyOwner{
lzEndpoint.setConfig(_version, _chainId, _configType, _config);
}
functionsetSendVersion(uint16 _version) externaloverrideonlyOwner{
lzEndpoint.setSendVersion(_version);
}
functionsetReceiveVersion(uint16 _version) externaloverrideonlyOwner{
lzEndpoint.setReceiveVersion(_version);
}
functionforceResumeReceive(uint16 _srcChainId, bytescalldata _srcAddress) externaloverrideonlyOwner{
lzEndpoint.forceResumeReceive(_srcChainId, _srcAddress);
}
// _path = abi.encodePacked(remoteAddress, localAddress)// this function set the trusted path for the cross-chain communicationfunctionsetTrustedRemote(uint16 _srcChainId, bytescalldata _path) externalonlyOwner{
trustedRemoteLookup[_srcChainId] = _path;
emit SetTrustedRemote(_srcChainId, _path);
}
functionsetTrustedRemoteAddress(uint16 _remoteChainId, bytescalldata _remoteAddress) externalonlyOwner{
trustedRemoteLookup[_remoteChainId] =abi.encodePacked(_remoteAddress, address(this));
emit SetTrustedRemoteAddress(_remoteChainId, _remoteAddress);
}
functiongetTrustedRemoteAddress(uint16 _remoteChainId) externalviewreturns (bytesmemory) {
bytesmemory path = trustedRemoteLookup[_remoteChainId];
require(path.length!=0, "LzApp: no trusted path record");
return path.slice(0, path.length-20); // the last 20 bytes should be address(this)
}
functionsetPrecrime(address _precrime) externalonlyOwner{
precrime = _precrime;
emit SetPrecrime(_precrime);
}
functionsetMinDstGas(uint16 _dstChainId, uint16 _packetType, uint _minGas) externalonlyOwner{
require(_minGas >0, "LzApp: invalid minGas");
minDstGasLookup[_dstChainId][_packetType] = _minGas;
emit SetMinDstGas(_dstChainId, _packetType, _minGas);
}
// if the size is 0, it means default size limitfunctionsetPayloadSizeLimit(uint16 _dstChainId, uint _size) externalonlyOwner{
payloadSizeLimitLookup[_dstChainId] = _size;
}
//--------------------------- VIEW FUNCTION ----------------------------------------functionisTrustedRemote(uint16 _srcChainId, bytescalldata _srcAddress) externalviewreturns (bool) {
bytesmemory trustedSource = trustedRemoteLookup[_srcChainId];
returnkeccak256(trustedSource) ==keccak256(_srcAddress);
}
}
Contract Source Code
File 33 of 41: Math.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)pragmasolidity ^0.8.0;/**
* @dev Standard math utilities missing in the Solidity language.
*/libraryMath{
enumRounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/functionmax(uint256 a, uint256 b) internalpurereturns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/functionmin(uint256 a, uint256 b) internalpurereturns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/functionaverage(uint256 a, uint256 b) internalpurereturns (uint256) {
// (a + b) / 2 can overflow.return (a & b) + (a ^ b) /2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/functionceilDiv(uint256 a, uint256 b) internalpurereturns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.return a ==0 ? 0 : (a -1) / b +1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/functionmulDiv(uint256 x,
uint256 y,
uint256 denominator
) internalpurereturns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256// variables such that product = prod1 * 2^256 + prod0.uint256 prod0; // Least significant 256 bits of the productuint256 prod1; // Most significant 256 bits of the productassembly {
let mm :=mulmod(x, y, not(0))
prod0 :=mul(x, y)
prod1 :=sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.if (prod1 ==0) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.require(denominator > prod1);
///////////////////////////////////////////////// 512 by 256 division.///////////////////////////////////////////////// Make division exact by subtracting the remainder from [prod1 prod0].uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder :=mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 :=sub(prod1, gt(remainder, prod0))
prod0 :=sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.// See https://cs.stackexchange.com/q/138556/92363.// Does not overflow because the denominator cannot be zero at this stage in the function.uint256 twos = denominator & (~denominator +1);
assembly {
// Divide denominator by twos.
denominator :=div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 :=div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos :=add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for// four bits. That is, denominator * inv = 1 mod 2^4.uint256 inverse = (3* denominator) ^2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works// in modular arithmetic, doubling the correct bits in each step.
inverse *=2- denominator * inverse; // inverse mod 2^8
inverse *=2- denominator * inverse; // inverse mod 2^16
inverse *=2- denominator * inverse; // inverse mod 2^32
inverse *=2- denominator * inverse; // inverse mod 2^64
inverse *=2- denominator * inverse; // inverse mod 2^128
inverse *=2- denominator * inverse; // inverse mod 2^256// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/functionmulDiv(uint256 x,
uint256 y,
uint256 denominator,
Rounding rounding
) internalpurereturns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up &&mulmod(x, y, denominator) >0) {
result +=1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/functionsqrt(uint256 a) internalpurereturns (uint256) {
if (a ==0) {
return0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.//// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.//// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`//// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.uint256 result =1<< (log2(a) >>1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision// into the expected uint128 result.unchecked {
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/functionsqrt(uint256 a, Rounding rounding) internalpurereturns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/functionlog2(uint256 value) internalpurereturns (uint256) {
uint256 result =0;
unchecked {
if (value >>128>0) {
value >>=128;
result +=128;
}
if (value >>64>0) {
value >>=64;
result +=64;
}
if (value >>32>0) {
value >>=32;
result +=32;
}
if (value >>16>0) {
value >>=16;
result +=16;
}
if (value >>8>0) {
value >>=8;
result +=8;
}
if (value >>4>0) {
value >>=4;
result +=4;
}
if (value >>2>0) {
value >>=2;
result +=2;
}
if (value >>1>0) {
result +=1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/functionlog2(uint256 value, Rounding rounding) internalpurereturns (uint256) {
unchecked {
uint256 result =log2(value);
return result + (rounding == Rounding.Up &&1<< result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/functionlog10(uint256 value) internalpurereturns (uint256) {
uint256 result =0;
unchecked {
if (value >=10**64) {
value /=10**64;
result +=64;
}
if (value >=10**32) {
value /=10**32;
result +=32;
}
if (value >=10**16) {
value /=10**16;
result +=16;
}
if (value >=10**8) {
value /=10**8;
result +=8;
}
if (value >=10**4) {
value /=10**4;
result +=4;
}
if (value >=10**2) {
value /=10**2;
result +=2;
}
if (value >=10**1) {
result +=1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/functionlog10(uint256 value, Rounding rounding) internalpurereturns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up &&10**result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/functionlog256(uint256 value) internalpurereturns (uint256) {
uint256 result =0;
unchecked {
if (value >>128>0) {
value >>=128;
result +=16;
}
if (value >>64>0) {
value >>=64;
result +=8;
}
if (value >>32>0) {
value >>=32;
result +=4;
}
if (value >>16>0) {
value >>=16;
result +=2;
}
if (value >>8>0) {
result +=1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/functionlog256(uint256 value, Rounding rounding) internalpurereturns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up &&1<< (result *8) < value ? 1 : 0);
}
}
}
Contract Source Code
File 34 of 41: NonblockingLzApp.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import"./LzApp.sol";
import"../util/ExcessivelySafeCall.sol";
/*
* the default LayerZero messaging behaviour is blocking, i.e. any failed message will block the channel
* this abstract class try-catch all fail messages and store locally for future retry. hence, non-blocking
* NOTE: if the srcAddress is not configured properly, it will still block the message pathway from (srcChainId, srcAddress)
*/abstractcontractNonblockingLzAppisLzApp{
usingExcessivelySafeCallforaddress;
constructor(address _endpoint) LzApp(_endpoint) {}
mapping(uint16=>mapping(bytes=>mapping(uint64=>bytes32))) public failedMessages;
eventMessageFailed(uint16 _srcChainId, bytes _srcAddress, uint64 _nonce, bytes _payload, bytes _reason);
eventRetryMessageSuccess(uint16 _srcChainId, bytes _srcAddress, uint64 _nonce, bytes32 _payloadHash);
// overriding the virtual function in LzReceiverfunction_blockingLzReceive(uint16 _srcChainId, bytesmemory _srcAddress, uint64 _nonce, bytesmemory _payload) internalvirtualoverride{
(bool success, bytesmemory reason) =address(this).excessivelySafeCall(gasleft(), 150, abi.encodeWithSelector(this.nonblockingLzReceive.selector, _srcChainId, _srcAddress, _nonce, _payload));
// try-catch all errors/exceptionsif (!success) {
_storeFailedMessage(_srcChainId, _srcAddress, _nonce, _payload, reason);
}
}
function_storeFailedMessage(uint16 _srcChainId, bytesmemory _srcAddress, uint64 _nonce, bytesmemory _payload, bytesmemory _reason) internalvirtual{
failedMessages[_srcChainId][_srcAddress][_nonce] =keccak256(_payload);
emit MessageFailed(_srcChainId, _srcAddress, _nonce, _payload, _reason);
}
functionnonblockingLzReceive(uint16 _srcChainId, bytescalldata _srcAddress, uint64 _nonce, bytescalldata _payload) publicvirtual{
// only internal transactionrequire(_msgSender() ==address(this), "NonblockingLzApp: caller must be LzApp");
_nonblockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload);
}
//@notice override this functionfunction_nonblockingLzReceive(uint16 _srcChainId, bytesmemory _srcAddress, uint64 _nonce, bytesmemory _payload) internalvirtual;
functionretryMessage(uint16 _srcChainId, bytescalldata _srcAddress, uint64 _nonce, bytescalldata _payload) publicpayablevirtual{
// assert there is message to retrybytes32 payloadHash = failedMessages[_srcChainId][_srcAddress][_nonce];
require(payloadHash !=bytes32(0), "NonblockingLzApp: no stored message");
require(keccak256(_payload) == payloadHash, "NonblockingLzApp: invalid payload");
// clear the stored message
failedMessages[_srcChainId][_srcAddress][_nonce] =bytes32(0);
// execute the message. revert if it fails again
_nonblockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload);
emit RetryMessageSuccess(_srcChainId, _srcAddress, _nonce, payloadHash);
}
}
Contract Source Code
File 35 of 41: ONFT1155.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import"./IONFT1155.sol";
import"./ONFT1155Core.sol";
import"@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
// NOTE: this ONFT contract has no public minting logic.// must implement your own minting logic in child classescontractONFT1155isONFT1155Core, ERC1155, IONFT1155{
constructor(stringmemory _uri, address _lzEndpoint) ERC1155(_uri) ONFT1155Core(_lzEndpoint) {}
functionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverride(ONFT1155Core, ERC1155, IERC165) returns (bool) {
return interfaceId ==type(IONFT1155).interfaceId||super.supportsInterface(interfaceId);
}
function_debitFrom(address _from, uint16, bytesmemory, uint[] memory _tokenIds, uint[] memory _amounts) internalvirtualoverride{
address spender = _msgSender();
require(spender == _from || isApprovedForAll(_from, spender), "ONFT1155: send caller is not owner nor approved");
_burnBatch(_from, _tokenIds, _amounts);
}
function_creditTo(uint16, address _toAddress, uint[] memory _tokenIds, uint[] memory _amounts) internalvirtualoverride{
_mintBatch(_toAddress, _tokenIds, _amounts, "");
}
}
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)pragmasolidity ^0.8.0;import"../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/abstractcontractOwnableisContext{
addressprivate _owner;
eventOwnershipTransferred(addressindexed previousOwner, addressindexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/modifieronlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/functionowner() publicviewvirtualreturns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/function_checkOwner() internalviewvirtual{
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/functionrenounceOwnership() publicvirtualonlyOwner{
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/functiontransferOwnership(address newOwner) publicvirtualonlyOwner{
require(newOwner !=address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/function_transferOwnership(address newOwner) internalvirtual{
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
Contract Source Code
File 38 of 41: ReentrancyGuard.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)pragmasolidity ^0.8.0;/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/abstractcontractReentrancyGuard{
// Booleans are more expensive than uint256 or any type that takes up a full// word because each write operation emits an extra SLOAD to first read the// slot's contents, replace the bits taken up by the boolean, and then write// back. This is the compiler's defense against contract upgrades and// pointer aliasing, and it cannot be disabled.// The values being non-zero value makes deployment a bit more expensive,// but in exchange the refund on every call to nonReentrant will be lower in// amount. Since refunds are capped to a percentage of the total// transaction's gas, it is best to keep them low in cases like this one, to// increase the likelihood of the full refund coming into effect.uint256privateconstant _NOT_ENTERED =1;
uint256privateconstant _ENTERED =2;
uint256private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/modifiernonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function_nonReentrantBefore() private{
// On the first call to nonReentrant, _status will be _NOT_ENTEREDrequire(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function_nonReentrantAfter() private{
// By storing the original value once again, a refund is triggered (see// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}
Contract Source Code
File 39 of 41: SafeERC20.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)pragmasolidity ^0.8.0;import"../IERC20.sol";
import"../extensions/draft-IERC20Permit.sol";
import"../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/librarySafeERC20{
usingAddressforaddress;
functionsafeTransfer(
IERC20 token,
address to,
uint256 value
) internal{
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
functionsafeTransferFrom(
IERC20 token,
addressfrom,
address to,
uint256 value
) internal{
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/functionsafeApprove(
IERC20 token,
address spender,
uint256 value
) internal{
// safeApprove should only be called when setting an initial allowance,// or when resetting it to zero. To increase and decrease it, use// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'require(
(value ==0) || (token.allowance(address(this), spender) ==0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
functionsafeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal{
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
functionsafeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal{
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
functionsafePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal{
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore +1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/function_callOptionalReturn(IERC20 token, bytesmemory data) private{
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that// the target address contains contract code and also asserts for success in the low-level call.bytesmemory returndata =address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length>0) {
// Return data is optionalrequire(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
Contract Source Code
File 40 of 41: Strings.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)pragmasolidity ^0.8.0;import"./math/Math.sol";
/**
* @dev String operations.
*/libraryStrings{
bytes16privateconstant _SYMBOLS ="0123456789abcdef";
uint8privateconstant _ADDRESS_LENGTH =20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/functiontoString(uint256 value) internalpurereturns (stringmemory) {
unchecked {
uint256 length = Math.log10(value) +1;
stringmemory buffer =newstring(length);
uint256 ptr;
/// @solidity memory-safe-assemblyassembly {
ptr :=add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assemblyassembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /=10;
if (value ==0) break;
}
return buffer;
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/functiontoHexString(uint256 value) internalpurereturns (stringmemory) {
unchecked {
return toHexString(value, Math.log256(value) +1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/functiontoHexString(uint256 value, uint256 length) internalpurereturns (stringmemory) {
bytesmemory buffer =newbytes(2* length +2);
buffer[0] ="0";
buffer[1] ="x";
for (uint256 i =2* length +1; i >1; --i) {
buffer[i] = _SYMBOLS[value &0xf];
value >>=4;
}
require(value ==0, "Strings: hex length insufficient");
returnstring(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/functiontoHexString(address addr) internalpurereturns (stringmemory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}
Contract Source Code
File 41 of 41: draft-IERC20Permit.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)pragmasolidity ^0.8.0;/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/interfaceIERC20Permit{
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/functionpermit(address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/functionnonces(address owner) externalviewreturns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/// solhint-disable-next-line func-name-mixedcasefunctionDOMAIN_SEPARATOR() externalviewreturns (bytes32);
}