Skip to content

Commit 7a23618

Browse files
committed
nattydao concept for challenge
1 parent 8e66fcb commit 7a23618

File tree

19 files changed

+2975
-0
lines changed

19 files changed

+2975
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
THIS IS TOTALLY UNFINISHED, but wanted to submit it just for the sake of 'why the hell not?'.
2+
3+
Basically there's a relay script that checks an external API for changes, loads a file with those changes, and then mints them as NFTs using an RTM. This relay is TBD (to be decentralized).
4+
5+
That RTM is calling into [scrypto/inatty-oracle/src/mint.rs](scrypto/inatty-oracle/src/mint.rs) in the `create_nft` method.
6+
7+
This is not an NFT for finance use cases, but an NFT for "Regenerative Finance" use cases.
8+
9+
------------------
10+
11+
## <This is all conceptual until Babylon. Please join now and help build this project with me!>
12+
13+
See [shardeez.xyz/refi](https://shardeez.xyz/refi) for resources on Regenerative Finance (ReFi). Let's learn about ReFi and build together!
14+
15+
## Idea for NattyDAO
16+
17+
### Mission
18+
19+
To support members of the Radix community to `touch grass` & `touch trash`.
20+
21+
DAO funds small-scale environmental benefits such as: wildland trash pickups, beach cleanups, de-paving (removing concrete and replacing w/ native plants), gardening projects, pollinator homes, and more.
22+
23+
### Mechanism
24+
25+
- Members propose a project, request funding from treasury.
26+
27+
- Holders of INATTY token vote to pass or reject proposal.
28+
29+
- Quadratic funding mechanism w/ a matching pool.
30+
31+
- Treasury funded by sale of NFTs, donations.
32+
33+
### iNATTY Token
34+
35+
The first token backed by relationships to nature. It's used to buy NFTs from the NattyDAO. It's also used to vote on proposals to fund environmental projects.
36+
37+
### iNATTY NFTs (THIS PART USED FOR SUBMISSION TO SCRYPTO CHALLENGE)
38+
39+
NFTs minted by the NattyDAO that represent a member outside experiencing nature. These NFTs are minted using data from the **iNatty Oracle**. Whenever a registered member experiences nature, an NFT is minted. This nature experience is provable because of integration with the iNaturalist API.
40+
41+
They are then offered for sale in an NFT marketplace. They can only be purchased with INATTY, and 50% of the funds go to the NattyDAO treasury, and 50% go to the member.
42+
43+
### iNATTY Oracle
44+
45+
Relays information about the member's associated iNaturalist accounts to the NattyDAO components. One part watches for new registrations of [iNaturalist.org](https://inaturalist.org) accounts and keeps track of the member's activity in a Scrypto Component. Another part watches for new observations on iNaturalist and mints NFTs for the member (metadata includes the natural experience, including image, species identified, location, and date).
46+
47+
### NattyDAO Treasury
48+
49+
This is used to incentivize members to participate in the NattyDAO. It is funded by the sale of iNATTY NFTs. Proposals can be made to the NattyDAO to spend funds from the treasury.
50+
51+
### Optimistic Funding (provable cleanups idea)
52+
53+
- Once funded the project is given 1 week to complete and prove to the community their efforts.
54+
55+
- If no dispute about their efforts, XRD automatically sent to their address
56+
57+
- Someone disputing must bond some XRD.
58+
59+
- Their dispute is voted on, if found out true then they get their bonded XRD back + some reward.
60+
61+
- If their dispute isn't corroborated by community, they lose their bond.
62+
63+
### References
64+
65+
- [Open Forest Protocol Whiteboard Series (YouTube)](https://www.youtube.com/watch?v=ZjFT2KoUgks&list=PLWJdg32OtDLUbxcE_Qr0GTHQ0L07mikej)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
INAT_API_KEY=""
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
chiggimps
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# Connect to the iNaturalist API and get the data for a given user.
2+
# There's a lot more we can do around metadata.
3+
# (e.g. extra rarity for reviewed observations...)
4+
import requests
5+
import sys
6+
import pandas as pd
7+
import numpy as np
8+
import os
9+
import json
10+
from dotenv import load_dotenv
11+
load_dotenv()
12+
13+
# path needed for cronjob access
14+
script_path: str = os.path.dirname(os.path.realpath(__file__))
15+
16+
################################
17+
# a class for this iNatty module instatiated per user
18+
class iNatty(object):
19+
20+
def __init__(self, user_name):
21+
self.user_name = user_name
22+
self.observedNew = []
23+
self.observedTotal = {}
24+
25+
def get_obs_from_db(self) -> dict:
26+
with open(os.path.join(script_path, 'observed.json'), 'r') as f:
27+
observed = json.loads(f.read())
28+
return observed
29+
30+
def get_observations(self) -> None:
31+
# Get past observations for all users
32+
self.observedTotal = self.get_obs_from_db()
33+
34+
# Get the observations for the user
35+
url = 'https://api.inaturalist.org/v1/observations'
36+
params = {'user_id': self.user_name, 'per_page': 25, 'order_by': 'observed_on', 'order': 'desc'}
37+
r = requests.get(url, params=params)
38+
39+
newOnes = False
40+
for obs in r.json()['results']:
41+
if str(obs['id']) not in self.observedTotal:
42+
o = self.parse_observation(obs)
43+
if o:
44+
self.observedNew.append(o)
45+
self.observedTotal[str(obs['id'])] = o
46+
newOnes = True
47+
48+
if newOnes:
49+
self.save_obs_to_db()
50+
# if there's a new one, we call the Radix Transaction Manifest to mint the NFT
51+
52+
return None
53+
54+
def parse_observation(self, obs) -> dict:
55+
# Parse the observations for the user
56+
obs_parsed = None
57+
try:
58+
obs_parsed = {
59+
"id": str(obs['id']),
60+
"user_name": self.user_name,
61+
"link": "https://www.inaturalist.org/observations/" + str(obs['id']),
62+
"observed_on": obs["observed_on"],
63+
"species": obs["species_guess"],
64+
"imageUrlSmall": obs["photos"][0]["url"],
65+
"imageUrlLarge": obs["photos"][0]["url"].replace("square", "original")
66+
}
67+
except Exception as e:
68+
print('error parsing observation: ', e, json.dumps(obs, indent=4, sort_keys=True))
69+
pass
70+
return obs_parsed
71+
72+
def get_user_info(self) -> dict:
73+
user_data = requests.get('https://api.inaturalist.org/v1/users/' + self.user_name + '?key=' + api_key).json()
74+
return user_data
75+
76+
def save_obs_to_db(self) -> None:
77+
# write over the file with the new data
78+
with open(os.path.join(script_path, 'observed.json'), 'w') as f:
79+
f.write(json.dumps(self.observedTotal, indent=4, sort_keys=True))
80+
return None
81+
82+
################################
83+
"""
84+
Take a user name and return the observations for that user
85+
Get username as first param from command line
86+
"""
87+
def main():
88+
user = sys.argv[1]
89+
c = iNatty(user)
90+
c.get_observations()
91+
return c.observedNew
92+
93+
################################
94+
if __name__ == '__main__':
95+
main()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Running relay for chiggimps
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# This RTM is called when a new nature experience is added to the database
2+
3+
# Need to get the admin_badge first, so we can show a proof before calling these functions
4+
5+
# Create a proof of a badge on your account.
6+
# The "create_proof" method returns a Proof to the authzone.
7+
# There's an authorization zone that contains the proofs that you create.
8+
CALL_METHOD
9+
ComponentAddress("[your_account_address]") "create_proof"
10+
ResourceAddress("[badge_address]");
11+
12+
CALL_FUNCTION
13+
PackageAddress("...")
14+
"INattyOracle"
15+
"create_nft"
16+
"DATA...";
17+
18+
CALL_FUNCTION
19+
PackageAddress("...")
20+
"INattyOracle"
21+
"update_nft"
22+
"DATA...";
23+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"141000772": {
3+
"id": "141000772",
4+
"imageUrlLarge": "https://inaturalist-open-data.s3.amazonaws.com/photos/241450468/original.jpg",
5+
"imageUrlSmall": "https://inaturalist-open-data.s3.amazonaws.com/photos/241450468/square.jpg",
6+
"link": "https://www.inaturalist.org/observations/141000772",
7+
"observed_on": "2022-10-10",
8+
"species": "Barred Owl",
9+
"user_name": "chiggimps"
10+
},
11+
"141301002": {
12+
"id": "141301002",
13+
"imageUrlLarge": "https://inaturalist-open-data.s3.amazonaws.com/photos/242036633/original.jpg",
14+
"imageUrlSmall": "https://inaturalist-open-data.s3.amazonaws.com/photos/242036633/square.jpg",
15+
"link": "https://www.inaturalist.org/observations/141301002",
16+
"observed_on": "2022-11-06",
17+
"species": null,
18+
"user_name": "chiggimps"
19+
}
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/bin/bash
2+
exec >log.txt 2>&1
3+
4+
# Runs the relay for each registered member
5+
file="dao_members.txt"
6+
# read line by line
7+
while IFS= read -r line
8+
do
9+
echo "Running relay for $line"
10+
# put a sleep time here to avoid rate limiting
11+
sleep 1
12+
python inatty.py $line
13+
done < "$file"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
certifi==2022.9.24
2+
charset-normalizer==2.1.1
3+
idna==3.4
4+
pymongo==4.2.0
5+
python-dotenv==0.21.0
6+
requests==2.28.1
7+
urllib3==1.26.12

0 commit comments

Comments
 (0)