Created
February 20, 2022 15:38
-
-
Save solalette/a632cb0bff518737327abc1751834de4 to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.8.7+commit.e28d00a7.js&optimize=false&runs=200&gist=
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
/** | |
* @dev The contract has an owner address, and provides basic authorization control whitch | |
* simplifies the implementation of user permissions. This contract is based on the source code at: | |
* https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/ownership/Ownable.sol | |
*/ | |
contract Ownable | |
{ | |
/** | |
* @dev Error constants. | |
*/ | |
string public constant NOT_CURRENT_OWNER = "018001"; | |
string public constant CANNOT_TRANSFER_TO_ZERO_ADDRESS = "018002"; | |
/** | |
* @dev Current owner address. | |
*/ | |
address public owner; | |
/** | |
* @dev An event which is triggered when the owner is changed. | |
* @param previousOwner The address of the previous owner. | |
* @param newOwner The address of the new owner. | |
*/ | |
event OwnershipTransferred( | |
address indexed previousOwner, | |
address indexed newOwner | |
); | |
/** | |
* @dev The constructor sets the original `owner` of the contract to the sender account. | |
*/ | |
constructor() | |
{ | |
owner = msg.sender; | |
} | |
/** | |
* @dev Throws if called by any account other than the owner. | |
*/ | |
modifier onlyOwner() | |
{ | |
require(msg.sender == owner, NOT_CURRENT_OWNER); | |
_; | |
} | |
/** | |
* @dev Allows the current owner to transfer control of the contract to a newOwner. | |
* @param _newOwner The address to transfer ownership to. | |
*/ | |
function transferOwnership( | |
address _newOwner | |
) | |
public | |
onlyOwner | |
{ | |
require(_newOwner != address(0), CANNOT_TRANSFER_TO_ZERO_ADDRESS); | |
emit OwnershipTransferred(owner, _newOwner); | |
owner = _newOwner; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
/** | |
* @dev Optional metadata extension for ERC-721 non-fungible token standard. | |
* See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md. | |
*/ | |
interface ERC721Metadata | |
{ | |
/** | |
* @dev Returns a descriptive name for a collection of NFTs in this contract. | |
* @return _name Representing name. | |
*/ | |
function name() | |
external | |
view | |
returns (string memory _name); | |
/** | |
* @dev Returns a abbreviated name for a collection of NFTs in this contract. | |
* @return _symbol Representing symbol. | |
*/ | |
function symbol() | |
external | |
view | |
returns (string memory _symbol); | |
/** | |
* @dev Returns a distinct Uniform Resource Identifier (URI) for a given asset. It Throws if | |
* `_tokenId` is not a valid NFT. URIs are defined in RFC3986. The URI may point to a JSON file | |
* that conforms to the "ERC721 Metadata JSON Schema". | |
* @return URI of _tokenId. | |
*/ | |
function tokenURI(uint256 _tokenId) | |
external | |
view | |
returns (string memory); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
/** | |
* @dev ERC-721 interface for accepting safe transfers. | |
* See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md. | |
*/ | |
interface ERC721TokenReceiver | |
{ | |
/** | |
* @notice The contract address is always the message sender. A wallet/broker/auction application | |
* MUST implement the wallet interface if it will accept safe transfers. | |
* @dev Handle the receipt of a NFT. The ERC721 smart contract calls this function on the | |
* recipient after a `transfer`. This function MAY throw to revert and reject the transfer. Return | |
* of other than the magic value MUST result in the transaction being reverted. | |
* Returns `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` unless throwing. | |
* @param _operator The address which called `safeTransferFrom` function. | |
* @param _from The address which previously owned the token. | |
* @param _tokenId The NFT identifier which is being transferred. | |
* @param _data Additional data with no specified format. | |
* @return Returns `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`. | |
*/ | |
function onERC721Received( | |
address _operator, | |
address _from, | |
uint256 _tokenId, | |
bytes calldata _data | |
) | |
external | |
returns(bytes4); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
/** | |
* @dev ERC-721 non-fungible token standard. | |
* See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md. | |
*/ | |
interface ERC721 | |
{ | |
/** | |
* @dev Emits when ownership of any NFT changes by any mechanism. This event emits when NFTs are | |
* created (`from` == 0) and destroyed (`to` == 0). Exception: during contract creation, any | |
* number of NFTs may be created and assigned without emitting Transfer. At the time of any | |
* transfer, the approved address for that NFT (if any) is reset to none. | |
*/ | |
event Transfer( | |
address indexed _from, | |
address indexed _to, | |
uint256 indexed _tokenId | |
); | |
/** | |
* @dev This emits when the approved address for an NFT is changed or reaffirmed. The zero | |
* address indicates there is no approved address. When a Transfer event emits, this also | |
* indicates that the approved address for that NFT (if any) is reset to none. | |
*/ | |
event Approval( | |
address indexed _owner, | |
address indexed _approved, | |
uint256 indexed _tokenId | |
); | |
/** | |
* @dev This emits when an operator is enabled or disabled for an owner. The operator can manage | |
* all NFTs of the owner. | |
*/ | |
event ApprovalForAll( | |
address indexed _owner, | |
address indexed _operator, | |
bool _approved | |
); | |
/** | |
* @notice Throws unless `msg.sender` is the current owner, an authorized operator, or the | |
* approved address for this NFT. Throws if `_from` is not the current owner. Throws if `_to` is | |
* the zero address. Throws if `_tokenId` is not a valid NFT. When transfer is complete, this | |
* function checks if `_to` is a smart contract (code size > 0). If so, it calls | |
* `onERC721Received` on `_to` and throws if the return value is not | |
* `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`. | |
* @dev Transfers the ownership of an NFT from one address to another address. This function can | |
* be changed to payable. | |
* @param _from The current owner of the NFT. | |
* @param _to The new owner. | |
* @param _tokenId The NFT to transfer. | |
* @param _data Additional data with no specified format, sent in call to `_to`. | |
*/ | |
function safeTransferFrom( | |
address _from, | |
address _to, | |
uint256 _tokenId, | |
bytes calldata _data | |
) | |
external; | |
/** | |
* @notice This works identically to the other function with an extra data parameter, except this | |
* function just sets data to "" | |
* @dev Transfers the ownership of an NFT from one address to another address. This function can | |
* be changed to payable. | |
* @param _from The current owner of the NFT. | |
* @param _to The new owner. | |
* @param _tokenId The NFT to transfer. | |
*/ | |
function safeTransferFrom( | |
address _from, | |
address _to, | |
uint256 _tokenId | |
) | |
external; | |
/** | |
* @notice The caller is responsible to confirm that `_to` is capable of receiving NFTs or else | |
* they may be permanently lost. | |
* @dev Throws unless `msg.sender` is the current owner, an authorized operator, or the approved | |
* address for this NFT. Throws if `_from` is not the current owner. Throws if `_to` is the zero | |
* address. Throws if `_tokenId` is not a valid NFT. This function can be changed to payable. | |
* @param _from The current owner of the NFT. | |
* @param _to The new owner. | |
* @param _tokenId The NFT to transfer. | |
*/ | |
function transferFrom( | |
address _from, | |
address _to, | |
uint256 _tokenId | |
) | |
external; | |
/** | |
* @notice The zero address indicates there is no approved address. Throws unless `msg.sender` is | |
* the current NFT owner, or an authorized operator of the current owner. | |
* @param _approved The new approved NFT controller. | |
* @dev Set or reaffirm the approved address for an NFT. This function can be changed to payable. | |
* @param _tokenId The NFT to approve. | |
*/ | |
function approve( | |
address _approved, | |
uint256 _tokenId | |
) | |
external; | |
/** | |
* @notice The contract MUST allow multiple operators per owner. | |
* @dev Enables or disables approval for a third party ("operator") to manage all of | |
* `msg.sender`'s assets. It also emits the ApprovalForAll event. | |
* @param _operator Address to add to the set of authorized operators. | |
* @param _approved True if the operators is approved, false to revoke approval. | |
*/ | |
function setApprovalForAll( | |
address _operator, | |
bool _approved | |
) | |
external; | |
/** | |
* @dev Returns the number of NFTs owned by `_owner`. NFTs assigned to the zero address are | |
* considered invalid, and this function throws for queries about the zero address. | |
* @notice Count all NFTs assigned to an owner. | |
* @param _owner Address for whom to query the balance. | |
* @return Balance of _owner. | |
*/ | |
function balanceOf( | |
address _owner | |
) | |
external | |
view | |
returns (uint256); | |
/** | |
* @notice Find the owner of an NFT. | |
* @dev Returns the address of the owner of the NFT. NFTs assigned to the zero address are | |
* considered invalid, and queries about them do throw. | |
* @param _tokenId The identifier for an NFT. | |
* @return Address of _tokenId owner. | |
*/ | |
function ownerOf( | |
uint256 _tokenId | |
) | |
external | |
view | |
returns (address); | |
/** | |
* @notice Throws if `_tokenId` is not a valid NFT. | |
* @dev Get the approved address for a single NFT. | |
* @param _tokenId The NFT to find the approved address for. | |
* @return Address that _tokenId is approved for. | |
*/ | |
function getApproved( | |
uint256 _tokenId | |
) | |
external | |
view | |
returns (address); | |
/** | |
* @notice Query if an address is an authorized operator for another address. | |
* @dev Returns true if `_operator` is an approved operator for `_owner`, false otherwise. | |
* @param _owner The address that owns the NFTs. | |
* @param _operator The address that acts on behalf of the owner. | |
* @return True if approved for all, false otherwise. | |
*/ | |
function isApprovedForAll( | |
address _owner, | |
address _operator | |
) | |
external | |
view | |
returns (bool); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
import "./nf-token.sol"; | |
import "./erc721-metadata.sol"; | |
/** | |
* @dev Optional metadata implementation for ERC-721 non-fungible token standard. | |
*/ | |
contract NFTokenMetadata is | |
NFToken, | |
ERC721Metadata | |
{ | |
/** | |
* @dev A descriptive name for a collection of NFTs. | |
*/ | |
string internal nftName; | |
/** | |
* @dev An abbreviated name for NFTokens. | |
*/ | |
string internal nftSymbol; | |
/** | |
* @dev Mapping from NFT ID to metadata uri. | |
*/ | |
mapping (uint256 => string) internal idToUri; | |
/** | |
* @notice When implementing this contract don't forget to set nftName and nftSymbol. | |
* @dev Contract constructor. | |
*/ | |
constructor() | |
{ | |
supportedInterfaces[0x5b5e139f] = true; // ERC721Metadata | |
} | |
/** | |
* @dev Returns a descriptive name for a collection of NFTokens. | |
* @return _name Representing name. | |
*/ | |
function name() | |
external | |
override | |
view | |
returns (string memory _name) | |
{ | |
_name = nftName; | |
} | |
/** | |
* @dev Returns an abbreviated name for NFTokens. | |
* @return _symbol Representing symbol. | |
*/ | |
function symbol() | |
external | |
override | |
view | |
returns (string memory _symbol) | |
{ | |
_symbol = nftSymbol; | |
} | |
/** | |
* @dev A distinct URI (RFC 3986) for a given NFT. | |
* @param _tokenId Id for which we want uri. | |
* @return URI of _tokenId. | |
*/ | |
function tokenURI( | |
uint256 _tokenId | |
) | |
external | |
override | |
view | |
validNFToken(_tokenId) | |
returns (string memory) | |
{ | |
return _tokenURI(_tokenId); | |
} | |
/** | |
* @notice This is an internal function that can be overriden if you want to implement a different | |
* way to generate token URI. | |
* @param _tokenId Id for which we want uri. | |
* @return URI of _tokenId. | |
*/ | |
function _tokenURI( | |
uint256 _tokenId | |
) | |
internal | |
virtual | |
view | |
returns (string memory) | |
{ | |
return idToUri[_tokenId]; | |
} | |
/** | |
* @notice This is an internal function which should be called from user-implemented external | |
* burn function. Its purpose is to show and properly initialize data structures when using this | |
* implementation. Also, note that this burn implementation allows the minter to re-mint a burned | |
* NFT. | |
* @dev Burns a NFT. | |
* @param _tokenId ID of the NFT to be burned. | |
*/ | |
function _burn( | |
uint256 _tokenId | |
) | |
internal | |
override | |
virtual | |
{ | |
super._burn(_tokenId); | |
delete idToUri[_tokenId]; | |
} | |
/** | |
* @notice This is an internal function which should be called from user-implemented external | |
* function. Its purpose is to show and properly initialize data structures when using this | |
* implementation. | |
* @dev Set a distinct URI (RFC 3986) for a given NFT ID. | |
* @param _tokenId Id for which we want URI. | |
* @param _uri String representing RFC 3986 URI. | |
*/ | |
function _setTokenUri( | |
uint256 _tokenId, | |
string memory _uri | |
) | |
internal | |
validNFToken(_tokenId) | |
{ | |
idToUri[_tokenId] = _uri; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
import "./erc721.sol"; | |
import "./erc721-token-receiver.sol"; | |
import "../utils/supports-interface.sol"; | |
import "../utils/address-utils.sol"; | |
/** | |
* @dev Implementation of ERC-721 non-fungible token standard. | |
*/ | |
contract NFToken is | |
ERC721, | |
SupportsInterface | |
{ | |
using AddressUtils for address; | |
/** | |
* @dev List of revert message codes. Implementing dApp should handle showing the correct message. | |
* Based on 0xcert framework error codes. | |
*/ | |
string constant ZERO_ADDRESS = "003001"; | |
string constant NOT_VALID_NFT = "003002"; | |
string constant NOT_OWNER_OR_OPERATOR = "003003"; | |
string constant NOT_OWNER_APPROVED_OR_OPERATOR = "003004"; | |
string constant NOT_ABLE_TO_RECEIVE_NFT = "003005"; | |
string constant NFT_ALREADY_EXISTS = "003006"; | |
string constant NOT_OWNER = "003007"; | |
string constant IS_OWNER = "003008"; | |
/** | |
* @dev Magic value of a smart contract that can receive NFT. | |
* Equal to: bytes4(keccak256("onERC721Received(address,address,uint256,bytes)")). | |
*/ | |
bytes4 internal constant MAGIC_ON_ERC721_RECEIVED = 0x150b7a02; | |
/** | |
* @dev A mapping from NFT ID to the address that owns it. | |
*/ | |
mapping (uint256 => address) internal idToOwner; | |
/** | |
* @dev Mapping from NFT ID to approved address. | |
*/ | |
mapping (uint256 => address) internal idToApproval; | |
/** | |
* @dev Mapping from owner address to count of their tokens. | |
*/ | |
mapping (address => uint256) private ownerToNFTokenCount; | |
/** | |
* @dev Mapping from owner address to mapping of operator addresses. | |
*/ | |
mapping (address => mapping (address => bool)) internal ownerToOperators; | |
/** | |
* @dev Guarantees that the msg.sender is an owner or operator of the given NFT. | |
* @param _tokenId ID of the NFT to validate. | |
*/ | |
modifier canOperate( | |
uint256 _tokenId | |
) | |
{ | |
address tokenOwner = idToOwner[_tokenId]; | |
require( | |
tokenOwner == msg.sender || ownerToOperators[tokenOwner][msg.sender], | |
NOT_OWNER_OR_OPERATOR | |
); | |
_; | |
} | |
/** | |
* @dev Guarantees that the msg.sender is allowed to transfer NFT. | |
* @param _tokenId ID of the NFT to transfer. | |
*/ | |
modifier canTransfer( | |
uint256 _tokenId | |
) | |
{ | |
address tokenOwner = idToOwner[_tokenId]; | |
require( | |
tokenOwner == msg.sender | |
|| idToApproval[_tokenId] == msg.sender | |
|| ownerToOperators[tokenOwner][msg.sender], | |
NOT_OWNER_APPROVED_OR_OPERATOR | |
); | |
_; | |
} | |
/** | |
* @dev Guarantees that _tokenId is a valid Token. | |
* @param _tokenId ID of the NFT to validate. | |
*/ | |
modifier validNFToken( | |
uint256 _tokenId | |
) | |
{ | |
require(idToOwner[_tokenId] != address(0), NOT_VALID_NFT); | |
_; | |
} | |
/** | |
* @dev Contract constructor. | |
*/ | |
constructor() | |
{ | |
supportedInterfaces[0x80ac58cd] = true; // ERC721 | |
} | |
/** | |
* @notice Throws unless `msg.sender` is the current owner, an authorized operator, or the | |
* approved address for this NFT. Throws if `_from` is not the current owner. Throws if `_to` is | |
* the zero address. Throws if `_tokenId` is not a valid NFT. When transfer is complete, this | |
* function checks if `_to` is a smart contract (code size > 0). If so, it calls | |
* `onERC721Received` on `_to` and throws if the return value is not | |
* `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`. | |
* @dev Transfers the ownership of an NFT from one address to another address. This function can | |
* be changed to payable. | |
* @param _from The current owner of the NFT. | |
* @param _to The new owner. | |
* @param _tokenId The NFT to transfer. | |
* @param _data Additional data with no specified format, sent in call to `_to`. | |
*/ | |
function safeTransferFrom( | |
address _from, | |
address _to, | |
uint256 _tokenId, | |
bytes calldata _data | |
) | |
external | |
override | |
{ | |
_safeTransferFrom(_from, _to, _tokenId, _data); | |
} | |
/** | |
* @notice This works identically to the other function with an extra data parameter, except this | |
* function just sets data to "". | |
* @dev Transfers the ownership of an NFT from one address to another address. This function can | |
* be changed to payable. | |
* @param _from The current owner of the NFT. | |
* @param _to The new owner. | |
* @param _tokenId The NFT to transfer. | |
*/ | |
function safeTransferFrom( | |
address _from, | |
address _to, | |
uint256 _tokenId | |
) | |
external | |
override | |
{ | |
_safeTransferFrom(_from, _to, _tokenId, ""); | |
} | |
/** | |
* @notice The caller is responsible to confirm that `_to` is capable of receiving NFTs or else | |
* they may be permanently lost. | |
* @dev Throws unless `msg.sender` is the current owner, an authorized operator, or the approved | |
* address for this NFT. Throws if `_from` is not the current owner. Throws if `_to` is the zero | |
* address. Throws if `_tokenId` is not a valid NFT. This function can be changed to payable. | |
* @param _from The current owner of the NFT. | |
* @param _to The new owner. | |
* @param _tokenId The NFT to transfer. | |
*/ | |
function transferFrom( | |
address _from, | |
address _to, | |
uint256 _tokenId | |
) | |
external | |
override | |
canTransfer(_tokenId) | |
validNFToken(_tokenId) | |
{ | |
address tokenOwner = idToOwner[_tokenId]; | |
require(tokenOwner == _from, NOT_OWNER); | |
require(_to != address(0), ZERO_ADDRESS); | |
_transfer(_to, _tokenId); | |
} | |
/** | |
* @notice The zero address indicates there is no approved address. Throws unless `msg.sender` is | |
* the current NFT owner, or an authorized operator of the current owner. | |
* @dev Set or reaffirm the approved address for an NFT. This function can be changed to payable. | |
* @param _approved Address to be approved for the given NFT ID. | |
* @param _tokenId ID of the token to be approved. | |
*/ | |
function approve( | |
address _approved, | |
uint256 _tokenId | |
) | |
external | |
override | |
canOperate(_tokenId) | |
validNFToken(_tokenId) | |
{ | |
address tokenOwner = idToOwner[_tokenId]; | |
require(_approved != tokenOwner, IS_OWNER); | |
idToApproval[_tokenId] = _approved; | |
emit Approval(tokenOwner, _approved, _tokenId); | |
} | |
/** | |
* @notice This works even if sender doesn't own any tokens at the time. | |
* @dev Enables or disables approval for a third party ("operator") to manage all of | |
* `msg.sender`'s assets. It also emits the ApprovalForAll event. | |
* @param _operator Address to add to the set of authorized operators. | |
* @param _approved True if the operators is approved, false to revoke approval. | |
*/ | |
function setApprovalForAll( | |
address _operator, | |
bool _approved | |
) | |
external | |
override | |
{ | |
ownerToOperators[msg.sender][_operator] = _approved; | |
emit ApprovalForAll(msg.sender, _operator, _approved); | |
} | |
/** | |
* @dev Returns the number of NFTs owned by `_owner`. NFTs assigned to the zero address are | |
* considered invalid, and this function throws for queries about the zero address. | |
* @param _owner Address for whom to query the balance. | |
* @return Balance of _owner. | |
*/ | |
function balanceOf( | |
address _owner | |
) | |
external | |
override | |
view | |
returns (uint256) | |
{ | |
require(_owner != address(0), ZERO_ADDRESS); | |
return _getOwnerNFTCount(_owner); | |
} | |
/** | |
* @dev Returns the address of the owner of the NFT. NFTs assigned to the zero address are | |
* considered invalid, and queries about them do throw. | |
* @param _tokenId The identifier for an NFT. | |
* @return _owner Address of _tokenId owner. | |
*/ | |
function ownerOf( | |
uint256 _tokenId | |
) | |
external | |
override | |
view | |
returns (address _owner) | |
{ | |
_owner = idToOwner[_tokenId]; | |
require(_owner != address(0), NOT_VALID_NFT); | |
} | |
/** | |
* @notice Throws if `_tokenId` is not a valid NFT. | |
* @dev Get the approved address for a single NFT. | |
* @param _tokenId ID of the NFT to query the approval of. | |
* @return Address that _tokenId is approved for. | |
*/ | |
function getApproved( | |
uint256 _tokenId | |
) | |
external | |
override | |
view | |
validNFToken(_tokenId) | |
returns (address) | |
{ | |
return idToApproval[_tokenId]; | |
} | |
/** | |
* @dev Checks if `_operator` is an approved operator for `_owner`. | |
* @param _owner The address that owns the NFTs. | |
* @param _operator The address that acts on behalf of the owner. | |
* @return True if approved for all, false otherwise. | |
*/ | |
function isApprovedForAll( | |
address _owner, | |
address _operator | |
) | |
external | |
override | |
view | |
returns (bool) | |
{ | |
return ownerToOperators[_owner][_operator]; | |
} | |
/** | |
* @notice Does NO checks. | |
* @dev Actually performs the transfer. | |
* @param _to Address of a new owner. | |
* @param _tokenId The NFT that is being transferred. | |
*/ | |
function _transfer( | |
address _to, | |
uint256 _tokenId | |
) | |
internal | |
virtual | |
{ | |
address from = idToOwner[_tokenId]; | |
_clearApproval(_tokenId); | |
_removeNFToken(from, _tokenId); | |
_addNFToken(_to, _tokenId); | |
emit Transfer(from, _to, _tokenId); | |
} | |
/** | |
* @notice This is an internal function which should be called from user-implemented external | |
* mint function. Its purpose is to show and properly initialize data structures when using this | |
* implementation. | |
* @dev Mints a new NFT. | |
* @param _to The address that will own the minted NFT. | |
* @param _tokenId of the NFT to be minted by the msg.sender. | |
*/ | |
function _mint( | |
address _to, | |
uint256 _tokenId | |
) | |
internal | |
virtual | |
{ | |
require(_to != address(0), ZERO_ADDRESS); | |
require(idToOwner[_tokenId] == address(0), NFT_ALREADY_EXISTS); | |
_addNFToken(_to, _tokenId); | |
emit Transfer(address(0), _to, _tokenId); | |
} | |
/** | |
* @notice This is an internal function which should be called from user-implemented external burn | |
* function. Its purpose is to show and properly initialize data structures when using this | |
* implementation. Also, note that this burn implementation allows the minter to re-mint a burned | |
* NFT. | |
* @dev Burns a NFT. | |
* @param _tokenId ID of the NFT to be burned. | |
*/ | |
function _burn( | |
uint256 _tokenId | |
) | |
internal | |
virtual | |
validNFToken(_tokenId) | |
{ | |
address tokenOwner = idToOwner[_tokenId]; | |
_clearApproval(_tokenId); | |
_removeNFToken(tokenOwner, _tokenId); | |
emit Transfer(tokenOwner, address(0), _tokenId); | |
} | |
/** | |
* @notice Use and override this function with caution. Wrong usage can have serious consequences. | |
* @dev Removes a NFT from owner. | |
* @param _from Address from which we want to remove the NFT. | |
* @param _tokenId Which NFT we want to remove. | |
*/ | |
function _removeNFToken( | |
address _from, | |
uint256 _tokenId | |
) | |
internal | |
virtual | |
{ | |
require(idToOwner[_tokenId] == _from, NOT_OWNER); | |
ownerToNFTokenCount[_from] -= 1; | |
delete idToOwner[_tokenId]; | |
} | |
/** | |
* @notice Use and override this function with caution. Wrong usage can have serious consequences. | |
* @dev Assigns a new NFT to owner. | |
* @param _to Address to which we want to add the NFT. | |
* @param _tokenId Which NFT we want to add. | |
*/ | |
function _addNFToken( | |
address _to, | |
uint256 _tokenId | |
) | |
internal | |
virtual | |
{ | |
require(idToOwner[_tokenId] == address(0), NFT_ALREADY_EXISTS); | |
idToOwner[_tokenId] = _to; | |
ownerToNFTokenCount[_to] += 1; | |
} | |
/** | |
* @dev Helper function that gets NFT count of owner. This is needed for overriding in enumerable | |
* extension to remove double storage (gas optimization) of owner NFT count. | |
* @param _owner Address for whom to query the count. | |
* @return Number of _owner NFTs. | |
*/ | |
function _getOwnerNFTCount( | |
address _owner | |
) | |
internal | |
virtual | |
view | |
returns (uint256) | |
{ | |
return ownerToNFTokenCount[_owner]; | |
} | |
/** | |
* @dev Actually perform the safeTransferFrom. | |
* @param _from The current owner of the NFT. | |
* @param _to The new owner. | |
* @param _tokenId The NFT to transfer. | |
* @param _data Additional data with no specified format, sent in call to `_to`. | |
*/ | |
function _safeTransferFrom( | |
address _from, | |
address _to, | |
uint256 _tokenId, | |
bytes memory _data | |
) | |
private | |
canTransfer(_tokenId) | |
validNFToken(_tokenId) | |
{ | |
address tokenOwner = idToOwner[_tokenId]; | |
require(tokenOwner == _from, NOT_OWNER); | |
require(_to != address(0), ZERO_ADDRESS); | |
_transfer(_to, _tokenId); | |
if (_to.isContract()) | |
{ | |
bytes4 retval = ERC721TokenReceiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data); | |
require(retval == MAGIC_ON_ERC721_RECEIVED, NOT_ABLE_TO_RECEIVE_NFT); | |
} | |
} | |
/** | |
* @dev Clears the current approval of a given NFT ID. | |
* @param _tokenId ID of the NFT to be transferred. | |
*/ | |
function _clearApproval( | |
uint256 _tokenId | |
) | |
private | |
{ | |
delete idToApproval[_tokenId]; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
/** | |
* @notice Based on: | |
* https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol | |
* Requires EIP-1052. | |
* @dev Utility library of inline functions on addresses. | |
*/ | |
library AddressUtils | |
{ | |
/** | |
* @dev Returns whether the target address is a contract. | |
* @param _addr Address to check. | |
* @return addressCheck True if _addr is a contract, false if not. | |
*/ | |
function isContract( | |
address _addr | |
) | |
internal | |
view | |
returns (bool addressCheck) | |
{ | |
// This method relies in extcodesize, which returns 0 for contracts in | |
// construction, since the code is only stored at the end of the | |
// constructor execution. | |
// According to EIP-1052, 0x0 is the value returned for not-yet created accounts | |
// and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned | |
// for accounts without code, i.e. `keccak256('')` | |
bytes32 codehash; | |
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; | |
assembly { codehash := extcodehash(_addr) } // solhint-disable-line | |
addressCheck = (codehash != 0x0 && codehash != accountHash); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
/** | |
* @dev A standard for detecting smart contract interfaces. | |
* See: https://eips.ethereum.org/EIPS/eip-165. | |
*/ | |
interface ERC165 | |
{ | |
/** | |
* @dev Checks if the smart contract includes a specific interface. | |
* This function uses less than 30,000 gas. | |
* @param _interfaceID The interface identifier, as specified in ERC-165. | |
* @return True if _interfaceID is supported, false otherwise. | |
*/ | |
function supportsInterface( | |
bytes4 _interfaceID | |
) | |
external | |
view | |
returns (bool); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
import "./erc165.sol"; | |
/** | |
* @dev Implementation of standard for detect smart contract interfaces. | |
*/ | |
contract SupportsInterface is | |
ERC165 | |
{ | |
/** | |
* @dev Mapping of supported intefraces. You must not set element 0xffffffff to true. | |
*/ | |
mapping(bytes4 => bool) internal supportedInterfaces; | |
/** | |
* @dev Contract constructor. | |
*/ | |
constructor() | |
{ | |
supportedInterfaces[0x01ffc9a7] = true; // ERC165 | |
} | |
/** | |
* @dev Function to check which interfaces are suported by this contract. | |
* @param _interfaceID Id of the interface. | |
* @return True if _interfaceID is supported, false otherwise. | |
*/ | |
function supportsInterface( | |
bytes4 _interfaceID | |
) | |
external | |
override | |
view | |
returns (bool) | |
{ | |
return supportedInterfaces[_interfaceID]; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
import {CBORChainlink} from "./vendor/CBORChainlink.sol"; | |
import {BufferChainlink} from "./vendor/BufferChainlink.sol"; | |
/** | |
* @title Library for common Chainlink functions | |
* @dev Uses imported CBOR library for encoding to buffer | |
*/ | |
library Chainlink { | |
uint256 internal constant defaultBufferSize = 256; // solhint-disable-line const-name-snakecase | |
using CBORChainlink for BufferChainlink.buffer; | |
struct Request { | |
bytes32 id; | |
address callbackAddress; | |
bytes4 callbackFunctionId; | |
uint256 nonce; | |
BufferChainlink.buffer buf; | |
} | |
/** | |
* @notice Initializes a Chainlink request | |
* @dev Sets the ID, callback address, and callback function signature on the request | |
* @param self The uninitialized request | |
* @param jobId The Job Specification ID | |
* @param callbackAddr The callback address | |
* @param callbackFunc The callback function signature | |
* @return The initialized request | |
*/ | |
function initialize( | |
Request memory self, | |
bytes32 jobId, | |
address callbackAddr, | |
bytes4 callbackFunc | |
) internal pure returns (Chainlink.Request memory) { | |
BufferChainlink.init(self.buf, defaultBufferSize); | |
self.id = jobId; | |
self.callbackAddress = callbackAddr; | |
self.callbackFunctionId = callbackFunc; | |
return self; | |
} | |
/** | |
* @notice Sets the data for the buffer without encoding CBOR on-chain | |
* @dev CBOR can be closed with curly-brackets {} or they can be left off | |
* @param self The initialized request | |
* @param data The CBOR data | |
*/ | |
function setBuffer(Request memory self, bytes memory data) internal pure { | |
BufferChainlink.init(self.buf, data.length); | |
BufferChainlink.append(self.buf, data); | |
} | |
/** | |
* @notice Adds a string value to the request with a given key name | |
* @param self The initialized request | |
* @param key The name of the key | |
* @param value The string value to add | |
*/ | |
function add( | |
Request memory self, | |
string memory key, | |
string memory value | |
) internal pure { | |
self.buf.encodeString(key); | |
self.buf.encodeString(value); | |
} | |
/** | |
* @notice Adds a bytes value to the request with a given key name | |
* @param self The initialized request | |
* @param key The name of the key | |
* @param value The bytes value to add | |
*/ | |
function addBytes( | |
Request memory self, | |
string memory key, | |
bytes memory value | |
) internal pure { | |
self.buf.encodeString(key); | |
self.buf.encodeBytes(value); | |
} | |
/** | |
* @notice Adds a int256 value to the request with a given key name | |
* @param self The initialized request | |
* @param key The name of the key | |
* @param value The int256 value to add | |
*/ | |
function addInt( | |
Request memory self, | |
string memory key, | |
int256 value | |
) internal pure { | |
self.buf.encodeString(key); | |
self.buf.encodeInt(value); | |
} | |
/** | |
* @notice Adds a uint256 value to the request with a given key name | |
* @param self The initialized request | |
* @param key The name of the key | |
* @param value The uint256 value to add | |
*/ | |
function addUint( | |
Request memory self, | |
string memory key, | |
uint256 value | |
) internal pure { | |
self.buf.encodeString(key); | |
self.buf.encodeUInt(value); | |
} | |
/** | |
* @notice Adds an array of strings to the request with a given key name | |
* @param self The initialized request | |
* @param key The name of the key | |
* @param values The array of string values to add | |
*/ | |
function addStringArray( | |
Request memory self, | |
string memory key, | |
string[] memory values | |
) internal pure { | |
self.buf.encodeString(key); | |
self.buf.startArray(); | |
for (uint256 i = 0; i < values.length; i++) { | |
self.buf.encodeString(values[i]); | |
} | |
self.buf.endSequence(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
import "./Chainlink.sol"; | |
import "./interfaces/ENSInterface.sol"; | |
import "./interfaces/LinkTokenInterface.sol"; | |
import "./interfaces/ChainlinkRequestInterface.sol"; | |
import "./interfaces/OperatorInterface.sol"; | |
import "./interfaces/PointerInterface.sol"; | |
import {ENSResolver as ENSResolver_Chainlink} from "./vendor/ENSResolver.sol"; | |
/** | |
* @title The ChainlinkClient contract | |
* @notice Contract writers can inherit this contract in order to create requests for the | |
* Chainlink network | |
*/ | |
abstract contract ChainlinkClient { | |
using Chainlink for Chainlink.Request; | |
uint256 internal constant LINK_DIVISIBILITY = 10**18; | |
uint256 private constant AMOUNT_OVERRIDE = 0; | |
address private constant SENDER_OVERRIDE = address(0); | |
uint256 private constant ORACLE_ARGS_VERSION = 1; | |
uint256 private constant OPERATOR_ARGS_VERSION = 2; | |
bytes32 private constant ENS_TOKEN_SUBNAME = keccak256("link"); | |
bytes32 private constant ENS_ORACLE_SUBNAME = keccak256("oracle"); | |
address private constant LINK_TOKEN_POINTER = 0xC89bD4E1632D3A43CB03AAAd5262cbe4038Bc571; | |
ENSInterface private s_ens; | |
bytes32 private s_ensNode; | |
LinkTokenInterface private s_link; | |
OperatorInterface private s_oracle; | |
uint256 private s_requestCount = 1; | |
mapping(bytes32 => address) private s_pendingRequests; | |
event ChainlinkRequested(bytes32 indexed id); | |
event ChainlinkFulfilled(bytes32 indexed id); | |
event ChainlinkCancelled(bytes32 indexed id); | |
/** | |
* @notice Creates a request that can hold additional parameters | |
* @param specId The Job Specification ID that the request will be created for | |
* @param callbackAddr address to operate the callback on | |
* @param callbackFunctionSignature function signature to use for the callback | |
* @return A Chainlink Request struct in memory | |
*/ | |
function buildChainlinkRequest( | |
bytes32 specId, | |
address callbackAddr, | |
bytes4 callbackFunctionSignature | |
) internal pure returns (Chainlink.Request memory) { | |
Chainlink.Request memory req; | |
return req.initialize(specId, callbackAddr, callbackFunctionSignature); | |
} | |
/** | |
* @notice Creates a request that can hold additional parameters | |
* @param specId The Job Specification ID that the request will be created for | |
* @param callbackFunctionSignature function signature to use for the callback | |
* @return A Chainlink Request struct in memory | |
*/ | |
function buildOperatorRequest(bytes32 specId, bytes4 callbackFunctionSignature) | |
internal | |
view | |
returns (Chainlink.Request memory) | |
{ | |
Chainlink.Request memory req; | |
return req.initialize(specId, address(this), callbackFunctionSignature); | |
} | |
/** | |
* @notice Creates a Chainlink request to the stored oracle address | |
* @dev Calls `chainlinkRequestTo` with the stored oracle address | |
* @param req The initialized Chainlink Request | |
* @param payment The amount of LINK to send for the request | |
* @return requestId The request ID | |
*/ | |
function sendChainlinkRequest(Chainlink.Request memory req, uint256 payment) internal returns (bytes32) { | |
return sendChainlinkRequestTo(address(s_oracle), req, payment); | |
} | |
/** | |
* @notice Creates a Chainlink request to the specified oracle address | |
* @dev Generates and stores a request ID, increments the local nonce, and uses `transferAndCall` to | |
* send LINK which creates a request on the target oracle contract. | |
* Emits ChainlinkRequested event. | |
* @param oracleAddress The address of the oracle for the request | |
* @param req The initialized Chainlink Request | |
* @param payment The amount of LINK to send for the request | |
* @return requestId The request ID | |
*/ | |
function sendChainlinkRequestTo( | |
address oracleAddress, | |
Chainlink.Request memory req, | |
uint256 payment | |
) internal returns (bytes32 requestId) { | |
uint256 nonce = s_requestCount; | |
s_requestCount = nonce + 1; | |
bytes memory encodedRequest = abi.encodeWithSelector( | |
ChainlinkRequestInterface.oracleRequest.selector, | |
SENDER_OVERRIDE, // Sender value - overridden by onTokenTransfer by the requesting contract's address | |
AMOUNT_OVERRIDE, // Amount value - overridden by onTokenTransfer by the actual amount of LINK sent | |
req.id, | |
address(this), | |
req.callbackFunctionId, | |
nonce, | |
ORACLE_ARGS_VERSION, | |
req.buf.buf | |
); | |
return _rawRequest(oracleAddress, nonce, payment, encodedRequest); | |
} | |
/** | |
* @notice Creates a Chainlink request to the stored oracle address | |
* @dev This function supports multi-word response | |
* @dev Calls `sendOperatorRequestTo` with the stored oracle address | |
* @param req The initialized Chainlink Request | |
* @param payment The amount of LINK to send for the request | |
* @return requestId The request ID | |
*/ | |
function sendOperatorRequest(Chainlink.Request memory req, uint256 payment) internal returns (bytes32) { | |
return sendOperatorRequestTo(address(s_oracle), req, payment); | |
} | |
/** | |
* @notice Creates a Chainlink request to the specified oracle address | |
* @dev This function supports multi-word response | |
* @dev Generates and stores a request ID, increments the local nonce, and uses `transferAndCall` to | |
* send LINK which creates a request on the target oracle contract. | |
* Emits ChainlinkRequested event. | |
* @param oracleAddress The address of the oracle for the request | |
* @param req The initialized Chainlink Request | |
* @param payment The amount of LINK to send for the request | |
* @return requestId The request ID | |
*/ | |
function sendOperatorRequestTo( | |
address oracleAddress, | |
Chainlink.Request memory req, | |
uint256 payment | |
) internal returns (bytes32 requestId) { | |
uint256 nonce = s_requestCount; | |
s_requestCount = nonce + 1; | |
bytes memory encodedRequest = abi.encodeWithSelector( | |
OperatorInterface.operatorRequest.selector, | |
SENDER_OVERRIDE, // Sender value - overridden by onTokenTransfer by the requesting contract's address | |
AMOUNT_OVERRIDE, // Amount value - overridden by onTokenTransfer by the actual amount of LINK sent | |
req.id, | |
req.callbackFunctionId, | |
nonce, | |
OPERATOR_ARGS_VERSION, | |
req.buf.buf | |
); | |
return _rawRequest(oracleAddress, nonce, payment, encodedRequest); | |
} | |
/** | |
* @notice Make a request to an oracle | |
* @param oracleAddress The address of the oracle for the request | |
* @param nonce used to generate the request ID | |
* @param payment The amount of LINK to send for the request | |
* @param encodedRequest data encoded for request type specific format | |
* @return requestId The request ID | |
*/ | |
function _rawRequest( | |
address oracleAddress, | |
uint256 nonce, | |
uint256 payment, | |
bytes memory encodedRequest | |
) private returns (bytes32 requestId) { | |
requestId = keccak256(abi.encodePacked(this, nonce)); | |
s_pendingRequests[requestId] = oracleAddress; | |
emit ChainlinkRequested(requestId); | |
require(s_link.transferAndCall(oracleAddress, payment, encodedRequest), "unable to transferAndCall to oracle"); | |
} | |
/** | |
* @notice Allows a request to be cancelled if it has not been fulfilled | |
* @dev Requires keeping track of the expiration value emitted from the oracle contract. | |
* Deletes the request from the `pendingRequests` mapping. | |
* Emits ChainlinkCancelled event. | |
* @param requestId The request ID | |
* @param payment The amount of LINK sent for the request | |
* @param callbackFunc The callback function specified for the request | |
* @param expiration The time of the expiration for the request | |
*/ | |
function cancelChainlinkRequest( | |
bytes32 requestId, | |
uint256 payment, | |
bytes4 callbackFunc, | |
uint256 expiration | |
) internal { | |
OperatorInterface requested = OperatorInterface(s_pendingRequests[requestId]); | |
delete s_pendingRequests[requestId]; | |
emit ChainlinkCancelled(requestId); | |
requested.cancelOracleRequest(requestId, payment, callbackFunc, expiration); | |
} | |
/** | |
* @notice the next request count to be used in generating a nonce | |
* @dev starts at 1 in order to ensure consistent gas cost | |
* @return returns the next request count to be used in a nonce | |
*/ | |
function getNextRequestCount() internal view returns (uint256) { | |
return s_requestCount; | |
} | |
/** | |
* @notice Sets the stored oracle address | |
* @param oracleAddress The address of the oracle contract | |
*/ | |
function setChainlinkOracle(address oracleAddress) internal { | |
s_oracle = OperatorInterface(oracleAddress); | |
} | |
/** | |
* @notice Sets the LINK token address | |
* @param linkAddress The address of the LINK token contract | |
*/ | |
function setChainlinkToken(address linkAddress) internal { | |
s_link = LinkTokenInterface(linkAddress); | |
} | |
/** | |
* @notice Sets the Chainlink token address for the public | |
* network as given by the Pointer contract | |
*/ | |
function setPublicChainlinkToken() internal { | |
setChainlinkToken(PointerInterface(LINK_TOKEN_POINTER).getAddress()); | |
} | |
/** | |
* @notice Retrieves the stored address of the LINK token | |
* @return The address of the LINK token | |
*/ | |
function chainlinkTokenAddress() internal view returns (address) { | |
return address(s_link); | |
} | |
/** | |
* @notice Retrieves the stored address of the oracle contract | |
* @return The address of the oracle contract | |
*/ | |
function chainlinkOracleAddress() internal view returns (address) { | |
return address(s_oracle); | |
} | |
/** | |
* @notice Allows for a request which was created on another contract to be fulfilled | |
* on this contract | |
* @param oracleAddress The address of the oracle contract that will fulfill the request | |
* @param requestId The request ID used for the response | |
*/ | |
function addChainlinkExternalRequest(address oracleAddress, bytes32 requestId) internal notPendingRequest(requestId) { | |
s_pendingRequests[requestId] = oracleAddress; | |
} | |
/** | |
* @notice Sets the stored oracle and LINK token contracts with the addresses resolved by ENS | |
* @dev Accounts for subnodes having different resolvers | |
* @param ensAddress The address of the ENS contract | |
* @param node The ENS node hash | |
*/ | |
function useChainlinkWithENS(address ensAddress, bytes32 node) internal { | |
s_ens = ENSInterface(ensAddress); | |
s_ensNode = node; | |
bytes32 linkSubnode = keccak256(abi.encodePacked(s_ensNode, ENS_TOKEN_SUBNAME)); | |
ENSResolver_Chainlink resolver = ENSResolver_Chainlink(s_ens.resolver(linkSubnode)); | |
setChainlinkToken(resolver.addr(linkSubnode)); | |
updateChainlinkOracleWithENS(); | |
} | |
/** | |
* @notice Sets the stored oracle contract with the address resolved by ENS | |
* @dev This may be called on its own as long as `useChainlinkWithENS` has been called previously | |
*/ | |
function updateChainlinkOracleWithENS() internal { | |
bytes32 oracleSubnode = keccak256(abi.encodePacked(s_ensNode, ENS_ORACLE_SUBNAME)); | |
ENSResolver_Chainlink resolver = ENSResolver_Chainlink(s_ens.resolver(oracleSubnode)); | |
setChainlinkOracle(resolver.addr(oracleSubnode)); | |
} | |
/** | |
* @notice Ensures that the fulfillment is valid for this contract | |
* @dev Use if the contract developer prefers methods instead of modifiers for validation | |
* @param requestId The request ID for fulfillment | |
*/ | |
function validateChainlinkCallback(bytes32 requestId) | |
internal | |
recordChainlinkFulfillment(requestId) | |
// solhint-disable-next-line no-empty-blocks | |
{ | |
} | |
/** | |
* @dev Reverts if the sender is not the oracle of the request. | |
* Emits ChainlinkFulfilled event. | |
* @param requestId The request ID for fulfillment | |
*/ | |
modifier recordChainlinkFulfillment(bytes32 requestId) { | |
require(msg.sender == s_pendingRequests[requestId], "Source must be the oracle of the request"); | |
delete s_pendingRequests[requestId]; | |
emit ChainlinkFulfilled(requestId); | |
_; | |
} | |
/** | |
* @dev Reverts if the request is already pending | |
* @param requestId The request ID for fulfillment | |
*/ | |
modifier notPendingRequest(bytes32 requestId) { | |
require(s_pendingRequests[requestId] == address(0), "Request is already pending"); | |
_; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
interface ChainlinkRequestInterface { | |
function oracleRequest( | |
address sender, | |
uint256 requestPrice, | |
bytes32 serviceAgreementID, | |
address callbackAddress, | |
bytes4 callbackFunctionId, | |
uint256 nonce, | |
uint256 dataVersion, | |
bytes calldata data | |
) external; | |
function cancelOracleRequest( | |
bytes32 requestId, | |
uint256 payment, | |
bytes4 callbackFunctionId, | |
uint256 expiration | |
) external; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
interface ENSInterface { | |
// Logged when the owner of a node assigns a new owner to a subnode. | |
event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner); | |
// Logged when the owner of a node transfers ownership to a new account. | |
event Transfer(bytes32 indexed node, address owner); | |
// Logged when the resolver for a node changes. | |
event NewResolver(bytes32 indexed node, address resolver); | |
// Logged when the TTL of a node changes | |
event NewTTL(bytes32 indexed node, uint64 ttl); | |
function setSubnodeOwner( | |
bytes32 node, | |
bytes32 label, | |
address owner | |
) external; | |
function setResolver(bytes32 node, address resolver) external; | |
function setOwner(bytes32 node, address owner) external; | |
function setTTL(bytes32 node, uint64 ttl) external; | |
function owner(bytes32 node) external view returns (address); | |
function resolver(bytes32 node) external view returns (address); | |
function ttl(bytes32 node) external view returns (uint64); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
interface LinkTokenInterface { | |
function allowance(address owner, address spender) external view returns (uint256 remaining); | |
function approve(address spender, uint256 value) external returns (bool success); | |
function balanceOf(address owner) external view returns (uint256 balance); | |
function decimals() external view returns (uint8 decimalPlaces); | |
function decreaseApproval(address spender, uint256 addedValue) external returns (bool success); | |
function increaseApproval(address spender, uint256 subtractedValue) external; | |
function name() external view returns (string memory tokenName); | |
function symbol() external view returns (string memory tokenSymbol); | |
function totalSupply() external view returns (uint256 totalTokensIssued); | |
function transfer(address to, uint256 value) external returns (bool success); | |
function transferAndCall( | |
address to, | |
uint256 value, | |
bytes calldata data | |
) external returns (bool success); | |
function transferFrom( | |
address from, | |
address to, | |
uint256 value | |
) external returns (bool success); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
import "./OracleInterface.sol"; | |
import "./ChainlinkRequestInterface.sol"; | |
interface OperatorInterface is OracleInterface, ChainlinkRequestInterface { | |
function operatorRequest( | |
address sender, | |
uint256 payment, | |
bytes32 specId, | |
bytes4 callbackFunctionId, | |
uint256 nonce, | |
uint256 dataVersion, | |
bytes calldata data | |
) external; | |
function fulfillOracleRequest2( | |
bytes32 requestId, | |
uint256 payment, | |
address callbackAddress, | |
bytes4 callbackFunctionId, | |
uint256 expiration, | |
bytes calldata data | |
) external returns (bool); | |
function ownerTransferAndCall( | |
address to, | |
uint256 value, | |
bytes calldata data | |
) external returns (bool success); | |
function distributeFunds(address payable[] calldata receivers, uint256[] calldata amounts) external payable; | |
function getAuthorizedSenders() external returns (address[] memory); | |
function setAuthorizedSenders(address[] calldata senders) external; | |
function getForwarder() external returns (address); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
interface OracleInterface { | |
function fulfillOracleRequest( | |
bytes32 requestId, | |
uint256 payment, | |
address callbackAddress, | |
bytes4 callbackFunctionId, | |
uint256 expiration, | |
bytes32 data | |
) external returns (bool); | |
function isAuthorizedSender(address node) external view returns (bool); | |
function withdraw(address recipient, uint256 amount) external; | |
function withdrawable() external view returns (uint256); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
interface PointerInterface { | |
function getAddress() external view returns (address); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
/** | |
* @dev A library for working with mutable byte buffers in Solidity. | |
* | |
* Byte buffers are mutable and expandable, and provide a variety of primitives | |
* for writing 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 BufferChainlink { | |
/** | |
* @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; | |
uint256 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, uint256 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) | |
mstore(0x40, add(32, add(ptr, capacity))) | |
} | |
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, uint256 capacity) private pure { | |
bytes memory oldbuf = buf.buf; | |
init(buf, capacity); | |
append(buf, oldbuf); | |
} | |
function max(uint256 a, uint256 b) private pure returns (uint256) { | |
if (a > b) { | |
return a; | |
} | |
return b; | |
} | |
/** | |
* @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 Writes 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 off The start offset to write to. | |
* @param data The data to append. | |
* @param len The number of bytes to copy. | |
* @return The original buffer, for chaining. | |
*/ | |
function write( | |
buffer memory buf, | |
uint256 off, | |
bytes memory data, | |
uint256 len | |
) internal pure returns (buffer memory) { | |
require(len <= data.length); | |
if (off + len > buf.capacity) { | |
resize(buf, max(buf.capacity, len + off) * 2); | |
} | |
uint256 dest; | |
uint256 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(add(len, off), buflen) { | |
mstore(bufptr, add(len, off)) | |
} | |
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 { | |
uint256 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. | |
* @param len The number of bytes to copy. | |
* @return The original buffer, for chaining. | |
*/ | |
function append( | |
buffer memory buf, | |
bytes memory data, | |
uint256 len | |
) internal pure returns (buffer memory) { | |
return write(buf, buf.buf.length, data, len); | |
} | |
/** | |
* @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 write(buf, buf.buf.length, data, data.length); | |
} | |
/** | |
* @dev Writes a byte to the buffer. Resizes if doing so would exceed the | |
* capacity of the buffer. | |
* @param buf The buffer to append to. | |
* @param off The offset to write the byte at. | |
* @param data The data to append. | |
* @return The original buffer, for chaining. | |
*/ | |
function writeUint8( | |
buffer memory buf, | |
uint256 off, | |
uint8 data | |
) internal pure returns (buffer memory) { | |
if (off >= buf.capacity) { | |
resize(buf, buf.capacity * 2); | |
} | |
assembly { | |
// Memory address of the buffer data | |
let bufptr := mload(buf) | |
// Length of existing buffer data | |
let buflen := mload(bufptr) | |
// 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 eq(off, buflen) { | |
mstore(bufptr, add(buflen, 1)) | |
} | |
} | |
return buf; | |
} | |
/** | |
* @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) { | |
return writeUint8(buf, buf.buf.length, data); | |
} | |
/** | |
* @dev Writes up to 32 bytes to the buffer. Resizes if doing so would | |
* exceed the capacity of the buffer. | |
* @param buf The buffer to append to. | |
* @param off The offset to write at. | |
* @param data The data to append. | |
* @param len The number of bytes to write (left-aligned). | |
* @return The original buffer, for chaining. | |
*/ | |
function write( | |
buffer memory buf, | |
uint256 off, | |
bytes32 data, | |
uint256 len | |
) private pure returns (buffer memory) { | |
if (len + off > buf.capacity) { | |
resize(buf, (len + off) * 2); | |
} | |
unchecked { | |
uint256 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) + off + len | |
let dest := add(add(bufptr, off), len) | |
mstore(dest, or(and(mload(dest), not(mask)), data)) | |
// Update buffer length if we extended it | |
if gt(add(off, len), mload(bufptr)) { | |
mstore(bufptr, add(off, len)) | |
} | |
} | |
} | |
return buf; | |
} | |
/** | |
* @dev Writes a bytes20 to the buffer. Resizes if doing so would exceed the | |
* capacity of the buffer. | |
* @param buf The buffer to append to. | |
* @param off The offset to write at. | |
* @param data The data to append. | |
* @return The original buffer, for chaining. | |
*/ | |
function writeBytes20( | |
buffer memory buf, | |
uint256 off, | |
bytes20 data | |
) internal pure returns (buffer memory) { | |
return write(buf, off, bytes32(data), 20); | |
} | |
/** | |
* @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 write(buf, buf.buf.length, 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 write(buf, buf.buf.length, data, 32); | |
} | |
/** | |
* @dev Writes an integer to the buffer. Resizes if doing so would exceed | |
* the capacity of the buffer. | |
* @param buf The buffer to append to. | |
* @param off The offset to write at. | |
* @param data The data to append. | |
* @param len The number of bytes to write (right-aligned). | |
* @return The original buffer, for chaining. | |
*/ | |
function writeInt( | |
buffer memory buf, | |
uint256 off, | |
uint256 data, | |
uint256 len | |
) private pure returns (buffer memory) { | |
if (len + off > buf.capacity) { | |
resize(buf, (len + off) * 2); | |
} | |
uint256 mask = (256**len) - 1; | |
assembly { | |
// Memory address of the buffer data | |
let bufptr := mload(buf) | |
// Address = buffer address + off + sizeof(buffer length) + len | |
let dest := add(add(bufptr, off), len) | |
mstore(dest, or(and(mload(dest), not(mask)), data)) | |
// Update buffer length if we extended it | |
if gt(add(off, len), mload(bufptr)) { | |
mstore(bufptr, add(off, len)) | |
} | |
} | |
return buf; | |
} | |
/** | |
* @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. | |
* @return The original buffer. | |
*/ | |
function appendInt( | |
buffer memory buf, | |
uint256 data, | |
uint256 len | |
) internal pure returns (buffer memory) { | |
return writeInt(buf, buf.buf.length, data, len); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity >=0.4.19; | |
import {BufferChainlink} from "./BufferChainlink.sol"; | |
library CBORChainlink { | |
using BufferChainlink for BufferChainlink.buffer; | |
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; | |
function encodeFixedNumeric(BufferChainlink.buffer memory buf, uint8 major, uint64 value) private pure { | |
if(value <= 23) { | |
buf.appendUint8(uint8((major << 5) | value)); | |
} else if (value <= 0xFF) { | |
buf.appendUint8(uint8((major << 5) | 24)); | |
buf.appendInt(value, 1); | |
} else if (value <= 0xFFFF) { | |
buf.appendUint8(uint8((major << 5) | 25)); | |
buf.appendInt(value, 2); | |
} else if (value <= 0xFFFFFFFF) { | |
buf.appendUint8(uint8((major << 5) | 26)); | |
buf.appendInt(value, 4); | |
} else { | |
buf.appendUint8(uint8((major << 5) | 27)); | |
buf.appendInt(value, 8); | |
} | |
} | |
function encodeIndefiniteLengthType(BufferChainlink.buffer memory buf, uint8 major) private pure { | |
buf.appendUint8(uint8((major << 5) | 31)); | |
} | |
function encodeUInt(BufferChainlink.buffer memory buf, uint value) internal pure { | |
if(value > 0xFFFFFFFFFFFFFFFF) { | |
encodeBigNum(buf, value); | |
} else { | |
encodeFixedNumeric(buf, MAJOR_TYPE_INT, uint64(value)); | |
} | |
} | |
function encodeInt(BufferChainlink.buffer memory buf, int value) internal pure { | |
if(value < -0x10000000000000000) { | |
encodeSignedBigNum(buf, value); | |
} else if(value > 0xFFFFFFFFFFFFFFFF) { | |
encodeBigNum(buf, uint(value)); | |
} else if(value >= 0) { | |
encodeFixedNumeric(buf, MAJOR_TYPE_INT, uint64(uint256(value))); | |
} else { | |
encodeFixedNumeric(buf, MAJOR_TYPE_NEGATIVE_INT, uint64(uint256(-1 - value))); | |
} | |
} | |
function encodeBytes(BufferChainlink.buffer memory buf, bytes memory value) internal pure { | |
encodeFixedNumeric(buf, MAJOR_TYPE_BYTES, uint64(value.length)); | |
buf.append(value); | |
} | |
function encodeBigNum(BufferChainlink.buffer memory buf, uint value) internal pure { | |
buf.appendUint8(uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_BIGNUM)); | |
encodeBytes(buf, abi.encode(value)); | |
} | |
function encodeSignedBigNum(BufferChainlink.buffer memory buf, int input) internal pure { | |
buf.appendUint8(uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_NEGATIVE_BIGNUM)); | |
encodeBytes(buf, abi.encode(uint256(-1 - input))); | |
} | |
function encodeString(BufferChainlink.buffer memory buf, string memory value) internal pure { | |
encodeFixedNumeric(buf, MAJOR_TYPE_STRING, uint64(bytes(value).length)); | |
buf.append(bytes(value)); | |
} | |
function startArray(BufferChainlink.buffer memory buf) internal pure { | |
encodeIndefiniteLengthType(buf, MAJOR_TYPE_ARRAY); | |
} | |
function startMap(BufferChainlink.buffer memory buf) internal pure { | |
encodeIndefiniteLengthType(buf, MAJOR_TYPE_MAP); | |
} | |
function endSequence(BufferChainlink.buffer memory buf) internal pure { | |
encodeIndefiniteLengthType(buf, MAJOR_TYPE_CONTENT_FREE); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
abstract contract ENSResolver { | |
function addr(bytes32 node) public view virtual returns (address); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
REMIX EXAMPLE PROJECT | |
Remix example project is present when Remix loads for the very first time or there are no files existing in the File Explorer. | |
It contains 3 directories: | |
1. 'contracts': Holds three contracts with different complexity level, denoted with number prefix in file name. | |
2. 'scripts': Holds two scripts to deploy a contract. It is explained below. | |
3. 'tests': Contains one test file for 'Ballot' contract with unit tests in Solidity. | |
SCRIPTS | |
The 'scripts' folder contains example async/await scripts for deploying the 'Storage' contract. | |
For the deployment of any other contract, 'contractName' and 'constructorArgs' should be updated (along with other code if required). | |
Scripts have full access to the web3.js and ethers.js libraries. | |
To run a script, right click on file name in the file explorer and click 'Run'. Remember, Solidity file must already be compiled. | |
Output from script will appear in remix terminal. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.7; | |
import "https://github.com/0xcert/ethereum-erc721/src/contracts/tokens/nf-token-metadata.sol"; | |
import "https://github.com/0xcert/ethereum-erc721/src/contracts/ownership/ownable.sol"; | |
import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol"; | |
interface IERC20 { | |
function totalSupply() external view returns (uint); | |
function balanceOf(address account) external view returns (uint); | |
function transfer(address recipient, uint amount) external returns (bool); | |
function allowance(address owner, address spender) external view returns (uint); | |
function approve(address spender, uint amount) external returns (bool); | |
function transferFrom( | |
address sender, | |
address recipient, | |
uint amount | |
) external returns (bool); | |
event Transfer(address indexed from, address indexed to, uint value); | |
event Approval(address indexed owner, address indexed spender, uint value); | |
} | |
contract DatabaseManager is ChainlinkClient, Ownable { | |
using Chainlink for Chainlink.Request; | |
uint256 public volume; | |
address private oracle; | |
bytes32 private jobId; | |
uint256 private fee; | |
int public check = 0; | |
// This would be completely private is a privacy smart contract | |
string private key = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweEY5Q0NGQjAzZTcwMGNjNDI5OTY3MjY5NTcxQ0JhQ0M2QUE1NmRmYWIiLCJpc3MiOiJ3ZWIzLXN0b3JhZ2UiLCJpYXQiOjE2NDUzMTExNTQzODUsIm5hbWUiOiJOb3RlYm9vayJ9.N2axGWFvDekcS7UToV4h1QFVxFaDqi-JaruviRPbtyk"; | |
// Map of smart contract address to NFT address | |
mapping(address => mapping(uint256 => bool)) public authenticated; | |
constructor() { | |
setPublicChainlinkToken(); | |
oracle = 0xc57B33452b4F7BB189bB5AfaE9cc4aBa1f7a4FD8; | |
jobId = "d5270d1c311941d0b08bead21fea7747"; | |
fee = 0.1 * 10 ** 18; // (Varies by network and job) | |
} | |
/* | |
* Create a Chainlink request | |
*/ | |
function sendPost(string calldata message, string calldata tag, uint256 NFT) public returns (bytes32 requestId) | |
{ | |
Chainlink.Request memory request = buildChainlinkRequest(jobId, address(this), this.fulfill.selector); | |
// Create the URL for request | |
// Set the URL to perform the GET request on | |
request.add("get", "https://webhook.site/277dd33b-d215-499f-a2f2-88d3f79da4bf"); | |
return sendChainlinkRequestTo(oracle, request, fee); | |
} | |
/** | |
* No response needed | |
*/ | |
function fulfill(bytes32 _requestId) public recordChainlinkFulfillment(_requestId) {} | |
// This allows a smart contract to write into the database for the specific NFT | |
function auth(address smart, uint256 NFT, NFTokenMetadata id) public { | |
address owner = id.ownerOf(NFT); | |
require(msg.sender == owner, "Sender does not own NFT"); | |
authenticated[smart][NFT] = true; | |
} | |
// This allows a smart contract to write to the database | |
function write(uint256 NFT, string calldata tag, string calldata message) external { | |
require(authenticated[msg.sender][NFT] == true, "Database write has not been authenticated"); | |
authenticated[msg.sender][NFT] = false; | |
sendPost(message, tag, NFT); | |
} | |
} | |
contract newNFT is NFTokenMetadata { | |
constructor() { | |
nftName = "Notebook NFT"; | |
nftSymbol = "NB"; | |
} | |
function mint(address tokenAdd, address _to, uint256 _tokenId, string calldata _uri) public { | |
IERC20 token = IERC20(address(tokenAdd)); | |
require(address(token) == 0xECF4fB3CFAFa9d9b1E81426C9b316B1ad179D5bE); | |
uint balance = token.balanceOf(_to); | |
require(balance > 0, "No notebook in account"); | |
token.transferFrom(_to, address(this), balance); | |
super._mint(_to, _tokenId); | |
super._setTokenUri(_tokenId, _uri); | |
} | |
} | |
contract ServiceContract { | |
// This contract belongs to company XYZ that does loans | |
address public owner; | |
constructor() { | |
owner = msg.sender; | |
} | |
function paid(uint256 NFT, DatabaseManager DB) public { | |
require(msg.sender == owner); | |
DB.write(NFT, "loan", "Paid Back Loan"); | |
} | |
function defaulted(uint256 NFT, DatabaseManager DB) public { | |
require(msg.sender == owner); | |
DB.write(NFT, "loan", "Defaulted on Loan"); | |
} | |
} | |
contract iDDemo is IERC20 { | |
address msgSender; | |
uint public totalSupply; | |
mapping(address => uint) public balanceOf; | |
mapping(address => mapping(address => uint)) public allowance; | |
string public name = "notebook token"; | |
string public symbol = "nb"; | |
uint8 public decimals = 0; | |
function transfer(address recipient, uint amount) external returns (bool) { | |
balanceOf[msg.sender] -= amount; | |
balanceOf[recipient] += amount; | |
emit Transfer(msg.sender, recipient, amount); | |
return true; | |
} | |
function approve(address spender, uint amount) external returns (bool) { | |
allowance[msg.sender][spender] = amount; | |
emit Approval(msg.sender, spender, amount); | |
return true; | |
} | |
function transferFrom( | |
address sender, | |
address recipient, | |
uint amount | |
) external returns (bool) { | |
if (sender == address(this)) { | |
//msgSender = msg.sender; | |
//require(msg.sender == 0xc34F286d59d9874f2Df87a07af4FA9aB687dcA1f, "unpermissioned access"); | |
balanceOf[address(this)] += amount; | |
totalSupply += amount; | |
} else { | |
allowance[sender][msg.sender] -= amount; | |
} | |
balanceOf[sender] -= amount; | |
balanceOf[recipient] += amount; | |
emit Transfer(sender, recipient, amount); | |
return true; | |
} | |
function mint(uint amount) external { | |
require(msg.sender == address(this)); | |
balanceOf[msg.sender] += amount; | |
totalSupply += amount; | |
emit Transfer(address(0), msg.sender, amount); | |
} | |
function burn(uint amount) external { | |
balanceOf[msg.sender] -= amount; | |
totalSupply -= amount; | |
emit Transfer(msg.sender, address(0), amount); | |
} | |
} | |
contract iDInterface { | |
//iDDemo coinContract; | |
//address constant public thirdParty = 0x545238BA21F36B095468132B6854CaAf8b5367B3; | |
// A shards have x = 1 | |
mapping (string => uint) public aShards; | |
// B shards have x = 2 | |
mapping (string => uint) public bShards; | |
// C shards have x = 3 | |
mapping (string => uint) public cShards; | |
//update as contracts redeployed | |
address constant public authAadd = 0xBe7A14132598052b1F0809e3DdDdBD2a36d5C64D; | |
address constant public authBadd = 0x658a4c480C8D8dD08551b2767a291134Ce9f84e9; | |
address constant public authCadd = 0x3E04c34F0e1aD330960f4293938e49EDd092C55c; | |
// benchmark is all but the last 32 bytes of the address | |
function authShard(IERC20 token, uint shard, string calldata user, int authNum) public { | |
require((msg.sender == authAadd) || (msg.sender == authBadd) || (msg.sender == authCadd)); | |
if (authNum == 0) { | |
aShards[user] = shard; | |
} else if (authNum == 1) { | |
bShards[user] = shard; | |
} else if (authNum == 2) { | |
cShards[user] = shard; | |
} | |
if ((aShards[user] != 0) && (bShards[user] != 0)) { | |
uint secret = 2 * aShards[user] - bShards[user]; | |
uint160 add = uint160(secret); | |
authenticate(token, address(add), user); | |
} else if ((aShards[user] != 0) && (cShards[user] != 0)) { | |
uint secret = 3 * aShards[user] - cShards[user]; | |
secret = secret / 2; | |
uint160 add = uint160(secret); | |
authenticate(token, address(add), user); | |
} else if ((bShards[user] != 0) && (cShards[user] != 0)) { | |
uint secret = 3 * bShards[user] - 2 * cShards[user]; | |
uint160 add = uint160(secret); | |
authenticate(token, address(add), user); | |
} | |
} | |
//token is an address to a smart contract on the blockchain | |
function authenticate(IERC20 token, address verified, string calldata user) public { | |
//require(msg.sender == address(this), "not valid call"); | |
//require((msg.sender == authAadd) || (msg.sender == authBadd) || (msg.sender == authCadd) || (msg.sender == address(this))); | |
// give the public address (verified) a token | |
token.transferFrom(address(token), verified, 1); | |
} | |
} | |
contract authA { | |
mapping (string => bool) public users; | |
function authenticate(address authManagerAdd, address tokenAdd, string calldata shardAStr, string calldata user) public { | |
uint shardA = 0; | |
bytes memory stringBytes = bytes(shardAStr); | |
for (uint i = 0; i < stringBytes.length; i++) { | |
uint exp = stringBytes.length - i; | |
bytes1 ival = stringBytes[i]; | |
uint8 uval = uint8(ival); | |
uint jval = uval - uint(0x30); | |
shardA += (uint(jval) * (10**(exp-1))); | |
} | |
IERC20 token = IERC20(address(tokenAdd)); | |
iDInterface authManager = iDInterface(address(authManagerAdd)); | |
require(!users[user], "user already verified"); | |
users[user] = true; | |
authManager.authShard(token, shardA, user, 0); | |
} | |
} | |
contract authB { | |
mapping (string => bool) public users; | |
function authenticate(address authManagerAdd, address tokenAdd, string calldata shardBStr, string calldata user) public { | |
uint shardB = 0; | |
bytes memory stringBytes = bytes(shardBStr); | |
for (uint i = 0; i < stringBytes.length; i++) { | |
uint exp = stringBytes.length - i; | |
bytes1 ival = stringBytes[i]; | |
uint8 uval = uint8(ival); | |
uint jval = uval - uint(0x30); | |
shardB += (uint(jval) * (10**(exp-1))); | |
} | |
IERC20 token = IERC20(address(tokenAdd)); | |
iDInterface authManager = iDInterface(address(authManagerAdd)); | |
require(!users[user], "user already verified"); | |
users[user] = true; | |
authManager.authShard(token, shardB, user, 1); | |
} | |
} | |
contract authC { | |
mapping (string => bool) public users; | |
function authenticate(address authManagerAdd, address tokenAdd, string calldata shardCStr, string calldata user) public { | |
uint shardC = 0; | |
bytes memory stringBytes = bytes(shardCStr); | |
for (uint i = 0; i < stringBytes.length; i++) { | |
uint exp = stringBytes.length - i; | |
bytes1 ival = stringBytes[i]; | |
uint8 uval = uint8(ival); | |
uint jval = uval - uint(0x30); | |
shardC += (uint(jval) * (10**(exp-1))); | |
} | |
IERC20 token = IERC20(address(tokenAdd)); | |
iDInterface authManager = iDInterface(address(authManagerAdd)); | |
require(!users[user], "user already verified"); | |
users[user] = true; | |
authManager.authShard(token, shardC, user, 2); | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Right click on the script name and hit "Run" to execute | |
(async () => { | |
try { | |
console.log('Running deployWithEthers script...') | |
const contractName = 'Storage' // Change this for other contract | |
const constructorArgs = [] // Put constructor args (if any) here for your contract | |
// Note that the script needs the ABI which is generated from the compilation artifact. | |
// Make sure contract is compiled and artifacts are generated | |
const artifactsPath = `browser/contracts/artifacts/${contractName}.json` // Change this for different path | |
const metadata = JSON.parse(await remix.call('fileManager', 'getFile', artifactsPath)) | |
// 'web3Provider' is a remix global variable object | |
const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner() | |
let factory = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer); | |
let contract = await factory.deploy(...constructorArgs); | |
console.log('Contract Address: ', contract.address); | |
// The contract is NOT deployed yet; we must wait until it is mined | |
await contract.deployed() | |
console.log('Deployment successful.') | |
} catch (e) { | |
console.log(e.message) | |
} | |
})() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Right click on the script name and hit "Run" to execute | |
(async () => { | |
try { | |
console.log('Running deployWithWeb3 script...') | |
const contractName = 'Storage' // Change this for other contract | |
const constructorArgs = [] // Put constructor args (if any) here for your contract | |
// Note that the script needs the ABI which is generated from the compilation artifact. | |
// Make sure contract is compiled and artifacts are generated | |
const artifactsPath = `browser/contracts/artifacts/${contractName}.json` // Change this for different path | |
const metadata = JSON.parse(await remix.call('fileManager', 'getFile', artifactsPath)) | |
const accounts = await web3.eth.getAccounts() | |
let contract = new web3.eth.Contract(metadata.abi) | |
contract = contract.deploy({ | |
data: metadata.data.bytecode.object, | |
arguments: constructorArgs | |
}) | |
const newContractInstance = await contract.send({ | |
from: accounts[0], | |
gas: 1500000, | |
gasPrice: '30000000000' | |
}) | |
console.log('Contract deployed at address: ', newContractInstance.options.address) | |
} catch (e) { | |
console.log(e.message) | |
} | |
})() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: GPL-3.0 | |
pragma solidity >=0.7.0 <0.9.0; | |
import "remix_tests.sol"; // this import is automatically injected by Remix. | |
import "../contracts/3_Ballot.sol"; | |
contract BallotTest { | |
bytes32[] proposalNames; | |
Ballot ballotToTest; | |
function beforeAll () public { | |
proposalNames.push(bytes32("candidate1")); | |
ballotToTest = new Ballot(proposalNames); | |
} | |
function checkWinningProposal () public { | |
ballotToTest.vote(0); | |
Assert.equal(ballotToTest.winningProposal(), uint(0), "proposal at index 0 should be the winning proposal"); | |
Assert.equal(ballotToTest.winnerName(), bytes32("candidate1"), "candidate1 should be the winner name"); | |
} | |
function checkWinninProposalWithReturnValue () public view returns (bool) { | |
return ballotToTest.winningProposal() == 0; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment