-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 56c2ff0
Showing
39 changed files
with
11,976 additions
and
0 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,6 @@ | ||
# Your Etherscan API key for contract source code verification. | ||
ETHERSCAN_API_KEY=ABC123ABC123ABC123ABC123ABC123ABC1 | ||
# Your infura.io project ID for deploying to Ethereum networks. | ||
INFURA_ID=73157d26f55d413eb06614f4ead1de461 | ||
# The private key of your address for deploying contracts on public networks. | ||
PRIVATE_KEY=0xabc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc1 |
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,5 @@ | ||
node_modules | ||
artifacts | ||
cache | ||
coverage | ||
*.js |
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,25 @@ | ||
module.exports = { | ||
env: { | ||
browser: false, | ||
es2021: true, | ||
mocha: true, | ||
node: true | ||
}, | ||
plugins: ["@typescript-eslint"], | ||
extends: ["airbnb-base", "prettier", "plugin:node/recommended"], | ||
parser: "@typescript-eslint/parser", | ||
parserOptions: { | ||
ecmaVersion: 12 | ||
}, | ||
rules: { | ||
"func-names": "off", | ||
"no-console": "off", | ||
"import/no-extraneous-dependencies": ["error", { devDependencies: true }], | ||
"node/no-unpublished-import": "off", | ||
"node/no-unsupported-features/es-syntax": ["error", { ignores: ["modules"] }], | ||
"no-shadow": "off", | ||
"@typescript-eslint/no-shadow": "error", | ||
"no-unused-vars": "off", | ||
"@typescript-eslint/no-unused-vars": "error" | ||
} | ||
}; |
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,65 @@ | ||
name: Code checks | ||
|
||
on: | ||
push: | ||
branches: [main] | ||
pull_request: | ||
branches: [main] | ||
|
||
jobs: | ||
lint: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- uses: actions/checkout@v3 | ||
|
||
- name: Setup NodeJS | ||
uses: actions/setup-node@v3 | ||
with: | ||
node-version: "18" | ||
cache: "npm" | ||
|
||
- name: Cache node modules | ||
uses: actions/cache@v3 | ||
id: cache | ||
with: | ||
path: "**/node_modules" | ||
key: npm-v1-${{ hashFiles('**/package-lock.json') }} | ||
restore-keys: npm-v1- | ||
|
||
- name: Install dependencies | ||
run: npm ci | ||
if: steps.cache.outputs.cache-hit != 'true' | ||
|
||
- name: Lint contracts | ||
run: npm run lint-contracts | ||
|
||
- name: Lint scripts | ||
run: npm run lint-ts | ||
|
||
tests: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- uses: actions/checkout@v3 | ||
|
||
- name: Setup NodeJS | ||
uses: actions/setup-node@v3 | ||
with: | ||
node-version: "18" | ||
cache: "npm" | ||
|
||
- name: Cache node modules | ||
uses: actions/cache@v3 | ||
id: cache | ||
with: | ||
path: "**/node_modules" | ||
key: npm-v1-${{ hashFiles('**/package-lock.json') }} | ||
restore-keys: npm-v1- | ||
|
||
- name: Install dependencies | ||
run: npm ci | ||
if: steps.cache.outputs.cache-hit != 'true' | ||
|
||
- name: Run tests | ||
run: npm test |
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,9 @@ | ||
node_modules | ||
.env | ||
coverage | ||
coverage.json | ||
typechain | ||
|
||
#Hardhat files | ||
cache | ||
artifacts |
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,6 @@ | ||
node_modules | ||
artifacts | ||
cache | ||
coverage* | ||
gasReporterOutput.json | ||
docs/templates |
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,16 @@ | ||
{ | ||
"useTabs": false, | ||
"tabWidth": 2, | ||
"singleQuote": false, | ||
"trailingComma": "none", | ||
"printWidth": 120, | ||
"overrides": [ | ||
{ | ||
"files": "*.sol", | ||
"options": { | ||
"tabWidth": 4, | ||
"bracketSpacing": true | ||
} | ||
} | ||
] | ||
} |
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,10 @@ | ||
{ | ||
"extends": "solhint:recommended", | ||
"rules": { | ||
"compiler-version": "off", | ||
"func-visibility": ["warn", { "ignoreConstructors": true }], | ||
"max-line-length": ["warn", 123], | ||
"no-inline-assembly": "off", | ||
"not-rely-on-time": "off" | ||
} | ||
} |
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 @@ | ||
node_modules |
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 @@ | ||
MIT License | ||
|
||
Copyright (c) 2023 guild.xyz | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
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,94 @@ | ||
# NFT reward factory | ||
|
||
NFT contracts used for [Guild.xyz](https://guild.xyz)'s `CONTRACT_CALL` reward. | ||
|
||
## Setup | ||
|
||
To run the project you need [Node.js](https://nodejs.org) development environment. | ||
|
||
Pull the repository from GitHub, then install its dependencies by executing this command: | ||
|
||
```bash | ||
npm install | ||
``` | ||
|
||
Certain actions, like deploying to a public network or verifying source code on block explorers, need environment variables in a file named `.env`. See _[.env.example](.env.example)_ for more info. | ||
|
||
### Some additional steps before deployment | ||
|
||
Open the script you wish to use, depending on if you want to deploy the contracts for the first time or upgrade an existing deployment. Notice the constants at the top and edit them according to your needs. | ||
|
||
## Contract deployment | ||
|
||
To deploy the smart contracts to a network, replace _[networkName]_ with the name of the network and _[scriptName]_ with the name of the script you wish to run in this command: | ||
|
||
```bash | ||
npx hardhat run scripts/[scriptName] --network [networkName] | ||
``` | ||
|
||
Networks can be configured in _[hardhat.config.ts](hardhat.config.ts)_. We've preconfigured the following: | ||
|
||
- `hardhat` (for local testing, default) | ||
- `ethereum` (Ethereum Mainnet) | ||
- `goerli` (Görli Ethereum Testnet) | ||
- `sepolia` (Sepolia Ethereum Testnet) | ||
- `bsc` (BNB Smart Chain) | ||
- `bsctest` (BNB Smart Chain Testnet) | ||
- `polygon` (Polygon Mainnet (formerly Matic)) | ||
- `mumbai` (Matic Mumbai Testnet) | ||
- `gnosis` (Gnosis Chain (formerly xDai Chain)) | ||
- `arbitrum` (Arbitrum One (Mainnet)) | ||
|
||
## Verification | ||
|
||
For source code verification on block explorers, you can use the Etherscan plugin: | ||
|
||
```bash | ||
npx hardhat verify [contractAddress] [constructorArguments] --network [networkName] | ||
``` | ||
|
||
For more detailed instructions, check out it's documentation [here](https://hardhat.org/plugins/nomiclabs-hardhat-etherscan#usage). | ||
|
||
## Linting | ||
|
||
The project uses [Solhint](https://github.com/protofire/solhint) for Solidity smart contracts and [ESLint](https://eslint.org) for TypeScript files. To lint all files, simply execute: | ||
|
||
```bash | ||
npm run lint | ||
``` | ||
|
||
To lint only the Solidity files: | ||
|
||
```bash | ||
npm run lint-contracts | ||
``` | ||
|
||
To lint only the TypeScript files: | ||
|
||
```bash | ||
npm run lint-ts | ||
``` | ||
|
||
## Tests | ||
|
||
To run the unit tests written for this project, execute this command in a terminal: | ||
|
||
```bash | ||
npm test | ||
``` | ||
|
||
To run the unit tests only in a specific file, just append the path to the command. For example, to run tests just for ContractName: | ||
|
||
```bash | ||
npm test test/ContractName.spec.ts | ||
``` | ||
|
||
## Documentation | ||
|
||
The documentation for the contracts is generated via the [solidity-docgen](https://github.com/OpenZeppelin/solidity-docgen) package. Run the tool via the following command: | ||
|
||
```bash | ||
npm run docgen | ||
``` | ||
|
||
The output can be found in the _[docs/contracts](docs/contracts)_ folder. |
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,110 @@ | ||
//SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.20; | ||
|
||
import { IGuildRewardNFT } from "./interfaces/IGuildRewardNFT.sol"; | ||
import { LibTransfer } from "./lib/LibTransfer.sol"; | ||
import { SoulboundERC721 } from "./token/SoulboundERC721.sol"; | ||
import { TreasuryManager } from "./utils/TreasuryManager.sol"; | ||
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; | ||
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; | ||
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; | ||
import { ECDSAUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol"; | ||
|
||
/// @title An NFT distributed as a reward for Guild.xyz users. | ||
contract GuildRewardNFT is | ||
IGuildRewardNFT, | ||
Initializable, | ||
OwnableUpgradeable, | ||
UUPSUpgradeable, | ||
SoulboundERC721, | ||
TreasuryManager | ||
{ | ||
using ECDSAUpgradeable for bytes32; | ||
using LibTransfer for address; | ||
using LibTransfer for address payable; | ||
|
||
address public validSigner; | ||
|
||
/// @notice The cid for tokenURI. | ||
string internal cid; | ||
|
||
/// @notice Empty space reserved for future updates. | ||
uint256[48] private __gap; | ||
|
||
/// @notice Sets metadata and the associated addresses. | ||
/// @param name The name of the token. | ||
/// @param symbol The symbol of the token. | ||
/// @param treasury The address where the collected fees will be sent. | ||
/// @param _validSigner The address that should sign the parameters for certain functions. | ||
/// @param _cid The cid used to construct the tokenURI for the token to be minted. | ||
function initialize( | ||
string memory name, | ||
string memory symbol, | ||
address payable treasury, | ||
address payable _validSigner, | ||
string calldata _cid | ||
) public initializer { | ||
validSigner = _validSigner; | ||
cid = _cid; | ||
__Ownable_init(); | ||
__UUPSUpgradeable_init(); | ||
__SoulboundERC721_init(name, symbol); | ||
__TreasuryManager_init(treasury); | ||
} | ||
|
||
function claim(address payToken, address receiver, bytes calldata signature) external payable { | ||
if (balanceOf(receiver) > 0) revert AlreadyClaimed(); | ||
if (!isValidSignature(receiver, signature)) revert IncorrectSignature(); | ||
|
||
uint256 tokenId = totalSupply(); | ||
|
||
uint256 fee = fee[payToken]; | ||
if (fee == 0) revert IncorrectPayToken(payToken); | ||
|
||
// Fee collection | ||
// When there is no msg.value, try transferring ERC20 | ||
// When there is msg.value, ensure it's the correct amount | ||
if (msg.value == 0) treasury.sendTokenFrom(msg.sender, payToken, fee); | ||
else if (msg.value != fee) revert IncorrectFee(msg.value, fee); | ||
else treasury.sendEther(fee); | ||
|
||
_safeMint(receiver, tokenId); | ||
|
||
emit Claimed(receiver, tokenId); | ||
} | ||
|
||
function burn(uint256 tokenId) external { | ||
if (msg.sender != ownerOf(tokenId)) revert IncorrectSender(); | ||
_burn(tokenId); | ||
} | ||
|
||
function setValidSigner(address newValidSigner) external onlyOwner { | ||
validSigner = newValidSigner; | ||
emit ValidSignerChanged(newValidSigner); | ||
} | ||
|
||
function updateTokenURI(string calldata newCid) external onlyOwner { | ||
cid = newCid; | ||
emit MetadataUpdate(); | ||
} | ||
|
||
function hasClaimed(address account) external view returns (bool claimed) { | ||
return balanceOf(account) > 0; | ||
} | ||
|
||
function tokenURI(uint256 tokenId) public view override returns (string memory) { | ||
if (!_exists(tokenId)) revert NonExistentToken(tokenId); | ||
|
||
return string.concat("ipfs://", cid); | ||
} | ||
|
||
// solhint-disable-next-line no-empty-blocks | ||
function _authorizeUpgrade(address) internal override onlyOwner {} | ||
|
||
/// @notice Checks the validity of the signature for the given params. | ||
function isValidSignature(address receiver, bytes calldata signature) internal view returns (bool) { | ||
if (signature.length != 65) revert IncorrectSignature(); | ||
bytes32 message = keccak256(abi.encode(receiver, block.chainid, address(this))).toEthSignedMessageHash(); | ||
return message.recover(signature) == validSigner; | ||
} | ||
} |
Oops, something went wrong.