Home

Blog

How to Integrate Brydge into an NFT Minting dApp

How to Integrate Brydge into an NFT Minting dApp

June 1, 2022

We at Brydge are strong believers in crypto’s multichain future. We’ll need to make substantial progress in UX to make that a reality. Direct-to-dApp (D2D) is a massive step in this direction.

D2D enables dApps to deploy on one chain and instantly accept any token from the rest.

Let’s say you’re a NFT ticketing provider deployed on Polygon. You chose Polygon because fees are low. And USDC for stability.

The trouble is, Ethereum has ~30x the asset value that Polygon does. So, odds are that your customers will start on Ethereum, bridge tokens to Polygon, wait a bit, swap into USDC, then buy a ticket. Ouch. Imagine explaining how a bridge or a DEX works to your parents? They’re probably headed back to Ticketmaster and happily paying the 35% premium.

Brydge enables you to accept payment in any token from any chain. So, your users can buy your NFTs using Ethereum ETH. Or Ethereum USDC. Or Polygon AAVE. Or thousands of other tokens from (soon) to be every chain. In 1 click. So simple, your parents could do it!

Integrating is also super simple and requires no contract redeployments. This tutorial will get you up and running accepting thousands of tokens from a variety of chains within 30 minutes!

Let’s get started!

The starter code we’ll use is found here. If you’re starting from scratch, learn how to build a full stack minting app here. You can easily retrofit this to your specific use case.

If you want to hop straight to the end, the finished code can be found

If you’re using our example, we have a little housekeeping to do to get up and running. If you already have a dApp up and running, skip this section.

Getting our NFT minting dApp prepared

Create an .env in root folder with and fill in the following info. Make sure to use a private key from a separate dev wallet!

PRIVATE_KEY = ""

WEB3_INFURA_PROJECT_ID=''

ETHERSCAN_CONTRACT_ADDR=''

PINATA_API_KEY=''

PINATA_API_SECRET=''

Then, run the following commands in terminal to get your environment set up. Note: the following commands deploy on Polygon mainnet which will cost real MATIC to deploy.

Get some for free at the Polygon faucet.
//below to be run in root folder (full-stack-nft-mint-tutorial branch=finished-code)

brownie compile

brownie run scripts/deploy_nft.py --network polygon-main

brownie run scripts/create_collection_data.py --network polygon-main

Next, drop your deployed NFT address that your console outputs into /client/config.js so you can interact with your contract from our front end.

This gets us going with a full stack NFT minting dApp. Mint one and check out Polygonscan!

Our Preferred Front-End Setup

We prefer ethers.js and useDapp to handle our providers. Just ethers.js by itself or Web3.js also work!

If you’re using our starter code, running an “npm install” in /client will install all dependencies. If not, install ethers.js and useDapp via npm or yarn, then read on!

First, let’s import a couple objects from useDapp and ethers. Then, let’s wrap our site in our useDapp provider. Our app.js will look like this when done:
//app.js
import '../styles/globals.css'
import { DAppProvider, Mainnet } from '@usedapp/core';
import { getDefaultProvider } from 'ethers'

function MyApp({ Component, pageProps }) {

const config = {
readOnlyChainId: Mainnet.chainId,
readOnlyUrls: {
[Mainnet.chainId]: getDefaultProvider('mainnet'),
},
};
return(
<DAppProvider config={config}>
<Component {...pageProps} />
</DAppProvider>
)
}

export default MyApp

Next, let’s head to our index.js. Right now, this is a standard NFT minting UI which accepts one token (MATIC) from one chain (Polygon). We’re about to take this up a few notches.


Let’s import the Brydge package. Run the following in your front end folder:

npm i @brydge-network/widget

Then import the package at the top of index.js:

//index.js
import { BrydgeWidget } from '@brydge-network/widget'

And paste the below component into your site:

<BrydgeWidget
jsonRpcEndpoints={{
1: 'https://mainnet.infura.io/v3/{your_infura_key}',
137: 'https://polygon-mainnet.infura.io/v3/{your_infura_key}',
}}
calls={}
provider={}
defaultOutputTokenAddress=''
defaultOutputAmount={}
title='' destinationChainId={}
/>

Seems that we have some blanks to fill in! You can find a full list of optional props and customizations available here. For now, we’ll focus on the required props. See how we’ve filled our widget out here:

//index.js
import { BrydgeWidget } from '@brydge-network/widget'
import { useEthers } from '@usedapp/core'

const MintableNFT = () => {
const { library } = useEthers()
const ifOfNFTToBuy = 3
return(
<BrydgwWidget
jsonRpcEndpoints={{
1: 'https://mainnet.infura.io/v3/{your_infura_key}',
137: 'https://polygon-mainnet.infura.io/v3/{your_infura_key}',
}}
calls={encodedCalls(ifOfNFTToBuy)}
provider={library}
defaultOutputTokenAddress='NATIVE'
defaultOutputAmount={0.001}
title='Mint Brydge Tutorial NFT'
destinationChainId={137}
/>
)
}
export default MintableNFT

Most of the above props are straightforwardly explained here. Calls is a bit trickier. Let’s see how encoding our calls works.

//index.js
import NFT from '../../build/contracts/BrydgeCollection.json'
import uriList from '../../metadata/data.json'
import { nftContractAddress } from '../config.js'

//...

function encodedCalls(nftId){
const mintPrice = ethers.utils.parseEther("0.001")
const nftUri = uriList[nftId]
const mintableContract = NFT.abi
const mintableContractInterface = new ethers.utils.Interface(mintableContract);
const mintableContractCalldata = mintableContractInterface.encodeFunctionData('mintBrydgeNFT', [nftUri]);
const calls = [
{ _to: nftContractAddress, _value: mintPrice, _calldata: mintableContractCalldata
},
]
return calls
}
//

We start by importing our NFT contract ABI, URI list, and nftContract address. All of these were generated when we compiled and deployed our contracts to the Polygon blockchain.

Next, since our contract requires payment of 0.001 MATIC to mint, we set mintPrice = 0.001.

We then grab the URI of the NFT we want to mint.

Then, we create an Interface from our contract’s ABI, and encode the function we want to call + the data it requires.

For the above example, we’re calling mintBrydgeNFT() and passing in nftUri.

And finally, we bundle our nftContract address, native token cost, and calldata into a returned object.

At the end, our index.js will look like this:

//index.js
import { useState } from 'react'
import { nftContractAddress } from '../config.js'
import { ethers } from 'ethers'
import { useEthers } from '@usedapp/core'
import { BrydgeWidget } from '@brydge-network/widget'

import NFT from '../../build/contracts/BrydgeCollection.json'
import uriList from '../../metadata/data.json'

const MintPage = () => {
const [mintedNFT, setMintedNFT] = useState(null)
const [miningStatus, setMiningStatus] = useState(null)
const [currentAccount, setCurrentAccount] = useState('')
const { library } = useEthers() const idOfNFTToBuy = 3

function encodedCalls(nftId){
const mintableContract = NFT.abi
const mintableContractInterface = new ethers.utils.Interface(mintableContract);
const mintPrice = ethers.utils.parseEther("0.001")
const nftUri = uriList[nftId]
const mintableContractCalldata = mintableContractInterface.encodeFunctionData('mintBrydgeNFT', [nftUri]);
const calls = [
{ _to: nftContractAddress, _value: mintPrice, _calldata: mintableContractCalldata
},
];
return calls

}
// Calls Metamask to connect wallet on clicking Connect Wallet button
const connectWallet = async () => {
try {
const { ethereum } = window

if (!ethereum) {
console.log('Metamask not detected')
return
}
let chainId = await ethereum.request({ method: 'eth_chainId' })
console.log('Connected to chain:' + chainId)

const rinkebyChainId = '0x4'
const polygonChainId = '0x89'
const ethereumChainId = '0x1'

const devChainId = 1337
const localhostChainId = `0x${Number(devChainId).toString(16)}`

if (chainId !== rinkebyChainId && chainId !== localhostChainId && chainId !== polygonChainId && chainId !== ethereumChainId) {
alert('You are not connected to the Rinkeby Testnet or Polygon Mainnet!')
return
}


const accounts = await ethereum.request({ method: 'eth_requestAccounts' })
console.log('Found account', accounts[0])
setCurrentAccount(accounts[0])
}catch (error) {
console.log('Error connecting to metamask', error)
}
}
return (
<div className='flex flex-col items-center pt-32 bg-[#0B132B] text-[#d3d3d3] min-h-screen'>
<div className='trasition hover:rotate-180 hover:scale-105 transition duration-500 ease-in-out'>
<svg xmlns='http://www.w3.org/2000/svg' width='60' height='60' fill='currentColor' viewBox='0 0 16 16' >
<path d='M8.186 1.113a.5.5 0 0 0-.372 0L1.846 3.5 8 5.961 14.154 3.5 8.186 1.113zM15 4.239l-6.5 2.6v7.922l6.5-2.6V4.24zM7.5 14.762V6.838L1 4.239v7.923l6.5 2.6zM7.443.184a1.5 1.5 0 0 1 1.114 0l7.129 2.852A.5.5 0 0 1 16 3.5v8.662a1 1 0 0 1-.629.928l-7.185 2.874a.5.5 0 0 1-.372 0L.63 13.09a1 1 0 0 1-.63-.928V3.5a.5.5 0 0 1 .314-.464L7.443.184z' />
</svg>
</div>
<h2 className='text-3xl font-bold mb-20 mt-12'> Mint Brydge NFT </h2>
{currentAccount === '' ? (
<button className='text-2xl font-bold py-3 px-12 bg-black shadow-lg shadow- [#6FFFE9] rounded-lg mb-10 hover:scale-105 transition duration-500 ease-in-out' onClick={connectWallet} > Connect Wallet </button>
): (
<BrydgeWidget
jsonRpcEndpoints={{
1: 'https://mainnet.infura.io/v3/{your_infura_key}',
137: 'https://polygon-mainnet.infura.io/v3/{your_infura_key}',
}}
provider={library}
defaultOutputTokenAddress='NATIVE'
defaultOutputAmount={0.001}
title='Mint Brydge Tutorial NFT'
destinationChainId={137}
/>
)}
{miningStatus === 1 ? (
<h2 className='text-3xl font-bold mb-20 mt-12'> NFT Minted Successfully! </h2>
) : (
<div></div>
)}
</div>
)
}

export default MintPage

Let’s save this file and run the following in your terminal:

npm run dev

Head to your browser and connect your wallet. Looking spiffy!

Make your dApp accessible to retail

Make your dApp accessible to retail

Make your dApp accessible to retail