按审计要求, 修改202403活动相关合约
This commit is contained in:
parent
663eea2ac8
commit
cf3bcd96c7
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -3259,7 +3259,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"schemaVersion": "3.4.16",
|
"schemaVersion": "3.4.16",
|
||||||
"updatedAt": "2024-01-12T05:44:22.587Z",
|
"updatedAt": "2024-02-27T05:13:36.919Z",
|
||||||
"networkType": "ethereum",
|
"networkType": "ethereum",
|
||||||
"devdoc": {
|
"devdoc": {
|
||||||
"kind": "dev",
|
"kind": "dev",
|
||||||
|
File diff suppressed because one or more lines are too long
@ -1,9 +1,8 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
pragma solidity 0.8.10;
|
pragma solidity 0.8.10;
|
||||||
|
|
||||||
import "../core/HasSignature.sol";
|
|
||||||
import "../utils/TimeChecker.sol";
|
|
||||||
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
|
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
|
||||||
|
import "../core/HasSignature.sol";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contract for activity NFT claim.
|
* Contract for activity NFT claim.
|
||||||
@ -14,13 +13,14 @@ interface IClaimAbleNFT {
|
|||||||
) external returns (uint256);
|
) external returns (uint256);
|
||||||
}
|
}
|
||||||
|
|
||||||
contract NFTClaimer is HasSignature, TimeChecker, ReentrancyGuard{
|
contract NFTClaimer is HasSignature, ReentrancyGuard{
|
||||||
uint256 private immutable _CACHED_CHAIN_ID;
|
uint256 private immutable _CACHED_CHAIN_ID;
|
||||||
address private immutable _CACHED_THIS;
|
address private immutable _CACHED_THIS;
|
||||||
|
address public immutable nftAddress;
|
||||||
address public signer;
|
address public signer;
|
||||||
uint256 public startTime;
|
uint256 public startTime;
|
||||||
uint256 public endTime;
|
uint256 public endTime;
|
||||||
mapping(address => bool) public tokenSupported;
|
|
||||||
mapping(address => uint256) public claimHistory;
|
mapping(address => uint256) public claimHistory;
|
||||||
|
|
||||||
event NFTClaimed(
|
event NFTClaimed(
|
||||||
@ -29,20 +29,17 @@ contract NFTClaimer is HasSignature, TimeChecker, ReentrancyGuard{
|
|||||||
uint256 tokenId,
|
uint256 tokenId,
|
||||||
uint256 nonce
|
uint256 nonce
|
||||||
);
|
);
|
||||||
event NFTSupportUpdated(address indexed nftAddress, bool support);
|
|
||||||
event SignerUpdated(address indexed signer);
|
event SignerUpdated(address indexed signer);
|
||||||
event StartTimeUpdated(uint256 indexed startTime);
|
event StartTimeUpdated(uint256 indexed startTime);
|
||||||
event EndTimeUpdated(uint256 indexed endTime);
|
event EndTimeUpdated(uint256 indexed endTime);
|
||||||
|
|
||||||
constructor() {
|
constructor(address _nftAddress) {
|
||||||
_CACHED_CHAIN_ID = block.chainid;
|
_CACHED_CHAIN_ID = block.chainid;
|
||||||
_CACHED_THIS = address(this);
|
_CACHED_THIS = address(this);
|
||||||
|
nftAddress = _nftAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateTokenSupport(address nftToken, bool support) external onlyOwner {
|
|
||||||
tokenSupported[nftToken] = support;
|
|
||||||
emit NFTSupportUpdated(nftToken, support);
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateStartTime(uint256 _startTime) external onlyOwner {
|
function updateStartTime(uint256 _startTime) external onlyOwner {
|
||||||
startTime = _startTime;
|
startTime = _startTime;
|
||||||
@ -57,37 +54,31 @@ contract NFTClaimer is HasSignature, TimeChecker, ReentrancyGuard{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev update signer
|
* @dev update signer
|
||||||
* @param account new signer address
|
* @param _account new signer address
|
||||||
*/
|
*/
|
||||||
function updateSigner(address account) external onlyOwner {
|
function updateSigner(address _account) external onlyOwner {
|
||||||
require(account != address(0), "NFTClaimer: address can not be zero");
|
require(_account != address(0), "NFTClaimer: address can not be zero");
|
||||||
signer = account;
|
signer = _account;
|
||||||
emit SignerUpdated(account);
|
emit SignerUpdated(_account);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev claim NFT
|
* @dev claim NFT
|
||||||
* Get whitelist signature from a third-party service, then call this method to claim NFT
|
* Get whitelist signature from a third-party service, then call this method to claim NFT
|
||||||
* @param nftAddress NFT address
|
|
||||||
* @param signTime sign time
|
|
||||||
* @param saltNonce nonce
|
* @param saltNonce nonce
|
||||||
* @param signature signature
|
* @param signature signature
|
||||||
*/
|
*/
|
||||||
function claim(
|
function claim(
|
||||||
address nftAddress,
|
|
||||||
uint256 signTime,
|
|
||||||
uint256 saltNonce,
|
uint256 saltNonce,
|
||||||
bytes calldata signature
|
bytes calldata signature
|
||||||
) external signatureValid(signature) timeValid(signTime) nonReentrant {
|
) external nonReentrant {
|
||||||
require(block.timestamp >= startTime, "NFTClaimer: not started");
|
require(block.timestamp >= startTime, "NFTClaimer: not started");
|
||||||
require(block.timestamp <= endTime, "NFTClaimer: already ended");
|
require(block.timestamp <= endTime, "NFTClaimer: already ended");
|
||||||
require(tokenSupported[nftAddress], "NFTClaimer: unsupported NFT");
|
|
||||||
address to = _msgSender();
|
address to = _msgSender();
|
||||||
require(claimHistory[to] == 0, "NFTClaimer: already claimed");
|
require(claimHistory[to] == 0, "NFTClaimer: already claimed");
|
||||||
bytes32 criteriaMessageHash = getMessageHash(
|
bytes32 criteriaMessageHash = getMessageHash(
|
||||||
to,
|
to,
|
||||||
nftAddress,
|
nftAddress,
|
||||||
signTime,
|
|
||||||
saltNonce
|
saltNonce
|
||||||
);
|
);
|
||||||
checkSigner(signer, criteriaMessageHash, signature);
|
checkSigner(signer, criteriaMessageHash, signature);
|
||||||
@ -100,13 +91,11 @@ contract NFTClaimer is HasSignature, TimeChecker, ReentrancyGuard{
|
|||||||
function getMessageHash(
|
function getMessageHash(
|
||||||
address _to,
|
address _to,
|
||||||
address _address,
|
address _address,
|
||||||
uint256 _signTime,
|
|
||||||
uint256 _saltNonce
|
uint256 _saltNonce
|
||||||
) public view returns (bytes32) {
|
) public view returns (bytes32) {
|
||||||
bytes memory encoded = abi.encodePacked(
|
bytes memory encoded = abi.encodePacked(
|
||||||
_to,
|
_to,
|
||||||
_address,
|
_address,
|
||||||
_signTime,
|
|
||||||
_CACHED_CHAIN_ID,
|
_CACHED_CHAIN_ID,
|
||||||
_CACHED_THIS,
|
_CACHED_THIS,
|
||||||
_saltNonce
|
_saltNonce
|
||||||
|
@ -11,8 +11,6 @@ contract HasSignature is Ownable {
|
|||||||
bytes32 hash,
|
bytes32 hash,
|
||||||
bytes memory signature
|
bytes memory signature
|
||||||
) public pure {
|
) public pure {
|
||||||
require(signer != address(0), "[BE] invalid signer");
|
|
||||||
require(signature.length == 65, "[BE] invalid signature length");
|
|
||||||
bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(hash);
|
bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(hash);
|
||||||
|
|
||||||
address recovered = ECDSA.recover(ethSignedMessageHash, signature);
|
address recovered = ECDSA.recover(ethSignedMessageHash, signature);
|
||||||
|
@ -2,72 +2,37 @@
|
|||||||
pragma solidity 0.8.10;
|
pragma solidity 0.8.10;
|
||||||
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
|
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
|
||||||
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
|
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
|
||||||
import "@openzeppelin/contracts/access/AccessControl.sol";
|
import "@openzeppelin/contracts/access/Ownable.sol";
|
||||||
|
|
||||||
contract BEBadgeV2 is AccessControl, ERC721Enumerable, ERC721Burnable {
|
contract BEBadgeV2 is Ownable, ERC721Enumerable, ERC721Burnable {
|
||||||
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
|
|
||||||
string private _baseTokenURI = "";
|
string private _baseTokenURI = "";
|
||||||
uint256 public immutable supplyLimit;
|
uint256 public immutable supplyLimit;
|
||||||
uint256 private _tokenIndex;
|
uint256 private _tokenIndex;
|
||||||
uint256 public maxBatchSize = 500;
|
mapping(address => bool) public minters;
|
||||||
|
|
||||||
// ============ Events ============
|
// ============ Events ============
|
||||||
event MetaAddressUpdated(address indexed metaAddress);
|
event MetaAddressUpdated(address indexed metaAddress);
|
||||||
event BatchLimitUpdated(uint256 indexed maxBatchSize);
|
event MinterUpdated(address indexed minter, bool support);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
string memory _name,
|
string memory _name,
|
||||||
string memory _symbol,
|
string memory _symbol,
|
||||||
uint256 _supplyLimt
|
uint256 _supplyLimt
|
||||||
) ERC721(_name, _symbol) {
|
) ERC721(_name, _symbol) {
|
||||||
_setRoleAdmin(MINTER_ROLE, DEFAULT_ADMIN_ROLE);
|
|
||||||
|
|
||||||
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
|
|
||||||
_setupRole(MINTER_ROLE, msg.sender);
|
|
||||||
supplyLimit = _supplyLimt;
|
supplyLimit = _supplyLimt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @dev Batch mint tokens and transfer to specified address.
|
|
||||||
*
|
|
||||||
* Requirements:
|
|
||||||
* - Caller must have `MINTER_ROLE`.
|
|
||||||
* - The total supply limit should not be exceeded if supplyLimit is greater than zero.
|
|
||||||
* - The number of tokenIds offered for minting should not exceed maxBatchSize.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function batchMint(
|
|
||||||
address to,
|
|
||||||
uint256 count
|
|
||||||
) external onlyRole(MINTER_ROLE) returns (uint256[] memory) {
|
|
||||||
require(count > 0, "count is too small");
|
|
||||||
require(count <= maxBatchSize, "Exceeds the maximum batch size");
|
|
||||||
require(
|
|
||||||
(supplyLimit == 0) || (totalSupply() + count <= supplyLimit),
|
|
||||||
"Exceeds the total supply"
|
|
||||||
);
|
|
||||||
uint256[] memory tokenIds = new uint256[](count);
|
|
||||||
for (uint256 i = 0; i < count; i++) {
|
|
||||||
_tokenIndex += 1;
|
|
||||||
_safeMint(to, _tokenIndex);
|
|
||||||
tokenIds[i] = _tokenIndex;
|
|
||||||
}
|
|
||||||
return tokenIds;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Safely mints a new token and assigns it to the specified address.
|
* @dev Safely mints a new token and assigns it to the specified address.
|
||||||
* Only the account with the MINTER_ROLE can call this function.
|
* Only the account with the MINTER_ROLE can call this function.
|
||||||
*
|
* tokenId begin with 1.
|
||||||
* @param to The address to which the newly minted token will be assigned.
|
* @param _to The address to which the newly minted token will be assigned.
|
||||||
*/
|
*/
|
||||||
function safeMint(address to) external onlyRole(MINTER_ROLE) returns (uint256){
|
function safeMint(address _to) external onlyMinter returns (uint256){
|
||||||
require(
|
require(_tokenIndex < supplyLimit, "Exceeds the total supply");
|
||||||
(supplyLimit == 0) || (totalSupply() < supplyLimit),
|
|
||||||
"Exceeds the total supply"
|
|
||||||
);
|
|
||||||
uint256 tokenId = ++_tokenIndex;
|
uint256 tokenId = ++_tokenIndex;
|
||||||
_safeMint(to, tokenId);
|
_safeMint(_to, tokenId);
|
||||||
return tokenId;
|
return tokenId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +41,7 @@ contract BEBadgeV2 is AccessControl, ERC721Enumerable, ERC721Burnable {
|
|||||||
*/
|
*/
|
||||||
function updateBaseURI(
|
function updateBaseURI(
|
||||||
string calldata baseTokenURI
|
string calldata baseTokenURI
|
||||||
) external onlyRole(DEFAULT_ADMIN_ROLE) {
|
) external onlyOwner() {
|
||||||
_baseTokenURI = baseTokenURI;
|
_baseTokenURI = baseTokenURI;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,20 +49,6 @@ contract BEBadgeV2 is AccessControl, ERC721Enumerable, ERC721Burnable {
|
|||||||
return _baseTokenURI;
|
return _baseTokenURI;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @dev Updates the maximum batch size for a batch operation.
|
|
||||||
* @param valNew The new maximum batch size.
|
|
||||||
* Requirements:
|
|
||||||
* - The caller must have the DEFAULT_ADMIN_ROLE.
|
|
||||||
* - The new batch size must be greater than 0.
|
|
||||||
*/
|
|
||||||
function updateBatchLimit(
|
|
||||||
uint256 valNew
|
|
||||||
) external onlyRole(DEFAULT_ADMIN_ROLE) {
|
|
||||||
require(valNew > 0, "Batch size is too short");
|
|
||||||
maxBatchSize = valNew;
|
|
||||||
emit BatchLimitUpdated(valNew);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev See {IERC165-_beforeTokenTransfer}.
|
* @dev See {IERC165-_beforeTokenTransfer}.
|
||||||
@ -120,9 +71,25 @@ contract BEBadgeV2 is AccessControl, ERC721Enumerable, ERC721Burnable {
|
|||||||
public
|
public
|
||||||
view
|
view
|
||||||
virtual
|
virtual
|
||||||
override(ERC721, AccessControl, ERC721Enumerable)
|
override(ERC721, ERC721Enumerable)
|
||||||
returns (bool)
|
returns (bool)
|
||||||
{
|
{
|
||||||
return super.supportsInterface(interfaceId);
|
return super.supportsInterface(interfaceId);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* @dev Updates the minters mapping to allow or disallow a specific address to mint tokens.
|
||||||
|
* Only the contract owner can call this function.
|
||||||
|
* @param _address The address to update the minting permission for.
|
||||||
|
* @param _support A boolean indicating whether the address should be allowed to mint tokens or not.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function updateMinters(address _address, bool _support) external onlyOwner {
|
||||||
|
minters[_address] = _support;
|
||||||
|
emit MinterUpdated(_address, _support);
|
||||||
|
}
|
||||||
|
|
||||||
|
modifier onlyMinter() {
|
||||||
|
require(minters[_msgSender()], "Address does not have the minter permission");
|
||||||
|
_;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
52
migrations/15_deploy_activity_202403.js
Normal file
52
migrations/15_deploy_activity_202403.js
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
const base = require("../scripts/base");
|
||||||
|
const NFTClaimer = artifacts.require("activity/NFTClaimer");
|
||||||
|
const NFT = artifacts.require("tokens/erc721/BEBadgeV2");
|
||||||
|
|
||||||
|
module.exports = async function (deployer, network, accounts) {
|
||||||
|
const config = require(`../config/config_${network}`);
|
||||||
|
let cfgs = base.loadData({ network });
|
||||||
|
|
||||||
|
// await deployer.deploy(NFT, 'BEBadgeV2', 'BEBadgeV2', 500);
|
||||||
|
// const nftInstance = await NFT.deployed();
|
||||||
|
// if (nftInstance) {
|
||||||
|
// console.log("NFT successfully deployed.");
|
||||||
|
// console.log("address: " + nftInstance.address);
|
||||||
|
// }
|
||||||
|
// base.updateArray({
|
||||||
|
// name: "BEBadgeV2",
|
||||||
|
// type: "erc721",
|
||||||
|
// json: "assets/contracts/BEBadgeV2.json",
|
||||||
|
// address: nftInstance.address,
|
||||||
|
// network,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// await deployer.deploy(NFTClaimer);
|
||||||
|
// const claimInstance = await NFTClaimer.deployed();
|
||||||
|
// if (claimInstance) {
|
||||||
|
// console.log("ClaimToken successfully deployed.");
|
||||||
|
// console.log("address: " + claimInstance.address);
|
||||||
|
// }
|
||||||
|
// base.updateArray({
|
||||||
|
// name: "NFTClaimer",
|
||||||
|
// type: "logic",
|
||||||
|
// json: "assets/contracts/NFTClaimer.json",
|
||||||
|
// address: claimInstance.address,
|
||||||
|
// network,
|
||||||
|
// });
|
||||||
|
|
||||||
|
|
||||||
|
const nftAddress = cfgs.find((c) => c.name === "BEBadgeV2").address
|
||||||
|
const nftInstance = await NFT.at(nftAddress);
|
||||||
|
const claimerAddress = cfgs.find((c) => c.name === "NFTClaimer").address
|
||||||
|
const claimInstance = await NFTClaimer.at(claimerAddress);
|
||||||
|
|
||||||
|
await claimInstance.updateTokenSupport(nftInstance.address, true);
|
||||||
|
console.log("updateTokenSupport successfully deployed.");
|
||||||
|
await claimInstance.updateSigner(config.admins.admin);
|
||||||
|
console.log("updateSigner successfully deployed.");
|
||||||
|
await claimInstance.updateStartTime((Date.now() / 1000 | 0) - 3600 * 24);
|
||||||
|
await claimInstance.updateEndTime((Date.now() / 1000 | 0) + 3600 * 24 * 10);
|
||||||
|
console.log("update start time and end time successfully deployed.");
|
||||||
|
await nftInstance.grantRole(await nftInstance.MINTER_ROLE(), claimInstance.address);
|
||||||
|
console.log("grantRole successfully deployed.");
|
||||||
|
};
|
14
out/sepolia_dev.json
Normal file
14
out/sepolia_dev.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "BEBadgeV2",
|
||||||
|
"type": "erc721",
|
||||||
|
"json": "assets/contracts/BEBadgeV2.json",
|
||||||
|
"address": "0x09F0dFFA584B1277D7c4E44265a6b5D03303Fc99"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "NFTClaimer",
|
||||||
|
"type": "logic",
|
||||||
|
"json": "assets/contracts/NFTClaimer.json",
|
||||||
|
"address": "0xe4112A9490765463471a9a73050328153C509B0b"
|
||||||
|
}
|
||||||
|
]
|
@ -20,29 +20,24 @@ contract("NFTClaimer", (accounts) => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
nft = await NFT.new("NFT", "NFT", 5);
|
nft = await NFT.new("NFT", "NFT", 5);
|
||||||
tokenClaimer = await NFTClaimer.new();
|
tokenClaimer = await NFTClaimer.new(nft.address);
|
||||||
await tokenClaimer.updateTokenSupport(nft.address, true);
|
|
||||||
await tokenClaimer.updateSigner(singer);
|
await tokenClaimer.updateSigner(singer);
|
||||||
await tokenClaimer.updateStartTime(start);
|
await tokenClaimer.updateStartTime(start);
|
||||||
await tokenClaimer.updateEndTime(end);
|
await tokenClaimer.updateEndTime(end);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should cliam token", async () => {
|
it("should cliam token", async () => {
|
||||||
const minterRole = await nft.MINTER_ROLE();
|
await nft.updateMinters(tokenClaimer.address, true);
|
||||||
await nft.grantRole(minterRole, tokenClaimer.address);
|
|
||||||
const token = nft.address;
|
const token = nft.address;
|
||||||
const chainId = await web3.eth.getChainId();
|
const chainId = await web3.eth.getChainId();
|
||||||
const address = tokenClaimer.address;
|
const address = tokenClaimer.address;
|
||||||
const startTime = Date.now() / 1000 | 0;
|
|
||||||
const saltNonce = (Math.random() * 1000) | 0;
|
const saltNonce = (Math.random() * 1000) | 0;
|
||||||
let signStr = web3.utils.soliditySha3.apply(this,
|
let signStr = web3.utils.soliditySha3.apply(this,
|
||||||
[user, token, startTime, chainId, address, saltNonce]);
|
[user, token, chainId, address, saltNonce]);
|
||||||
let signature = await web3.eth.sign(signStr, singer);
|
let signature = await web3.eth.sign(signStr, singer);
|
||||||
signature = signature.replace(/00$/, "1b").replace(/01$/, "1c");
|
signature = signature.replace(/00$/, "1b").replace(/01$/, "1c");
|
||||||
|
|
||||||
const receipt = await tokenClaimer.claim(
|
const receipt = await tokenClaimer.claim(
|
||||||
token,
|
|
||||||
startTime,
|
|
||||||
saltNonce,
|
saltNonce,
|
||||||
signature,
|
signature,
|
||||||
{ from: user }
|
{ from: user }
|
||||||
@ -51,31 +46,46 @@ contract("NFTClaimer", (accounts) => {
|
|||||||
const balanceOfUser = await nft.balanceOf(user);
|
const balanceOfUser = await nft.balanceOf(user);
|
||||||
assert.equal(balanceOfUser, 1, "Incorrect user balance");
|
assert.equal(balanceOfUser, 1, "Incorrect user balance");
|
||||||
});
|
});
|
||||||
it("should revert cliam token for error signature", async () => {
|
it("should revert cliam token for no minter permission", async () => {
|
||||||
const minterRole = await nft.MINTER_ROLE();
|
|
||||||
await nft.grantRole(minterRole, tokenClaimer.address);
|
|
||||||
const token = nft.address;
|
const token = nft.address;
|
||||||
const chainId = await web3.eth.getChainId();
|
const chainId = await web3.eth.getChainId();
|
||||||
const address = tokenClaimer.address;
|
const address = tokenClaimer.address;
|
||||||
const startTime = Date.now() / 1000 | 0;
|
|
||||||
const saltNonce = (Math.random() * 1000) | 0;
|
const saltNonce = (Math.random() * 1000) | 0;
|
||||||
let signStr = web3.utils.soliditySha3.apply(this,
|
let signStr = web3.utils.soliditySha3.apply(this,
|
||||||
[user, token, startTime, chainId, address, saltNonce]);
|
[user, token, chainId, address, saltNonce]);
|
||||||
|
let signature = await web3.eth.sign(signStr, singer);
|
||||||
|
signature = signature.replace(/00$/, "1b").replace(/01$/, "1c");
|
||||||
|
|
||||||
|
const err = `Address does not have the minter permission`
|
||||||
|
await expectRevert(
|
||||||
|
tokenClaimer.claim(
|
||||||
|
saltNonce,
|
||||||
|
signature,
|
||||||
|
{ from: user }
|
||||||
|
),
|
||||||
|
err
|
||||||
|
);
|
||||||
|
|
||||||
|
});
|
||||||
|
it("should revert cliam token for error signature", async () => {
|
||||||
|
await nft.updateMinters(tokenClaimer.address, true);
|
||||||
|
const token = nft.address;
|
||||||
|
const chainId = await web3.eth.getChainId();
|
||||||
|
const address = tokenClaimer.address;
|
||||||
|
const saltNonce = (Math.random() * 1000) | 0;
|
||||||
|
let signStr = web3.utils.soliditySha3.apply(this,
|
||||||
|
[user, token, chainId, address, saltNonce]);
|
||||||
let signature = await web3.eth.sign(signStr, singer);
|
let signature = await web3.eth.sign(signStr, singer);
|
||||||
signature = signature.replace(/00$/, "1b").replace(/01$/, "1c");
|
signature = signature.replace(/00$/, "1b").replace(/01$/, "1c");
|
||||||
|
|
||||||
const receipt = await tokenClaimer.claim(
|
const receipt = await tokenClaimer.claim(
|
||||||
token,
|
|
||||||
startTime,
|
|
||||||
saltNonce,
|
saltNonce,
|
||||||
signature,
|
signature,
|
||||||
{ from: user }
|
{ from: user }
|
||||||
);
|
);
|
||||||
const err = `[BE] signature used. please send another transaction with new signature`
|
const err = `NFTClaimer: already claimed.`
|
||||||
await expectRevert(
|
await expectRevert(
|
||||||
tokenClaimer.claim(
|
tokenClaimer.claim(
|
||||||
token,
|
|
||||||
startTime,
|
|
||||||
saltNonce,
|
saltNonce,
|
||||||
signature,
|
signature,
|
||||||
{ from: user }
|
{ from: user }
|
||||||
@ -88,37 +98,30 @@ contract("NFTClaimer", (accounts) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should revert cliam token for already claimed", async () => {
|
it("should revert cliam token for already claimed", async () => {
|
||||||
const minterRole = await nft.MINTER_ROLE();
|
await nft.updateMinters(tokenClaimer.address, true);
|
||||||
await nft.grantRole(minterRole, tokenClaimer.address);
|
|
||||||
const token = nft.address;
|
const token = nft.address;
|
||||||
const chainId = await web3.eth.getChainId();
|
const chainId = await web3.eth.getChainId();
|
||||||
const address = tokenClaimer.address;
|
const address = tokenClaimer.address;
|
||||||
const startTime = Date.now() / 1000 | 0;
|
|
||||||
const saltNonce = (Math.random() * 1000) | 0;
|
const saltNonce = (Math.random() * 1000) | 0;
|
||||||
let signStr = web3.utils.soliditySha3.apply(this,
|
let signStr = web3.utils.soliditySha3.apply(this,
|
||||||
[user, token, startTime, chainId, address, saltNonce]);
|
[user, token, chainId, address, saltNonce]);
|
||||||
let signature = await web3.eth.sign(signStr, singer);
|
let signature = await web3.eth.sign(signStr, singer);
|
||||||
signature = signature.replace(/00$/, "1b").replace(/01$/, "1c");
|
signature = signature.replace(/00$/, "1b").replace(/01$/, "1c");
|
||||||
|
|
||||||
const receipt = await tokenClaimer.claim(
|
const receipt = await tokenClaimer.claim(
|
||||||
token,
|
|
||||||
startTime,
|
|
||||||
saltNonce,
|
saltNonce,
|
||||||
signature,
|
signature,
|
||||||
{ from: user }
|
{ from: user }
|
||||||
);
|
);
|
||||||
|
|
||||||
const startTime2 = Date.now() / 1000 | 0;
|
|
||||||
const saltNonce2 = (Math.random() * 1000) | 0;
|
const saltNonce2 = (Math.random() * 1000) | 0;
|
||||||
let signStr2 = web3.utils.soliditySha3.apply(this,
|
let signStr2 = web3.utils.soliditySha3.apply(this,
|
||||||
[user, token, startTime2, chainId, address, saltNonce2]);
|
[user, token, chainId, address, saltNonce2]);
|
||||||
let signature2 = await web3.eth.sign(signStr2, singer);
|
let signature2 = await web3.eth.sign(signStr2, singer);
|
||||||
signature2 = signature2.replace(/00$/, "1b").replace(/01$/, "1c");
|
signature2 = signature2.replace(/00$/, "1b").replace(/01$/, "1c");
|
||||||
const err = `NFTClaimer: already claimed`
|
const err = `NFTClaimer: already claimed`
|
||||||
await expectRevert(
|
await expectRevert(
|
||||||
tokenClaimer.claim(
|
tokenClaimer.claim(
|
||||||
token,
|
|
||||||
startTime2,
|
|
||||||
saltNonce2,
|
saltNonce2,
|
||||||
signature2,
|
signature2,
|
||||||
{ from: user }
|
{ from: user }
|
||||||
@ -127,24 +130,20 @@ contract("NFTClaimer", (accounts) => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("should revert cliam token for activity not begin", async () => {
|
it("should revert cliam token for activity not begin", async () => {
|
||||||
const minterRole = await nft.MINTER_ROLE();
|
await nft.updateMinters(tokenClaimer.address, true);
|
||||||
await tokenClaimer.updateStartTime(Date.now() / 1000 | 0 + 3600);
|
await tokenClaimer.updateStartTime(Date.now() / 1000 | 0 + 3600);
|
||||||
await nft.grantRole(minterRole, tokenClaimer.address);
|
|
||||||
const token = nft.address;
|
const token = nft.address;
|
||||||
const chainId = await web3.eth.getChainId();
|
const chainId = await web3.eth.getChainId();
|
||||||
const address = tokenClaimer.address;
|
const address = tokenClaimer.address;
|
||||||
const startTime = Date.now() / 1000 | 0;
|
|
||||||
const saltNonce = (Math.random() * 1000) | 0;
|
const saltNonce = (Math.random() * 1000) | 0;
|
||||||
let signStr = web3.utils.soliditySha3.apply(this,
|
let signStr = web3.utils.soliditySha3.apply(this,
|
||||||
[user, token, startTime, chainId, address, saltNonce]);
|
[user, token, chainId, address, saltNonce]);
|
||||||
let signature = await web3.eth.sign(signStr, singer);
|
let signature = await web3.eth.sign(signStr, singer);
|
||||||
signature = signature.replace(/00$/, "1b").replace(/01$/, "1c");
|
signature = signature.replace(/00$/, "1b").replace(/01$/, "1c");
|
||||||
|
|
||||||
const err = `NFTClaimer: not started`
|
const err = `NFTClaimer: not started`
|
||||||
await expectRevert(
|
await expectRevert(
|
||||||
tokenClaimer.claim(
|
tokenClaimer.claim(
|
||||||
token,
|
|
||||||
startTime,
|
|
||||||
saltNonce,
|
saltNonce,
|
||||||
signature,
|
signature,
|
||||||
{ from: user }
|
{ from: user }
|
||||||
@ -153,24 +152,20 @@ contract("NFTClaimer", (accounts) => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("should revert cliam token for activity already end", async () => {
|
it("should revert cliam token for activity already end", async () => {
|
||||||
const minterRole = await nft.MINTER_ROLE();
|
await nft.updateMinters(tokenClaimer.address, true);
|
||||||
await tokenClaimer.updateEndTime((Date.now() / 1000 | 0) - 3600);
|
await tokenClaimer.updateEndTime((Date.now() / 1000 | 0) - 3600);
|
||||||
await nft.grantRole(minterRole, tokenClaimer.address);
|
|
||||||
const token = nft.address;
|
const token = nft.address;
|
||||||
const chainId = await web3.eth.getChainId();
|
const chainId = await web3.eth.getChainId();
|
||||||
const address = tokenClaimer.address;
|
const address = tokenClaimer.address;
|
||||||
const startTime = Date.now() / 1000 | 0;
|
|
||||||
const saltNonce = (Math.random() * 1000) | 0;
|
const saltNonce = (Math.random() * 1000) | 0;
|
||||||
let signStr = web3.utils.soliditySha3.apply(this,
|
let signStr = web3.utils.soliditySha3.apply(this,
|
||||||
[user, token, startTime, chainId, address, saltNonce]);
|
[user, token, chainId, address, saltNonce]);
|
||||||
let signature = await web3.eth.sign(signStr, singer);
|
let signature = await web3.eth.sign(signStr, singer);
|
||||||
signature = signature.replace(/00$/, "1b").replace(/01$/, "1c");
|
signature = signature.replace(/00$/, "1b").replace(/01$/, "1c");
|
||||||
|
|
||||||
const err = `NFTClaimer: already ended`
|
const err = `NFTClaimer: already ended`
|
||||||
await expectRevert(
|
await expectRevert(
|
||||||
tokenClaimer.claim(
|
tokenClaimer.claim(
|
||||||
token,
|
|
||||||
startTime,
|
|
||||||
saltNonce,
|
saltNonce,
|
||||||
signature,
|
signature,
|
||||||
{ from: user }
|
{ from: user }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user