Prior to 2022, Web3 + AI seemed like a far fetched ambitious idea. The Web3 ecosystem was still at a very nascent stage with unsatisfactory UX and scalability bottlenecks. On the other hand, reliable AI models were being developed and battle-tested.
But recently, highly-skilled developers working on these issues have brought to light breakthrough applications of zero-knowledge proofs, modular architecture, WASM execution and appchains to solve the biggest road breaks in mass Web3 adoption. On the flip side, products like ChatGPT and Bard have become essential tools that we didn't know we needed.
This has provided the necessary bandwidth for other to work on a projects where Blockchain and AI can be used in unison. One of the biggest projects in this space is ORA Protocol (previously HyperOracle).
So, if anyone ever asked you to choose between Web3 and AI, you know what to tell them now (*whispers shut the __).
About ORA Protocol
ORA Protocol is the world's first Programmable zkOracle allowing developers to bring AI inference on-chain. ORA breaks down the limitations of smart contracts with richer data sources and compute so developers can innovate freely.
ORA Protocol has 2 primary products:
AI Oracle (OAO, Onchain AI Oracle): Brings the power of AI onchain (this is what we'll be working on today)
ZK Oracle: Brings complex compute and historical data onchain.
Learn more about ORA Protocol here
OAO
Lets talk about ORA Protocol's most recent launch the OAO(Onchain AI Oracle). This is a breakthrough technology leveraging the power opML(Optimistic Machine Learning). This means the result generated by the AI model can be cryptographically proven using a technique called Optimistic Proofs.
OAO namely has 2 modes:
Llama 2: Brings the famous Llama2 model onchain for text-to-text prompts
Stable Diffusion: Allows text-to-image conversion using the Stable Diffusion model.
Personalized Data model: Future implementations will allow developers to bring their own data model for further fine tuning.
Learn more about OAO here
Start Building
We'll be creating a ERC721 Smart Contract using Solidity that can call AI models, generate images and create a NFT (all ONCHAIN!)
As you might have guessed, we'll be using OAO for this.
We'll be developing our smart contract in Remix.ide to make the setup process easier.
Or if you prefer a git repo, the source code is available here
Create a file name OAO.sol (or whatever you like) and use the code below
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
interface IOAO{
function calculateAIResult(uint256 modelId, string calldata prompt) external;
function getAIResult(uint256 modelId, string calldata prompt) external view returns (string memory);
}
contract OAO is ERC721, ERC721URIStorage{
address iOao;
uint256 private _nextTokenId;
string constant ipfsPrepend="https://ipfs.io/ipfs/";
event ONFTMinted(address owner,uint256 tokenId,string tokenURI);
constructor(address _iOao) ERC721("OAONFT", "ONFT"){
iOao=_iOao;
}
function createArt(string memory prompt) public{
IOAO(iOao).calculateAIResult(1,prompt);
}
function fetchIpfsHash(string memory prompt) public view returns(string memory){
string memory ipfsHash = IOAO(iOao).getAIResult(1,prompt);
return ipfsHash;
}
function safeMint(string memory prompt) public{
bytes memory uri = abi.encodePacked(ipfsPrepend,fetchIpfsHash(prompt));
uint256 tokenId = _nextTokenId++;
_safeMint(msg.sender, tokenId);
_setTokenURI(tokenId, string(uri));
tokenId++;
emit ONFTMinted(msg.sender,tokenId,string(uri));
}
function tokenURI(uint256 tokenId)
public
view
override(ERC721, ERC721URIStorage)
returns (string memory)
{
return super.tokenURI(tokenId);
}
function supportsInterface(bytes4 interfaceId)
public
view
override(ERC721, ERC721URIStorage)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
}
Let's go over what's going on in this contract:
We import Open Zeppelin's ERC721 contract. This is a pretty standard step while developing NFT contracts.
We create an interface to define the functions that we will be using from the official OAO contracts by the ORA team. These are simply the functions definitions.
Next we start our contract:
iOao
,_nextTokenId
,ipfsPrepend
are state variables to store the OAO address, current token id and the link prepend respectively.Next we create the constructor, which takes in an address parameter. The ERC721 constructor needs to be initialized as well with
name
andsymbol
values respectively. (feel free to use different values)Now, we create the
createArt
function which takes in any arbitrary input string and passes it to the AI model by OAO. The model configs are as follows:0
: For Llama 21
: For Stable Diffusion
For our purpose, we are only interested with text-to-image hence we hardcode it to
1
The next function is
fetchIpfsHash
which is a read-only function. It fetches the result of the prompt sent to the onchain AI. So, the OAO creates an image from the text and stores the resultant image in IPFS. Hence, this function will return an IPFS hash.The previous function returns only the content hash of the image; eg:
QmaD2WSUGxouY6yTnbfGoX2sezN6QktUriCczDTPbzhC9j
.Unfortunately, we cannot view the image if we put this into the search bar. We need to prepend it with some other sections as well. In this case,https://ipfs.io/ipfs/
,which is what we store in the variableipfsPrepend
. When concatenating, it forms the entire link:
https://ipfs.io/ipfs/QmaD2WSUGxouY6yTnbfGoX2sezN6QktUriCczDTPbzhC9j
Now, the main function called
safeMint
,this will retrieve the result fromfetchIpfsHash
,create and mint an NFT out of it.The other two functions called,
tokenURI
andsupportsInterface
are something you need to write everytime for an ERC721 contract.(no need to worry about these two)
Once you've understood the code, compile it using ctrl + S
and then lets deploy it.
Go to the deploy
tab, and make sure your contract is selected under the contract option is the side panel. Under the development
option select Injected Provider- Metamask and log in to your account when asked to. Make sure it is a dev account. Do not use an account with real funds in it. Next, get some test Sepolia ETH and fund your wallet.
Next to the deploy button, we'll need to put in the address of the OAO contract since we require it in the constructor. Use this address:
0xb880D47D3894D99157B52A7F869aB3B1E2D4349d
Hit DEPLOY
After some time you'll get a confirmation and you'll be able to interact with the contract from the browser itself.
This is how it should look like. Use the createArt
function and enter the prompt you want to generate. It can literally be anything (I used "cyberpunk style Madara Uchiha standing at the top of a tower in Tokyo").
Once that function executes, next select safeMint
and pass in the exact same prompt. After a while, it'll generate the NFT. You can go to the tokenURI
function and pass in your token id(0 if its your first transaction). That will spit out the complete IPFS link and you can view your onchain AI image.
If you're wondering why you cannot view the image in a NFT marketplace like Opensea, thats because this is just a bare bone basic NFT which doesn't follow Opensea's metadata standards. But the point of this was to teach you how to embed prompt-to-text in your smart contracts itself. You can learn how to create a proper structured JSON metadata in IPFS, upload the generated image there and use that as your NFT. Here's a link to Opensea's standards
Read more about the prospect of Blockchain X AI by the founder of Ethereum, Vitalik Buterin
https://vitalik.eth.limo/general/2024/01/30/cryptoai.html
That’s it for this post. I hope you have a better understanding on how to use AI with Web3
For more informative posts, follow me on Twitter
Thank you for reading 🎉