// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../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:
*
* ```solidity
* 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}:
*
* ```solidity
* 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. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
mapping(bytes32 role => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with an {AccessControlUnauthorizedAccount} error including the required role.
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
return _roles[role].hasRole[account];
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
* is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
* is missing `role`.
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual returns (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.
*/
function grantRole(bytes32 role, address account) public virtual onlyRole(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.
*/
function revokeRole(bytes32 role, address account) public virtual onlyRole(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 `callerConfirmation`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
if (!hasRole(role, account)) {
_roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
/**
* @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
if (hasRole(role, account)) {
_roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;
import {AsideChainlink} from "./AsideChainlink.sol";
contract Aside0x05 is AsideChainlink {
error DisabledFunction();
error AlreadyUnlocked();
error InvalidElectionResult(uint256 result);
event Unlock();
bool private _harris = false;
bool private _trump = false;
/**
* @notice Creates a new Aside0x05 contract.
* @param baseURI_ The base URI of the token.
* @param admin_ The address to set as the DEFAULT_ADMIN of this contract.
* @param minter_ The address to set as the MINTER of this contract.
* @param updater_ The address to set as the UPDATER of this contract.
* @param verse_ The address of Verse's custodial wallet.
* @param timelock_ The duration of the timelock upon which all tokens are automatically unlocked.
* @param router_ The address of the Chainlink Functions router.
* @param donId_ The id of the Chainlink Functions DON.
* @param subscriptionId_ The id of the Chainlink Functions subscription.
* @param callbackGasLimit_ The callback gas limit of the Chainlink Functions call.
* @param source_ The source of the Chainlink Functions call.
*/
constructor(
string memory baseURI_,
address admin_,
address minter_,
address updater_,
address verse_,
uint256 timelock_,
address router_,
bytes32 donId_,
uint64 subscriptionId_,
uint32 callbackGasLimit_,
string memory source_
)
AsideChainlink(
"What Can Be",
"WCB",
baseURI_,
100,
admin_,
minter_,
updater_,
verse_,
timelock_,
router_,
donId_,
subscriptionId_,
callbackGasLimit_,
source_
)
{
_aMint(0x4D3DfD28AA35869D52C5cE077Aa36E3944b48d1C, 94);
_aMint(0x4CD7d2004a323133330D5A62aD7C734fAfD35236, 95);
_aMint(0x3c7e48216C74D7818aB1Fd226e56C60C4D659bA6, 96);
_aMint(0x3c7e48216C74D7818aB1Fd226e56C60C4D659bA6, 97);
_aMint(0x3c7e48216C74D7818aB1Fd226e56C60C4D659bA6, 98);
_aMint(0x3c7e48216C74D7818aB1Fd226e56C60C4D659bA6, 99);
}
// #region getter functions
/**
* @notice Returns the result of the 2024 US election as stated by Wikidata oracles.
* @return 0 if Harris, 1 if Trump, 3 otherwise.
*/
function result() public view returns (uint256) {
if (_harris) return 0;
if (_trump) return 1;
return 3;
}
// #endregion
/**
* @notice This function is disabled on this drop and replaced by `update()`.
*/
function unlock(uint256[] calldata) external pure override {
revert DisabledFunction();
}
// #region internal Chainlink functions
/**
* @notice Callback function for fulfilling a Chainlink Functions request.
* @param requestId The id of the request to fulfill.
* @param response The HTTP response data.
* @param err Any errors from the Chainlink Functions request.
*/
function fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err)
internal
override
onlyValidRequestId(requestId)
onlyValidCallback(err)
{
uint256 _result = uint256(bytes32(response));
if (_result == 0) {
_harris = true;
emit Unlock();
} else if (_result == 1) {
_trump = true;
emit Unlock();
} else {
revert InvalidElectionResult(_result);
}
}
// #endregion
// #region internal functions
function _isUnlocked(uint256 tokenId) internal view virtual override returns (bool) {
if (tokenId <= 46 || tokenId == 94 || tokenId == 95 || tokenId == 96) return _harris || _areAllUnlocked();
if (tokenId >= 47 && tokenId != 94 && tokenId != 95 && tokenId != 96) return _trump || _areAllUnlocked();
return _areAllUnlocked();
}
// #endregion
// #region internal hook functions
function _afterUpdate(bytes32, /*requestId*/ string[] memory /*args*/ ) internal virtual override {
if (_harris || _trump) revert AlreadyUnlocked();
}
// #endregion
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;
import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import {ERC721Burnable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
abstract contract AsideBase is ERC721, ERC721Burnable, AccessControl {
error TokenLocked(uint256 tokenId);
error TokenAlreadyUnlocked(uint256 tokenId);
error InvalidTokenId(uint256 tokenId);
error InvalidUnlock(uint256 tokenId);
error InvalidParametersMatch();
event Unlock(uint256 indexed tokenId);
event EmergencyUnlock();
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
uint256 public immutable NB_OF_TOKENS;
address public immutable VERSE;
uint256 public immutable TIMELOCK_DEADLINE;
string public BASE_URI; // strings cannot be immutable
bool private _eUnlocked = false; // emergency unlock
mapping(uint256 => bool) private _unlocks; // tokenId => isUnlocked
/**
* @notice Creates a new AsideBase contract.
* @param name_ The name of the token.
* @param symbol_ The symbol of the token.
* @param baseURI_ The base URI of the token.
* @param nbOfTokens_ The number of tokens allowed to be minted.
* @param admin_ The address to set as the DEFAULT_ADMIN of this contract.
* @param minter_ The address to set as the MINTER of this contract.
* @param verse_ The address of Verse's custodial wallet.
* @param timelock_ The duration of the timelock upon which all tokens are automatically unlocked.
*/
constructor(
string memory name_,
string memory symbol_,
string memory baseURI_,
uint256 nbOfTokens_,
address admin_,
address minter_,
address verse_,
uint256 timelock_
) ERC721(name_, symbol_) {
_grantRole(DEFAULT_ADMIN_ROLE, admin_);
_grantRole(MINTER_ROLE, minter_);
BASE_URI = baseURI_;
NB_OF_TOKENS = nbOfTokens_;
VERSE = verse_;
TIMELOCK_DEADLINE = block.timestamp + timelock_;
}
/**
* @notice Mints `tokenId`, transfers it to `to` and checks for `to` acceptance.
* @param to The address to receive the token to be minted.
* @param tokenId The id of the token to be minted.
*/
function mint(address to, uint256 tokenId) external onlyRole(MINTER_ROLE) {
_aMint(to, tokenId);
}
/**
* @notice Mints `tokenIds`, transfers them to `to` and checks for `to` acceptance.
* @param to The addresses to receive the tokens to be minted.
* @param tokenIds The ids of the tokens to be minted.
*/
function mintBatch(address[] memory to, uint256[] memory tokenIds) external onlyRole(MINTER_ROLE) {
uint256 length = to.length;
if (length != tokenIds.length) revert InvalidParametersMatch();
for (uint256 i = 0; i < length; i++) {
_aMint(to[i], tokenIds[i]);
}
}
/**
* @notice Unlocks tokens `tokenIds`.
* @dev Each tokenId in `tokenIds` must exist.
* @dev Each tokenId in `tokenIds` must be locked.
* @param tokenIds The ids of the tokens to unlock.
*/
function unlock(uint256[] calldata tokenIds) external virtual {
_beforeUnlock(tokenIds);
uint256 length = tokenIds.length;
for (uint256 i = 0; i < length; i++) {
_unlock(tokenIds[i]);
}
}
// #region admin-only functions
/**
* @notice Unlocks all the tokens at once.
* @dev This function is only to be used in case of an emergency.
*/
function eUnlock() external onlyRole(DEFAULT_ADMIN_ROLE) {
_eUnlocked = true;
emit EmergencyUnlock();
}
// #endregion
// #region getter functions
/**
* @notice Checks whether all the tokens have been unlocked at once in an emergency or not.
* @return A boolean indicating whether all the tokens have been unlocked at once in an emergency or
* not.
*/
function isEUnlocked() public view returns (bool) {
return _eUnlocked;
}
/**
* @notice Checks whether all the tokens are unlocked, either because of an emergency unlock or
* because the timelock deadline has been reached.
* @return A boolean indicating whether all the tokens are unlocked or not.
*/
function areAllUnlocked() public view returns (bool) {
return _areAllUnlocked();
}
/**
* @notice Checks whether token `tokenId` is unlocked or not.
* @dev `tokenId` must exist.
* @param tokenId The id of the token to check whether it is unlocked or not.
* @return A boolean indicating whether token `tokenId` is unlocked or not.
*/
function isUnlocked(uint256 tokenId) public view returns (bool) {
_requireOwned(tokenId);
return _isUnlocked(tokenId);
}
// #endregion
// #region internal functions
function _baseURI() internal view override returns (string memory) {
return BASE_URI;
}
function _areAllUnlocked() internal view virtual returns (bool) {
return block.timestamp >= TIMELOCK_DEADLINE || _eUnlocked;
}
function _isUnlocked(uint256 tokenId) internal view virtual returns (bool) {
return _unlocks[tokenId] || _areAllUnlocked();
}
function _requireLocked(uint256 tokenId) internal view {
_requireOwned(tokenId);
if (_isUnlocked(tokenId)) revert TokenAlreadyUnlocked(tokenId);
}
function _aMint(address to, uint256 tokenId) internal {
_safeMint(to, tokenId);
_afterMint(to, tokenId);
}
function _unlock(uint256 tokenId) internal {
_unlocks[tokenId] = true;
emit Unlock(tokenId);
}
// #endregion
// #region internal hook functions
function _update(address to, uint256 tokenId, address auth) internal override(ERC721) returns (address) {
address owner = _ownerOf(tokenId);
if (!_isUnlocked(tokenId) && owner != address(0) && owner != VERSE && owner != address(0x3c7e48216C74D7818aB1Fd226e56C60C4D659bA6))
{
revert TokenLocked(tokenId);
}
if (to == address(0)) _unlocks[tokenId] = false;
return super._update(to, tokenId, auth);
}
function _afterMint(address, uint256 tokenId) internal virtual {
if (tokenId >= NB_OF_TOKENS) revert InvalidTokenId(tokenId);
}
function _beforeUnlock(uint256[] memory tokenIds) internal virtual {
uint256 length = tokenIds.length;
for (uint256 i = 0; i < length; i++) {
_requireLocked(tokenIds[i]);
}
}
// #endregion
// #region required overrides
function supportsInterface(bytes4 interfaceId) public view override(ERC721, AccessControl) returns (bool) {
return super.supportsInterface(interfaceId);
}
// #endregion
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;
import {AsideBase} from "./AsideBase.sol";
import {FunctionsClient} from "chainlink/src/v0.8/functions/v1_0_0/FunctionsClient.sol";
import {FunctionsRequest} from "chainlink/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol";
abstract contract AsideChainlink is AsideBase, FunctionsClient {
using FunctionsRequest for FunctionsRequest.Request;
error InvalidDonId();
error InvalidSubscriptionId();
error InvalidCallbackGasLimit();
error InvalidSource();
error InvalidRequestId(bytes32 requestId);
error InvalidCallback(bytes err);
error DeprecatedData();
modifier onlyValidRequestId(bytes32 requestId) {
if (requestId != _lastRequestId) revert InvalidRequestId(requestId);
_;
}
modifier onlyValidCallback(bytes memory err) {
if (err.length != 0) revert InvalidCallback(err);
_;
}
bytes32 public constant UPDATER_ROLE = keccak256("UPDATER_ROLE");
bytes32 private _donId;
uint64 private _subscriptionId;
uint32 private _callbackGasLimit;
string private _source;
bytes32 private _lastRequestId;
/**
* @notice Creates a new AsideChainlink contract.
* @param name_ The name of the token.
* @param symbol_ The symbol of the token.
* @param baseURI_ The base URI of the token.
* @param nbOfTokens_ The number of tokens allowed to be minted.
* @param admin_ The address to set as the DEFAULT_ADMIN of this contract.
* @param minter_ The address to set as the MINTER of this contract.
* @param updater_ The address to set as the UPDATER of this contract.
* @param verse_ The address of Verse's custodial wallet.
* @param timelock_ The duration of the timelock upon which all tokens are automatically unlocked.
* @param router_ The address of the Chainlink Functions router.
* @param donId_ The id of the Chainlink Functions DON.
* @param subscriptionId_ The id of the Chainlink Functions subscription.
* @param callbackGasLimit_ The callback gas limit of the Chainlink Functions call.
* @param source_ The source of the Chainlink Functions call.
*/
constructor(
string memory name_,
string memory symbol_,
string memory baseURI_,
uint256 nbOfTokens_,
address admin_,
address minter_,
address updater_,
address verse_,
uint256 timelock_,
address router_,
bytes32 donId_,
uint64 subscriptionId_,
uint32 callbackGasLimit_,
string memory source_
) AsideBase(name_, symbol_, baseURI_, nbOfTokens_, admin_, minter_, verse_, timelock_) FunctionsClient(router_) {
_grantRole(UPDATER_ROLE, updater_);
_setDonId(donId_);
_setSubscriptionId(subscriptionId_);
_setCallbackGasLimit(callbackGasLimit_);
_setSource(source_);
}
function update(string[] calldata args) external onlyRole(UPDATER_ROLE) {
FunctionsRequest.Request memory request;
request.initializeRequestForInlineJavaScript(_source);
if (args.length > 0) request.setArgs(args);
bytes32 requestId = _sendRequest(request.encodeCBOR(), _subscriptionId, _callbackGasLimit, _donId);
_lastRequestId = requestId;
_afterUpdate(requestId, args);
}
// #region admin-only functions
/**
* @notice Sets the Chainlink Functions DON id.
* @param donId_ The id of the Chainlink Functions DON.
*/
function setDonId(bytes32 donId_) external onlyRole(DEFAULT_ADMIN_ROLE) {
_setDonId(donId_);
}
/**
* @notice Sets the Chainlink Functions subscription id.
* @param subscriptionId_ The id of the Chainlink Functions subscription.
*/
function setSubscriptionId(uint64 subscriptionId_) external onlyRole(DEFAULT_ADMIN_ROLE) {
_setSubscriptionId(subscriptionId_);
}
/**
* @notice Sets the callback gas limit of the Chainlink Functions call.
* @param callbackGasLimit_ The callback gas limit of the Chainlink Functions call.
*/
function setCallbackGasLimit(uint32 callbackGasLimit_) external onlyRole(DEFAULT_ADMIN_ROLE) {
_setCallbackGasLimit(callbackGasLimit_);
}
/**
* @notice Sets the source of the Chainlink Functions call.
* @param source_ The source of the Chainlink Functions call.
*/
function setSource(string memory source_) external onlyRole(DEFAULT_ADMIN_ROLE) {
_setSource(source_);
}
// #endregion
// #region getter functions
/**
* @notice Returns the Chainlink Functions router address.
* @return The address of the Chainlink Functions router.
*/
function router() public view returns (address) {
return address(i_router);
}
/**
* @notice Returns the Chainlink Functions DON id.
* @return The id of the Chainlink Functions DON.
*/
function donId() public view returns (bytes32) {
return _donId;
}
/**
* @notice Returns the Chainlink Functions subscription id.
* @return The id of the Chainlink Functions subscription.
*/
function subscriptionId() public view returns (uint64) {
return _subscriptionId;
}
/**
* @notice Returns the callback gas limit of the Chainlink Functions call.
* @return The callback gas limit of the Chainlink Functions call.
*/
function callbackGasLimit() public view returns (uint32) {
return _callbackGasLimit;
}
/**
* @notice Returns the source of the Chainlink Functions call.
* @return The source of the Chainlink Functions call.
*/
function source() public view returns (string memory) {
return _source;
}
/**
* @notice Returns the id of the last request made to Chainlink Functions.
* @return The id of the last request made to Chainlink Functions.
*/
function lastRequestId() public view returns (bytes32) {
return _lastRequestId;
}
// #endregion
// #region internal hook functions
function _afterUpdate(bytes32, /*requestId*/ string[] memory /*args*/ ) internal virtual {}
// #endregion
// #region private functions
function _setDonId(bytes32 donId_) private {
if (donId_ == bytes32(0)) revert InvalidDonId();
_donId = donId_;
}
function _setSubscriptionId(uint64 subscriptionId_) private {
if (subscriptionId_ == uint64(0)) revert InvalidSubscriptionId();
_subscriptionId = subscriptionId_;
}
function _setCallbackGasLimit(uint32 callbackGasLimit_) private {
if (callbackGasLimit_ == uint32(0)) revert InvalidCallbackGasLimit();
_callbackGasLimit = callbackGasLimit_;
}
function _setSource(string memory source_) private {
if (bytes(source_).length == 0) revert InvalidSource();
_source = source_;
}
// #endregion
}
// SPDX-License-Identifier: BSD-2-Clause
pragma solidity ^0.8.4;
/**
* @dev A library for working with mutable byte buffers in Solidity.
*
* Byte buffers are mutable and expandable, and provide a variety of primitives
* for appending to them. At any time you can fetch a bytes object containing the
* current contents of the buffer. The bytes object should not be stored between
* operations, as it may change due to resizing of the buffer.
*/
library Buffer {
/**
* @dev Represents a mutable buffer. Buffers have a current value (buf) and
* a capacity. The capacity may be longer than the current value, in
* which case it can be extended without the need to allocate more memory.
*/
struct buffer {
bytes buf;
uint capacity;
}
/**
* @dev Initializes a buffer with an initial capacity.
* @param buf The buffer to initialize.
* @param capacity The number of bytes of space to allocate the buffer.
* @return The buffer, for chaining.
*/
function init(buffer memory buf, uint capacity) internal pure returns(buffer memory) {
if (capacity % 32 != 0) {
capacity += 32 - (capacity % 32);
}
// Allocate space for the buffer data
buf.capacity = capacity;
assembly {
let ptr := mload(0x40)
mstore(buf, ptr)
mstore(ptr, 0)
let fpm := add(32, add(ptr, capacity))
if lt(fpm, ptr) {
revert(0, 0)
}
mstore(0x40, fpm)
}
return buf;
}
/**
* @dev Initializes a new buffer from an existing bytes object.
* Changes to the buffer may mutate the original value.
* @param b The bytes object to initialize the buffer with.
* @return A new buffer.
*/
function fromBytes(bytes memory b) internal pure returns(buffer memory) {
buffer memory buf;
buf.buf = b;
buf.capacity = b.length;
return buf;
}
function resize(buffer memory buf, uint capacity) private pure {
bytes memory oldbuf = buf.buf;
init(buf, capacity);
append(buf, oldbuf);
}
/**
* @dev Sets buffer length to 0.
* @param buf The buffer to truncate.
* @return The original buffer, for chaining..
*/
function truncate(buffer memory buf) internal pure returns (buffer memory) {
assembly {
let bufptr := mload(buf)
mstore(bufptr, 0)
}
return buf;
}
/**
* @dev Appends len bytes of a byte string to a buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @param len The number of bytes to copy.
* @return The original buffer, for chaining.
*/
function append(buffer memory buf, bytes memory data, uint len) internal pure returns(buffer memory) {
require(len <= data.length);
uint off = buf.buf.length;
uint newCapacity = off + len;
if (newCapacity > buf.capacity) {
resize(buf, newCapacity * 2);
}
uint dest;
uint src;
assembly {
// Memory address of the buffer data
let bufptr := mload(buf)
// Length of existing buffer data
let buflen := mload(bufptr)
// Start address = buffer address + offset + sizeof(buffer length)
dest := add(add(bufptr, 32), off)
// Update buffer length if we're extending it
if gt(newCapacity, buflen) {
mstore(bufptr, newCapacity)
}
src := add(data, 32)
}
// Copy word-length chunks while possible
for (; len >= 32; len -= 32) {
assembly {
mstore(dest, mload(src))
}
dest += 32;
src += 32;
}
// Copy remaining bytes
unchecked {
uint mask = (256 ** (32 - len)) - 1;
assembly {
let srcpart := and(mload(src), not(mask))
let destpart := and(mload(dest), mask)
mstore(dest, or(destpart, srcpart))
}
}
return buf;
}
/**
* @dev Appends a byte string to a buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @return The original buffer, for chaining.
*/
function append(buffer memory buf, bytes memory data) internal pure returns (buffer memory) {
return append(buf, data, data.length);
}
/**
* @dev Appends a byte to the buffer. Resizes if doing so would exceed the
* capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @return The original buffer, for chaining.
*/
function appendUint8(buffer memory buf, uint8 data) internal pure returns(buffer memory) {
uint off = buf.buf.length;
uint offPlusOne = off + 1;
if (off >= buf.capacity) {
resize(buf, offPlusOne * 2);
}
assembly {
// Memory address of the buffer data
let bufptr := mload(buf)
// Address = buffer address + sizeof(buffer length) + off
let dest := add(add(bufptr, off), 32)
mstore8(dest, data)
// Update buffer length if we extended it
if gt(offPlusOne, mload(bufptr)) {
mstore(bufptr, offPlusOne)
}
}
return buf;
}
/**
* @dev Appends len bytes of bytes32 to a buffer. Resizes if doing so would
* exceed the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @param len The number of bytes to write (left-aligned).
* @return The original buffer, for chaining.
*/
function append(buffer memory buf, bytes32 data, uint len) private pure returns(buffer memory) {
uint off = buf.buf.length;
uint newCapacity = len + off;
if (newCapacity > buf.capacity) {
resize(buf, newCapacity * 2);
}
unchecked {
uint mask = (256 ** len) - 1;
// Right-align data
data = data >> (8 * (32 - len));
assembly {
// Memory address of the buffer data
let bufptr := mload(buf)
// Address = buffer address + sizeof(buffer length) + newCapacity
let dest := add(bufptr, newCapacity)
mstore(dest, or(and(mload(dest), not(mask)), data))
// Update buffer length if we extended it
if gt(newCapacity, mload(bufptr)) {
mstore(bufptr, newCapacity)
}
}
}
return buf;
}
/**
* @dev Appends a bytes20 to the buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @return The original buffer, for chhaining.
*/
function appendBytes20(buffer memory buf, bytes20 data) internal pure returns (buffer memory) {
return append(buf, bytes32(data), 20);
}
/**
* @dev Appends a bytes32 to the buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @return The original buffer, for chaining.
*/
function appendBytes32(buffer memory buf, bytes32 data) internal pure returns (buffer memory) {
return append(buf, data, 32);
}
/**
* @dev Appends a byte to the end of the buffer. Resizes if doing so would
* exceed the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @param len The number of bytes to write (right-aligned).
* @return The original buffer.
*/
function appendInt(buffer memory buf, uint data, uint len) internal pure returns(buffer memory) {
uint off = buf.buf.length;
uint newCapacity = len + off;
if (newCapacity > buf.capacity) {
resize(buf, newCapacity * 2);
}
uint mask = (256 ** len) - 1;
assembly {
// Memory address of the buffer data
let bufptr := mload(buf)
// Address = buffer address + sizeof(buffer length) + newCapacity
let dest := add(bufptr, newCapacity)
mstore(dest, or(and(mload(dest), not(mask)), data))
// Update buffer length if we extended it
if gt(newCapacity, mload(bufptr)) {
mstore(bufptr, newCapacity)
}
}
return buf;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "../../@ensdomains/buffer/v0.1.0/Buffer.sol";
/**
* @dev A library for populating CBOR encoded payload in Solidity.
*
* https://datatracker.ietf.org/doc/html/rfc7049
*
* The library offers various write* and start* methods to encode values of different types.
* The resulted buffer can be obtained with data() method.
* Encoding of primitive types is staightforward, whereas encoding of sequences can result
* in an invalid CBOR if start/write/end flow is violated.
* For the purpose of gas saving, the library does not verify start/write/end flow internally,
* except for nested start/end pairs.
*/
library CBOR {
using Buffer for Buffer.buffer;
struct CBORBuffer {
Buffer.buffer buf;
uint256 depth;
}
uint8 private constant MAJOR_TYPE_INT = 0;
uint8 private constant MAJOR_TYPE_NEGATIVE_INT = 1;
uint8 private constant MAJOR_TYPE_BYTES = 2;
uint8 private constant MAJOR_TYPE_STRING = 3;
uint8 private constant MAJOR_TYPE_ARRAY = 4;
uint8 private constant MAJOR_TYPE_MAP = 5;
uint8 private constant MAJOR_TYPE_TAG = 6;
uint8 private constant MAJOR_TYPE_CONTENT_FREE = 7;
uint8 private constant TAG_TYPE_BIGNUM = 2;
uint8 private constant TAG_TYPE_NEGATIVE_BIGNUM = 3;
uint8 private constant CBOR_FALSE = 20;
uint8 private constant CBOR_TRUE = 21;
uint8 private constant CBOR_NULL = 22;
uint8 private constant CBOR_UNDEFINED = 23;
function create(uint256 capacity) internal pure returns(CBORBuffer memory cbor) {
Buffer.init(cbor.buf, capacity);
cbor.depth = 0;
return cbor;
}
function data(CBORBuffer memory buf) internal pure returns(bytes memory) {
require(buf.depth == 0, "Invalid CBOR");
return buf.buf.buf;
}
function writeUInt256(CBORBuffer memory buf, uint256 value) internal pure {
buf.buf.appendUint8(uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_BIGNUM));
writeBytes(buf, abi.encode(value));
}
function writeInt256(CBORBuffer memory buf, int256 value) internal pure {
if (value < 0) {
buf.buf.appendUint8(
uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_NEGATIVE_BIGNUM)
);
writeBytes(buf, abi.encode(uint256(-1 - value)));
} else {
writeUInt256(buf, uint256(value));
}
}
function writeUInt64(CBORBuffer memory buf, uint64 value) internal pure {
writeFixedNumeric(buf, MAJOR_TYPE_INT, value);
}
function writeInt64(CBORBuffer memory buf, int64 value) internal pure {
if(value >= 0) {
writeFixedNumeric(buf, MAJOR_TYPE_INT, uint64(value));
} else{
writeFixedNumeric(buf, MAJOR_TYPE_NEGATIVE_INT, uint64(-1 - value));
}
}
function writeBytes(CBORBuffer memory buf, bytes memory value) internal pure {
writeFixedNumeric(buf, MAJOR_TYPE_BYTES, uint64(value.length));
buf.buf.append(value);
}
function writeString(CBORBuffer memory buf, string memory value) internal pure {
writeFixedNumeric(buf, MAJOR_TYPE_STRING, uint64(bytes(value).length));
buf.buf.append(bytes(value));
}
function writeBool(CBORBuffer memory buf, bool value) internal pure {
writeContentFree(buf, value ? CBOR_TRUE : CBOR_FALSE);
}
function writeNull(CBORBuffer memory buf) internal pure {
writeContentFree(buf, CBOR_NULL);
}
function writeUndefined(CBORBuffer memory buf) internal pure {
writeContentFree(buf, CBOR_UNDEFINED);
}
function startArray(CBORBuffer memory buf) internal pure {
writeIndefiniteLengthType(buf, MAJOR_TYPE_ARRAY);
buf.depth += 1;
}
function startFixedArray(CBORBuffer memory buf, uint64 length) internal pure {
writeDefiniteLengthType(buf, MAJOR_TYPE_ARRAY, length);
}
function startMap(CBORBuffer memory buf) internal pure {
writeIndefiniteLengthType(buf, MAJOR_TYPE_MAP);
buf.depth += 1;
}
function startFixedMap(CBORBuffer memory buf, uint64 length) internal pure {
writeDefiniteLengthType(buf, MAJOR_TYPE_MAP, length);
}
function endSequence(CBORBuffer memory buf) internal pure {
writeIndefiniteLengthType(buf, MAJOR_TYPE_CONTENT_FREE);
buf.depth -= 1;
}
function writeKVString(CBORBuffer memory buf, string memory key, string memory value) internal pure {
writeString(buf, key);
writeString(buf, value);
}
function writeKVBytes(CBORBuffer memory buf, string memory key, bytes memory value) internal pure {
writeString(buf, key);
writeBytes(buf, value);
}
function writeKVUInt256(CBORBuffer memory buf, string memory key, uint256 value) internal pure {
writeString(buf, key);
writeUInt256(buf, value);
}
function writeKVInt256(CBORBuffer memory buf, string memory key, int256 value) internal pure {
writeString(buf, key);
writeInt256(buf, value);
}
function writeKVUInt64(CBORBuffer memory buf, string memory key, uint64 value) internal pure {
writeString(buf, key);
writeUInt64(buf, value);
}
function writeKVInt64(CBORBuffer memory buf, string memory key, int64 value) internal pure {
writeString(buf, key);
writeInt64(buf, value);
}
function writeKVBool(CBORBuffer memory buf, string memory key, bool value) internal pure {
writeString(buf, key);
writeBool(buf, value);
}
function writeKVNull(CBORBuffer memory buf, string memory key) internal pure {
writeString(buf, key);
writeNull(buf);
}
function writeKVUndefined(CBORBuffer memory buf, string memory key) internal pure {
writeString(buf, key);
writeUndefined(buf);
}
function writeKVMap(CBORBuffer memory buf, string memory key) internal pure {
writeString(buf, key);
startMap(buf);
}
function writeKVArray(CBORBuffer memory buf, string memory key) internal pure {
writeString(buf, key);
startArray(buf);
}
function writeFixedNumeric(
CBORBuffer memory buf,
uint8 major,
uint64 value
) private pure {
if (value <= 23) {
buf.buf.appendUint8(uint8((major << 5) | value));
} else if (value <= 0xFF) {
buf.buf.appendUint8(uint8((major << 5) | 24));
buf.buf.appendInt(value, 1);
} else if (value <= 0xFFFF) {
buf.buf.appendUint8(uint8((major << 5) | 25));
buf.buf.appendInt(value, 2);
} else if (value <= 0xFFFFFFFF) {
buf.buf.appendUint8(uint8((major << 5) | 26));
buf.buf.appendInt(value, 4);
} else {
buf.buf.appendUint8(uint8((major << 5) | 27));
buf.buf.appendInt(value, 8);
}
}
function writeIndefiniteLengthType(CBORBuffer memory buf, uint8 major)
private
pure
{
buf.buf.appendUint8(uint8((major << 5) | 31));
}
function writeDefiniteLengthType(CBORBuffer memory buf, uint8 major, uint64 length)
private
pure
{
writeFixedNumeric(buf, major, length);
}
function writeContentFree(CBORBuffer memory buf, uint8 value) private pure {
buf.buf.appendUint8(uint8((MAJOR_TYPE_CONTENT_FREE << 5) | value));
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @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.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC-165 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);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/ERC721.sol)
pragma solidity ^0.8.20;
import {IERC721} from "./IERC721.sol";
import {IERC721Receiver} from "./IERC721Receiver.sol";
import {IERC721Metadata} from "./extensions/IERC721Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {Strings} from "../../utils/Strings.sol";
import {IERC165, ERC165} from "../../utils/introspection/ERC165.sol";
import {IERC721Errors} from "../../interfaces/draft-IERC6093.sol";
/**
* @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC-721] Non-Fungible Token Standard, including
* the Metadata extension, but not including the Enumerable extension, which is available separately as
* {ERC721Enumerable}.
*/
abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Errors {
using Strings for uint256;
// Token name
string private _name;
// Token symbol
string private _symbol;
mapping(uint256 tokenId => address) private _owners;
mapping(address owner => uint256) private _balances;
mapping(uint256 tokenId => address) private _tokenApprovals;
mapping(address owner => mapping(address operator => bool)) private _operatorApprovals;
/**
* @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC721-balanceOf}.
*/
function balanceOf(address owner) public view virtual returns (uint256) {
if (owner == address(0)) {
revert ERC721InvalidOwner(address(0));
}
return _balances[owner];
}
/**
* @dev See {IERC721-ownerOf}.
*/
function ownerOf(uint256 tokenId) public view virtual returns (address) {
return _requireOwned(tokenId);
}
/**
* @dev See {IERC721Metadata-name}.
*/
function name() public view virtual returns (string memory) {
return _name;
}
/**
* @dev See {IERC721Metadata-symbol}.
*/
function symbol() public view virtual returns (string memory) {
return _symbol;
}
/**
* @dev See {IERC721Metadata-tokenURI}.
*/
function tokenURI(uint256 tokenId) public view virtual returns (string memory) {
_requireOwned(tokenId);
string memory baseURI = _baseURI();
return bytes(baseURI).length > 0 ? string.concat(baseURI, tokenId.toString()) : "";
}
/**
* @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
* by default, can be overridden in child contracts.
*/
function _baseURI() internal view virtual returns (string memory) {
return "";
}
/**
* @dev See {IERC721-approve}.
*/
function approve(address to, uint256 tokenId) public virtual {
_approve(to, tokenId, _msgSender());
}
/**
* @dev See {IERC721-getApproved}.
*/
function getApproved(uint256 tokenId) public view virtual returns (address) {
_requireOwned(tokenId);
return _getApproved(tokenId);
}
/**
* @dev See {IERC721-setApprovalForAll}.
*/
function setApprovalForAll(address operator, bool approved) public virtual {
_setApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC721-isApprovedForAll}.
*/
function isApprovedForAll(address owner, address operator) public view virtual returns (bool) {
return _operatorApprovals[owner][operator];
}
/**
* @dev See {IERC721-transferFrom}.
*/
function transferFrom(address from, address to, uint256 tokenId) public virtual {
if (to == address(0)) {
revert ERC721InvalidReceiver(address(0));
}
// Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists
// (from != 0). Therefore, it is not needed to verify that the return value is not 0 here.
address previousOwner = _update(to, tokenId, _msgSender());
if (previousOwner != from) {
revert ERC721IncorrectOwner(from, tokenId, previousOwner);
}
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) public {
safeTransferFrom(from, to, tokenId, "");
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual {
transferFrom(from, to, tokenId);
_checkOnERC721Received(from, to, tokenId, data);
}
/**
* @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist
*
* IMPORTANT: Any overrides to this function that add ownership of tokens not tracked by the
* core ERC-721 logic MUST be matched with the use of {_increaseBalance} to keep balances
* consistent with ownership. The invariant to preserve is that for any address `a` the value returned by
* `balanceOf(a)` must be equal to the number of tokens such that `_ownerOf(tokenId)` is `a`.
*/
function _ownerOf(uint256 tokenId) internal view virtual returns (address) {
return _owners[tokenId];
}
/**
* @dev Returns the approved address for `tokenId`. Returns 0 if `tokenId` is not minted.
*/
function _getApproved(uint256 tokenId) internal view virtual returns (address) {
return _tokenApprovals[tokenId];
}
/**
* @dev Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in
* particular (ignoring whether it is owned by `owner`).
*
* WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this
* assumption.
*/
function _isAuthorized(address owner, address spender, uint256 tokenId) internal view virtual returns (bool) {
return
spender != address(0) &&
(owner == spender || isApprovedForAll(owner, spender) || _getApproved(tokenId) == spender);
}
/**
* @dev Checks if `spender` can operate on `tokenId`, assuming the provided `owner` is the actual owner.
* Reverts if `spender` does not have approval from the provided `owner` for the given token or for all its assets
* the `spender` for the specific `tokenId`.
*
* WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this
* assumption.
*/
function _checkAuthorized(address owner, address spender, uint256 tokenId) internal view virtual {
if (!_isAuthorized(owner, spender, tokenId)) {
if (owner == address(0)) {
revert ERC721NonexistentToken(tokenId);
} else {
revert ERC721InsufficientApproval(spender, tokenId);
}
}
}
/**
* @dev Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override.
*
* NOTE: the value is limited to type(uint128).max. This protect against _balance overflow. It is unrealistic that
* a uint256 would ever overflow from increments when these increments are bounded to uint128 values.
*
* WARNING: Increasing an account's balance using this function tends to be paired with an override of the
* {_ownerOf} function to resolve the ownership of the corresponding tokens so that balances and ownership
* remain consistent with one another.
*/
function _increaseBalance(address account, uint128 value) internal virtual {
unchecked {
_balances[account] += value;
}
}
/**
* @dev Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner
* (or `to`) is the zero address. Returns the owner of the `tokenId` before the update.
*
* The `auth` argument is optional. If the value passed is non 0, then this function will check that
* `auth` is either the owner of the token, or approved to operate on the token (by the owner).
*
* Emits a {Transfer} event.
*
* NOTE: If overriding this function in a way that tracks balances, see also {_increaseBalance}.
*/
function _update(address to, uint256 tokenId, address auth) internal virtual returns (address) {
address from = _ownerOf(tokenId);
// Perform (optional) operator check
if (auth != address(0)) {
_checkAuthorized(from, auth, tokenId);
}
// Execute the update
if (from != address(0)) {
// Clear approval. No need to re-authorize or emit the Approval event
_approve(address(0), tokenId, address(0), false);
unchecked {
_balances[from] -= 1;
}
}
if (to != address(0)) {
unchecked {
_balances[to] += 1;
}
}
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
return from;
}
/**
* @dev Mints `tokenId` and transfers it to `to`.
*
* WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
*
* Requirements:
*
* - `tokenId` must not exist.
* - `to` cannot be the zero address.
*
* Emits a {Transfer} event.
*/
function _mint(address to, uint256 tokenId) internal {
if (to == address(0)) {
revert ERC721InvalidReceiver(address(0));
}
address previousOwner = _update(to, tokenId, address(0));
if (previousOwner != address(0)) {
revert ERC721InvalidSender(address(0));
}
}
/**
* @dev Mints `tokenId`, transfers it to `to` and checks for `to` acceptance.
*
* Requirements:
*
* - `tokenId` must not exist.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function _safeMint(address to, uint256 tokenId) internal {
_safeMint(to, tokenId, "");
}
/**
* @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
* forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
*/
function _safeMint(address to, uint256 tokenId, bytes memory data) internal virtual {
_mint(to, tokenId);
_checkOnERC721Received(address(0), to, tokenId, data);
}
/**
* @dev Destroys `tokenId`.
* The approval is cleared when the token is burned.
* This is an internal function that does not check if the sender is authorized to operate on the token.
*
* Requirements:
*
* - `tokenId` must exist.
*
* Emits a {Transfer} event.
*/
function _burn(uint256 tokenId) internal {
address previousOwner = _update(address(0), tokenId, address(0));
if (previousOwner == address(0)) {
revert ERC721NonexistentToken(tokenId);
}
}
/**
* @dev Transfers `tokenId` from `from` to `to`.
* As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
*
* Emits a {Transfer} event.
*/
function _transfer(address from, address to, uint256 tokenId) internal {
if (to == address(0)) {
revert ERC721InvalidReceiver(address(0));
}
address previousOwner = _update(to, tokenId, address(0));
if (previousOwner == address(0)) {
revert ERC721NonexistentToken(tokenId);
} else if (previousOwner != from) {
revert ERC721IncorrectOwner(from, tokenId, previousOwner);
}
}
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking that contract recipients
* are aware of the ERC-721 standard to prevent tokens from being forever locked.
*
* `data` is additional data, it has no specified format and it is sent in call to `to`.
*
* This internal function is like {safeTransferFrom} in the sense that it invokes
* {IERC721Receiver-onERC721Received} on the receiver, and can be used to e.g.
* implement alternative mechanisms to perform token transfer, such as signature-based.
*
* Requirements:
*
* - `tokenId` token must exist and be owned by `from`.
* - `to` cannot be the zero address.
* - `from` cannot be the zero address.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function _safeTransfer(address from, address to, uint256 tokenId) internal {
_safeTransfer(from, to, tokenId, "");
}
/**
* @dev Same as {xref-ERC721-_safeTransfer-address-address-uint256-}[`_safeTransfer`], with an additional `data` parameter which is
* forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
*/
function _safeTransfer(address from, address to, uint256 tokenId, bytes memory data) internal virtual {
_transfer(from, to, tokenId);
_checkOnERC721Received(from, to, tokenId, data);
}
/**
* @dev Approve `to` to operate on `tokenId`
*
* The `auth` argument is optional. If the value passed is non 0, then this function will check that `auth` is
* either the owner of the token, or approved to operate on all tokens held by this owner.
*
* Emits an {Approval} event.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/
function _approve(address to, uint256 tokenId, address auth) internal {
_approve(to, tokenId, auth, true);
}
/**
* @dev Variant of `_approve` with an optional flag to enable or disable the {Approval} event. The event is not
* emitted in the context of transfers.
*/
function _approve(address to, uint256 tokenId, address auth, bool emitEvent) internal virtual {
// Avoid reading the owner unless necessary
if (emitEvent || auth != address(0)) {
address owner = _requireOwned(tokenId);
// We do not use _isAuthorized because single-token approvals should not be able to call approve
if (auth != address(0) && owner != auth && !isApprovedForAll(owner, auth)) {
revert ERC721InvalidApprover(auth);
}
if (emitEvent) {
emit Approval(owner, to, tokenId);
}
}
_tokenApprovals[tokenId] = to;
}
/**
* @dev Approve `operator` to operate on all of `owner` tokens
*
* Requirements:
* - operator can't be the address zero.
*
* Emits an {ApprovalForAll} event.
*/
function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {
if (operator == address(0)) {
revert ERC721InvalidOperator(operator);
}
_operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
/**
* @dev Reverts if the `tokenId` doesn't have a current owner (it hasn't been minted, or it has been burned).
* Returns the owner.
*
* Overrides to ownership logic should be done to {_ownerOf}.
*/
function _requireOwned(uint256 tokenId) internal view returns (address) {
address owner = _ownerOf(tokenId);
if (owner == address(0)) {
revert ERC721NonexistentToken(tokenId);
}
return owner;
}
/**
* @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target address. This will revert if the
* recipient doesn't accept the token transfer. The call is not executed if the target address is not a contract.
*
* @param from address representing the previous owner of the given token ID
* @param to target address that will receive the tokens
* @param tokenId uint256 ID of the token to be transferred
* @param data bytes optional data to send along with the call
*/
function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory data) private {
if (to.code.length > 0) {
try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {
if (retval != IERC721Receiver.onERC721Received.selector) {
revert ERC721InvalidReceiver(to);
}
} catch (bytes memory reason) {
if (reason.length == 0) {
revert ERC721InvalidReceiver(to);
} else {
/// @solidity memory-safe-assembly
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721Burnable.sol)
pragma solidity ^0.8.20;
import {ERC721} from "../ERC721.sol";
import {Context} from "../../../utils/Context.sol";
/**
* @title ERC-721 Burnable Token
* @dev ERC-721 Token that can be burned (destroyed).
*/
abstract contract ERC721Burnable is Context, ERC721 {
/**
* @dev Burns `tokenId`. See {ERC721-_burn}.
*
* Requirements:
*
* - The caller must own `tokenId` or be an approved operator.
*/
function burn(uint256 tokenId) public virtual {
// Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists
// (from != 0). Therefore, it is not needed to verify that the return value is not 0 here.
_update(address(0), tokenId, _msgSender());
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {IFunctionsRouter} from "./interfaces/IFunctionsRouter.sol";
import {IFunctionsClient} from "./interfaces/IFunctionsClient.sol";
import {FunctionsRequest} from "./libraries/FunctionsRequest.sol";
/// @title The Chainlink Functions client contract
/// @notice Contract developers can inherit this contract in order to make Chainlink Functions requests
abstract contract FunctionsClient is IFunctionsClient {
using FunctionsRequest for FunctionsRequest.Request;
IFunctionsRouter internal immutable i_router;
event RequestSent(bytes32 indexed id);
event RequestFulfilled(bytes32 indexed id);
error OnlyRouterCanFulfill();
constructor(address router) {
i_router = IFunctionsRouter(router);
}
/// @notice Sends a Chainlink Functions request
/// @param data The CBOR encoded bytes data for a Functions request
/// @param subscriptionId The subscription ID that will be charged to service the request
/// @param callbackGasLimit the amount of gas that will be available for the fulfillment callback
/// @return requestId The generated request ID for this request
function _sendRequest(
bytes memory data,
uint64 subscriptionId,
uint32 callbackGasLimit,
bytes32 donId
) internal returns (bytes32) {
bytes32 requestId = i_router.sendRequest(
subscriptionId,
data,
FunctionsRequest.REQUEST_DATA_VERSION,
callbackGasLimit,
donId
);
emit RequestSent(requestId);
return requestId;
}
/// @notice User defined function to handle a response from the DON
/// @param requestId The request ID, returned by sendRequest()
/// @param response Aggregated response from the execution of the user's source code
/// @param err Aggregated error from the execution of the user code or from the execution pipeline
/// @dev Either response or error parameter will be set, but never both
function fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal virtual;
/// @inheritdoc IFunctionsClient
function handleOracleFulfillment(bytes32 requestId, bytes memory response, bytes memory err) external override {
if (msg.sender != address(i_router)) {
revert OnlyRouterCanFulfill();
}
fulfillRequest(requestId, response, err);
emit RequestFulfilled(requestId);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {CBOR} from "../../../vendor/solidity-cborutils/v2.0.0/CBOR.sol";
/// @title Library for encoding the input data of a Functions request into CBOR
library FunctionsRequest {
using CBOR for CBOR.CBORBuffer;
uint16 public constant REQUEST_DATA_VERSION = 1;
uint256 internal constant DEFAULT_BUFFER_SIZE = 256;
enum Location {
Inline, // Provided within the Request
Remote, // Hosted through remote location that can be accessed through a provided URL
DONHosted // Hosted on the DON's storage
}
enum CodeLanguage {
JavaScript
// In future version we may add other languages
}
struct Request {
Location codeLocation; // ════════════╸ The location of the source code that will be executed on each node in the DON
Location secretsLocation; // ═════════╸ The location of secrets that will be passed into the source code. *Only Remote secrets are supported
CodeLanguage language; // ════════════╸ The coding language that the source code is written in
string source; // ════════════════════╸ Raw source code for Request.codeLocation of Location.Inline, URL for Request.codeLocation of Location.Remote, or slot decimal number for Request.codeLocation of Location.DONHosted
bytes encryptedSecretsReference; // ══╸ Encrypted URLs for Request.secretsLocation of Location.Remote (use addSecretsReference()), or CBOR encoded slotid+version for Request.secretsLocation of Location.DONHosted (use addDONHostedSecrets())
string[] args; // ════════════════════╸ String arguments that will be passed into the source code
bytes[] bytesArgs; // ════════════════╸ Bytes arguments that will be passed into the source code
}
error EmptySource();
error EmptySecrets();
error EmptyArgs();
error NoInlineSecrets();
/// @notice Encodes a Request to CBOR encoded bytes
/// @param self The request to encode
/// @return CBOR encoded bytes
function encodeCBOR(Request memory self) internal pure returns (bytes memory) {
CBOR.CBORBuffer memory buffer = CBOR.create(DEFAULT_BUFFER_SIZE);
buffer.writeString("codeLocation");
buffer.writeUInt256(uint256(self.codeLocation));
buffer.writeString("language");
buffer.writeUInt256(uint256(self.language));
buffer.writeString("source");
buffer.writeString(self.source);
if (self.args.length > 0) {
buffer.writeString("args");
buffer.startArray();
for (uint256 i = 0; i < self.args.length; ++i) {
buffer.writeString(self.args[i]);
}
buffer.endSequence();
}
if (self.encryptedSecretsReference.length > 0) {
if (self.secretsLocation == Location.Inline) {
revert NoInlineSecrets();
}
buffer.writeString("secretsLocation");
buffer.writeUInt256(uint256(self.secretsLocation));
buffer.writeString("secrets");
buffer.writeBytes(self.encryptedSecretsReference);
}
if (self.bytesArgs.length > 0) {
buffer.writeString("bytesArgs");
buffer.startArray();
for (uint256 i = 0; i < self.bytesArgs.length; ++i) {
buffer.writeBytes(self.bytesArgs[i]);
}
buffer.endSequence();
}
return buffer.buf.buf;
}
/// @notice Initializes a Chainlink Functions Request
/// @dev Sets the codeLocation and code on the request
/// @param self The uninitialized request
/// @param codeLocation The user provided source code location
/// @param language The programming language of the user code
/// @param source The user provided source code or a url
function initializeRequest(
Request memory self,
Location codeLocation,
CodeLanguage language,
string memory source
) internal pure {
if (bytes(source).length == 0) revert EmptySource();
self.codeLocation = codeLocation;
self.language = language;
self.source = source;
}
/// @notice Initializes a Chainlink Functions Request
/// @dev Simplified version of initializeRequest for PoC
/// @param self The uninitialized request
/// @param javaScriptSource The user provided JS code (must not be empty)
function initializeRequestForInlineJavaScript(Request memory self, string memory javaScriptSource) internal pure {
initializeRequest(self, Location.Inline, CodeLanguage.JavaScript, javaScriptSource);
}
/// @notice Adds Remote user encrypted secrets to a Request
/// @param self The initialized request
/// @param encryptedSecretsReference Encrypted comma-separated string of URLs pointing to off-chain secrets
function addSecretsReference(Request memory self, bytes memory encryptedSecretsReference) internal pure {
if (encryptedSecretsReference.length == 0) revert EmptySecrets();
self.secretsLocation = Location.Remote;
self.encryptedSecretsReference = encryptedSecretsReference;
}
/// @notice Adds DON-hosted secrets reference to a Request
/// @param self The initialized request
/// @param slotID Slot ID of the user's secrets hosted on DON
/// @param version User data version (for the slotID)
function addDONHostedSecrets(Request memory self, uint8 slotID, uint64 version) internal pure {
CBOR.CBORBuffer memory buffer = CBOR.create(DEFAULT_BUFFER_SIZE);
buffer.writeString("slotID");
buffer.writeUInt64(slotID);
buffer.writeString("version");
buffer.writeUInt64(version);
self.secretsLocation = Location.DONHosted;
self.encryptedSecretsReference = buffer.buf.buf;
}
/// @notice Sets args for the user run function
/// @param self The initialized request
/// @param args The array of string args (must not be empty)
function setArgs(Request memory self, string[] memory args) internal pure {
if (args.length == 0) revert EmptyArgs();
self.args = args;
}
/// @notice Sets bytes args for the user run function
/// @param self The initialized request
/// @param args The array of bytes args (must not be empty)
function setBytesArgs(Request memory self, bytes[] memory args) internal pure {
if (args.length == 0) revert EmptyArgs();
self.bytesArgs = args;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/// @title Library of types that are used for fulfillment of a Functions request
library FunctionsResponse {
// Used to send request information from the Router to the Coordinator
struct RequestMeta {
bytes data; // ══════════════════╸ CBOR encoded Chainlink Functions request data, use FunctionsRequest library to encode a request
bytes32 flags; // ═══════════════╸ Per-subscription flags
address requestingContract; // ══╗ The client contract that is sending the request
uint96 availableBalance; // ═════╝ Common LINK balance of the subscription that is controlled by the Router to be used for all consumer requests.
uint72 adminFee; // ═════════════╗ Flat fee (in Juels of LINK) that will be paid to the Router Owner for operation of the network
uint64 subscriptionId; // ║ Identifier of the billing subscription that will be charged for the request
uint64 initiatedRequests; // ║ The number of requests that have been started
uint32 callbackGasLimit; // ║ The amount of gas that the callback to the consuming contract will be given
uint16 dataVersion; // ══════════╝ The version of the structure of the CBOR encoded request data
uint64 completedRequests; // ════╗ The number of requests that have successfully completed or timed out
address subscriptionOwner; // ═══╝ The owner of the billing subscription
}
enum FulfillResult {
FULFILLED, // 0
USER_CALLBACK_ERROR, // 1
INVALID_REQUEST_ID, // 2
COST_EXCEEDS_COMMITMENT, // 3
INSUFFICIENT_GAS_PROVIDED, // 4
SUBSCRIPTION_BALANCE_INVARIANT_VIOLATION, // 5
INVALID_COMMITMENT // 6
}
struct Commitment {
bytes32 requestId; // ═════════════════╸ A unique identifier for a Chainlink Functions request
address coordinator; // ═══════════════╗ The Coordinator contract that manages the DON that is servicing a request
uint96 estimatedTotalCostJuels; // ════╝ The maximum cost in Juels (1e18) of LINK that will be charged to fulfill a request
address client; // ════════════════════╗ The client contract that sent the request
uint64 subscriptionId; // ║ Identifier of the billing subscription that will be charged for the request
uint32 callbackGasLimit; // ═══════════╝ The amount of gas that the callback to the consuming contract will be given
uint72 adminFee; // ═══════════════════╗ Flat fee (in Juels of LINK) that will be paid to the Router Owner for operation of the network
uint72 donFee; // ║ Fee (in Juels of LINK) that will be split between Node Operators for servicing a request
uint40 gasOverheadBeforeCallback; // ║ Represents the average gas execution cost before the fulfillment callback.
uint40 gasOverheadAfterCallback; // ║ Represents the average gas execution cost after the fulfillment callback.
uint32 timeoutTimestamp; // ═══════════╝ The timestamp at which a request will be eligible to be timed out
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)
pragma solidity ^0.8.20;
/**
* @dev External interface of AccessControl declared to support ERC-165 detection.
*/
interface IAccessControl {
/**
* @dev The `account` is missing a role.
*/
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/
error AccessControlBadConfirmation();
/**
* @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.
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed 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}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed 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`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (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.
*/
function grantRole(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.
*/
function revokeRole(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 `callerConfirmation`.
*/
function renounceRole(bytes32 role, address callerConfirmation) external;
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @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[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC-721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC-721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
* {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC-721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the address zero.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Metadata.sol)
pragma solidity ^0.8.20;
import {IERC721} from "../IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional metadata extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721Metadata is IERC721 {
/**
* @dev Returns the token collection name.
*/
function name() external view returns (string memory);
/**
* @dev Returns the token collection symbol.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) external view returns (string memory);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.20;
/**
* @title ERC-721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC-721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be
* reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/// @title Chainlink Functions client interface.
interface IFunctionsClient {
/// @notice Chainlink Functions response handler called by the Functions Router
/// during fullilment from the designated transmitter node in an OCR round.
/// @param requestId The requestId returned by FunctionsClient.sendRequest().
/// @param response Aggregated response from the request's source code.
/// @param err Aggregated error either from the request's source code or from the execution pipeline.
/// @dev Either response or error parameter will be set, but never both.
function handleOracleFulfillment(bytes32 requestId, bytes memory response, bytes memory err) external;
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {FunctionsResponse} from "../libraries/FunctionsResponse.sol";
/// @title Chainlink Functions Router interface.
interface IFunctionsRouter {
/// @notice The identifier of the route to retrieve the address of the access control contract
/// The access control contract controls which accounts can manage subscriptions
/// @return id - bytes32 id that can be passed to the "getContractById" of the Router
function getAllowListId() external view returns (bytes32);
/// @notice Set the identifier of the route to retrieve the address of the access control contract
/// The access control contract controls which accounts can manage subscriptions
function setAllowListId(bytes32 allowListId) external;
/// @notice Get the flat fee (in Juels of LINK) that will be paid to the Router owner for operation of the network
/// @return adminFee
function getAdminFee() external view returns (uint72 adminFee);
/// @notice Sends a request using the provided subscriptionId
/// @param subscriptionId - A unique subscription ID allocated by billing system,
/// a client can make requests from different contracts referencing the same subscription
/// @param data - CBOR encoded Chainlink Functions request data, use FunctionsClient API to encode a request
/// @param dataVersion - Gas limit for the fulfillment callback
/// @param callbackGasLimit - Gas limit for the fulfillment callback
/// @param donId - An identifier used to determine which route to send the request along
/// @return requestId - A unique request identifier
function sendRequest(
uint64 subscriptionId,
bytes calldata data,
uint16 dataVersion,
uint32 callbackGasLimit,
bytes32 donId
) external returns (bytes32);
/// @notice Sends a request to the proposed contracts
/// @param subscriptionId - A unique subscription ID allocated by billing system,
/// a client can make requests from different contracts referencing the same subscription
/// @param data - CBOR encoded Chainlink Functions request data, use FunctionsClient API to encode a request
/// @param dataVersion - Gas limit for the fulfillment callback
/// @param callbackGasLimit - Gas limit for the fulfillment callback
/// @param donId - An identifier used to determine which route to send the request along
/// @return requestId - A unique request identifier
function sendRequestToProposed(
uint64 subscriptionId,
bytes calldata data,
uint16 dataVersion,
uint32 callbackGasLimit,
bytes32 donId
) external returns (bytes32);
/// @notice Fulfill the request by:
/// - calling back the data that the Oracle returned to the client contract
/// - pay the DON for processing the request
/// @dev Only callable by the Coordinator contract that is saved in the commitment
/// @param response response data from DON consensus
/// @param err error from DON consensus
/// @param juelsPerGas - current rate of juels/gas
/// @param costWithoutFulfillment - The cost of processing the request (in Juels of LINK ), without fulfillment
/// @param transmitter - The Node that transmitted the OCR report
/// @param commitment - The parameters of the request that must be held consistent between request and response time
/// @return fulfillResult -
/// @return callbackGasCostJuels -
function fulfill(
bytes memory response,
bytes memory err,
uint96 juelsPerGas,
uint96 costWithoutFulfillment,
address transmitter,
FunctionsResponse.Commitment memory commitment
) external returns (FunctionsResponse.FulfillResult, uint96);
/// @notice Validate requested gas limit is below the subscription max.
/// @param subscriptionId subscription ID
/// @param callbackGasLimit desired callback gas limit
function isValidCallbackGasLimit(uint64 subscriptionId, uint32 callbackGasLimit) external view;
/// @notice Get the current contract given an ID
/// @param id A bytes32 identifier for the route
/// @return contract The current contract address
function getContractById(bytes32 id) external view returns (address);
/// @notice Get the proposed next contract given an ID
/// @param id A bytes32 identifier for the route
/// @return contract The current or proposed contract address
function getProposedContractById(bytes32 id) external view returns (address);
/// @notice Return the latest proprosal set
/// @return ids The identifiers of the contracts to update
/// @return to The addresses of the contracts that will be updated to
function getProposedContractSet() external view returns (bytes32[] memory, address[] memory);
/// @notice Proposes one or more updates to the contract routes
/// @dev Only callable by owner
function proposeContractsUpdate(bytes32[] memory proposalSetIds, address[] memory proposalSetAddresses) external;
/// @notice Updates the current contract routes to the proposed contracts
/// @dev Only callable by owner
function updateContracts() external;
/// @dev Puts the system into an emergency stopped state.
/// @dev Only callable by owner
function pause() external;
/// @dev Takes the system out of an emergency stopped state.
/// @dev Only callable by owner
function unpause() external;
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an success flag (no overflow).
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an success flag (no overflow).
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an success flag (no overflow).
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a success flag (no division by zero).
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (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 towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// The following calculation ensures accurate ceiling division without overflow.
// Since a is non-zero, (a - 1) / b will not overflow.
// The largest possible result occurs when (a - 1) / b is type(uint256).max,
// but the largest value we can obtain is type(uint256).max - 1, which happens
// when a = type(uint256).max and b = 1.
unchecked {
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.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (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 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 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.
uint256 twos = denominator & (0 - denominator);
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.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && 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
* towards zero.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// 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.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (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.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (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.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* 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.
*/
function log256(uint256 value) internal pure returns (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 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)
pragma solidity ^0.8.20;
import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
uint8 private constant ADDRESS_LENGTH = 20;
/**
* @dev The `value` string doesn't fit in the specified `length`.
*/
error StringsInsufficientHexLength(uint256 value, uint256 length);
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toStringSigned(int256 value) internal pure returns (string memory) {
return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
uint256 localValue = value;
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = HEX_DIGITS[localValue & 0xf];
localValue >>= 4;
}
if (localValue != 0) {
revert StringsInsufficientHexLength(value, length);
}
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
* representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard ERC-20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC-721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC-1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}
{
"compilationTarget": {
"src/Aside0x05.sol": "Aside0x05"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [
":@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
":chainlink/=lib/chainlink/contracts/",
":ds-test/=lib/forge-std/lib/ds-test/src/",
":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
":forge-std/=lib/forge-std/src/",
":openzeppelin-contracts/=lib/openzeppelin-contracts/"
]
}
[{"inputs":[{"internalType":"string","name":"baseURI_","type":"string"},{"internalType":"address","name":"admin_","type":"address"},{"internalType":"address","name":"minter_","type":"address"},{"internalType":"address","name":"updater_","type":"address"},{"internalType":"address","name":"verse_","type":"address"},{"internalType":"uint256","name":"timelock_","type":"uint256"},{"internalType":"address","name":"router_","type":"address"},{"internalType":"bytes32","name":"donId_","type":"bytes32"},{"internalType":"uint64","name":"subscriptionId_","type":"uint64"},{"internalType":"uint32","name":"callbackGasLimit_","type":"uint32"},{"internalType":"string","name":"source_","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[],"name":"AlreadyUnlocked","type":"error"},{"inputs":[],"name":"DeprecatedData","type":"error"},{"inputs":[],"name":"DisabledFunction","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721IncorrectOwner","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721InsufficientApproval","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC721InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"ERC721InvalidOperator","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721InvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC721InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC721InvalidSender","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721NonexistentToken","type":"error"},{"inputs":[],"name":"EmptyArgs","type":"error"},{"inputs":[],"name":"EmptySource","type":"error"},{"inputs":[{"internalType":"bytes","name":"err","type":"bytes"}],"name":"InvalidCallback","type":"error"},{"inputs":[],"name":"InvalidCallbackGasLimit","type":"error"},{"inputs":[],"name":"InvalidDonId","type":"error"},{"inputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"name":"InvalidElectionResult","type":"error"},{"inputs":[],"name":"InvalidParametersMatch","type":"error"},{"inputs":[{"internalType":"bytes32","name":"requestId","type":"bytes32"}],"name":"InvalidRequestId","type":"error"},{"inputs":[],"name":"InvalidSource","type":"error"},{"inputs":[],"name":"InvalidSubscriptionId","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"InvalidTokenId","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"InvalidUnlock","type":"error"},{"inputs":[],"name":"NoInlineSecrets","type":"error"},{"inputs":[],"name":"OnlyRouterCanFulfill","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"TokenAlreadyUnlocked","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"TokenLocked","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[],"name":"EmergencyUnlock","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"RequestFulfilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"RequestSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[],"name":"Unlock","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Unlock","type":"event"},{"inputs":[],"name":"BASE_URI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NB_OF_TOKENS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TIMELOCK_DEADLINE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UPDATER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"areAllUnlocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"callbackGasLimit","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"donId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eUnlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"requestId","type":"bytes32"},{"internalType":"bytes","name":"response","type":"bytes"},{"internalType":"bytes","name":"err","type":"bytes"}],"name":"handleOracleFulfillment","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isEUnlocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"isUnlocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastRequestId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"to","type":"address[]"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"mintBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"result","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"router","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"callbackGasLimit_","type":"uint32"}],"name":"setCallbackGasLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"donId_","type":"bytes32"}],"name":"setDonId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"source_","type":"string"}],"name":"setSource","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"subscriptionId_","type":"uint64"}],"name":"setSubscriptionId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"source","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"subscriptionId","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"name":"unlock","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"string[]","name":"args","type":"string[]"}],"name":"update","outputs":[],"stateMutability":"nonpayable","type":"function"}]