DEV Community

Cover image for I found out the NFT police is real, so I made a bot and I'll tell you how to
Choudhry
Choudhry

Posted on • Updated on

I found out the NFT police is real, so I made a bot and I'll tell you how to

12/02/2022 UPDATE I took down the bot it was fun while it lasted. I'll leave the article up for the memes and jokes.

I will explain how I built this Twitter bot freenftbot, but first allow me to have to floor to tell you how I got here. Like all good internet stories it started with a meme.

After seeing this meme I went down the rabbit hole and in a shocking turn of events. These scammy influencers got people on Twitter attacking people for using jpgs they don't own the NFT of.

So I thought it's time to take a stand against the cringe mining, pixelated dildo jpg having, virtual hypebeasts. It's time to use my unique set of skills and terrible prioritization of time and build a Twitter bot.

So you might be asking what does the bot do?

It's simple you follow the instructions here: (I have screenshots of people failing this)
Image "Bot tweet" And Profit xD:
Image "NFT bro reply"


How I did it and you can too

To be clear I'm going going to give tips around places I got stuck and skip the straight forward parts or easy to google parts.

Perquisites

  • Some python skills
  • Twitter developer access for the API get it and apply for ELEVATED access so you get access to the V1 API because V2 doesn't have media upload yet. here (I create a separate account for my bot. I would say do that too, but live your life Queen)
  • Set up Google cloud project if you haven't used your free tier look into it. I'll explain parts of it, but google is your friend.
  • Some NFT images I grabed this kaggle dataset

To kick off these are my global scope variables

import tweepy
import config # I put secrets and tokens here
# client is the V2 API
client = tweepy.Client(
    bearer_token=config.BEARER_TOKEN,
    consumer_key=config.KEY,
    consumer_secret=config.SECRET,
    access_token=config.ACCESS_TOKEN,
    access_token_secret=config.ACCESS_TOKEN_SECRET,
)

# api is the V1 API
auth = tweepy.OAuthHandler(config.KEY, config.SECRET)
auth.set_access_token(config.ACCESS_TOKEN, config.ACCESS_TOKEN_SECRET)
api = tweepy.API(auth)

os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "<google service account key json>"
storage_client = storage.Client("<google cloud project>")
bucket = storage_client.bucket("<google storage bucket>")  # where all the NFT images are
Enter fullscreen mode Exit fullscreen mode


The documentation is actually really good here

One neat thing about google cloud functions, if the environment hasn't been deleted it'll reuse this variables so they won't be re-assigned every run. Smaller carbon footprint. #OurPlanet

Now how do you get all mentions from the last 5 minutes?
client.get_users_mentions(id=ID, start_time=<time 5 mins ago>)
now do it again, but handle pagination

def get_nft_mentions(start_time, max=100):
    nft_tweets = set() # avoid duplicates
    response = client.get_users_mentions(id=ID, max_results=max, start_time=start_time)
    next_token = True
    while next_token:
        tweets = response.data
        if tweets != None:
            for tweet in tweets:
                if does_text_have_hashtag(tweet.text) and is_following(tweet.author_id):
                    nft_tweets.add(tweet)
        if "next_token" in response.meta:
            response = response = client.get_users_mentions(
                id=ID,
                max_results=max,
                tweet_fields=["author_id"],
                start_time=start_time,
                pagination_token=response.meta["next_token"],
            )
        else:
            next_token = False
    return nft_tweets
Enter fullscreen mode Exit fullscreen mode

We have a set of tweets to loop over. We just need to grab a random NFT from our bucket that's easy using our neatfy csv file of all of our NFTs we got with the images and some pandas:

def download_file(file_name):
    destination_file = "/tmp/" + file_name # You can use tmp in cloud function for tmp files just like the NFT images for this
    blob = bucket.blob(file_name)
    blob.download_to_filename(destination_file)
    return destination_file

def pick_nft(nft_frame):
    nft_row = nft_frame.sample(n=1)
    nft_hash = nft_row["IPFS HASH"].iloc[0]
    nft_file = download_file(f"{nft_hash}.jpg")
    return nft_file, nft_row["INITIAL SEQUENCE INDEX"].iloc[0]


def get_media_id(nft):
    return api.simple_upload(nft).media_id_string # Remember api. uses the V1 API client. uses the V2 API. V2 doesn't have media upload (yet)
Enter fullscreen mode Exit fullscreen mode

So we have a tweet to reply to and a image uploaded ready to reply with.
Image ppap(dead meme lol)

def reply_with_nft(tweet, media_id):
    return client.create_tweet(in_reply_to_tweet_id=tweet.id, media_ids=[media_id])
Enter fullscreen mode Exit fullscreen mode

put it all together in a main function

def main(request): # Need a parameter for cloud functions
    csv_file = download_file("hashes.csv")
    nft_frame = pd.read_csv(csv_file)
    tweets = get_nft_mentions(get_time_five_mins_ago())

    errors = []
    for tweet in tweets:
        # chosen NFT and upload it
        nft_path, nft_index = pick_nft(nft_frame)
        media_id = get_media_id(nft_path)

        # reply to tweet
        response = reply_with_nft(tweet, media_id)

        # if response is clean all user to cd file and remove nft
        if len(response.errors) == 0:
            nft_frame.drop(nft_index, axis=0, inplace=True)
        else:
            print(response.errors)
            errors.append(response.errors)

        nft_frame.to_csv(csv_file, index=False)
        upload_file(csv_file)

    if len(errors) >= 0: 
        return "There's some problems boss" # you need a return statement for cloud functions
    else:
        return "all good"
Enter fullscreen mode Exit fullscreen mode

AND THERE YOU HAVE IT! it's not the prettiest cloud function, but it's a valid cloud function. We set the bar at "it works kinda" around here. Now the one I have in production had a few extra bells and whistles, but let's not get caught up with the devil in the details.

The Power of the cloud

First we need a cloud function. You can work it out! I believe in you. Well I don't know you, so I don't, but try anyways. There's a few things I can give you tips on.

Cloud Function Tips:

  • uncheck "Require HTTPS" is just causes issues I couldn't get it work, but good luck if you want it.
  • If you choose to upload your project through zip the main file needs to be in the root of the zip file.
  • Under "Runtime, build, connections and security settings" the time out is defaulted to 60 seconds there's a max of 540 seconds.
  • Error messages are found under the details tab.

If all goes well and you have a green tick. We now have:

But how do we use it? For this case I used Cloud Scheduler!

Pick a time frequency. Under "Configure the execution" Target Type is HTTP URL you get that from the cloud function then add a "OIDC TOKEN" under Auth Header for the Audience use the HTTP URL again (I don't get it either) and hit the blue button and hope for the best.

Tips if it fails:

  • If the error is "internal" check your cloud function logs.
  • If the error is "Permission Denied" your service account permissions are fried. - Confucius (art of war)

Thanks you for reading I hope I made you laugh because God help you if you found me helpful. If you have nothing else better to do go follow me on twitter @itsChoudhry

Lastly I would like to give credit to a Twitter friend who said "Building a twitter bots is fun" - Talal check out his bots FriendCircleBot and WordCloudBot

Top comments (0)