The Token Negotiator (Brand Connector) is a new technology product within Smart Token Labs TokenScript framework. Delivered as an open-source NPM package to provide on and off-chain token attestations into any website.
https://www.npmjs.com/package/@tokenscript/token-negotiator
The goal of this article is to show you how to integrate the library into a website for building your first tokenized web app (TAPP - which we have coined internally at this time). In this walkthrough, we will use the popular library React to demonstrate how to connect tokens to any web experience.
To ensure you get the most from this article let’s cover some initial definitions and terminology used in a Q & A format.
All tokens described in this article refer to an NFT (non-fungible tokens found on a blockchain) or a cryptographically created non-fungible token (held in device memory, email or web storage).
These types of tokens can represent anything in a digital format such as a car key, a concert ticket, piece of art or your identity. However, there are many possibilities still to be discovered.
The tokenized web is an evolutionary idea where the use of tokens drives the user experience.
Attestation is evidence or proof of something. For example, you show a valid passport and flight ticket at the airport to prove you are eligible to fly. The same idea can be applied to the tokenized web, where token ownership rights can be attested against to do something in return.
Traditional web services (commonly referred to as Web 2.0) provide various ways to accomplish tasks that can be done with tokens (gated experiences, creation of a proof that can be used across different domains), however, what we will disclose in this article will open your imagination to a new paradigm that has more possibilities and capabilities than the web we know today.
The Tokenized web is a fairly new concept where there is much to learn and build in this space to understand its full capability and risks of using this technology.
To date, we have found little risk to using tokens for users who keep their credentials safe and for businesses that apply suitable solutions to their needs.
First install a new instance of a React App, with the following command.
npx create-react-app my-app
Once complete change the directory.
cd my-app
Then
npm run start
Where you should now see the following.
Let’s next install the Token Negotiator (Brand Connector) with the following command.
npm i @tokenscript/token-negotiator
Once installed, we can work towards loading some tokens into the page. Next, create a script inside your directory called “tokenContextProvider.js” as shown in the application directory below.
Inside this file, we are going to configure the library implementing this via Reacts ContextProvider API which will provide the tokens via props to components.
Inside the newly created file add the following.
import React, { createContext, useState, useEffect } from 'react';
import { Client } from '@tokenscript/token-negotiator';
import "@tokenscript/token-negotiator/dist/theme/style.css";
const TokenContext = createContext({
tokens: []
});
let negotiator;
const TokenContextProvider = (props) => {
const [tokens, setTokens] = useState([]);
useEffect(() => {
negotiator.on("tokens-selected", (tokens) => {
let selectedTokensState = [];
const { selectedTokens } = tokens;
if(selectedTokens["demo-tokens"].tokens) {
selectedTokensState.push(...selectedTokens["demo-tokens"].tokens);
}
setTokens(selectedTokensState);
});
}, []);
return (
<TokenNegotiatorInstance render={({ negotiator }) => (
<TokenContext.Provider props={negotiator} value={{ tokens, negotiator }}>
{props.children}
</TokenContext.Provider>
)} />
)
}
class TokenNegotiatorInstance extends React.Component {
constructor(props) {
super(props);
if(negotiator) return;
negotiator = new Client({
type: 'active',
issuers: [
{ collectionID: "demo-tokens", contract: '0x26472AA24D795AbcB687bddb44d733ef55Ebdf09', chain: 'Rinkeby' }
],
options: {
overlay: {
openingHeading: "Open a new world of discounts available with your tokens.",
issuerHeading: "Discount with your tokens",
repeatAction: "try again",
theme: "light",
position: "bottom-right"
}
},
filter: {}
});
negotiator.negotiate();
}
render() {
return this.props.render({ negotiator: negotiator })
};
}
export { TokenContext, TokenContextProvider }
Change the contract address ’0x264...’ and chain ‘rinkeby’ to match the smart contract address and location of an NFT you own. If you don’t own an NFT there are many ways to mint them on a test net, with and without code with platforms such as OpenSea.
issuers: [
{
collectionID: "demo-tokens",
contract: '0x26472AA24D795AbcB687bddb44d733ef55Ebdf09',
chain: 'rinkeby'
}
]
Once you have an NFT and you’ve configured the Token Negotiator, let’s next add four changes to enable the library to read user tokens.
Next, inside the “App.js” include the following changes. This connects the library and injects a token overlay component into the class element “overlay-tn”.
import { TokenContextProvider } from './TokenContextProvider';
import StoreFront from './StoreFront';
const App = () => {
return (
<TokenContextProvider>
<>
<StoreFront />
<div className="overlay-tn"></div>
</>
</TokenContextProvider>
)
}
export default App;
Then create a new component called “StoreFront.js” which is made to show a list of products for sale.
import React, { useContext } from 'react';
import StoreItem from "./StoreItem";
import { TokenContext } from "./TokenContextProvider";
export default function StoreFront() {
const { tokens } = useContext(TokenContext);
const mockStoreFrontItems = [
{ size: "140px", price: 200, src: "https://picsum.photos/id/100/200/300", title: "Lorem" },
{ size: "90px", price: 150, src: "https://picsum.photos/id/200/200/300", title: "Aliqua" },
{ size: "170px", price: 400, src: "https://picsum.photos/id/300/200/300", title: "Adipiscing" },
{ size: "120px", price: 300, src: "https://picsum.photos/id/400/200/300", title: "Sit" },
{ size: "100px", price: 600, src: "https://picsum.photos/id/500/200/300", title: "Exercitation" },
{ size: "110px", price: 300, src: "https://picsum.photos/id/600/200/300", title: "Consectetur" },
];
const tokenSelected = tokens.length > 0;
const storeWideDiscount = tokenSelected ? 0.9 : undefined;
return (
<div>
<h1 style={{ textAlign: "center", marginTop: "38px", fontSize: "24px" }}>
The Art Gallery
</h1>
<h2 style={{ textAlign: "center", marginTop: "38px", fontSize: "16px", margin: 0, fontWeight: 400 }}>
Discover original paintings & artwork in our beautiful online collection.
</h2>
<div style={{ display: 'flex', flexFlow: "row wrap", justifyContent: "center", margin: "20px" }}>
{mockStoreFrontItems.map((item, index) => {
return <StoreItem key={index} discount={ storeWideDiscount } item={item} />;
})}
</div>
</div>
);
}
Lastly, create a new component called “StoreItem.js” which will display data about each store product.
export default function StoreItem({ item, discount }) {
const { price, title, src, size } = item;
const itemPrice = discount ? (price * discount).toFixed(2) : price;
return (
<div style={{ textAlign: "center", margin: "20px" }}>
<p style={{ fontWeight: "800" }}>{title}</p>
<img style={{ border: "4px solid black", width: size }} src={src} />
<div>Price: ${itemPrice}</div>
{ discount &&
<span style={{ textDecoration: "line-through" }}> ${price} </span>
}
</div>
);
}
Configuration Step: Based on Create-React-App / webpack 5 changes. Or jump ahead with the finished version we made earlier.
In Webpack version 5, they stopped providing Node.js profiles by default and now ask that developers import which of them they need. This has impacted many projects including Create-React-App, however, there is a solution below to fix this.
https://www.alchemy.com/blog/how-to-polyfill-node-core-modules-in-webpack-5
Alternatively, if you want to jump ahead without completing this step you can find the completed example code here.
Great job, now this has been configured we can test the example application. You should now see the following display when serving the application.
From within the project directory, on the command line run
npm run start
In this guide, we’ve shown how to install the Token Negotiator (Brand Connector) within a React JS project. This enables owners of a specific NFT collection to enable a discount.
We hope this article has inspired you, where there are endless possibilities of what can be done with tokens using the TokenScript framework.
“TokenScript will set a new standard for token composability in a Web3 future where tokens are as ubiquitous as web pages, and where tokens will become primary objects of ownership, identity, and interaction.” ~ Weiwu CTO
Our passion is to build open-source technologies toward building a better web for everyone.
Please share any feedback and thoughts below. We will soon follow up with another article to explain the use of off-chain tokens, which are cryptographically designed without the requirement of using a blockchain.
Smart Token Labs - https://smarttokenlabs.com/
Token Negotiator - https://www.npmjs.com/package/@tokenscript/token-negotiator
Examples - https://tokenscript.github.io/token-negotiator-gh-pages/
TokenScript - https://tokenscript.org/
Twitter - https://www.twitter.com/tokenscript
Attestation Working Group Discord - https://discord.gg/jgGTX99s