-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
ETHERSCAN_API_KEY=ABC123ABC123ABC123ABC123ABC123ABC1 | ||
ROPSTEN_URL=https://eth-ropsten.alchemyapi.io/v2/<YOUR ALCHEMY KEY> | ||
PRIVATE_KEY=0xabc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc1 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
node_modules | ||
artifacts | ||
cache | ||
coverage |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
module.exports = { | ||
env: { | ||
browser: false, | ||
es2021: true, | ||
mocha: true, | ||
node: true, | ||
}, | ||
plugins: ["@typescript-eslint"], | ||
extends: [ | ||
"standard", | ||
"plugin:prettier/recommended", | ||
"plugin:node/recommended", | ||
], | ||
parser: "@typescript-eslint/parser", | ||
parserOptions: { | ||
ecmaVersion: 12, | ||
}, | ||
rules: { | ||
"node/no-unsupported-features/es-syntax": [ | ||
"error", | ||
{ ignores: ["modules"] }, | ||
], | ||
}, | ||
}; |
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 |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
hardhat.config.ts | ||
scripts | ||
test |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
node_modules | ||
artifacts | ||
cache | ||
coverage* | ||
gasReporterOutput.json |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"extends": "solhint:recommended", | ||
"rules": { | ||
"compiler-version": ["error", "^0.8.0"], | ||
"func-visibility": ["warn", { "ignoreConstructors": true }] | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node_modules |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# Advanced Sample Hardhat Project | ||
|
||
This project demonstrates an advanced Hardhat use case, integrating other tools commonly used alongside Hardhat in the ecosystem. | ||
|
||
The project comes with a sample contract, a test for that contract, a sample script that deploys that contract, and an example of a task implementation, which simply lists the available accounts. It also comes with a variety of other tools, preconfigured to work with the project code. | ||
|
||
Try running some of the following tasks: | ||
|
||
```shell | ||
npx hardhat accounts | ||
npx hardhat compile | ||
npx hardhat clean | ||
npx hardhat test | ||
npx hardhat node | ||
npx hardhat help | ||
REPORT_GAS=true npx hardhat test | ||
npx hardhat coverage | ||
npx hardhat run scripts/deploy.ts | ||
TS_NODE_FILES=true npx ts-node scripts/deploy.ts | ||
npx eslint '**/*.{js,ts}' | ||
npx eslint '**/*.{js,ts}' --fix | ||
npx prettier '**/*.{json,sol,md}' --check | ||
npx prettier '**/*.{json,sol,md}' --write | ||
npx solhint 'contracts/**/*.sol' | ||
npx solhint 'contracts/**/*.sol' --fix | ||
``` | ||
|
||
# Etherscan verification | ||
|
||
To try out Etherscan verification, you first need to deploy a contract to an Ethereum network that's supported by Etherscan, such as Ropsten. | ||
|
||
In this project, copy the .env.example file to a file named .env, and then edit it to fill in the details. Enter your Etherscan API key, your Ropsten node URL (eg from Alchemy), and the private key of the account which will send the deployment transaction. With a valid .env file in place, first deploy your contract: | ||
|
||
```shell | ||
hardhat run --network ropsten scripts/sample-script.ts | ||
``` | ||
|
||
Then, copy the deployment address and paste it in to replace `DEPLOYED_CONTRACT_ADDRESS` in this command: | ||
|
||
```shell | ||
npx hardhat verify --network ropsten DEPLOYED_CONTRACT_ADDRESS "Hello, Hardhat!" | ||
``` | ||
|
||
# Performance optimizations | ||
|
||
For faster runs of your tests and scripts, consider skipping ts-node's type checking by setting the environment variable `TS_NODE_TRANSPILE_ONLY` to `1` in hardhat's environment. For more details see [the documentation](https://hardhat.org/guides/typescript.html#performance-optimizations). |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
// SPDX-FileCopyrightText: 2021 Toucan Labs | ||
// | ||
// SPDX-License-Identifier: UNLICENSED | ||
|
||
// If you encounter a vulnerability or an issue, please contact <[email protected]> or visit security.toucan.earth | ||
pragma solidity ^0.8.0; | ||
|
||
import '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol'; | ||
import '@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol'; | ||
import '@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol'; | ||
import '@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol'; | ||
import '@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol'; | ||
|
||
import './IToucanContractRegistry.sol'; | ||
import './CarbonOffsetBadgesStorage.sol'; | ||
import './CarbonProjects.sol'; | ||
|
||
/// @notice The `CarbonOffsetBadges` contract lets users mint Badge-NFTs | ||
/// These Badges serve to display how much CO2 a user has offset via the protocols | ||
contract CarbonOffsetBadges is | ||
ERC721EnumerableUpgradeable, | ||
OwnableUpgradeable, | ||
UUPSUpgradeable, | ||
CarbonOffsetBadgesStorage | ||
{ | ||
// Libraries | ||
using CountersUpgradeable for CountersUpgradeable.Counter; | ||
using AddressUpgradeable for address; | ||
|
||
// Events | ||
event BadgeMinted(uint256 tokenId); | ||
|
||
// ---------------------------------------- | ||
// Upgradable related functions | ||
// ---------------------------------------- | ||
|
||
function initialize(address _contractRegistry) public virtual initializer { | ||
__Context_init_unchained(); | ||
__ERC721_init_unchained( | ||
'Toucan Protocol: Retirement Badges for Carbon Offset Project Vintage Batches', | ||
'TOUCAN-COBRB' | ||
); | ||
__Ownable_init_unchained(); | ||
contractRegistry = _contractRegistry; | ||
} | ||
|
||
function _authorizeUpgrade(address newImplementation) | ||
internal | ||
virtual | ||
override | ||
onlyOwner | ||
{} | ||
|
||
function setToucanContractRegistry(address _address) | ||
public | ||
virtual | ||
onlyOwner | ||
{ | ||
contractRegistry = _address; | ||
} | ||
|
||
// Mint new Badge NFT that shows how many offsets have been retired | ||
function mintBadge( | ||
address to, | ||
uint256 projectVintageTokenId, | ||
uint256 amount | ||
) external virtual { | ||
// Logic requires that minting can only originate from a project-vintage ERC20 contract | ||
require( | ||
IToucanContractRegistry(contractRegistry).checkERC20( | ||
_msgSender() | ||
) == true, | ||
'pERC20 not official' | ||
); | ||
_tokenIds.increment(); | ||
uint256 newItemId = _tokenIds.current(); | ||
|
||
_safeMint(to, newItemId); | ||
badges[newItemId].projectVintageTokenId = projectVintageTokenId; | ||
badges[newItemId].retiredAmount = amount; | ||
|
||
emit BadgeMinted(newItemId); | ||
} | ||
|
||
function setBaseURI(string memory baseURI_) external virtual onlyOwner { | ||
baseURI = baseURI_; | ||
} | ||
|
||
function _baseURI() internal view virtual override returns (string memory) { | ||
return baseURI; | ||
} | ||
|
||
/// @dev allows setting a URI or a hash to be used by the `tokenURI` getter | ||
/// Unique values are enforced. This approach gives us good flexibility | ||
/// Allows for usage of cloud storage or IPFS pinning (and/or permastorage) | ||
function setTokenURI(uint256 tokenId, string memory _tokenURI) | ||
internal | ||
virtual | ||
{ | ||
require( | ||
_exists(tokenId), | ||
'ERC721URIStorage: URI set of nonexistent token' | ||
); | ||
bytes32 h = keccak256(abi.encode(_tokenURI)); | ||
require(hashes[h] == false); | ||
hashes[h] = true; | ||
badges[tokenId].tokenURI = _tokenURI; | ||
} | ||
|
||
/// @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. | ||
/// based on the ERC721URIStorage implementation | ||
function tokenURI(uint256 tokenId) | ||
public | ||
view | ||
virtual | ||
override | ||
returns (string memory) | ||
{ | ||
require( | ||
_exists(tokenId), | ||
'ERC721URIStorage: URI query for nonexistent token' | ||
); | ||
|
||
string memory uri = badges[tokenId].tokenURI; | ||
string memory base = _baseURI(); | ||
|
||
// If there is no base URI, return just the uri (or hash) | ||
if (bytes(base).length == 0) { | ||
return uri; | ||
} | ||
// If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked) | ||
if (bytes(uri).length > 0) { | ||
return string(abi.encodePacked(base, uri)); | ||
} | ||
return super.tokenURI(tokenId); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// SPDX-FileCopyrightText: 2021 Toucan Labs | ||
// | ||
// SPDX-License-Identifier: UNLICENSED | ||
|
||
// If you encounter a vulnerability or an issue, please contact <[email protected]> or visit security.toucan.earth | ||
pragma solidity ^0.8.0; | ||
|
||
import '@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol'; | ||
|
||
import './IToucanContractRegistry.sol'; | ||
import './CarbonProjects.sol'; | ||
|
||
contract CarbonOffsetBadgesStorage { | ||
using CountersUpgradeable for CountersUpgradeable.Counter; | ||
|
||
struct Data { | ||
uint256 projectVintageTokenId; | ||
uint256 retiredAmount; | ||
string tokenURI; | ||
} | ||
|
||
string public baseURI; | ||
address public contractRegistry; | ||
CountersUpgradeable.Counter internal _tokenIds; | ||
|
||
mapping(uint256 => Data) public badges; | ||
mapping(bytes32 => bool) internal hashes; | ||
} |