src/content/post/how-to-offset-NFT-emissions.mdx 20.3 K raw
1
---
2
title: "How to Offset Your NFT Project Carbon Emissions with Aerial"
3
publishDate: "22 Apr 2022"
4
description: "Learn how Aerial is helping make NFTs carbon neutral with their emissions API"
5
tags: ["web3", "nfts", "tutorials", "web development", "tech philosophy"]
6
ogImage: "https://miro.medium.com/v2/resize:fit:4800/format:webp/1*KxoVDEZFH3mJrlfeguMYjg.jpeg"
7
---
8
9
import { Image } from "@astrojs/image/components";
10
import medium from "../../assets/medium.png";
11
import OutLinkButton from "../../components/OutLinkButton.astro";
12
13
<OutLinkButton
14
	link="https://medium.com/pinata/how-to-offset-your-nft-project-carbon-emissions-with-aerial-b5b4b95faba0"
15
	site="Medium"
16
	image={medium}
17
/>
18
19
As a believer in NFTs and Web3, I am always ecstatic to see what can be done with this new technology. I get bullish over new projects, experimental ideas, and cutting edge utility (especially when it’s something we make at Pinata like [Submarine.me](https://submarine.me)). However, I don’t look at this Metaverse with rose colored glasses. There are many imperfections in this space, and one of the worst ones is environmental impact.
20
21
While I love dooting around on my computer, I also love the outdoors. I love hiking, seeing mountains, hearing rivers, and smelling wildflowers. I love hearing birds in the morning and geese at night. I love to watch my son experience nature and get excited over a butterfly. So yeah, it kinda kills me to think of how this wonderful industry of crypto can harm this amazing planet.
22
23
<Image
24
	src="https://cdn-images-1.medium.com/max/2400/1*xQEP67xsPsQ4vU7wjKLFBw.png"
25
	alt="ethereum carbon emissions chart"
26
	width={1920}
27
	aspectRatio={16 / 9}
28
/>
29
30
The energy consumed by proof of work blockchains is staggering. It’s no secret, and if we want to enjoy this planet we need to accept it. I know I feel defensive when someone attacks something I enjoy, but it helps to take a deep breath and ask the big questions: “could I be wrong?” If crypto is putting the planet in danger, what do we do?
31
32
It might sound easy to just throw Web3 out the window and call it a day, but as with most technological advances, the cat is out of the bag. There’s no putting the lid back on Pandora’s box. In my opinion, there is no easy fix to this problem. There will be a need for multiple approaches to help offset our carbon footprint, including but not limited to better blockchain mechanisms and organizations that pursue renewable energy and conservation.
33
34
This is where [Aerial](https://aerial.is/) steps in. Aerial is a sustainability platform that helps users track their carbon footprint and make donations to help offset their carbon footprint. They are known for their beautiful [mobile application](https://aerial.is/download), but more recently they have developed an API that can track and estimate the carbon footprint of NFT projects and crypto! Per their website, “Emissions are calculated based on the energy consumption of the [Ethereum network](http://ethereumenergyconsumption.com/) and the average [gas used](https://etherscan.io/chart/gasused) per transaction.” Since [Pinata](https://pinata.cloud/) is the home of NFT media we want to always support initiatives like this to make NFTs more sustainable!
35
36
They have some awesome and simple ways you can integrate their widget to your website that looks something like this:
37
38
```javascript
39
<iframe src="https://www.aerial.is/nft/embed?address=0x3e88721fa41d5e102d54b4a04e550222efdd234d">
40
```
41
42
<Image
43
	src="https://cdn-images-1.medium.com/max/2000/1*IPAefM4T_NiRygdri_DzhA.png"
44
	alt="screenshot of widget"
45
	width={1920}
46
	aspectRatio={6 / 2}
47
/>
48
49
In this post we’ll take their API a step further and build our own custom widget. We can use it in our frontend website that displays more details about the project’s emissions with the goal of making visitors more aware!
50
51
If you want to follow along for this tutorial, you’ll need to have npm installed and be familiar with a frontend framework like React. First thing we’ll do is create a new React app and CD into it.
52
53
```bash
54
npx create-react-app aerial-component
55
56
cd aerial-component && npm start
57
```
58
59
Then we’ll delete the CSS files and boilerplate so we are left with this in App.js
60
61
```javascript
62
function App() {
63
	return <div className="App"></div>;
64
}
65
66
export default App;
67
```
68
69
Now let’s make a new component. Create a new file in the src folder called Aerial.js and fill it with this starter code
70
71
```javascript
72
const Aerial = () => {
73
	return <h1>Aerial</h1>;
74
};
75
76
export default Aerial;
77
```
78
79
Now let’s import the new component to our App.js
80
81
```javascript
82
import Aerial from "./Aerial";
83
84
function App() {
85
	return (
86
		<div className="App">
87
			<Aerial />
88
		</div>
89
	);
90
}
91
92
export default App;
93
```
94
95
If you run npm start you should see your basic app with “Aerial” in the top left!
96
97
Now that we have our new component ready to go, we need to start making some API calls and fetching the data. If you need a reference for how to use Aerial’s API you can see their reference [here](https://www.notion.so/aerial/Aerial-API-343ebee875784ca18c244a5aae9fa7d3).
98
99
It’s really quite easy, all we have to do to fetch some basic data is use the following format
100
101
```
102
GET https://aerial.is/_nft/<address>
103
```
104
105
This will return data in the following format
106
107
```json
108
{
109
 "co2": <emissions in CO2>,
110
 "gas": <gas used>,
111
 "transactions": <number of transactions>,
112
 "credits": <credits required to offset>,
113
 "cost": <cost to offset in USD>,
114
 "credits_purchased": <number of credits already purchased>,
115
 "transactions_offset": <number of transactions already offset>
116
}
117
```
118
119
So let’s give it a shot! First thing we need to do is install Axios to help us with our API calls. Go back to the terminal and run
120
121
```bash
122
npm install axios
123
```
124
125
Now make sure to import it into the top of our Aerial component like so
126
127
```javascript
128
import axios from "axios";
129
```
130
131
Now we’re going to make a quick function that will get the data. For our example we’re going to use the NFT contract address 0x2acab3dea77832c09420663b0e1cb386031ba17b.
132
133
```javascript
134
const getEmissionsData = async () => {
135
	try {
136
		const response = await axios.get(
137
			"https://aerial.is/_nft/0x2acab3dea77832c09420663b0e1cb386031ba17b"
138
		);
139
		console.log(response.data);
140
	} catch (error) {
141
		console.log(error);
142
	}
143
};
144
```
145
146
To run this function we’ll use the useEffect hook to fetch the data as we load the app. To do that we simply need to import it at the top like so
147
148
```javascript
149
import { useEffect } from "react";
150
```
151
152
Then we need to run the function inside useEffect,
153
154
```javascript
155
useEffect(() => {
156
	getEmissionsData();
157
}, []);
158
```
159
160
This is what our code will look like with everything in place:
161
162
```javascript
163
import { useEffect } from "react";
164
import axios from "axios";
165
166
const Aerial = () => {
167
	const getEmissionsData = async () => {
168
		try {
169
			const response = await axios.get(
170
				"https://aerial.is/_nft/0x2acab3dea77832c09420663b0e1cb386031ba17b"
171
			);
172
			console.log(response.data);
173
		} catch (error) {
174
			console.log(error);
175
		}
176
	};
177
178
	useEffect(() => {
179
		getEmissionsData();
180
	}, []);
181
182
	return (
183
		<div className="aerial-container">
184
			<h1>Aerial</h1>
185
		</div>
186
	);
187
};
188
189
export default Aerial;
190
```
191
192
If we run the app and check the dev console, we can see our data!
193
194
<Image
195
	src="https://cdn-images-1.medium.com/max/2000/1*UrdopTgDhErJObLI3V8DwQ.png"
196
	alt="dev tools"
197
	width={1920}
198
	aspectRatio={16 / 4}
199
/>
200
201
Now that we have the data, it’s as simple as displaying it so users on our website can see it!
202
203
To store the data we’ll import the useState hook at the top of our app along with useEffect
204
205
```javascript
206
import { useEffect, useState } from "react";
207
```
208
209
Then right above our function to grab the data, we’ll declare our state variable as an empty array where we can push stuff in later.
210
211
```javascript
212
const [emissionsData, setEmissionsData] = useState([]);
213
```
214
215
Now all we have to do is edit our function just a little bit to push that data into our state using the “setEmissionsData”! Here is our function now
216
217
```javascript
218
const getEmissionsData = async () => {
219
	try {
220
		const response = await axios.get(
221
			"https://aerial.is/_nft/0x2acab3dea77832c09420663b0e1cb386031ba17b"
222
		);
223
		console.log(response.data);
224
		setEmissionsData(response.data);
225
	} catch (error) {
226
		console.log(error);
227
	}
228
};
229
```
230
231
The next thing we’re gonna do is create two components inside our file, one as a loading indicator, and the other as the data we want to display. To do this we’ll just make two more functions like this
232
233
```javascript
234
const loading = () => (
235
	<div className="loading-container">
236
		<h1>Loading</h1>
237
	</div>
238
);
239
240
const emissionsComponent = () => {
241
	return (
242
		<div className="data-container">
243
			<h1>Data goes here</h1>
244
		</div>
245
	);
246
};
247
```
248
249
To switch between the two we’ll create a new state called “isLoading” right underneath our previous state. We’ll set the default value to “false” for now
250
251
```javascript
252
const [emissionsData, setEmissionsData] = useState([]);
253
const [isLoading, setIsLoading] = useState(false);
254
```
255
256
Back in our getEmissionsData function we need to turn the “loading” on when we start the request, and then off when we’re done.
257
258
```javascript
259
const getEmissionsData = async () => {
260
	try {
261
		setIsLoading(true);
262
		const response = await axios.get(
263
			"https://aerial.is/_nft/0x2acab3dea77832c09420663b0e1cb386031ba17b"
264
		);
265
		console.log(response.data);
266
		setEmissionsData(response.data);
267
		setIsLoading(false);
268
	} catch (error) {
269
		console.log(error);
270
	}
271
};
272
```
273
274
Finally, way down at the bottom where we render the whole app, we’ll add in some conditional rendering to say “display the loading component while loading, then display the data component when not loading.”
275
276
```javascript
277
return <div className="aerial-container">{isLoading ? loading() : emissionsComponent()}</div>;
278
```
279
280
As a quick recap this is what our component looks like at the moment
281
282
```javascript
283
import { useState, useEffect } from "react";
284
import axios from "axios";
285
286
const Aerial = () => {
287
	const [emissionsData, setEmissionsData] = useState([]);
288
	const [isLoading, setIsLoading] = useState(false);
289
290
	const getEmissionsData = async () => {
291
		try {
292
			setIsLoading(true);
293
			const response = await axios.get(
294
				"https://aerial.is/_nft/0x2acab3dea77832c09420663b0e1cb386031ba17b"
295
			);
296
			console.log(response.data);
297
			setEmissionsData(response.data);
298
			setIsLoading(false);
299
		} catch (error) {
300
			console.log(error);
301
		}
302
	};
303
304
	const loading = () => (
305
		<div className="loading-container">
306
			<h1>Loading</h1>
307
		</div>
308
	);
309
310
	const emissionsComponent = () => {
311
		return (
312
			<div className="data-container">
313
				<h1>Data goes here</h1>
314
			</div>
315
		);
316
	};
317
318
	useEffect(() => {
319
		getEmissionsData();
320
	}, []);
321
322
	return <div className="aerial-container">{isLoading ? loading() : emissionsComponent()}</div>;
323
};
324
325
export default Aerial;
326
```
327
328
Ok now the good part! Time to parse that data and display it. We’re going to go over a few of the pieces of data and how you may want to display them.
329
330
The first is the CO2 emissions, which the API returns as a raw number in the unit of Kg. The best way to make this number manageable in my opinion is to round up the number, and use some javascript to add the commas for each three digits. So back in our emissionsComponent, I have declared the following variable from our saved state.
331
332
```javascript
333
const co2 = new Intl.NumberFormat().format(Math.round(emissionsData.co2));
334
```
335
336
Next up is the gas used for this project, and for this one it returns a whole number so no need to round it up. We’ll just format it to be readable.
337
338
```javascript
339
const gas = new Intl.NumberFormat().format(emissionsData.gas);
340
```
341
342
Aerial of course also provides their unit for donations to offset the carbon emissions they call “credits.” The API can return the total credits need to make the NFT project carbon neutral, how many are purchased so far, and how much it would cost in total to offset the project in USD. To make this data more readable, we want to display how many credits have been purchased, how many are needed to offset, and how much it would cost to completely offset the project. We just need a little math to make that happen!
343
344
For the credits remaining, we just need to subtract the credits already purchased from the total credits needed to offset like so.
345
346
```javascript
347
const creditsRemaining = new Intl.NumberFormat().format(
348
	emissionsData.credits - emissionsData.credits_purchased
349
);
350
```
351
352
Of course we want to display how many have already purchased and that’s pretty simple.
353
354
```javascript
355
const creditsPurchased = new Intl.NumberFormat().format(emissionsData.credits_purchased);
356
```
357
358
Now the more complicated part is calculating how much the remaining cost is. The API gives us the total cost, but it does not include how much has been spent. So for us to get this number we need to divide the emissions cost with the total credits needed to offset, then multiply that against the total emissions credits minus the credits already purchased. In the end it looks like this!
359
360
```javascript
361
const cost = new Intl.NumberFormat().format(
362
	(emissionsData.cost / emissionsData.credits) *
363
		(emissionsData.credits - emissionsData.credits_purchased)
364
);
365
```
366
367
Lastly, we want the number of total number of transactions already offset.
368
369
```
370
const transactions = new Intl.NumberFormat().format(emissionsData.transactions)
371
```
372
373
Alright that was a bit of work to get sorted, but now we can easily plug this into our emissionsComponent so people can see the data in a more easy to read format. We’re also going to display this in a nice grid with each data cell in a box, so our code inside emissions is going to look like this.
374
375
```javascript
376
return (
377
	<div className="data-container">
378
		<div className="header">
379
			<h1>Deadfellaz Carbon Offset</h1>
380
		</div>
381
		<div className="data-grid">
382
			<div className="data-cell">
383
				<h2>{co2} Kg</h2>
384
				<h3>CO2 Emissions</h3>
385
			</div>
386
			<div className="data-cell">
387
				<h2>{gas}</h2>
388
				<h3>Gas Used</h3>
389
			</div>
390
			<div className="data-cell">
391
				<h2>{transactions}</h2>
392
				<h3>Transactions</h3>
393
			</div>
394
			<div className="data-cell">
395
				<h2>${cost}</h2>
396
				<h3>Cost to Offset</h3>
397
			</div>
398
			<div className="data-cell">
399
				<h2>{creditsRemaining}</h2>
400
				<h3>Credits needed to offset</h3>
401
			</div>
402
			<div className="data-cell">
403
				<h2>{creditsPurchased}</h2>
404
				<h3>Credits Purchased so Far</h3>
405
			</div>
406
		</div>
407
		<a
408
			className="cta-button"
409
			target="_blank"
410
			rel="noreferrer"
411
			href="https://aerial.is/nft/0x2acab3dea77832c09420663b0e1cb386031ba17b"
412
		>
413
			Offset
414
		</a>
415
	</div>
416
);
417
```
418
419
At the bottom we’ve also added a button where a user can click on it and be directed to Aerials page for that particular NFT project, where they can make purchase credits to help offset that project.
420
421
To make this whole component feel clean as well as themed for the project, we took some colors and styled from DeadFellaz and added it to this page with some CSS; we also added a fun Lottie animation for the loading component instead of just a header that says loading. In the end our code looks like this!
422
423
```javascript
424
import { useState, useEffect } from "react";
425
import "./Aerial.css";
426
import axios from "axios";
427
import Lottie from "react-lottie";
428
import co2 from "./co2.json";
429
430
const Aerial = () => {
431
	const [emissionsData, setEmissionsData] = useState([]);
432
	const [isLoading, setIsLoading] = useState(false);
433
434
	const getEmissionsData = async () => {
435
		try {
436
			setIsLoading(true);
437
			const response = await axios.get(
438
				"https://aerial.is/_nft/0x2acab3dea77832c09420663b0e1cb386031ba17b"
439
			);
440
			console.log(response.data);
441
			setEmissionsData(response.data);
442
			setIsLoading(false);
443
		} catch (error) {
444
			console.log(error);
445
		}
446
	};
447
448
	const loading = () => (
449
		<div className="loading-container">
450
			<Lottie options={{ animationData: co2 }} height={400} width={400} />
451
		</div>
452
	);
453
454
	const emissionsComponent = () => {
455
		const co2 = new Intl.NumberFormat().format(Math.round(emissionsData.co2));
456
		const gas = new Intl.NumberFormat().format(emissionsData.gas);
457
		const creditsRemaining = new Intl.NumberFormat().format(
458
			emissionsData.credits - emissionsData.credits_purchased
459
		);
460
		const creditsPurchased = new Intl.NumberFormat().format(emissionsData.credits_purchased);
461
		const cost = new Intl.NumberFormat().format(
462
			(emissionsData.cost / emissionsData.credits) *
463
				(emissionsData.credits - emissionsData.credits_purchased)
464
		);
465
		const transactions = new Intl.NumberFormat().format(emissionsData.transactions);
466
467
		return (
468
			<div className="data-container">
469
				<div className="header">
470
					<h1>Deadfellaz Carbon Offset</h1>
471
				</div>
472
				<div className="data-grid">
473
					<div className="data-cell">
474
						<h2>{co2} Kg</h2>
475
						<h3>CO2 Emissions</h3>
476
					</div>
477
					<div className="data-cell">
478
						<h2>{gas}</h2>
479
						<h3>Gas Used</h3>
480
					</div>
481
					<div className="data-cell">
482
						<h2>{transactions}</h2>
483
						<h3>Transactions</h3>
484
					</div>
485
					<div className="data-cell">
486
						<h2>${cost}</h2>
487
						<h3>Cost to Offset</h3>
488
					</div>
489
					<div className="data-cell">
490
						<h2>{creditsRemaining}</h2>
491
						<h3>Credits needed to offset</h3>
492
					</div>
493
					<div className="data-cell">
494
						<h2>{creditsPurchased}</h2>
495
						<h3>Credits Purchased so Far</h3>
496
					</div>
497
				</div>
498
				<a
499
					className="cta-button"
500
					target="_blank"
501
					rel="noreferrer"
502
					href="https://aerial.is/nft/0x2acab3dea77832c09420663b0e1cb386031ba17b"
503
				>
504
					Offset
505
				</a>
506
			</div>
507
		);
508
	};
509
510
	useEffect(() => {
511
		getEmissionsData();
512
	}, []);
513
514
	return <div className="aerial-container">{isLoading ? loading() : emissionsComponent()}</div>;
515
};
516
517
export default Aerial;
518
```
519
520
Here is a quick preview of our final project
521
522
![gif](https://cdn-images-1.medium.com/max/2000/1*4tyAgdhStdoWa-aofwGgBQ.gif)
523
524
You can actually view the working component live [here](https://aerial-component.vercel.app/), and you can freely download the repo on [GitHub](https://github.com/stevedsimkins/aerial-component)!
525
526
If you wanted to take this step further you can request an API key from Aerial to use their offsetting endpoints. These let you not only fetch the data, but also provide a way to make a payment for the credits with Stripe or even Coinbase if you have merchant accounts with both of them! In the end it will always be a little easier to redirect users to Aerial.is to make those credit purchases, but I still love that Aerial has made this an option.
527
528
Aerial’s API is a great way to display emissions for Ethereum projects and help offset them, however if you are still working on your NFT project there are some simple steps you can take to help offset emissions before you launch!
529
530
One of the best things you can do is select a proof of stake blockchain like Solana, Tezos, Flow, or Polygon to create your NFTs on. You can read more on the difference between proof of work and proof of stake blockchains [here](https://www.coinbase.com/learn/crypto-basics/what-is-proof-of-work-or-proof-of-stake), but essentially the amount of energy is significantly lower on proof of stake chains because of how they verify transactions.
531
532
If you do choose Ethereum there are a lot more gas friendly smart contracts being developed such as [ERC-721A by Azuki](https://www.erc721a.org/) or [ERC-1155D](https://medium.com/donkeverse/introducing-erc1155d-the-most-efficient-non-fungible-token-contract-in-existence-c1d0a62e30f1). You can also consider changing how many NFTs you mint for a project. 5,000 to 10,000 is a really popular number, but as Solana has proven you don’t need that many to have a successful project. If you’re doing a much smaller 1/1 project you can even consider using [lazy minting](https://medium.com/rarible-dao/nft-minting-vs-lazy-minting-mining-explained-4330dd57a4c4). However, if your Ethereum contract ends up putting out emissions, you can offset them from the start with [Aerial](https://aerial.is/nft)!
533
534
In conclusion, as NFTs progress and blockchains progress, I believe we will find better and more eco-friendly solutions for energy usage. One of the best thing we can do now is to raise awareness, and it starts with each one of us! Using initiatives like Aerial to bring the issue front and center to your NFT holds is an easy way to not only help educate the public, but also provide an avenue to help offset those emissions. At [Pinata](https://pinata.cloud/) we would love to see this more and more as we assist creators with their NFT media.
535
536
It’s easy to assume that NFTs and Web3 aren’t going away anytime soon, but I’m not sure if we can say the same thing about our planet unless we take care of it.