NFT Billboard Example
Create Your Own NFT Billboard with User Data
Build an NFT Billboard with Superfluid UserData
In this tutorial, we make a small tweak to the contracts used in the TradeableCashflow Super App to test out Superfluid's userData parameters. We set up a Scaffold-eth based repo, remove (comment out) some of the extra front end stuff, and then create a few scripts to allow us to easily create, read, update, and delete flows (we love CRUD).
NOTE: We recommend reading through our Super Apps tutorial before completing this tutorial.
Our dapp will turn the TradeableCashflow into a tradeable NFT billboard that can be rented with streams. The message displayed on our billboard will be the parameter passed in as userData. If the billboard is traded, all rental cashflows will be redirected toward the new owner.

You can follow along with the video version of this tutorial on Youtube, and fork the repo here as well:
Before we get started with project setup, you'll also want to head over to the Superfluid Dashboard to claim testnet Super DAI (fDAIx) in at least one account on the network you'd like to use for the tutorial (I would suggest claiming these tokens on Mumbai, the Matic Testnet). To claim test DAI, you can head to the currencies tab in the dashboard and click the plus button on the far right in the DAI row to get your hands on some test Super DAIx.


You'll want to have 2 Ethereum addresses ready: one of which you'll need your private key for (that has our test tokens), the other which we'll just be observing.
Scaffold-Eth and Hardhat Configuration


You'll want to create a new .env file and put this URL there - in my case I've called it MUMBAI_ALCHEMY_URL.
I've also gotten the private key associated with the address I'll be using to deploy contracts and create flows. I've set this as an environment variable as well called MUMBAI_DEPLOYER_PRIV_KEY.
NOTE: be VERY careful with your private keys. Do not push them to github or share them publicly. If you need help locating your keys within metamask, you can click on 'Account Details' in the menu and enter your password to 'Export Private Key.'
The standard hardhat.config file will have quite a few network options to choose from. However, in our case, I need to change my default network to "polytest," and include my Alchemy URL and keys under 'accounts' so that hardhat can use my account as a signer when deploying contracts.
Note: if you choose to use a different testnet, you'll need to change the default network to network you wish to use.
Next, scroll down to 'polytest' in the list of potential networks that Scaffold-eth lists in hardhat.config. Add in your URL from Alchemy in 'url' and your private key in 'accounts.' Note: you'll need to prepend '0x' onto your private key. Again - these should be saved as environment variables - don't openly share your private key!
Note: if you choose to use a different testnet, you'll need to add this data for the network you wish to use (i.e. goerli, ropsten, etc.)
Finally, we need to adjust our solidity compiler so that it's compatible with our project.
Contracts
Next, we'll add in our two key contracts: RedirectAll.sol and TradeableCashflow.sol. As I mentioned, these are very similar to the example in our SuperApps tutorial, but with a few small changes to the RedirectAll.sol contract:
1) We need to add variables which will store the incoming context and userData within the callbacks
2) We'll add new logic at the bottom of each callback:
Inside of the afterAgreementCreated callback:
Inside of the afterAgreementUpdated callback:
Inside of the afterAgreementTerminated callback:
This logic will take in the message passed in as userData to calls made to the constant flow agreement which target the flow into this app, decode it, and set it to a storage variable so that we can very easily see what's going on throughout this process. Feel free to make this code your own and do your own gas optimization as you see fit π
Contract Deployment
Scaffold-eth makes contract deployment easy: we simply need to use the already installed hardhat plugin, hardhat-deploy, to run our deployments. Each time we want to deploy a new NFT billboard contract, we can simply run yarn deploy to do so.
Inside of the already created deploy folder from Scaffold-eth, we'll pass in a few key addresses from the superfluid protocol as variables, and use them to write a deployment script for our Tradeable Cashflow (NFT billboard) contract.
We get the addresses for host, cfa, and fDAIx from the Superfluid network directory. If you want to deploy to a different testnet, you'll need to make adjustments here.
Next, we'll need to add a deployment script for our TradeableCashflow.sol contract. Remember, TradeableCashflow.sol inherits from RedirectAll.sol, so we only need to deploy the single NFT contract.
We'll use the function getNamedAccounts() to get our deployer address. Because we included our account in the 'accounts' property in 'polytest' within hardhat.config, we'll get our address first when calling that function.
We can then deploy our contract fromm that address, and pass in the necessary parameters to the constructor of the TradeableCashflow contract (owner, name, symbol, host, cfa, acceptedToken).
Hardhat Scripts For Flow CRUD Functionality
Then, in the bulk of our createFlow, updateFlow, and deleteFlow scripts, we'll create contract objects, define a web3 provider, and submit our call using the pattern outlined in Alchemy's docs on submitting transactions with web3.js.
Updating a flow is almost identical, but with a change in the userData and flowRate parameters:
Our delete flow script has 2 key differences: there is no flowrate passed in, and no userData either. We set the value of userData inside of our contract back to an empty string when an agreement is terminated.
Finally, we'll also create a script which helps us read on chain data that corresponds to our flow. This will allow us to see what Context looks like when passed around within the protocol, and it allows us to see what userData looks like when appended onto it as a bytes value. Once we can identify its place in the Context struct, we just need to decode it to make use of it.
A sample output from readData.js:
If you want, you can also check out the Superfluid dashboard to see these flows being created in real time (you just can't see the userData there)!
The Front End - Displaying our Billboard
In this repository, you'll see that you have many of the other components and UI elements from scaffold-eth still there. We left them there to give you the opportunity to continue tinkering with the rest of the framework if you choose to. However, to display our NFT Billboard, we'll need to make a few changes.
First, within the views folder, we'll make a copy of the 'ExampleUI.jsx' file called 'NFTBillboard.jsx' and make a few changes.
We'll add message and billboardOwner to our list of exports, and remove some of the items from ExampleUI:
And we'll also change the content our function component returns to reflect our data:
If you peer into the original 'ExampleUI.jsx' file, you'll see that we removed a great deal of content. All that's left is the top section and an Address component where we'll display our content's address. Again - you're welcome to utilize the other front end content if you'd like in your own applications π
Next, we need to add our NFTBillboard component to our App.jsx file, and make sure that we have logic that will read the message (i.e. userData) and owner of our billboard (the _receiver we pass in when we deployed our contract).
At the top of our file, we'll import the component
We'll then need to make sure that our react app is reading data from the right network. To do this, we'll need to make a change to targetNetwork . In our case, we'll set the network to NETWORKS.mumbai - but if you're using a different network, you'll need to specify that here.
To get the values for the billboard owner and message, we'll need to use the useContractReader hook that's included in scaffold-eth from eth-hooks. You can read more about eth-hooks here.
The scaffold-eth framework already defines a helpful readContracts variable that we can pass to useContractReader which will allow us to read data from our deployed contracts. If you want to create new contracts that you can write to, you'll use the writeContracts variable instead.
We can set our message and billboardOwner variables like this:
Finally, we'll include our NFTBillboard component in our body, and set the "/" route to render our billboard component.
You'll notice that much of the body in App.jsx is commented out. If you're curious about what the other elements do, feel free to uncomment them and play around.
There you have it! You can run yarn start to run your react app locally, then yarn deploy on your contracts to see things render! To send your message, you can call createFlow to see the message appear on your billboard in real time.
I would also recommend opening up the superfluid dashboard to see how flows are moving into and out of your NFT contract. In the account you're using to deploy the contract, you'll see that you have a flow created into the contract.
Then, if you look at the account you used for the owner of the tradeable cashflow (i.e. billboard) contract, you'll see that you have an incoming stream from the contract itself.
Last updated
Was this helpful?

