This commit is contained in:
CounterFire2023 2024-05-29 13:22:36 +08:00
commit 59b6fc8f34
20 changed files with 5894 additions and 0 deletions

32
.gitignore vendored Normal file
View File

@ -0,0 +1,32 @@
node_modules
.env
# Hardhat files
/cache
/artifacts
# TypeChain files
/typechain
/typechain-types
# solidity-coverage files
/coverage
/coverage.json
# Hardhat Ignition default folder for deployments against a local node
ignition/deployments/chain-31337
/.idea/
/typechain/
/dist/
/yarn-error.log
/deployments/dev/
/deployments/localhost/
/deployments/proxy/
/typechain-types/
/reports/gas-used-output.color
/.DS_Store
.DS_Store
/contracts/dist/
/contracts/types/
openzeppelin

5
.prettierignore Normal file
View File

@ -0,0 +1,5 @@
node_modules
artifacts
cache
coverage*
gasReporterOutput.json

3
.prettierrc Normal file
View File

@ -0,0 +1,3 @@
{
"printWidth": 120
}

53
.solhint.json Normal file
View File

@ -0,0 +1,53 @@
{
"plugins": ["prettier"],
"rules": {
"code-complexity": ["warn", 7],
"explicit-types": ["error"],
"function-max-lines": ["off", 50],
"max-line-length": ["off", 120],
"max-states-count": ["off", 15],
"no-console": "error",
"no-empty-blocks": "warn",
"no-global-import": "warn",
"no-unused-import": "warn",
"no-unused-vars": "warn",
"one-contract-per-file": "warn",
"payable-fallback": "warn",
"constructor-syntax": "warn",
"comprehensive-interface": "off",
"quotes": ["error", "double"],
"const-name-snakecase": "warn",
"foundry-test-functions": ["off", ["setUp"]],
"func-name-mixedcase": "warn",
"modifier-name-mixedcase": "warn",
"named-parameters-mapping": "warn",
"named-return-values": "off",
"private-vars-leading-underscore": ["off", {"strict": false}],
"use-forbidden-name": "warn",
"var-name-mixedcase": "warn",
"imports-on-top": "warn",
"visibility-modifier-order": "warn",
"avoid-call-value": "error",
"avoid-low-level-calls": "error",
"avoid-sha3": "error",
"avoid-suicide": "error",
"avoid-throw": "error",
"avoid-tx-origin": "error",
"check-send-result": "error",
"compiler-version": ["error", "0.8.23"],
"func-visibility": ["error", {"ignoreConstructors": true}],
"multiple-sends": "warn",
"no-complex-fallback": "warn",
"no-inline-assembly": "warn",
"not-rely-on-block-hash": "warn",
"reentrancy": "warn",
"state-visibility": "warn",
"prettier/prettier": "error"
}
}

1
.solhintignore Normal file
View File

@ -0,0 +1 @@
node_modules

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"solidity.compileUsingRemoteVersion": "v0.8.23+commit.f704f362"
}

13
README.md Normal file
View File

@ -0,0 +1,13 @@
# Sample Hardhat Project
This project demonstrates a basic Hardhat use case. It comes with a sample contract, a test for that contract, and a Hardhat Ignition module that deploys that contract.
Try running some of the following tasks:
```shell
npx hardhat help
npx hardhat test
REPORT_GAS=true npx hardhat test
npx hardhat node
npx hardhat ignition deploy ./ignition/modules/Lock.ts
```

View File

@ -0,0 +1,99 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;
import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import {HasSignature} from "../core/HasSignature.sol";
/**
* Contract for the activity of NFT claim stage 2.
*/
interface IClaimAbleNFT {
function safeMint(
address to
) external returns (uint256);
}
contract NFTClaimStage2 is HasSignature, ReentrancyGuard{
uint256 private immutable _CACHED_CHAIN_ID;
address private immutable _CACHED_THIS;
address public immutable nftAddress;
address public verifier;
bool public isPaused = false;
mapping(address user => uint256 status) public claimHistory;
event NFTClaimed(
address indexed nftAddress,
address indexed to,
uint256 tokenId,
uint256 nonce
);
event StateUpdated(bool isPaused);
event VerifierUpdated(address indexed verifier);
constructor(address _nftAddress) {
_CACHED_CHAIN_ID = block.chainid;
_CACHED_THIS = address(this);
nftAddress = _nftAddress;
}
modifier whenNotPaused() {
require(!isPaused, "NFTClaimer: paused");
_;
}
function updatePaused(bool _isPaused) external onlyOwner {
isPaused = _isPaused;
emit StateUpdated(_isPaused);
}
/**
* @dev update verifier address
*/
function updateVerifier(address _verifier) external onlyOwner {
require(_verifier != address(0), "NFTClaimer: address can not be zero");
verifier = _verifier;
emit VerifierUpdated(_verifier);
}
/**
* @dev claim NFT
* Get whitelist signature from a third-party service, then call this method to claim NFT
* @param saltNonce nonce
* @param signature signature
*/
function claim(
uint256 saltNonce,
bytes calldata signature
) external nonReentrant whenNotPaused {
address to = _msgSender();
require(claimHistory[to] == 0, "NFTClaimer: already claimed");
bytes32 criteriaMessageHash = getMessageHash(
to,
nftAddress,
saltNonce
);
checkSigner(verifier, criteriaMessageHash, signature);
uint256 tokenId = IClaimAbleNFT(nftAddress).safeMint(to);
claimHistory[to] = tokenId;
_useSignature(signature);
emit NFTClaimed(nftAddress, to, tokenId, saltNonce);
}
function getMessageHash(
address _to,
address _address,
uint256 _saltNonce
) public view returns (bytes32) {
bytes memory encoded = abi.encodePacked(
_to,
_address,
_CACHED_CHAIN_ID,
_CACHED_THIS,
_saltNonce
);
return keccak256(encoded);
}
}

View File

@ -0,0 +1,33 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
contract HasSignature is Ownable {
mapping(bytes signature => bool status) private _usedSignatures;
function checkSigner(
address signer,
bytes32 hash,
bytes memory signature
) public pure {
bytes32 ethSignedMessageHash = ECDSA.toEthSignedMessageHash(hash);
address recovered = ECDSA.recover(ethSignedMessageHash, signature);
require(recovered == signer, "[BE] invalid signature");
}
modifier signatureValid(bytes calldata signature) {
require(
!_usedSignatures[signature],
"[BE] signature used. please send another transaction with new signature"
);
_;
}
function _useSignature(bytes calldata signature) internal {
if (!_usedSignatures[signature]) {
_usedSignatures[signature] = true;
}
}
}

View File

@ -0,0 +1,42 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;
// import {ImmutableERC721Base} from "@imtbl/contracts/token/erc721/abstract/ImmutableERC721Base.sol";
import {ImmutableERC721MintByID} from "@imtbl/contracts/token/erc721/preset/ImmutableERC721MintByID.sol";
contract CFNFTGame is ImmutableERC721MintByID{
/**
* @notice Grants `DEFAULT_ADMIN_ROLE` to the supplied `owner` address
* @param owner_ The address to grant the `DEFAULT_ADMIN_ROLE` to
* @param baseURI_ The base URI for the collection
* @param contractURI_ The contract URI for the collection
* @param operatorAllowlist_ The address of the operator allowlist
* @param royaltyReceiver_ The address of the royalty receiver
* @param feeNumerator_ The royalty fee numerator
* @dev the royalty receiver and amount (this can not be changed once set)
*/
constructor(
address owner_,
string memory name_,
string memory symbol_,
string memory baseURI_,
string memory contractURI_,
address operatorAllowlist_,
address royaltyReceiver_,
uint96 feeNumerator_
)
ImmutableERC721MintByID(
owner_,
name_,
symbol_,
baseURI_,
contractURI_,
operatorAllowlist_,
royaltyReceiver_,
feeNumerator_
)
{}
}

View File

@ -0,0 +1,36 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
contract TimeChecker is Ownable {
uint256 public duration;
uint256 public minDuration;
event DurationUpdated(uint256 indexed duration);
constructor() {
duration = 1 days;
minDuration = 30 minutes;
}
/**
* @dev Check if the time is valid
*/
modifier timeValid(uint256 time) {
require(
time + duration >= block.timestamp,
"expired, please send another transaction with new signature"
);
_;
}
/**
* @dev Change duration value
*/
function updateDuation(uint256 valNew) external onlyOwner {
require(valNew > minDuration, "duration too short");
duration = valNew;
emit DurationUpdated(valNew);
}
}

View File

@ -0,0 +1,22 @@
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { DeployFunction } from "hardhat-deploy/types";
import { ethers } from "hardhat";
const deployNFTClaim: DeployFunction =
async function (hre: HardhatRuntimeEnvironment) {
const provider = ethers.provider;
const from = await (await provider.getSigner()).getAddress();
console.log(from);
const ret = await hre.deployments.deploy("NFTClaimStage2", {
from,
args: [],
log: true,
});
console.log("==NFTClaimStage2 addr=", ret.address);
};
deployNFTClaim.tags = ["NFTClaimStage2"];
export default deployNFTClaim;

22
deploy/2_deploy_nft.ts Normal file
View File

@ -0,0 +1,22 @@
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { DeployFunction } from "hardhat-deploy/types";
import { ethers } from "hardhat";
const deployNFTForGame: DeployFunction =
async function (hre: HardhatRuntimeEnvironment) {
const provider = ethers.provider;
const from = await (await provider.getSigner()).getAddress();
console.log(from);
const ret = await hre.deployments.deploy("CFNFTGame", {
from,
args: [],
log: true,
});
console.log("==CFNFTGame addr=", ret.address);
};
deployNFTForGame.tags = ["CFNFTGame"];
export default deployNFTForGame;

View File

@ -0,0 +1 @@
13473

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

70
hardhat.config.ts Normal file
View File

@ -0,0 +1,70 @@
import * as dotenv from "dotenv";
import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";
import 'hardhat-deploy'
dotenv.config();
const config: HardhatUserConfig = {
solidity: {
compilers: [
{
version: "0.8.23",
settings: {
optimizer: {
enabled: true,
runs: 200,
},
},
},
{
version: "0.8.19",
settings: {
optimizer: {
enabled: true,
runs: 200,
},
},
},
{
version: "0.8.20",
settings: {
optimizer: {
enabled: true,
runs: 200,
},
},
},
{
version: "0.8.17",
settings: {
viaIR: true,
optimizer: { enabled: true, runs: 4_294_967_295 },
metadata: {
bytecodeHash: "none",
},
outputSelection: {
"*": {
"*": ["evm.assembly", "irOptimized", "devdoc"],
},
},
},
},
],
},
paths: {
tests: "./test",
},
networks: {
sepolia: {
url: process.env.SEPOLIA_URL || "",
accounts: process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [],
},
imtbl_test: {
url: process.env.IMTBL_TEST_URL || "",
accounts: process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [],
},
},
};
export default config;

51
package.json Normal file
View File

@ -0,0 +1,51 @@
{
"name": "contracts-imtbl",
"version": "1.0.0",
"description": "contracts for Immutable zkEVM",
"main": "index.js",
"scripts": {
"test": "hardhat test",
"compile": "hardhat compile",
"clean": "hardhat clean",
"deploy": "hardhat deploy --network imtbl_test",
"deploy:nftclaim": "hardhat deploy --tags NFTClaimStage2 --network imtbl_test --reset",
"solhint": "solhint --config ./.solhint.json"
},
"author": "",
"license": "ISC",
"dependencies": {
"@imtbl/contracts": "^2.2.7",
"@openzeppelin/contracts": "^4.9.3"
},
"devDependencies": {
"@nomicfoundation/hardhat-chai-matchers": "^2.0.0",
"@nomicfoundation/hardhat-ethers": "^3.0.0",
"@nomicfoundation/hardhat-ignition": "^0.15.4",
"@nomicfoundation/hardhat-ignition-ethers": "^0.15.0",
"@nomicfoundation/hardhat-toolbox": "^5.0.0",
"@nomicfoundation/hardhat-verify": "^2.0.0",
"@nomicfoundation/ignition-core": "^0.15.4",
"@typechain/ethers-v6": "^0.5.0",
"@typechain/hardhat": "^9.0.0",
"@types/chai": "^4.2.0",
"@types/mocha": ">=9.1.0",
"@typescript-eslint/eslint-plugin": "^5.60.0",
"@typescript-eslint/parser": "^5.60.0",
"chai": "^4.2.0",
"dotenv": "^16.4.5",
"ethers": "^6.12.1",
"hardhat": "^2.22.4",
"hardhat-deploy": "^0.12.4",
"hardhat-deploy-ethers": "^0.4.2",
"hardhat-gas-reporter": "^1.0.8",
"prettier": "^3.2.4",
"prettier-plugin-solidity": "^1.3.1",
"solhint": "^3.3.8",
"solhint-community": "^3.7.0",
"solhint-plugin-prettier": "^0.1.0",
"solidity-coverage": "^0.8.1",
"ts-node": "^10.9.2",
"typechain": "^8.3.0",
"typescript": "^5.4.5"
}
}

15
tsconfig.json Normal file
View File

@ -0,0 +1,15 @@
{
"compilerOptions": {
"target": "es2020",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"outDir": "dist",
"declaration": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"skipLibCheck": true
},
"include": ["./index.ts", "./test/**/*.ts", "./deploy"],
"files": ["hardhat.config.ts"]
}

4633
yarn.lock Normal file

File diff suppressed because it is too large Load Diff