The unofficial Nike CryptoKicks timeline

An ode to the Ethereum Rinkeby testnet

The unofficial Nike CryptoKicks timeline

An ode to the Ethereum Rinkeby testnet

An Intro

With the Ethereum merge being a super duper awesome success, the Rinkeby testnet is being deprecated in October. I thought I would take a moment to go down memory lane and take a look at some of the test transactions I've done on Rinkeby over the years in my learning of how to develop for the Ethereum blockchain. As I was going through them, it got me thinking about my involvement with the beginnings of Nike's CryptoKicks and how Rinkeby really helped me demo it to folks internally.

Below you will find the story behind my journey on creating CryptoKicks and links to the original transactions on the Ethereum Rinkeby testnet.

A Reason to Start

One of my original goals for CryptoKicks was to connect sneakers on the blockchain to combat counterfeiting. I read online somewhere that it was estimated to be about a 5 billion dollar issue and totally worthy of my time. The Nike CEO at the time,  had mentioned in one of his rare all-hand's meetings about wanting to move the company to get closer to the customer. I thought that through Blockchain technology we could do that and provide counterfeit protection for them at the same time.

I was an original investor in Ethereum back at the ICO in 2014, and have been following it closely ever since. All I had at the time was $10 in Bitcoin, and like many of you I wished I'd had more to go ALL in. A family and obligations like food, always take precedence though over foolish things like ICOs.

Even when Ethereum was just a testnet, I was trying to figure out how
to write transactions and smart contracts as the technology fascinated me. I was more of a System Engineer/System Administrator, versus a programmer/coder back then, so hacking at it was pretty hard for me initially. But, I always have a knack for getting things working in technology.

Back to the story, Nike had hired a new CTO who was from banking, and he initially offered a 15 minute one on one for folks willing to chat with him as he was a new leader in the technology Org and wanted to learn about us.

I knew that was my opening to do something great! I was banking on him being from the banking industry and knowing something about blockchains or maybe even Ethereum. I was right he did! The week prior to our meeting, I hacked together a very crude demo to show off what could be done with Ethereum ERC-20 tokens and cheep NFC chips by linking my Waffle Runners to the blockchain (note: this was before ERC-721 existed). He was impressed, and I walked out of the meeting with a LOT of swagger and energy. When do you get to chat with the CTO of a Fortune 500 company like Nike, and blow their minds with bleeding edge tech? Never.

CryptoKittie overlooking sneakers
waffle runners snuggled in their original box

Here is my original Ethereum live transaction date:  10/17/2016 9:37:41 PM

https://etherscan.io/tx/0x62f114e98a434e40a9986ab7a8c68950b18b15149c23970b4c998b9ae58dcc8f

If I recall, the input data 1967044a8a394d72948974b3412882f7 in the transaction below was a serial number or something. I think it was a hash of it? I don't remember the code. The NFC chip triggered an automation on my Android phone, which would open a link on my blog with data pertaining to my Waffle Runners. It was hacky, but it did the job.

Presentation matters more than the tech at this point in the story.

I actually spent real ETH on that demo. ~$12 per ETH back then WOW! Imagine that!

Energized, I then started a Slack channel which later morphed into the "Community of Practice" via guerrilla marketing. We gathered like minded folks and I was teaching on the ways to develop for Ethereum. Sort of like a Blockchain Obi-Wan ;)

Afterwards, I presented the same demo to an internal incubator meeting around Christmas of 2016. I submitted the demo to become a internally registered project in 2017. I initially called it nGen [Nike Genuine] as I thought that would be a nifty name ;)


Blockchain Sneaker Registry (nGen [Nike Genuine])
Encrypted smart tags linked to the Ethereum blockchain to provide an undeniable proof of authenticity for athletic apparel.

Meanwhile over the course of 2017, I continued to meet and teach folks how to work with the Ethereum blockchain, and held sessions for the community of practice. It obviously grew in numbers during the crazy ICO bull run of 2017.

And now, the fun begins...

A improvement proposal for the ERC-721 token was added 9/22/2017
to Ethereum Github [https://github.com/ethereum/EIPs/issues/721]

A test version of CryptoKitties was unveiled at ETH Waterloo on October 19, 2017.

I was completely fascinated with the NFT idea as linking sneakers to ERC-20 tokens wasn't really going to work out in the long run, and so I worked towards figuring out how to link an ERC-721 to a shoe by using my previous work on nGen to create CryptoKicks. The word CryptoKicks was a direct reference to Cryptokitties, but replacing kitties with the colloquial term for shoes, kicks.

Yes, I am that clever guy you all know /s

I remember sitting on the couch and asking my wife if CrypoKicks sounded like a great product name, she agreed it was pretty nifty. It always makes sense to bounce things off of the spouse when making important product decisions.

The official internal CryptoKicks project submission was in March of 2018. My first code commits to the internal code repos were that same month. It was purely a technical proof of concept and there were no images on the web app, just raw text. If you can imagine an HTML page with Bootstrap forms you get the picture, it was pretty rough, but WORKED. It also ran only locally on my laptop.

I showed it to others in Nike Technology as a proof of concept, but
without visuals it really fell flat. I then rebuilt it in ReactJS and used images from KickDraw [ LINK ] to provide a better visual representation for people. One thing I've learned working at Nike is that EVERYTHING is about presentation! That really got the people's brains juicing once I could use the Rinkeby testnet to send them their own personalized sneaker NFT based on the serial of the sneakers they were wearing at the time. I remember the weird looks I would get when I'd ask them for one of their shoes off their feet during a meeting, copy the serial number, and then create the transaction right there in front of them.

The Rinkeby testnet made that possible for me.

Example:

Some of my first Rinkeby interactions were around this time. If you search my dev wallet address on Etherscan, you will find gems like this transaction:

Example from 4/6/2018:
https://rinkeby.etherscan.io/tx/0xd3fb924d20c2bd462df466b279f9c1f7e55ade36289de650758085c0ffa0c602

One of the first transactions had me laughing out loud when I looked back at it while researching my old transactions.

I like turtles in the input data field is how I was testing.

This contract on Rinkeby is the OG working CryptoKicks contract address, and mainly what I used to provide most of the demos:

https://rinkeby.etherscan.io/address/0x90ae128da518af688fb2fa56b65be96219bb1b45

My Waffle Runner's also made it into this new PoC as well [Serial Number: 0000999998]:

https://rinkeby.etherscan.io/tx/0xeb88472913feae6c508a58dc6ba500948eba6f0f7a9240cf429a013805258fea

To prove my dev wallet ownership, here is a mint of NFT token 51 on Sep-19-2022 12:28:44 AM +UTC:

DEAFMICE ROCKS - 9/2022

https://rinkeby.etherscan.io/tx/0xf19e62bf549366690e7ad7e0d8f76fb73c7f4bd028f8726441b82af4955e7ff1

UPDATE: I've switched away from using the Deafmice online persona this month, as I wanted to move in a different direction. You'll notice deafmice.com redirects you to this site, and both the END domains deafmice.eth and funinternetthings.eth point to my hot wallet address.

In a weird twist, Rinkeby is still technically online as of me writing this post. From the stats dashboard it is still producing blocks.

Rinkeby: Network Dashboard

So, I thought that as long as there is an RPC endpoint and I broadcast a transaction using my old dev wallet, I should be able to hopefully write to the chain. I used some old Python code to interact with the old contract.

Oddly enough Ankr still has a RPC endpoint up and running ;)

Build on Eth/eth_rinkeby With Instant RPC Endpoint
Use a fast, reliable & free Eth/eth_rinkeby public RPC endpoint

Unfortunately, Etherscan is no longer looking at Rinkeby data so I cannot show a screenshot, only the output from my code below:

Warning: Python Code! You can skip ahead if not interested. This is only here for future reference.

# app.py

# Connect to Ankr and pull down Block info

import json
import os
from pprint import pprint
from web3 import Web3
from web3.middleware import geth_poa_middleware

# Using Infura as an ETH node
ANKR_URL = os.getenv('ANKR_URL')
# Exported Key from Metamask
PRIVATE_KEY = os.getenv('PRIVATE_KEY')


def main():
    print('Opening connection to the Ether')
    w3 = Web3(Web3.HTTPProvider(ANKR_URL))
    connected = w3.isConnected()
    if connected:
        print(f'We are connected: {connected}')
        print(f'Node Version: {w3.clientVersion}')
    else:
        return print('Not Connected to chain')
    # get Chain name
    chain_id = w3.eth.chainId
    print(chain_id)

    if chain_id == 4 or chain_id == 5:
        # Fix for PoA networks
        print('Enable fix for PoA chains')
        w3.middleware_onion.inject(geth_poa_middleware, layer=0)
    else:
        print('PoW chain, no middleware needed')
    # Get the latest block
    latest_block = w3.eth.blockNumber
    print(f'Latest Block Number: {latest_block}')

    # Get specific block data
    # block_raw_data = w3.eth.getBlock(latest_block)
    # print(f'Latest Block Data:')
    # Convert to dictionary so pprint can handle it nicely
    # block_data = dict(block_raw_data)
    # pprint(block_data)

    # ### Accounts ###
    # Use PRIVATE_KEY for Ether account
    account = w3.eth.account.from_key(PRIVATE_KEY)
    # print(dir(account))
    # Get Account address
    a1_address = account.address
    print(f'Your account address: {a1_address}')
    # Get Balance of your account
    a1_balance_wei = w3.eth.getBalance(a1_address)
    # By default balances are stored in Wei, the smallest unit of Ether
    # We us built in functioality to convert
    a1_balance = w3.fromWei(a1_balance_wei, 'ether')
    print(f'Your account balance: {a1_balance} ETH')

    # ### Contracts ###
    # CryptoKicks Rinkeby ETH address
    contract_address = '0x90AE128da518aF688FB2Fa56b65Be96219bb1b45'
    # CryptoKicks contract compiled ABI
    with open('cryptokicks.json') as f:
        # Get json data
        contract_abi = json.load(f)

    # Get contract
    contract = w3.eth.contract(
        address=contract_address,
        abi=contract_abi
    )
    # Basic Contract details
    contract_name = contract.caller().name()
    print(f'Contract Name: {contract_name}')
    contract_symbol = contract.caller().symbol()
    print(f'Contract Symbol: {contract_symbol}')
    contract_owner = contract.caller().owner()
    print(f'Contract Owner Address: {contract_owner}')

    # Contract Functions Available
    contract_functions = contract.functions
    f = [i for i in contract_functions]
    print(f)

    # Token details
    total_supply = contract.caller().totalSupply()
    print(f'Total Number of Tokens: {total_supply}')
    # Get one token
    token_id = contract.caller().tokenByIndex(0)
    print(f'First Token ID: {token_id}')
    token_uri = contract.caller().tokenURI(token_id)
    print(f'Token URI: {token_uri}')

    # Get last token
    last_token_id = contract.caller().tokenByIndex(total_supply-1)
    print(f'Last Token ID: {last_token_id}')
    last_token_uri = contract.caller().tokenURI(last_token_id)
    print(f'Last Token URI: {last_token_uri}')

    # Create a token
    # Comment this out after tx posted
    # uri = "funinternetthings"
    # tx_dict = contract.functions.createRandomKicks(
    #     uri).buildTransaction(
    #     {
    #         'chainId': chain_id,
    #         'gas': 200000,
    #         'nonce': w3.eth.getTransactionCount(a1_address)
    #     }
    # )
    # print(tx_dict)
    # # Sign the tx from your account
    # signed_tx = w3.eth.account.signTransaction(tx_dict, PRIVATE_KEY)
    # # Send the TX to chain
    # txn_hash = w3.eth.sendRawTransaction(signed_tx.rawTransaction)
    # # This is a blocking function to wait for mined tx
    # txn_receipt = w3.eth.waitForTransactionReceipt(txn_hash)
    # print("Transaction receipt mined:")
    # pprint(dict(txn_receipt))
    # print("\nWas transaction successful?")
    # pprint(txn_receipt["status"])
    # if txn_receipt['status'] == 1:
    #     # We are SUCCESS
    #     print("We are SUCCESS")
    # else:
    #     print("We are FAIL")

    # ### Transaction Data ###
    # Show data from last transaction
    transaction_hash = "0xaaaeff6fb2c6113ab97923764e123fa2bbe3d196e54247a46c9de3e14dae31ea"
    tx_data = w3.eth.getTransaction(transaction_hash=transaction_hash)
    pprint(tx_data)
    # Token Uri is put in tx.input, but needs to be decoded
    input_data = contract.decode_function_input(tx_data.input)
    # get the _uri fro the contract data
    token_uri_data = input_data[1]['_uri']
    print(token_uri_data)

    # TX Events
    # kicksGenerated
    receipt = w3.eth.getTransactionReceipt(transaction_hash)
    logs = contract.events.kicksGenerated().processReceipt(receipt)
    # we emit a user and token ID on creation
    print(f"Owner ID: {logs[0]['args']['_owner']}")
    print(f"CryptoKick ID: {logs[0]['args']['_tokenId']}")

    if logs[0]['args']['_tokenId'] == last_token_id:
        print("Last token matched. TX hash")


if __name__ == '__main__':
    main()
python working_with_blockchain_app.py
Opening connection to the Ether
We are connected: True
Node Version: erigon/2022.08.2/linux-amd64/go1.19
4
Enable fix for PoA chains
Latest Block Number: 11570741
Your account address: 0x06Cdc101B8ceD7b8C9E1c698Ab8141E8f0C7E7F8
Your account balance: 5.82553992165339997 ETH
Contract Name: cryptokicks
Contract Symbol: CKS
Contract Owner Address: 0x06Cdc101B8ceD7b8C9E1c698Ab8141E8f0C7E7F8
['name', 'getApproved', 'approve', 'totalSupply', 'transferFrom', 'tokenOfOwnerByIndex', 'safeTransferFrom', 'exists', 'tokenByIndex', 'ownerOf', 'balanceOf', 'owner', 'symbol', 'setApprovalForAll', 'safeTransferFrom', 'createRandomKicks', 'tokenURI', 'isApprovedForAll', 'transferOwnership']
Total Number of Tokens: 52
First Token ID: 1997670191981520482540801616208235668515393854245661572126051434
Token URI: I like turtles
Last Token ID: 9793235340025502982372092338265704214953601982396031590546089993
Last Token URI: funinternetthings
AttributeDict({'blockHash': HexBytes('0x30d123786bf90ef43c1e2dab1dd59c68ab50902236e840d5c7fe8ba4f53762de'), 'blockNumber': 11570517, 'from': '0x06Cdc101B8ceD7b8C9E1c698Ab8141E8f0C7E7F8', 'gas': 200000, 'gasPrice': 2313278007, 'maxPriorityFeePerGas': 2313278000, 'maxFeePerGas': 2313278014, 'hash': HexBytes('0xaaaeff6fb2c6113ab97923764e123fa2bbe3d196e54247a46c9de3e14dae31ea'), 'input': '0xc7bca7d10000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001166756e696e7465726e65747468696e6773000000000000000000000000000000', 'nonce': 257, 'to': '0x90AE128da518aF688FB2Fa56b65Be96219bb1b45', 'transactionIndex': 10, 'value': 0, 'type': '0x2', 'accessList': [], 'chainId': '0x4', 'v': 0, 'r': HexBytes('0xbc51b4d949228d993357c388bbc0d1b90e15f5422c4af814c3086a387ad91f56'), 's': HexBytes('0x50ec2448311986842015ef0421019f7609c0f34b9048bb34b941476786d7bee6')})
funinternetthings
Owner ID: 0x06Cdc101B8ceD7b8C9E1c698Ab8141E8f0C7E7F8
CryptoKick ID: 9793235340025502982372092338265704214953601982396031590546089993
Last token matched. TX hash

In my testing, I was getting a MismatchedABI error as I think the ABI I am using is very old and outdated, but it worked!

From the code output above you can see that the last token in the contract has the input data of funinternetthings, pretty neat eh? Now back to the fun stuff.

The CryptoKicks Patent

I met a fellow like minded colleague a while back while pitching nGen around to different innovations teams [at Nike it seemed like every org had an innovation team at the time]. He later reached back out to me as he had been thinking of something like a CryptoKicks idea, but more Tamagotchi like. When you have one of the smartest people on the planet on board you have to instantly go ALL in!

He brought the legal folks and myself together to start the formal idea process on what the patent would later become. Honestly, I am pretty sure that without him the whole idea would have died on the vine immediately. We all started chatting and working on it around the Spring of 2018.

Side Quest: Getting Certified as an Ethereum Blockchain Developer

In the Summer of 2018, I went through the Consensys Ethereum Blockchain Certification and my final project may or may not have been pretty dang close to CryptoKitties like some of the other students ;).

My student project idea was to link Bicycles to the blockchain via their serial numbers.

I created this contract for it: 0x4adfFa4BFab2f1b2186b2fD4DFDbf758A20Fa8cb

https://rinkeby.etherscan.io/address/0x4adffa4bfab2f1b2186b2fd4dfdbf758a20fa8cb

I had a Viner Strava Bianca at the time with the serial number was BVC0961604030, so that went in the URI field for input data:

https://rinkeby.etherscan.io/tx/0x674bfa2dc248f0d3dbc210cc9d84e0b57a83095d438879a9e8f96204d6b1eae0

At the office, the tech innovation folks brought together an interesting
internal conference called Nike Blockchain day. Since I had already been
evangelizing blockchain internally I was invited to speak. I gave a presentation on my journey in beating Cancer, working at Nike, and finally at the end gave a working demo of CryptoKicks to a wider audience.

Behind the scenes, the legal folks were pushing the paperwork through and getting the patent speedily routed through the USPTO. I am literally astonished on the timing from when they said they filed, to when it was awarded [seriously amazing work!]. I was expecting to be talking about maybe getting it awarded next year as most folks I had talked with told me to expect about a five year turn around!

In the Fall, I went to the Ethereum DevCon4 in Prague and fell in love with the city of Prague, and the Ethereum developer community. The recent Merge just proves how amazing they are.

In December of 2018, we received a Provisional Patent, meaning it was going to go
through the system, just needed to dot some i's and cross some t's.

During most of the year of 2019, there were lots of meeting and lots of interest
internally about building and releasing an actual working product. It was pretty much a whirlwind that I vaguely remember.

In one of those meetings I do remember as it was pretty surreal, as the folks at
global communications pulled me into a meeting to teach them about Blockchain Technology and "what the heck is an NFT?" and "What the heck is a CryptoKick?" as they knew the patent was going to be awarded soon, and they wanted to get ahead of any story that may arise. That was a such a weird time, teaching people at the highest levels what Blockchain tech is and how it could benefit the company.

We were issued the patent in December of 2019 to a ton of news. Guess that is what happens when a major company jumps in feet first to blockchains. I remember seeing articles from Taiwan, I couldn't read them but my BitMoji was there!

Patent Link:
https://pdfpiw.uspto.gov/.piw?docid=10505726&PageNum=1&&IDKey=DEF6196CEC57&HomeUrl=http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO2%2526Sect2=HITOFF%2526p=1%2526u=%25252Fnetahtml%25252FPTO%25252Fsearch-bool.html%2526r=1%2526f=G%2526l=50%2526co1=AND%2526d=PTXT%2526s1=Nike%2526s2=Crypto%2526OS=Nike%252BAND%252BCrypto%2526RS=Nike%252BAND%252BCrypto

Google Patents link is sometimes easier to read:
https://patents.google.com/patent/US10505726B1/en

Of all the hype and news The Next Web is really the only one that 'Got It.'

Nike now holds patent for blockchain-based sneakers called ‘CryptoKicks’
The US Patent Office has today issued sportswear brand Nike’s patent for its blockchain-compatible sneakers dubbed “CrpytoKicks.”

It was pretty neat seeing my BitMoji plastered all over the news.


All that from a demo created on the Rinkeby testnet.

End the trail.

In January of 2020, we were in meetings and word of a certain novel virus was
ripping through China. Not much to think about right?

We could just kept moving along, and then
it.

all.

shut.

down.    

everything did.

You all know the rest of the story of COVID-19 and how it all played out.

The original CryptoKicks idea and version we were thinking of died during the pandemic. I was told to stop working on CryptoKicks by executive leadership in February of 2020 and have not been involved since. The company has since gone on to purchase RTFKT, and hopefully one day they will be able to realize the dream.

Final Thoughts

Meanwhile, I keep learning more and more about new and exciting Blockchain Technologies. I went through the first 8 weeks of Alchemy's Road to Web3 Blockchain course this Summer, as I felt I needed a developer refresher on Ethereum. I flew through the challenges using Rinkeby and it felt great to be using it again for a limited time, but now I have to move on to the Goerli testnet.

The Ethereum Rinkeby testnet has been good to me and I will miss it, as without it, I really don't believe that my knowledge would be where it is today, and am darn certain CryptoKicks would be something|somewhere else as the idea was always out there, it just needed to be helped to the surface at the right time and right place on the right testnet.

Goodbye Rinkeby, thanks for all the transactions.

If you have any questions or comments, please feel free to reach out to me on Mastodon.

Jeremy

DISCLAIMER

I write these posts only for myself and do not speak for my employer. These are the events as I experienced them, they are accurate as far as I can remember with a few years in between.


AleWi, CC BY-SA 4.0, via Wikimedia Commons
Mastodon