Skip to content

Commit

Permalink
Adds ERC721PsiUpgradeable with passing tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Nidhhoggr committed Dec 26, 2022
1 parent b9a3508 commit 062dbec
Show file tree
Hide file tree
Showing 18 changed files with 596 additions and 563 deletions.
17 changes: 14 additions & 3 deletions contracts/ERC721Psi.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,25 @@

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "solidity-bits/contracts/BitMaps.sol";
import "./interface/IERC721Psi.sol";

/**
* @dev Interface of ERC721 token receiver.
*/
interface ERC721Psi__IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}

contract ERC721Psi is IERC721Psi {

using Address for address;
using Strings for uint256;
using BitMaps for BitMaps.BitMap;
Expand Down Expand Up @@ -452,8 +463,8 @@ contract ERC721Psi is IERC721Psi {
if (to.isContract()) {
r = true;
for(uint256 tokenId = startTokenId; tokenId < startTokenId + quantity; tokenId++){
try IERC721Receiver(to).onERC721Received( _msgSenderERC721Psi(), from, tokenId, _data) returns (bytes4 retval) {
r = r && retval == IERC721Receiver.onERC721Received.selector;
try ERC721Psi__IERC721Receiver(to).onERC721Received( _msgSenderERC721Psi(), from, tokenId, _data) returns (bytes4 retval) {
r = r && retval == ERC721Psi__IERC721Receiver.onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == 0) {
revert TransferToNonERC721ReceiverImplementer();
Expand Down
75 changes: 75 additions & 0 deletions contracts/ERC721PsiInitializable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
* @dev This is a base contract to aid in writing upgradeable diamond facet contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*/

import {ERC721PsiInitializableStorage} from './ERC721PsiInitializableStorage.sol';

abstract contract ERC721PsiInitializable {
using ERC721PsiInitializableStorage for ERC721PsiInitializableStorage.Layout;

/**
* @dev Modifier to protect an initializer function from being invoked twice.
*/
modifier initializerERC721Psi() {
// If the contract is initializing we ignore whether _initialized is set in order to support multiple
// inheritance patterns, but we only do this in the context of a constructor, because in other contexts the
// contract may have been reentered.
require(
ERC721PsiInitializableStorage.layout()._initializing
? _isConstructor()
: !ERC721PsiInitializableStorage.layout()._initialized,
'ERC721Psi__Initializable: contract is already initialized'
);

bool isTopLevelCall = !ERC721PsiInitializableStorage.layout()._initializing;
if (isTopLevelCall) {
ERC721PsiInitializableStorage.layout()._initializing = true;
ERC721PsiInitializableStorage.layout()._initialized = true;
}

_;

if (isTopLevelCall) {
ERC721PsiInitializableStorage.layout()._initializing = false;
}
}

/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} modifier, directly or indirectly.
*/
modifier onlyInitializingERC721Psi() {
require(
ERC721PsiInitializableStorage.layout()._initializing,
'ERC721PsiInitializable: contract is not initializing'
);
_;
}

/// @dev Returns true if and only if the function is running in the constructor
function _isConstructor() private view returns (bool) {
// extcodesize checks the size of the code stored in an address, and
// address returns the current address. Since the code is still not
// deployed when running a constructor, any checks on its code size will
// yield zero, making it an effective way to detect if a contract is
// under construction or not.
address self = address(this);
uint256 cs;
assembly {
cs := extcodesize(self)
}
return cs == 0;
}
}
29 changes: 29 additions & 0 deletions contracts/ERC721PsiInitializableStorage.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
* @dev This is a base storage for the initialization function for upgradeable diamond facet contracts
**/

library ERC721PsiInitializableStorage {
struct Layout {
/*
* Indicates that the contract has been initialized.
*/
bool _initialized;
/*
* Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}

bytes32 internal constant STORAGE_SLOT = keccak256('ERC721Psi.contracts.storage.initializable.facet');

function layout() internal pure returns (Layout storage l) {
bytes32 slot = STORAGE_SLOT;
assembly {
l.slot := slot
}
}
}
42 changes: 42 additions & 0 deletions contracts/ERC721PsiStorage.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "solidity-bits/contracts/BitMaps.sol";

library ERC721PsiStorage {



struct Layout {
// =============================================================
// STORAGE
// =============================================================

// The next token ID to be minted.
uint256 _currentIndex;
// The number of tokens burned.
uint256 _burnCounter;
// Token name
string _name;
// Token symbol
string _symbol;
// Mapping from token ID to owner address
mapping(uint256 => address) _owners;
// Mapping from token ID to approved address.
mapping(uint256 => address) _tokenApprovals;
// Mapping from owner to operator approvals
mapping(address => mapping(address => bool)) _operatorApprovals;
// stores batchhead
BitMaps.BitMap _batchHead;
}

bytes32 internal constant STORAGE_SLOT = keccak256('ERC721Psi.contracts.storage.ERC721A');

function layout() internal pure returns (Layout storage l) {
bytes32 slot = STORAGE_SLOT;
assembly {
l.slot := slot
}
}
}
Loading

0 comments on commit 062dbec

Please sign in to comment.