Skip to content

Hackathon project from ETHWaterloo '23, focused on environmental conservation and social responsibility. It transforms energy from both on-chain and off-chain regenerative activities, converting it into real trees to foster a sustainable future.

License

Notifications You must be signed in to change notification settings

webthethird/Habitat

Repository files navigation

Habitat 🌱 ETHGlobal Waterloo 2023

Carbon dioxide levels in the atmosphere have been steadily rising since 1980 and are currently at an all time high. An onslaught of wildfires, new infrastructure, and pollution have resulted in the net loss of forest area worldwide. With the health of the planet deteriorating, most of us have found ourselves wondering how we can contribute to the survival of the earth with just our daily actions.

Our application, Habitat, focuses on bridging the gap between environmental sustainability and the onchain universe. The goal is to motivate users to engage in sustainable behaviours and document regenerative transactions or actions that are already part of their daily lives by instilling fun competitiveness, and rewarding eco-preserving benefits such as planting real trees in the world. Habitat reaches its true potential when it is integrated as a sub-application to an existing core protocol or wallet, like Worldcoin, which allows the core application users to give back to the environment while making day-to-day transactions on the app.

The application presents multiple activities considered ‘regenerative’ for the earth, such as donating to a charity or biking to work. Once a user verifies their World ID and completes an activity listed, the system uses Ethereum Attestation Service (EAS) to attest to both onchain and offchain regenerative activities. The completion of these activities grants users green energy points, which they can use towards acquiring an NFT tree with their soul bound token account. Each NFT tree minted will also be planted in real life, thus contributing to a greener, healthier planet. The product also has a key emphasis on fun competition, as users will be able to engage with friends and view the point progression of others. And for an extra kick of motivation, NFT tree holders are eligible to receive access to an exclusive community via Sismo, where they can track the location of their planted tree(s) and other rewards.

How it's Made

This project uses Scaffold-ETH 2 as the template framework. We implemented World ID to ensure that each user interacting with the app is unique. We implemented tokenbound to represent the piece of land that users will eventually receive NFT trees on.

We used several sponsor technologies, such as World ID, Ethereum Attestation Service, Sismo, Tokenbound & ERC-6551, and NounsDAO.

  • First, because we want to assure that only one Habitat (soulbound) NFT can be minted per person, we integrate World ID into our on-boarding process and prevent gaming the system.
  • Next, when the user creates their Habitat NFT, the mint function calls into the ERC-6551 account registry to create a new tokenbound account, allowing the NFT to hold its NFTrees. The Habitat NFT stores its own SVG data onchain, but when it owns NFTrees it will concatenate the SVG data of each tree, gradually accumulating a composed SVG forest.
  • In order to mint an NFTree to their Habitat, a user must receive an attestation for performing a “regenerative activity”, such as scanning a Presto card to take the bus, biking to work with BikeShare, or donating to an impact organization like TreeCanada. We registered a DonationAttestation schema to the EAS SchemaRegistry on Sepolia, which uses a custom Resolver contract. The DonationEASResolver is permitted to grant “green points” to a user via the Habitat NFT contract each time it receives an attestation, at a rate of 100 points per ETH. To mint an NFTree (and plant a real tree) a user must accumulate 10 green points.
  • Finally, once a user receives their first attestation, we use Sismo to connect to EAS as a data provider, which can then be used to gate users of the attestation.
  • Besides targeting individual users, Habitat is also aimed towards motivating communities, like the Nouns community to earn energy points collectively by doing more regenerative activities collectively. The benefit of such a feat would be that the Nouns community can plant a group of trees together which can potentially form the "Nouns forest", which can be monetized or used for further environmental efforts in the future.

🏗 Scaffold-ETH 2

🧪 An open-source, up-to-date toolkit for building decentralized applications (dapps) on the Ethereum blockchain. It's designed to make it easier for developers to create and deploy smart contracts and build user interfaces that interact with those contracts.

⚙️ Built using NextJS, RainbowKit, Hardhat, Wagmi, and Typescript.

  • Contract Hot Reload: Your frontend auto-adapts to your smart contract as you edit it.
  • 🔥 Burner Wallet & Local Faucet: Quickly test your application with a burner wallet and local faucet.
  • 🔐 Integration with Wallet Providers: Connect to different wallet providers and interact with the Ethereum network.

Contents

Requirements

Before you begin, you need to install the following tools:

Quickstart

To get started with Scaffold-ETH 2, follow the steps below:

  1. Clone this repo & install dependencies
git clone https://github.com/scaffold-eth/scaffold-eth-2.git
cd scaffold-eth-2
yarn install
  1. Run a local network in the first terminal:
yarn chain

This command starts a local Ethereum network using Hardhat. The network runs on your local machine and can be used for testing and development. You can customize the network configuration in hardhat.config.ts.

  1. On a second terminal, deploy the test contract:
yarn deploy

This command deploys a test smart contract to the local network. The contract is located in packages/hardhat/contracts and can be modified to suit your needs. The yarn deploy command uses the deploy script located in packages/hardhat/deploy to deploy the contract to the network. You can also customize the deploy script.

  1. On a third terminal, start your NextJS app:
yarn start

Visit your app on: http://localhost:3000. You can interact with your smart contract using the contract component or the example ui in the frontend. You can tweak the app config in packages/nextjs/scaffold.config.ts.

Run smart contract test with yarn hardhat:test

  • Edit your smart contract YourContract.sol in packages/hardhat/contracts
  • Edit your frontend in packages/nextjs/pages
  • Edit your deployment scripts in packages/hardhat/deploy

Deploying your Smart Contracts to a Live Network

Once you are ready to deploy your smart contracts, there are a few things you need to adjust.

  1. Select the network

By default, yarn deploy will deploy the contract to the local network. You can change the defaultNetwork in packages/hardhat/hardhat.config.ts. You could also simply run yarn deploy --network target_network to deploy to another network.

Check the hardhat.config.ts for the networks that are pre-configured. You can also add other network settings to the hardhat.config.ts file. Here are the Alchemy docs for information on specific networks.

Example: To deploy the contract to the Sepolia network, run the command below:

yarn deploy --network sepolia
  1. Generate a new account or add one to deploy the contract(s) from. Additionally you will need to add your Alchemy API key. Rename .env.example to .env and fill the required keys.
ALCHEMY_API_KEY="",
DEPLOYER_PRIVATE_KEY=""

The deployer account is the account that will deploy your contracts. Additionally, the deployer account will be used to execute any function calls that are part of your deployment script.

You can generate a random account / private key with yarn generate or add the private key of your crypto wallet. yarn generate will create a random account and add the DEPLOYER_PRIVATE_KEY to the .env file. You can check the generated account with yarn account.

  1. Deploy your smart contract(s)

Run the command below to deploy the smart contract to the target network. Make sure to have some funds in your deployer account to pay for the transaction.

yarn deploy --network network_name
  1. Verify your smart contract

You can verify your smart contract on Etherscan by running:

yarn verify --network network_name

Deploying your NextJS App

Hint: We recommend connecting your GitHub repo to Vercel (through the Vercel UI) so it gets automatically deployed when pushing to main.

If you want to deploy directly from the CLI, run yarn vercel and follow the steps to deploy to Vercel. Once you log in (email, github, etc), the default options should work. It'll give you a public URL.

If you want to redeploy to the same production URL you can run yarn vercel --prod. If you omit the --prod flag it will deploy it to a preview/test URL.

Make sure your packages/nextjs/scaffold.config.ts file has the values you need.

Interacting with your Smart Contracts: SE-2 Custom Hooks

Scaffold-ETH 2 provides a collection of custom React hooks designed to simplify interactions with your deployed smart contracts. These hooks are wrappers around wagmi, automatically loading the necessary contract ABI and address. They offer an easy-to-use interface for reading from, writing to, and monitoring events emitted by your smart contracts.

To help developers get started with smart contract interaction using Scaffold-ETH 2, we've provided the following custom hooks:

These hooks offer a simplified and streamlined interface for interacting with your smart contracts. If you need to interact with external contracts, you can use wagmi directly, or add external contract data to your deployedContracts.ts file.

useScaffoldContractRead:

Use this hook to read public variables and get data from read-only functions of your smart contract.

const { data: totalCounter } = useScaffoldContractRead({
  contractName: "YourContract",
  functionName: "getGreeting",
  args: ["ARGUMENTS IF THE FUNCTION ACCEPTS ANY"],
});

This example retrieves the data returned by the getGreeting function of the YourContract smart contract. If the function accepts any arguments, they can be passed in the args array. The retrieved data is stored in the data property of the returned object.

useScaffoldContractWrite:

Use this hook to send a transaction to your smart contract to write data or perform an action.

const { writeAsync, isLoading, isMining } = useScaffoldContractWrite({
  contractName: "YourContract",
  functionName: "setGreeting",
  args: ["The value to set"],
  // For payable functions, expressed in ETH
  value: "0.01",
  // The number of block confirmations to wait for before considering transaction to be confirmed (default : 1).
  blockConfirmations: 1,
  // The callback function to execute when the transaction is confirmed.
  onBlockConfirmation: (txnReceipt) => {
    console.log("Transaction blockHash", txnReceipt.blockHash);
  },
});

To send the transaction, you can call the writeAsync function returned by the hook. Here's an example usage:

<button className="btn btn-primary" onClick={writeAsync}>
  Send TX
</button>

This example sends a transaction to the YourContract smart contract to call the setGreeting function with the arguments passed in args. The writeAsync function sends the transaction to the smart contract, and the isLoading and isMining properties indicate whether the transaction is currently being processed by the network.

useScaffoldEventSubscriber:

Use this hook to subscribe to events emitted by your smart contract, and receive real-time updates when these events are emitted.

useScaffoldEventSubscriber({
  contractName: "YourContract",
  eventName: "GreetingChange",
  // The listener function is called whenever a GreetingChange event is emitted by the contract.
  // It receives the parameters emitted by the event, for this example: GreetingChange(address greetingSetter, string newGreeting, bool premium, uint256 value);
  listener: (greetingSetter, newGreeting, premium, value) => {
    console.log(greetingSetter, newGreeting, premium, value);
  },
});

This example subscribes to the GreetingChange event emitted by the YourContract smart contract, and logs the parameters emitted by the event to the console whenever it is emitted. The listener function accepts the parameters emitted by the event, and can be customized according to your needs.

useScaffoldEventHistory:

Use this hook to retrieve historical event logs for your smart contract, providing past activity data.

const {
  data: events,
  isLoading: isLoadingEvents,
  error: errorReadingEvents,
  } = useScaffoldEventHistory({
  contractName: "YourContract",
  eventName: "GreetingChange",
  // Specify the starting block number from which to read events.
  fromBlock: 31231,
  blockData: true,
  // Apply filters to the event based on parameter names and values { [parameterName]: value },
  filters: { premium: true }
  // If set to true it will return the transaction data for each event (default: false),
  transactionData: true,
  // If set to true it will return the receipt data for each event (default: false),
  receiptData: true
});

This example retrieves the historical event logs for the GreetingChange event of the YourContract smart contract, starting from block number 31231 and filtering events where the premium parameter is true. The data property of the returned object contains an array of event objects, each containing the event parameters and (optionally) the block, transaction, and receipt data. The isLoading property indicates whether the event logs are currently being fetched, and the error property contains any error that occurred during the fetching process (if applicable).

useDeployedContractInfo:

Use this hook to fetch details about a deployed smart contract, including the ABI and address.

// ContractName: name of the deployed contract
const { data: deployedContractData } = useDeployedContractInfo(contractName);

This example retrieves the details of the deployed contract with the specified name and stores the details in the deployedContractData object.

useScaffoldContract:

Use this hook to get your contract instance by providing the contract name. It enables you interact with your contract methods. For reading data or sending transactions, it's recommended to use useScaffoldContractRead and useScaffoldContractWrite.

const { data: yourContract } = useScaffoldContract({
  contractName: "YourContract",
});
// Returns the greeting and can be called in any function, unlike useScaffoldContractRead
await yourContract?.greeting();

// Used to write to a contract and can be called in any function
import { Signer } from "ethers";
import { useSigner } from "wagmi";

const { data: signer, isError, isLoading } = useSigner();
const { data: yourContract } = useScaffoldContract({
  contractName: "YourContract",
  signerOrProvider: signer as Signer,
});
const setGreeting = async () => {
  // Call the method in any function
  await yourContract?.setGreeting("the greeting here");
};

This example uses the useScaffoldContract hook to obtain a contract instance for the YourContract smart contract. The data property of the returned object contains the contract instance that can be used to call any of the smart contract methods.

Disabling type and linting error checks

Hint Typescript helps you catch errors at compile time, which can save time and improve code quality, but can be challenging for those who are new to the language or who are used to the more dynamic nature of JavaScript. Below are the steps to disable type & lint check at different levels

Disabling commit checks

We run pre-commit git hook which lints the staged files and don't let you commit if there is an linting error.

To disable this, go to .husky/pre-commit file and comment out yarn lint-staged --verbose

- yarn lint-staged --verbose
+ # yarn lint-staged --verbose

Deploying to Vercel without any checks

By default, Vercel runs types and lint checks before building your app. The deployment will fail if there are any types or lint errors.

To ignore these checks while deploying from the CLI, use:

yarn vercel:yolo

If your repo is connected to Vercel, you can set NEXT_PUBLIC_IGNORE_BUILD_ERROR to true in a environment variable.

Disabling Github Workflow

We have github workflow setup checkout .github/workflows/lint.yaml which runs types and lint error checks every time code is pushed to main branch or pull request is made to main branch

To disable it, delete .github directory

Contributing to Scaffold-ETH 2

We welcome contributions to Scaffold-ETH 2!

Please see CONTRIBUTING.MD for more information and guidelines for contributing to Scaffold-ETH 2.

About

Hackathon project from ETHWaterloo '23, focused on environmental conservation and social responsibility. It transforms energy from both on-chain and off-chain regenerative activities, converting it into real trees to foster a sustainable future.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published