-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Build `SQTGift` NFT contract * Add `SQTRedeem` contract * Update `redeem` function * Update gift contracts * Add extra condition to redeem * Add more events * Update contracts/SQTGift.sol Co-authored-by: Ian He <[email protected]> * Update contracts/SQTGift.sol Co-authored-by: Ian He <[email protected]> * Update revert codes for `SQTGift` * Update revert code for `SQTRedeem` * remove redeem logic from SQTGift * improve test * clean up * add sqtGift to ts * add batchMint() and publish to testnet --------- Co-authored-by: Ian He <[email protected]>
- Loading branch information
Showing
12 changed files
with
409 additions
and
5 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
// Copyright (C) 2020-2023 SubQuery Pte Ltd authors & contributors | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
pragma solidity 0.8.15; | ||
|
||
import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; | ||
import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol"; | ||
import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol"; | ||
import '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol'; | ||
|
||
import '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; | ||
import '@openzeppelin/contracts-upgradeable/utils/introspection/ERC165CheckerUpgradeable.sol'; | ||
import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; | ||
|
||
import './interfaces/ISQTGift.sol'; | ||
|
||
contract SQTGift is Initializable, OwnableUpgradeable, ERC721Upgradeable, ERC721URIStorageUpgradeable, ERC721EnumerableUpgradeable, ISQTGift { | ||
|
||
uint256 public nextSeriesId; | ||
|
||
/// @notice seriesId => GiftSeries | ||
mapping(uint256 => GiftSeries) public series; | ||
|
||
/// @notice account => seriesId => gift count | ||
mapping(address => mapping(uint256 => uint8)) public allowlist; | ||
|
||
/// @notice tokenId => Gift | ||
mapping(uint256 => Gift) public gifts; | ||
|
||
event AllowListAdded(address indexed account, uint256 indexed seriesId, uint8 amount); | ||
event AllowListRemoved(address indexed account, uint256 indexed seriesId, uint8 amount); | ||
|
||
event SeriesCreated(uint256 indexed seriesId, uint256 maxSupply, string tokenURI); | ||
event SeriesActiveUpdated(uint256 indexed seriesId, bool active); | ||
|
||
event GiftMinted(address indexed to, uint256 indexed seriesId, uint256 indexed tokenId, string tokenURI); | ||
|
||
function initialize() external initializer { | ||
__Ownable_init(); | ||
__ERC721_init("SQT Gift", "SQTG"); | ||
__ERC721URIStorage_init(); | ||
__ERC721Enumerable_init(); | ||
} | ||
|
||
function batchAddToAllowlist(uint256[] calldata _seriesId, address[] calldata _address, uint8[] calldata _amount) public onlyOwner { | ||
require(_seriesId.length == _address.length, 'SQG003'); | ||
require(_seriesId.length == _amount.length, 'SQG003'); | ||
for (uint256 i = 0; i < _seriesId.length; i++) { | ||
addToAllowlist(_seriesId[i], _address[i], _amount[i]); | ||
} | ||
} | ||
|
||
function addToAllowlist(uint256 _seriesId, address _address, uint8 _amount) public onlyOwner { | ||
require(series[_seriesId].maxSupply > 0, "SQG001"); | ||
allowlist[_address][_seriesId] += _amount; | ||
|
||
emit AllowListAdded(_address, _seriesId, _amount); | ||
} | ||
|
||
function removeFromAllowlist(uint256 _seriesId, address _address, uint8 _amount) public onlyOwner { | ||
require(series[_seriesId].maxSupply > 0, "SQG001"); | ||
require(allowlist[_address][_seriesId] >= _amount, "SQG002"); | ||
allowlist[_address][_seriesId] -= _amount; | ||
|
||
emit AllowListRemoved(_address, _seriesId, _amount); | ||
} | ||
|
||
function createSeries( | ||
uint256 _maxSupply, | ||
string memory _tokenURI | ||
) external onlyOwner { | ||
require(_maxSupply > 0, "SQG006"); | ||
series[nextSeriesId] = GiftSeries({ | ||
maxSupply: _maxSupply, | ||
totalSupply: 0, | ||
active: true, | ||
tokenURI: _tokenURI | ||
}); | ||
|
||
emit SeriesCreated(nextSeriesId, _maxSupply, _tokenURI); | ||
|
||
nextSeriesId += 1; | ||
|
||
} | ||
|
||
function setSeriesActive(uint256 _seriesId, bool _active) external onlyOwner { | ||
require(series[_seriesId].maxSupply > 0, "SQG001"); | ||
series[_seriesId].active = _active; | ||
|
||
emit SeriesActiveUpdated(_seriesId, _active); | ||
} | ||
|
||
function setMaxSupply(uint256 _seriesId, uint256 _maxSupply) external onlyOwner { | ||
require(_maxSupply > 0, "SQG006"); | ||
series[_seriesId].maxSupply = _maxSupply; | ||
} | ||
|
||
function _beforeTokenTransfer(address from, address to, uint256 tokenId, uint256 batchSize) internal override( | ||
ERC721Upgradeable, | ||
ERC721EnumerableUpgradeable | ||
) { | ||
super._beforeTokenTransfer(from, to, tokenId, batchSize); | ||
} | ||
|
||
function supportsInterface(bytes4 interfaceId) public view override( | ||
IERC165Upgradeable, | ||
ERC721Upgradeable, | ||
ERC721EnumerableUpgradeable, | ||
ERC721URIStorageUpgradeable | ||
) returns (bool) { | ||
return interfaceId == type(ISQTGift).interfaceId || super.supportsInterface(interfaceId); | ||
} | ||
|
||
function tokenURI(uint256 tokenId) public view override( | ||
ERC721Upgradeable, | ||
ERC721URIStorageUpgradeable | ||
) returns (string memory) { | ||
return super.tokenURI(tokenId); | ||
} | ||
|
||
function _burn(uint256 tokenId) internal override(ERC721Upgradeable, ERC721URIStorageUpgradeable) { | ||
super._burn(tokenId); | ||
} | ||
|
||
function _baseURI() internal view virtual override returns (string memory) { | ||
return "ipfs://"; | ||
} | ||
|
||
function mint(uint256 _seriesId) public { | ||
GiftSeries memory giftSerie = series[_seriesId]; | ||
require(giftSerie.active, "SQG004"); | ||
require(allowlist[msg.sender][_seriesId] > 0, "SQG002"); | ||
|
||
require(giftSerie.totalSupply < giftSerie.maxSupply, "SQG005"); | ||
series[_seriesId].totalSupply += 1; | ||
|
||
uint256 tokenId = totalSupply() + 1; | ||
gifts[tokenId].seriesId = _seriesId; | ||
|
||
_safeMint(msg.sender, tokenId); | ||
_setTokenURI(tokenId, giftSerie.tokenURI); | ||
|
||
allowlist[msg.sender][_seriesId]--; | ||
|
||
emit GiftMinted(msg.sender, _seriesId, tokenId, giftSerie.tokenURI); | ||
} | ||
|
||
function batchMint(uint256 _seriesId) external { | ||
GiftSeries memory giftSerie = series[_seriesId]; | ||
require(giftSerie.active, "SQG004"); | ||
uint8 allowAmount = allowlist[msg.sender][_seriesId]; | ||
require(allowAmount > 0, "SQG002"); | ||
for (uint256 i = 0; i < allowAmount; i++) { | ||
mint(_seriesId); | ||
} | ||
} | ||
|
||
function getSeries(uint256 tokenId) external view returns (uint256) { | ||
return gifts[tokenId].seriesId; | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
// Copyright (C) 2020-2023 SubQuery Pte Ltd authors & contributors | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
pragma solidity 0.8.15; | ||
|
||
import "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol"; | ||
import '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol'; | ||
import '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; | ||
import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; | ||
|
||
import './interfaces/ISQTGift.sol'; | ||
|
||
contract SQTRedeem is Initializable, OwnableUpgradeable { | ||
function initialize(address _sqtoken) external initializer {} | ||
// | ||
// address public sqtoken; | ||
// | ||
// bool public redeemable; | ||
// | ||
// mapping (address => bool) public allowlist; | ||
// | ||
// event SQTRedeemed(address indexed to, address nft, uint256 indexed tokenId, uint256 sqtValue); | ||
// | ||
// function initialize(address _sqtoken) external initializer { | ||
// __Ownable_init(); | ||
// | ||
// sqtoken = _sqtoken; | ||
// } | ||
// | ||
// function desposit(uint256 amount) public onlyOwner { | ||
// require(IERC20(sqtoken).transferFrom(msg.sender, address(this), amount), 'SQR001'); | ||
// } | ||
// | ||
// function withdraw(uint256 amount) public onlyOwner { | ||
// require(IERC20(sqtoken).transfer(msg.sender, amount), 'SQR001'); | ||
// } | ||
// | ||
// function addToAllowlist(address _address) public onlyOwner { | ||
// allowlist[_address] = true; | ||
// } | ||
// | ||
// function removeFromAllowlist(address _address) public onlyOwner { | ||
// allowlist[_address] = false; | ||
// } | ||
// | ||
// function setRedeemable(bool _redeemable) external onlyOwner { | ||
// redeemable = _redeemable; | ||
// } | ||
// | ||
// function redeem(address nft, uint256 tokenId) public { | ||
// require(redeemable, "SQR002"); | ||
// require(allowlist[nft], "SQR003"); | ||
// | ||
// IERC165Upgradeable nftContract = IERC165Upgradeable(nft); | ||
// require(nftContract.supportsInterface(type(ISQTGift).interfaceId), "SQR004"); | ||
// | ||
// ISQTGift sqtGift = ISQTGift(nft); | ||
// require(sqtGift.getGiftRedeemable(tokenId), "SQG005"); | ||
// require(sqtGift.ownerOf(tokenId) == msg.sender, "SQG006"); | ||
// uint256 sqtValue = sqtGift.getSQTRedeemableValue(tokenId); | ||
// require(sqtValue > 0, "SQG007"); | ||
// sqtGift.afterTokenRedeem(tokenId); | ||
// | ||
// require(IERC20(sqtoken).transfer(msg.sender, sqtValue), "SQR001"); | ||
// | ||
// emit SQTRedeemed(msg.sender, nft, tokenId, sqtValue); | ||
// } | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// Copyright (C) 2020-2023 SubQuery Pte Ltd authors & contributors | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
pragma solidity 0.8.15; | ||
|
||
import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; | ||
|
||
struct GiftSeries { | ||
uint256 maxSupply; | ||
uint256 totalSupply; | ||
bool active; | ||
string tokenURI; | ||
} | ||
|
||
struct Gift { | ||
uint256 seriesId; | ||
} | ||
|
||
interface ISQTGift is IERC721Upgradeable { | ||
function getSeries(uint256 tokenId) 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
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
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
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
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
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
Oops, something went wrong.