# Table of Contents - [Docs](#docs) - [Docs](#docs) - [Glossary - Tokenbound Documentation](#glossary-tokenbound-documentation) - [Projects using Tokenbound - Tokenbound Documentation](#projects-using-tokenbound-tokenbound-documentation) - [Frequently Asked Questions - Tokenbound Documentation](#frequently-asked-questions-tokenbound-documentation) - [Overview - Tokenbound Documentation](#overview-tokenbound-documentation) - [Migrating to V3 - Tokenbound Documentation](#migrating-to-v3-tokenbound-documentation) - [SDK Reference - Tokenbound Documentation](#sdk-reference-tokenbound-documentation) - [Smart Contract Addresses - Tokenbound Documentation](#smart-contract-addresses-tokenbound-documentation) - [Tokenbound iFrame - Tokenbound Documentation](#tokenbound-iframe-tokenbound-documentation) - [Query TBA address for an NFT - Tokenbound Documentation](#query-tba-address-for-an-nft-tokenbound-documentation) - [Deploy the ERC-6551 Registry - Tokenbound Documentation](#deploy-the-erc-6551-registry-tokenbound-documentation) - [Connect to dapps as an NFT - Tokenbound Documentation](#connect-to-dapps-as-an-nft-tokenbound-documentation) - [Interact with your Tokenbound Account (TBA) on local blockchain using nodejs - Tokenbound Documentation](#interact-with-your-tokenbound-account-tba-on-local-blockchain-using-nodejs-tokenbound-documentation) - [Account - Tokenbound Documentation](#account-tokenbound-documentation) - [Deploy a custom account implementation - Tokenbound Documentation](#deploy-a-custom-account-implementation-tokenbound-documentation) - [Registry - Tokenbound Documentation](#registry-tokenbound-documentation) - [Unknown](#unknown) --- # Docs [Skip to content](/#vocs-content) Search [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Sun Moon [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [ERC-6551](https://eips.ethereum.org/EIPS/eip-6551) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) ![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg) Open-source tooling for ERC-6551 Token Bound Accounts npmpnpmyarn npm install @tokenbound/sdk [Get started](/intro) [GitHub](https://github.com/tokenbound) --- # Docs [Skip to content](/intro#vocs-content) Search [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Sun Moon [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [ERC-6551](https://eips.ethereum.org/EIPS/eip-6551) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Menu What is Tokenbound? On this page Chevron Right What is Tokenbound?[](/intro#what-is-tokenbound) --------------------------------------------------- Tokenbound is a suite of open-source tools that allow developers to easily integrate ERC-6551 accounts into their applications. Tokenbound currently provides: * An [ERC-6551 account implementation](/contracts/account) * A [front-end SDK](/sdk/installation) for interacting with ERC-6551 accounts * An [account explorer UI](https://tokenbound.org) for viewing and interacting with ERC-6551 accounts What is ERC-6551?[](/intro#what-is-erc-6551) ----------------------------------------------- ERC-6551 is proposed system of smart contracts that gives every NFT its own wallet address. This allows all NFTs to own assets, interact with applications, and participate as sovereign agents in the Ethereum ecosystem. ERC-6551 is unique in its approach because it requires zero changes to existing NFT smart contracts or infrastructure. Read more about ERC-6551 [here](https://eips.ethereum.org/EIPS/eip-6551) . --- # Glossary - Tokenbound Documentation [Skip to content](/glossary#vocs-content) Search [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Sun Moon [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [ERC-6551](https://eips.ethereum.org/EIPS/eip-6551) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Menu Glossary On this page Chevron Right This page lists all of the terms and their definitions that are used in these docs. Consider these as the building blocks of the Tokenbound Accounts system. #### TBA[](/glossary#tba) Short for Tokenbound Account. This is the account associated with a particular NFT. An NFT on a particular chain is uniquely identified as a contract address and tokenId pair. For example, one ERC721 contract can have multiple unique token IDs associated with it, and each tokenId will have a unique account associated with it. A TBA isn't generated, it's calculated. The address is deterministic and is calculated based on the NFT contract, the ID of the token and the [Account](/contracts/account) implementation #### Registry Contract[](/glossary#registry-contract) The presence of a [registry contract](/contracts/registry) on a particular chain makes it possible for that chain to support TBAs. This contract holds the method to calculate the address of a given NFT (contract, tokenID pair) #### Account[](/glossary#account) Implementation of the TBA. We provide a [default Account implementation](/contracts/account) which can be overridden if required. Note that the address of a TBA would change if the implementation contract is changed. #### TBA Explorer[](/glossary#tba-explorer) We built [tokenbound.org](https://tokenbound.org) to provide a way for anyone to view the wallet associated with any NFT. The easiest way to view any NFT's account is to take an NFT's OpenSea URL and replace `opensea.io` with `tokenbound.org` and view the assets. --- # Projects using Tokenbound - Tokenbound Documentation [Skip to content](/showcase#vocs-content) Search [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Sun Moon [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) Showcase Chevron Down [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Menu Projects using Tokenbound On this page Chevron Right ### [Lens Protocol V2](https://www.lens.xyz/) [](/showcase#lens-protocol-v2) ![Lens Protocol V2](https://i.imgur.com/syvVca5.jpg) Lens Protocol V2 reintroduces the power of composability by providing out-of-the-box support between profiles and the ERC-6551 token standard. With V2, value from ‘mints’ and ‘collects’ can be accrued to profiles instead of to their owner's address. ### [Orb](https://www.orb.ac/) [](/showcase#orb) ![Orb.ac](https://i.imgur.com/H4K0ZOj.jpg) Orb Communities are composable and interoperable, built on top of the Lens Protocol. It makes it easy to integrate community features across Lens apps. ### [Lenspeer](https://lenspeer.com/) [](/showcase#lenspeer) ![Lenspeer](https://i.imgur.com/cUI2BCc.jpg) Lenspeer built a Lens Wallet which exposes the 6551 account for your Lens profile ### [Galverse](https://www.bonfire.xyz) [](/showcase#galverse) ![Galverse](https://i.imgur.com/9cxW4AK.jpg) A new era of anime with a unique vision powered by a community made for everyone. Each NFT comes with a TBA to store assets associated with the character. ### [Bonfire](https://www.bonfire.xyz) [](/showcase#bonfire) ![Bonfire](https://i.imgur.com/cHkbMJt.jpg) Create unique digital spaces for your creative community. The platform supports sign in with TBA and gate your pages with TBA. ### [Pinata (Cosmic Cowboys)](https://www.pinata.cloud) [](/showcase#pinata-cosmic-cowboys) ![Pinata (Cosmic Cowboys)](https://i.imgur.com/GrYb5pm.jpg) A new on-chain game powered by Pinata and ERC6551. Engage with AI controlled NPCs that make decisions and alter the course of the game, and perhaps even join them 👀 ### [Silo.gg](https://silo.gg) [](/showcase#silogg) ![Silo](https://i.imgur.com/mizXezB.jpg) On-chain multiplayer coordination games made easy. ### [Spacebar](https://www.spacebar.xyz) [](/showcase#spacebar) ![Spacebar](https://i.imgur.com/vT2o7MU.jpg) Playground for Onchain Identities. Bring your PFP NFT + Socialize + Play ### [GroupOS by Station Network](https://station.mirror.xyz/wV3sS2WN8DymlBtRVa5tn6tLxQx3mu_6rEdoydy_SGU) [](/showcase#groupos-by-station-network) ![GroupOS](https://i.imgur.com/wNVcvu7.jpg) Station provides rails for groups to mobilize and do cool things on the Internet. GroupOS, our flagship product, is a modular toolkit powering digital collectives to own, govern, reward, and grow their networks, programmatically. ### [Sofamon](https://sofamon.xyz/) [](/showcase#sofamon) ![Sofamon](https://i.imgur.com/4ctaQD3.png) The desktop pet which makes your onchain interactions 10x more interesting ### [Tribes](https://www.tribes.xyz/) [](/showcase#tribes) ![Tribes](https://i.imgur.com/CZFzpeE.png) Chat, transact and co-own assets with anybody on Ethereum and Solana. ### [The Managers](https://themanagers.wtf/) [](/showcase#the-managers) ![Managers](https://i.imgur.com/59bd4Vk.jpg) An innovative NFT collection harnessing the power of ERC6551 or TokenBound Account (TBA) technology. Manage assets directly with your NFT. Explore new possibilities, use cases, and even sell your TBA Managers NFT just like any other. ### [Kiosk](https://tbkiosk.xyz/projects) [](/showcase#kiosk) ![Kiosk](https://i.imgur.com/AY4Cu6Q.png) Building the App Store For Smart NFTs. ### [MOPN](https://www.mopn.xyz/) [](/showcase#mopn) ![MOPN](https://i.imgur.com/CBwBncM.jpg) MOPN (Map Of Populars NFTs) is an infinity fully on-chain game built on Ethereum, open-source, fair launch, no admin. On a limited public map, players can freely place any ERC-721 NFTs. All NFTs follow the simple rules, engaging in open competition and cooperation, which leads to emergence of order. ### [zkApes](https://zkape.io) [](/showcase#zkapes) ![zkApes](https://i.imgur.com/ErPkoby.jpg) Mobile wallet with ERC-6551 support ### [Plena Finance](/showcase/link3.to/plenafinance) [](/showcase#plena-finance) ![Plena Finance](https://i.imgur.com/AptSANh.jpg) The First crypto super app. With ERC6551 an NFT that gives you access to physical and digital rewards. With ERC6551 elevate your portfolios beyond asset containers, using them as collateral in DeFi ecosystems. ### [Degen Distillery](https://www.degendistillery.com) [](/showcase#degen-distillery) ![Degen Distillery](https://i.imgur.com/XuMjzqQ.png) An NFT that gives you access to physical and digital rewards. ### [FatPay (SunPayCardPass)](https://www.fatpay.org) [](/showcase#fatpay-sunpaycardpass) ![FatPay (SunPayCardPass)](https://i.imgur.com/UaIEMCH.jpg) SunPay Card Pass (SPCP) is an ERC-6551 NFT that allows its holder to redeem SunPay Card. ### [Instate Protocol](https://instate.vercel.app/map) [](/showcase#instate-protocol) ![Instate Protocol](https://i.imgur.com/LTupaxf.pngg) Discover and mint local NFTs from around the globe. ### [NFTR - the NFT name registry](https://www.nftr.name/) [](/showcase#nftr---the-nft-name-registry) ![NFTR](https://i.imgur.com/GXrdJNz.png) Name your NFT with a unique name. Your NFT's domain name grants it a landing page and (soon) the ability to deploy named TBAs. The TBA's names are subdomains of your NFT's name. ### [Subscription Bound Accounts (SBA)](https://devfolio.co/projects/sba-b742) [](/showcase#subscription-bound-accounts-sba) ![SBA](https://i.imgur.com/ftZpq7X.png) SBAs allows any platform on the Celo blockchain to on board their users trough subscriptions that include the ability to mint some credits (ERC20) to the user based on the amount of super tokens being streamed. These features allow flexible tiers based subscriptions with an smooth on boarding. ### [MiYou DM](https://dm.miyou.io2) [](/showcase#miyou-dm) ![MiYou DM](https://i.imgur.com/Br1HcNZ.png) An email for Web3. Users obtain stamps from MiYou DM and use them in any email by MiYouPro App. ### [Tokengraph.cloud](https://tokengraph.cloud) [](/showcase#tokengraphcloud) ![tokengraph](https://tokengraph.cloud/social-card.png) A tool built by Pinata.cloud to help demonstrate the multiple vectors that NFTs and data can be linked thanks to ERC-6551! Plug in the address of any TBA to see how it's connected with other NFTs, tokens, and wallets. Previous hackathon bounty winners 🏆[](/showcase#previous-hackathon-bounty-winners-) --------------------------------------------------------------------------------------- ### [Piggybank NFTs](https://ethglobal.com/showcase/piggybank-6551-nft-e2ai5) [](/showcase#piggybank-nfts) ![Piggybank NFTs](https://i.imgur.com/hy3jRcw.png) Piggybank NFTs are 6551-powered ETH savings accounts. Anyone can mint a Piggybank, send it some ETH, and keep track of your growing balance in the NFT's onchain rendered SVG metadata. To get the ETH out, you'll have to burn the Piggybank NFT. ### [Habitat](https://ethglobal.com/showcase/habitat-zpg07) [](/showcase#habitat) ![Habitat](https://i.imgur.com/g76Mg0R.png) Habitat is a sub-application focused on environmental conservation and social responsibility. It transforms energy from both on-chain and off-chain regenerative activities, converting it into real trees to foster a sustainable future. ### [Fukuro](https://ethglobal.com/showcase/fukuro-3cdwv) [](/showcase#fukuro) ![Fukuro](https://i.imgur.com/APCAM4Y.png) Bundle curations with EIP 6551. Auction marketplace for EIP 6551 supported tokens. ### [Aquanet](https://ethglobal.com/showcase/aquanet-dzz2c) [](/showcase#aquanet) ![Aquanet](https://i.imgur.com/1W797K6.png) A social network designed for AI-Driven NFTs to interact with each other and develop unique personalities. ### [Tokenbound Titans](https://ethglobal.com/showcase/tokenbound-titans-5w6oq) [](/showcase#tokenbound-titans) ![Tokenbound Titans](https://i.imgur.com/L2puved.png) An implementation of ERC-6551 for NPC gaming; in combination with dynamic generative NFTs ### [ETHStacks](https://ethglobal.com/showcase/ethstacks-gdtth) [](/showcase#ethstacks) ![EthStacks](https://i.imgur.com/CWAvQBX.png) ETHStacks.xyz is an account management interface for token bound accounts (TBAs). Stack your assets through token bound accounts and manage them all through a simple interface. --- # Frequently Asked Questions - Tokenbound Documentation [Skip to content](/faq#vocs-content) Search [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Sun Moon [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [ERC-6551](https://eips.ethereum.org/EIPS/eip-6551) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Menu FAQ On this page Chevron Right ### What is a Token Bound Account (TBA)?[](/faq#what-is-a-token-bound-account-tba) A "Token Bound Account" is a smart contract account, controlled by an NFT. It can do everything a normal wallet can do and is compatible with every NFT you already own. ### Why now for ERC-6551 and Token Bound Accounts?[](/faq#why-now-for-erc-6551-and-token-bound-accounts) Hundreds of thousands of NFT projects have launched in the last few years, from CC0 projects to multi-billion dollar media/entertainment companies. NFTs have reached mainstream appeal over the last 2 years. However, ERC-721, the token standard that coined the term NFTs, has remained roughly the same since it was created 6 years ago. The standard didn’t/couldn’t anticipate all the potential use cases when it was conceived in 2017. One such use case is ownership from a token level. NFTs and most tokens are assets that are owned and controlled by a wallet, typically that is Metamask, Rainbow, Coinbase, Ledger, etc. but as NFTs have grown into full blown communities, the demand for utility and general usefulness has reached new heights. Projects with enough capital often organize IRL social gatherings that require huge amounts of capital and resources. Projects with less capital pursue on-chain game mechanics such as staking, farming, airdrops, voting, and purchasing. However most of these mechanics are often difficult to build and as a result each project has their own implementation that essentially does the same thing as the other but has more potential security vulnerabilities. The concept of ERC-6551 and Token Bound Accounts allow NFTs to have its own ethereum identity in the form of a smart contract wallet. ERC-6551 will allow for all NFT projects to add in important utilities to their tokens without heavy capital investment and effectively leveling up the entire NFT asset class together. ### I’ve seen other projects where NFTs can own assets. How is ERC-6551 different?[](/faq#ive-seen-other-projects-where-nfts-can-own-assets-how-is-erc-6551-different) ERC-6551 focuses on ease of use and adoption. Unlike other proposals and projects, Token Bound works with no action needed by project owners, no wrapping contracts, and no change to the ERC-721 standard. Most importantly, every ERC-721 and ERC-1155 NFT you already own works with Token Bound Accounts — projects and creators don’t need to deploy a whole new contract to use Token Bound, and you can start using ERC-6551 immediately. ### Why is ERC-6551 important? Why should I care?[](/faq#why-is-erc-6551-important-why-should-i-care) Digital collectibles/art are the future of creation. More than ever, people around the world are using technology to create digital goods such as NFTs. ERC-6551 is the most effective way to increase the surface area of interaction for NFTs. It was designed to be easily adopted by existing marketplaces, wallets, and dapps. It is permissionless and decentralized so that no single company owns your NFT’s wallet. When it comes to token provenance ERC-6551 allows your NFT to have an on-chain identity where history is created from the NFT itself rather than your wallet. ### How do I know if my NFT has an account/wallet address?[](/faq#how-do-i-know-if-my-nft-has-an-accountwallet-address) Every NFT already has an Address we can compute using ERC-6551 and Token Bound. You can view the tokens inside of your Token Bound Accounts on [https://tokenbound.org/](https://tokenbound.org/) . As adoption grows we are pushing for further integration into wallet apps such as Metamask, Rainbow Wallet, Coinbase, and marketplaces like OpenSea, Zora, and blur. Our SDK tooling and documentation also make it easy for creators and developers to integrate this functionality right into their own websites and apps. ### What can I put in my NFT’s token bound account?[](/faq#what-can-i-put-in-my-nfts-token-bound-account) Absolutely anything you would put into your old wallet. ETH, USDC, ERC-20, ERC-721, ERC-1155, and any other tokens you would normally send to your Metamask, Ledger, etc. ### How can I trust my NFT’s wallet?[](/faq#how-can-i-trust-my-nfts-wallet) We take security seriously and we have already completed a preliminary audit with 0xMacro. We will be conducting an additional audit with Certik (with support from our contributing partner Manifold), and seeking additional coverage through Code4rena. ### Can I nest my Token Bound NFTs inside of each other?[](/faq#can-i-nest-my-token-bound-nfts-inside-of-each-other) Yes! Since every NFT is a Token Bound Account, there are no limits to how many tokens you may have nested in your NFTs, or how far down you go. If you want to put an NFT inside of an NFT inside of an NFT you can. When you transfer that NFT to someone else, everything inside automatically goes along with it. This opens up many new patterns of bundling NFTs together for trading, gaming, governance and more. ### How do I use ERC-6551 for my project?[](/faq#how-do-i-use-erc-6551-for-my-project) The ERC-6551 reference implementation is open source and can be used by any project. Tokebound also provides open-source tooling that makes it much easier for dapps to integrate. If you'd like to learn more about how to integrate ERC-6551 into your project, please join the [working group](https://t.me/tokenbound) ### What are some of the core use cases for ERC 6551?[](/faq#what-are-some-of-the-core-use-cases-for-erc-6551) The possibilities are endless when it comes to Token Bound Accounts. However, some clear use cases are as such: * Inventory system for owning items, outfits, equipments * Community loyalty or reputation systems * Mint or curate baskets of assets (art, collectibles, defi) * Composable media structures (stems to songs, art layers to painting, digital textiles to garments) * New on-chain game mechanics * On-chain meme/derivative economies * NFTs as onboarding vehicles instead of wallets --- # Overview - Tokenbound Documentation [Skip to content](/sdk/installation#vocs-content) Search [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Sun Moon [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [ERC-6551](https://eips.ethereum.org/EIPS/eip-6551) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Menu Installation On this page Chevron Right The Tokenbound SDK currently supports projects using Ethers or Viem to interact with Ethereum. The SDK makes it easy to query ERC-6551 account addresses for any NFT and execute transactions against accounts. npmpnpmyarn npm install @tokenbound/sdk The Tokenbound SDK is compatible with both [viem](https://viem.sh/) and [Ethers](https://docs.ethers.org/v6/) . viem is a core SDK dependency, so we recommend using viem except for legacy Ethers projects. Note: If making use of one of the many Web3 starter kits, please make sure that you're using a recent release of viem (>1.0), Ethers 5.7+, or 6 to avoid issues. Example apps[](/sdk/installation#example-apps) ------------------------------------------------- To help you get started more quickly, we've assembled bare-bones [example apps using the Tokenbound SDK](https://github.com/tokenbound/sdk/tree/main/examples) using viem, Ethers 5.7, and Ethers 6 respectively. These examples are using Goerli testnet (chainId: 5). * [vite-wagmi-viem](https://github.com/tokenbound/sdk/tree/main/examples/vite-wagmi-viem) * [vite-wagmi-ethers](https://github.com/tokenbound/sdk/tree/main/examples/vite-wagmi-ethers) * [vite-wagmi-ethers6](https://github.com/tokenbound/sdk/tree/main/examples/vite-wagmi-ethers6) * [vite-wagmi-ethers-rainbowkit](https://github.com/tokenbound/sdk/tree/main/examples/vite-wagmi-ethers-rainbowkit) --- # Migrating to V3 - Tokenbound Documentation [Skip to content](/sdk/migrating-to-v3#vocs-content) Search [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Sun Moon [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [ERC-6551](https://eips.ethereum.org/EIPS/eip-6551) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Menu Migrating to v0.3.1 On this page Chevron Right We've made every effort to maintain backwards compatibility with deployed V2 contracts, and for the most part you shouldn't need to change much to get started with ERC-6551 development using the new contracts. That said, V3 is a big release and we're taking the opportunity to do a little bit of cleanup to make the SDK more flexible and easier to test. Some of these changes will also make development easier for the community. There are a few key changes you'll want to be aware of if you're migrating from V2. Breaking Changes[](/sdk/migrating-to-v3#breaking-changes) ------------------------------------------------------------ ### Custom Implementation Addresses + Versioning[](/sdk/migrating-to-v3#custom-implementation-addresses--versioning) If your app uses the standard Tokenbound V2 implementation [see 0.2.0 →](https://docs.tokenbound.org/contracts/deployments) , you'll need to instantiate the `TokenboundClient` with the `version` parameter set to use V2: **Basic V2:** import { TokenboundClient, TBVersion } from "@tokenbound/sdk" const tokenboundClient = new TokenboundClient({ walletClient, chainId: 1, version: TBVersion.V2, }) If your app uses a custom account implementation based on V2 contracts (eg. not one of the [deployed 0.2.0 addresses →](https://docs.tokenbound.org/contracts/deployments) ), you'll need to pass both the `version` and `implementationAddress` parameters when instantiating your TokenboundClient: : **V2 with custom `implementationAddress`:** import { TokenboundClient, TBVersion } from "@tokenbound/sdk" const CUSTOM_V2_ACCOUNT_IMPLEMENTATION = "0x9fff..." const tokenboundClient = new TokenboundClient({ walletClient, chainId: 1, implementationAddress: CUSTOM_V2_ACCOUNT_IMPLEMENTATION, version: TBVersion.V2, }) ### createAccount return type[](/sdk/migrating-to-v3#createaccount-return-type) Previous iterations of the `createAccount` method returned an `0x${string}` with the created account address. In V3, createAccount returns an object containing both the created account address and the hash of the transaction. This will make debugging and testing easier, and should help developers handle UI updates relating to the transaction more easily. ###### Previous:[](/sdk/migrating-to-v3#previous) const createdAccount = await tokenboundClient.createAccount({...}) ###### Now:[](/sdk/migrating-to-v3#now) const { account, txHash } = await tokenboundClient.createAccount({...}) ### createAccount + getAccount with customImplementation parameters[](/sdk/migrating-to-v3#createaccount--getaccount-with-customimplementation-parameters) Previously, we allowed for a custom `implementationAddress` and/or `registryAddress` to be specified directly on the `getAccount` and `createAccount` methods. These parameters have been removed. You can still specify each of these parameters when instantiating the TokenboundClient for the same effect. ### ABI exports[](/sdk/migrating-to-v3#abi-exports) We're moving to versioned exports of the ABIs so that developers can differentiate them: export { erc6551AccountAbiV2, erc6551RegistryAbiV2, erc6551AccountAbiV3, erc6551AccountProxyAbiV3, erc6551RegistryAbiV3, } --- # SDK Reference - Tokenbound Documentation [Skip to content](/sdk/methods#vocs-content) Search [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Sun Moon [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [ERC-6551](https://eips.ethereum.org/EIPS/eip-6551) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Menu SDK Reference On this page Chevron Right TokenboundClient[](/sdk/methods#tokenboundclient) ---------------------------------------------------- The TokenboundClient class provides an interface for interacting with tokenbound accounts, enabling operations like account creation, transaction execution, token transfers (including ERC-721, ERC-1155, and ERC-20 tokens), and message signing. The client is instantiated with an object containing two parameters: | Parameter | | | --- | --- | | One of **signer** _or_ **walletClient** | mandatory | | One of **chainId** _or_ **chain** | mandatory | Use either a viem `walletClient` [(see walletClient docs)](https://viem.sh/docs/clients/wallet.html) _or_ an Ethers `signer` [(see signer docs)](https://docs.ethers.org/v5/api/signer/) for transactions that require a user to sign. Note that viem is an SDK dependency, so walletClient is preferable for most use cases. _Use of Ethers signer is recommended only for legacy projects_. The TokenboundClient is configured to use the [Version 3.1 ERC-6551 contract deployments →](https://docs.tokenbound.org/contracts/deployments) by default. For instructions about using a **Custom Account Implementation** and/or a **Legacy V2 Tokenbound Account Implementation**, see the [Advanced Usage](/sdk/methods#advanced-usage) section at the bottom of this document. ### Standard configuration[](/sdk/methods#standard-configuration) If you're using one of the [standard V2/V3 ERC-6551 contract deployments →](https://docs.tokenbound.org/contracts/deployments) , you can simply pass the`chainId`. This will set `Chain` internally using imports from [`viem/chains`](https://viem.sh/docs/clients/chains.html) . To keep the bundle size to a minimum, only standard chains are included in the SDK package. import { useAccount, WalletClient } from 'wagmi' import { TokenboundClient } from '@tokenbound/sdk' const { address } = useAccount() const walletClient: WalletClient = createWalletClient({ chainId: goerli, account: address, transport: http(), }) const tokenboundClient = new TokenboundClient({ walletClient, chainId: 5 }) ### Custom chain[](/sdk/methods#custom-chain) If your chain isn't listed on the [deployments page →](https://docs.tokenbound.org/contracts/deployments) , you'll need to pass the full `Chain` object from the [`viem/chains`](https://viem.sh/docs/clients/chains.html) package using the `chain` parameter. import { zora } from 'viem/chains' const tokenboundClient = new TokenboundClient({ walletClient, chain: zora }) ### Using Ethers.js[](/sdk/methods#using-ethersjs) Ethers 5 / 6 are supported as an alternative to viem. const { data: signer } = useSigner() const tokenboundClient = new TokenboundClient({ signer, chainId: 1 }) ### Making your first call[](/sdk/methods#making-your-first-call) Now you can use the TokenboundClient to interact with the Tokenbound contracts: const tokenboundClient = new TokenboundClient({ walletClient, chainId: 1 }) const tokenboundAccount = tokenboundClient.getAccount({ tokenContract: '', tokenId: '', }) console.log(tokenboundAccount) //0x1a2...3b4cd For easy reference, we've prepared [code examples](https://github.com/tokenbound/sdk/tree/main/examples) for a few simple SDK interactions. TokenboundClient SDK Methods[](/sdk/methods#tokenboundclient-sdk-methods) ---------------------------------------------------------------------------- The TokenboundClient enables creation of and interaction with Tokenbound accounts: ### prepareCreateAccount[](/sdk/methods#preparecreateaccount) Prepares an account creation transaction to be submitted via `sendTransaction` **Returns** a promise resolving to a prepared transaction that can be used to create a Tokenbound account for a given token contract and token ID. When using the standard V3 implementation, this will be a `MultiCallTx` that will create and initialize the account in one pass. If using a custom account implementation with V3, a basic prepared transaction will be returned in the form `{to, value, data}`, and the created account will need to be initialized in a second step. If using the legacy V2 implementation, the return will be a standard object of the form `{to, value, data}`, and account initialization is handled for you. const preparedAccount = await tokenboundClient.prepareCreateAccount({ tokenContract: '', tokenId: '', }) console.log(preparedAccount) //0x1a2...3b4cd | Parameter | Description | Type | | --- | --- | --- | | **tokenContract** | The address of the token contract. | string | | **tokenId** | The token ID. | string | | **salt** | The salt used to create a unique account address (optional) | number | | **chainId** | The id of the chain on which the account will exist (optional) | number | | **appendedCalls** | An array of calls to execute via Multicall3 (optional) | Call3\[\] | See [Appending Calls To Account Creation](/sdk/methods#appending-calls-to-account-creation) for `appendedCalls` documentation. * * * ### createAccount[](/sdk/methods#createaccount) Creates a tokenbound account for an NFT. The deterministic address is calculated using the `create2` opcode using the listed parameters along with chainId and implementation address. `createAccount` adds the account to the registry and initializes it for use. Prior to account creation, the address can already receive assets. Deploying the account allows the NFT's owner to interact with the account. **Returns** an object containing the account address of the tokenbound account created and the hash of the transaction. If an account already exists, the existing account is returned. const { account, txHash } = await tokenboundClient.createAccount({ tokenContract: '', tokenId: '', }) console.log(account) //0x1a2...3b4cd | Parameter | Description | Type | | --- | --- | --- | | **tokenContract** | The address of the token contract. | string | | **tokenId** | The token ID. | string | | **salt** | The salt used to create a unique account address (optional) | number | | **chainId** | The id of the chain on which the account will exist (optional) | number | | **appendedCalls** | An array of calls to execute via Multicall3 (optional) | Call3\[\] | See [Appending Calls To Account Creation](/sdk/methods#appending-calls-to-account-creation) for `appendedCalls` documentation. * * * ### getAccount[](/sdk/methods#getaccount) Gets the tokenbound account address for an NFT. **Returns** the tokenbound account address for a given token contract and token ID. const tokenboundAccount = tokenboundClient.getAccount({ tokenContract: '', tokenId: '', }) console.log(tokenboundAccount) //0x1a2...3b4cd | Parameter | Description | Type | | --- | --- | --- | | **tokenContract** | The address of the token contract. | string | | **tokenId** | The token ID. | string | | **salt** | The salt used when the account was created (optional) | number | * * * ### checkAccountDeployment[](/sdk/methods#checkaccountdeployment) Check if the tokenbound account address has been activated using createAccount. **Returns** a boolean indicating if a tokenbound account has been deployed (created) at the accountAddress const SAPIENZ_GOERLI_TOKEN_TBA_TOKENID_0 = '0x33D622b211C399912eC0feaaf1caFD01AFA53980' as `0x${string}` const isAccountDeployed = await tokenboundClient.checkAccountDeployment({ accountAddress: SAPIENZ_GOERLI_TOKEN_TBA_TOKENID_0, }) console.log('IS SAPIENZ 0 DEPLOYED?', isAccountDeployed) //... | Parameter | Description | Type | | --- | --- | --- | | **accountAddress** | The Tokenbound account address. | string | * * * ### getNFT[](/sdk/methods#getnft) Extracts information about the origin NFT that is paired with the tokenbound account. **Returns** a Promise that resolves to a **TokenboundAccountNFT** object. The TokenboundAccountNFT object contains the following properties: * **_tokenContract_**: The token contract address * **_tokenId_**: The token ID * **_chainId_**: The chain ID const nft = await tokenboundClient.getNFT({ accountAddress: '', }) const { tokenContract, tokenId, chainId } = nft console.log({ tokenContract, tokenId, chainId }) | Parameter | Description | Type | | --- | --- | --- | | **accountAddress** | The Tokenbound account address. | string | * * * ### prepareExecution[](/sdk/methods#prepareexecution) Prepares an arbitrary contract call for execution against any contract. **Note**: this method replaces the deprecated V2 method `prepareExecuteCall`. **Returns** A Promise with prepared transaction to execute a call on a Tokenbound account. Can be sent via `sendTransaction` on an Ethers signer or via WalletClient. const preparedExecution = await tokenboundClient.prepareExecution({ account: '', to: '', value: '', data: '', }) console.log(preparedExecution) //... | Parameter | Description | Type | | --- | --- | --- | | **account** | The Tokenbound account address. | string | | **to** | The contract address. | string | | **value** | The value to send, in wei. | bigint | | **data** (optional) | The ABI-encoded call data | string | | **chainId** (optional) | The ID of the chain the transaction should be executed on (optional). If supplied, this will send a cross-chain transaction from the TBA via a bridge | string | * * * ### execute[](/sdk/methods#execute) Performs an arbitrary contract call against any contract. This means any onchain action you can perform with your EOA wallet can be done with your NFT's Tokenbound account. You can mint or transfer NFTs, approve contracts, make and vote on DAO proposals, and much more. **Note**: this method replaces the deprecated V2 method `executeCall`. **Returns** a hash of the transaction that executed a call using a Tokenbound account. const executedCall = await tokenboundClient.execute({ account: '', to: '', value: '', data: '', }) console.log(executedCall) | Parameter | Description | Type | | --- | --- | --- | | **account** | The Tokenbound account address. | string | | **to** | The contract address. | string | | **value** | The value to send, in wei. | bigint | | **data** (optional) | The ABI-encoded call data. | `0x{string}` | | **chainId** (optional) | The ID of the chain the transaction should be executed on (optional). If supplied, this will send a cross-chain transaction from the TBA via a bridge | string | Here's a more robust example, where we see how to use your TBA to mint an NFT using Zora's [ERC721Drop contract](https://etherscan.io/address/0x7c74dfe39976dc395529c14e54a597809980e01c#code) by calling the contract's `purchase` function. // Webb's First Deep Field (unlimited mint drop): // https://zora.co/collect/eth:0x28ee638f2fcb66b4106acab7efd225aeb2bd7e8d const zora721 = { abi: zora721DropABI, proxyContractAddress: getAddress('0x28ee638f2fcb66b4106acab7efd225aeb2bd7e8d'), mintPrice: BigInt(0), quantity: 2, tbaAddress: getAddress('0xc33f0A7FcD69Ba00b4e980463199CD38E30d0E5c'), } const encodedMintFunctionData = encodeFunctionData({ abi: zora721.abi, functionName: 'purchase', args: [BigInt(zora721.quantity)], }) const mintToTBATxHash = await tokenboundClient.execute({ account: zora721.tbaAddress, to: zora721.proxyContractAddress, value: zora721.mintPrice * BigInt(zora721.quantity), data: encodedMintFunctionData, }) * * * ### isValidSigner[](/sdk/methods#isvalidsigner) Checks if a tokenbound account has signing authorization. This determines whether the active `WalletClient` or `Signer` can be used to sign transactions on behalf of the TBA. **Returns** a Promise that resolves to true if the account is a valid signer, otherwise false NOTE: This method is not available to V2-based implementations const isValidSigner = await tokenboundClient.isValidSigner({ account: ZORA721_TBA_ADDRESS, }) console.log('isValidSigner?', isValidSigner) | Parameter | Description | Type | | --- | --- | --- | | **account** | The Tokenbound account address. | string | * * * ### transferNFT[](/sdk/methods#transfernft) Transfer an NFT to a recipient from a Tokenbound account **Returns** a Promise that resolves to the transaction hash of the transfer const transferNFT = await tokenboundClient.transferNFT({ account: '', tokenType: 'ERC721', tokenContract: '', tokenId: '', recipientAddress: '', }) console.log(transferNFT) //... | Parameter | Description | Type | | --- | --- | --- | | **account** | The Tokenbound account address. | string | | **tokenType** | Token type: 'ERC721' or 'ERC1155' | string | | **tokenContract** | The address of the token contract. | string | | **tokenId** | The tokenId of the NFT. | string | | **recipientAddress** | The recipient address or ENS. | string | | **amount** | The number of tokens to send (1155 only). | number | | **chainId** (optional) | The ID of the chain the transaction should be executed on (optional). If supplied, this will send a cross-chain transaction from the TBA via a bridge | string | * * * ### transferETH[](/sdk/methods#transfereth) Transfer ETH to a recipient from a Tokenbound account **Returns** a Promise that resolves to the transaction hash of the transfer const transferETH = await tokenboundClient.transferETH({ account: '', amount: 0.01, recipientAddress: '', }) console.log(transferERC20) //... | Parameter | Description | Type | | --- | --- | --- | | **account** | The Tokenbound account address. | string | | **amount** | Amount, in decimal form (eg. 0.01 ETH). | number | | **recipientAddress** | The recipient address or ENS. | string | | **chainId** (optional) | The ID of the chain the transaction should be executed on (optional). If supplied, this will send a cross-chain transaction from the TBA via a bridge | string | * * * ### transferERC20[](/sdk/methods#transfererc20) Transfer ERC-20 tokens to a recipient from a Tokenbound account **Returns** a Promise that resolves to the transaction hash of the transfer const transferERC20 = await tokenboundClient.transferERC20({ account: '', amount: 0.1, recipientAddress: '', erc20tokenAddress: '', erc20tokenDecimals: '', }) console.log(transferERC20) //... | Parameter | Description | Type | | --- | --- | --- | | **account** | The Tokenbound account address. | string | | **amount** | Amount, in decimal form (eg. 0.1 USDC). | number | | **recipientAddress** | The recipient address or ENS. | string | | **erc20tokenAddress** | The ERC-20 token address. | string | | **erc20tokenDecimals** | The ERC-20 token decimal specification (1-18). | number | | **chainId** (optional) | The ID of the chain the transaction should be executed on (optional). If supplied, this will send a cross-chain transaction from the TBA via a bridge | string | * * * ### deconstructBytecode[](/sdk/methods#deconstructbytecode) Deconstructs the bytecode of a Tokenbound account into its constituent parts. **Returns** a Promise that resolves to a **SegmentedERC6551Bytecode** object, or null if the account is not deployed. The **SegmentedERC6551Bytecode** object contains the following properties: * **_erc1167Header_**: ERC-1167 Header * **_implementationAddress_**: The ERC-6551 implementation address * **_erc1167Footer_**: ERC-1167 Footer * **_salt_**: The salt value * **_tokenId_**: The token ID * **_tokenContract_**: The token contract address * **_chainId_**: The chain ID const segmentedBytecode = await tokenboundClient.deconstructBytecode({ accountAddress: '', }) console.log(segmentedBytecode) | Parameter | Description | Type | | ------------------ | ------------------------------- | ------ | | **accountAddress** | The Tokenbound account address. | string | * * * ### signMessage[](/sdk/methods#signmessage) Gets an [EIP-191](https://eips.ethereum.org/EIPS/eip-191) formatted signature for a message. **Returns** a Promise that resolves to a signed Hex string The message to be signed is typed as `UniversalSignableMessage` so that it can elegantly handle Ethers 5, Ethers 6, and viem's expected types for all signable formats. Check the types associated with signMessage for [viem](https://viem.sh/docs/actions/wallet/signMessage.html) , [Ethers 5](https://docs.ethers.org/v5/api/signer/#Signer-signMessage) , and [Ethers 6](https://docs.ethers.org/v6/api/providers/#Signer-signMessage) as needed. // Ethers 5 const arrayMessage: ArrayLike = [72, 101, 108, 108, 111] // "Hello" in ASCII // Ethers 5 or Ethers 6 const uint8ArrayMessage: Uint8Array = new Uint8Array([72, 101, 108, 108, 111]) // "Hello" in ASCII Note that this method is just for convenience. Since your EOA wallet is responsible for signing, messages can also be signed explicitly using your EOA wallet address in viem or Ethers. const signedMessage = await tokenboundClient.signMessage({ message: 'Ice cream so good', }) console.log(signedMessage) // Works in Ethers 5 or 6, throws in viem const signedUint8Message = await tokenboundClient.signMessage({ message: uint8ArrayMessage, }) console.log(signedUint8Message) // Works in viem const signedRawUint8Message = await tokenboundClient.signMessage({ message: { raw: uint8ArrayMessage }, }) console.log(signedUint8Message) | Parameter | Description | Type | | --- | --- | --- | | **message** | The message to be signed. | UniversalSignableMessage | * * * Advanced Usage[](/sdk/methods#advanced-usage) ------------------------------------------------ ### Custom Account Implementation[](/sdk/methods#custom-account-implementation) If your team has deployed a custom [account implementation](/contracts/account) contract, you'll need to point the SDK to your custom implementation instead of the default implementation. If your custom implementation uses the legacy V2 account logic, you'll also need to supply a version parameter to instruct the TokenboundClient to make use of the V2 methods. import { TokenboundClient } from '@tokenbound/sdk' const tokenboundClient = new TokenboundClient({ walletClient: '', chainId: '', implementationAddress: '', }) // Custom implementation AND custom registry (uncommon for most implementations) const tokenboundClientWithCustomRegistry = new TokenboundClient({ walletClient: '', chainId: '', implementationAddress: '', registryAddress: '', }) * * * ### Legacy V2 Tokenbound Account Implementation[](/sdk/methods#legacy-v2-tokenbound-account-implementation) If your application was created using the **standard legacy V2 account implementation** ([see 0.2.0 →](https://docs.tokenbound.org/contracts/deployments) ), you'll need to instruct the `TokenboundClient` to use it by specifying the `TBVersion` import { TokenboundClient, TBVersion } from '@tokenbound/sdk' const tokenboundClient = new TokenboundClient({ walletClient, chainId: 1, version: TBVersion.V2, }) * * * ### Appending Calls To Account Creation[](/sdk/methods#appending-calls-to-account-creation) You can make your first transaction using a newly-created TBA by appending a call to `createAccount`'s internal multicall sequence for execution after the account creation and initialization steps. To determine your account address before it has been created, use the `getAccount` method. You can then use the account as the Call3 `target`. The Tokenbound SDK uses a fork of Multicall3 with support for authenticated calls. The value of msg.sender is appended to the calldata of each call in the style of [ERC-2771](https://eips.ethereum.org/EIPS/eip-2771) , allowing contract recipients to verify the multicall sender. See the [Multicall3 docs](https://github.com/mds1/multicall) for detailed info regarding this approach. Pay special attention to the notices re: contract writes. Here's an example that uses your just-deployed token bound account to make a transaction. import { Call3 } from '@tokenbound/sdk' import { encodeFunctionData } from 'viem' const tokenboundAccount = tokenboundClient.getAccount({ tokenContract: "", tokenId: "", }) // Let's claim an ERC-1155 token from one of ThirdWeb's DropERC1115 contract deployments // https://thirdweb.com/thirdweb.eth/DropERC1155 const maxClaimablePerWallet = 1 const pricePerToken = 0 const quantity = 1 const currencyAddress = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE' // ETH // Configure the arguments for the claim const claimConfig = { receivingTBA: tokenboundAccount, pricePerToken, quantity, tokenId: 0, currencyAddress, allowListProof: { proof: [], quantityLimitPerWallet: maxClaimablePerWallet ?? 1, pricePerToken, currency: currencyAddress, }, data: '0x', } // Encode function data for use in prepareExecution call const encodedClaimFunctionData = encodeFunctionData({ abi: rewardContractABI, functionName: 'claim', args: [\ claimConfig.receivingTBA,\ claimConfig.tokenId,\ claimConfig.quantity,\ claimConfig.currencyAddress,\ claimConfig.pricePerToken,\ claimConfig.allowListProof,\ claimConfig.data,\ ], }) // Prepare execution call via Tokenbound account const preparedExecution = await tokenboundClient.prepareExecution({ account: tokenboundAccount, to: CLAIM_CONTRACT_ADDRESS, value: 0n, data: encodedClaimFunctionData, }) // Assemble a Call3 call that can be used by createAccount's internal Multicall3 invocation const appendedCall: Call3 = { target: tokenboundAccount, // <-- Execute with TBA contract allowFailure: false, callData: preparedExecution.data, // <-- Encoded TBA 'execute' function data } const { account, txHash } = await tokenboundClient.createAccount({ tokenContract: "", tokenId: "", appendedCalls: [appendedCall] // <-- Call(s) to be executed sequentially after account creation }) console.log(account) //0x1a2...3b4cd * * * ### Custom PublicClient or RPC URL[](/sdk/methods#custom-publicclient-or-rpc-url) If using viem, you can specify a custom PublicClient RPC URL for use by the TokenboundClient's internal PublicClient. Alternately, you can simply configure and pass your own publicClient. This option was added to enable internal testing on local chains. | Parameter | | | --- | --- | | **publicClientRPCUrl** | optional | | **publicClient** | optional | import { TokenboundClient } from '@tokenbound/sdk' const tokenboundClient = new TokenboundClient({ walletClient: '', chainId: '', publicClientRPCUrl: '', }) --- # Smart Contract Addresses - Tokenbound Documentation [Skip to content](/contracts/deployments#vocs-content) Search [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Sun Moon [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [ERC-6551](https://eips.ethereum.org/EIPS/eip-6551) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Menu Deployed Addresses On this page Chevron Right The ERC-6551 registry and Tokenbound account contracts are permissionlessly deployable at the following addresses on any chain. If the chain you are building on is not in the table below, you can deploy the contracts yourself using our [self-deployment tool](https://tokenbound-v3-deployer.vercel.app/) . #### ERC-6551 Registry[](/contracts/deployments#erc-6551-registry) | EVM Network | Chain ID | Registry Address | | --- | --- | --- | | Goerli | 5 | [0x000000006551c19487814612e58FE06813775758](https://goerli.etherscan.io/address/0x000000006551c19487814612e58FE06813775758) | | Mumbai | 80001 | [0x000000006551c19487814612e58FE06813775758](https://mumbai.polygonscan.com/address/0x000000006551c19487814612e58FE06813775758) | | OP Goerli | 420 | [0x000000006551c19487814612e58FE06813775758](https://goerli-optimism.etherscan.io/address/0x000000006551c19487814612e58FE06813775758) | | Base Goerli | 84531 | [0x000000006551c19487814612e58FE06813775758](https://goerli.basescan.org/address/0x000000006551c19487814612e58FE06813775758) | | Linea Goerli | 59140 | [0x000000006551c19487814612e58FE06813775758](https://goerli.lineascan.build/address/0x000000006551c19487814612e58FE06813775758) | | Ethereum | 1 | [0x000000006551c19487814612e58FE06813775758](https://etherscan.io/address/0x000000006551c19487814612e58FE06813775758) | | Polygon | 137 | [0x000000006551c19487814612e58FE06813775758](https://polygonscan.com/address/0x000000006551c19487814612e58FE06813775758) | | Optimism | 10 | [0x000000006551c19487814612e58FE06813775758](https://optimistic.etherscan.io/address/0x000000006551c19487814612e58FE06813775758) | | Base | 8453 | [0x000000006551c19487814612e58FE06813775758](https://basescan.org/address/0x000000006551c19487814612e58FE06813775758) | | Linea | 59144 | [0x000000006551c19487814612e58FE06813775758](https://lineascan.build/address/0x000000006551c19487814612e58FE06813775758) | | Frame Sepolia | 68840142 | [0x000000006551c19487814612e58FE06813775758](https://explorer.testnet.frame.xyz/address/0x000000006551c19487814612e58FE06813775758) | | Klaytn | 8217 | [0x000000006551c19487814612e58FE06813775758](https://www.klaytnfinder.io/account/0x000000006551c19487814612e58FE06813775758) | | Klaytn Baobab | 1001 | [0x000000006551c19487814612e58FE06813775758](https://baobab.klaytnfinder.io/account/0x000000006551c19487814612e58FE06813775758) | #### Tokenbound Account Proxy[](/contracts/deployments#tokenbound-account-proxy) _Use this address as the `implementation` parameter when calling `createAccount` on the registry_ | EVM Network | Chain ID | Account Proxy Address | | --- | --- | --- | | Goerli | 5 | [0x55266d75D1a14E4572138116aF39863Ed6596E7F](https://goerli.etherscan.io/address/0x55266d75D1a14E4572138116aF39863Ed6596E7F) | | Mumbai | 80001 | [0x55266d75D1a14E4572138116aF39863Ed6596E7F](https://mumbai.polygonscan.com/address/0x55266d75D1a14E4572138116aF39863Ed6596E7F) | | OP Goerli | 420 | [0x55266d75D1a14E4572138116aF39863Ed6596E7F](https://goerli-optimism.etherscan.io/address/0x55266d75D1a14E4572138116aF39863Ed6596E7F) | | Base Goerli | 84531 | [0x55266d75D1a14E4572138116aF39863Ed6596E7F](https://goerli.basescan.org/address/0x55266d75D1a14E4572138116aF39863Ed6596E7F) | | Linea Goerli | 59140 | [0x55266d75D1a14E4572138116aF39863Ed6596E7F](https://goerli.lineascan.build/address/0x55266d75D1a14E4572138116aF39863Ed6596E7F) | | Ethereum | 1 | [0x55266d75D1a14E4572138116aF39863Ed6596E7F](https://etherscan.io/address/0x55266d75D1a14E4572138116aF39863Ed6596E7F) | | Polygon | 137 | [0x55266d75D1a14E4572138116aF39863Ed6596E7F](https://polygonscan.com/address/0x55266d75D1a14E4572138116aF39863Ed6596E7F) | | Optimism | 10 | [0x55266d75D1a14E4572138116aF39863Ed6596E7F](https://optimistic.etherscan.io/address/0x55266d75D1a14E4572138116aF39863Ed6596E7F) | | Base | 8453 | [0x55266d75D1a14E4572138116aF39863Ed6596E7F](https://basescan.org/address/0x55266d75D1a14E4572138116aF39863Ed6596E7F) | | Linea | 59144 | [0x55266d75D1a14E4572138116aF39863Ed6596E7F](https://lineascan.build/address/0x55266d75D1a14E4572138116aF39863Ed6596E7F) | | Frame Sepolia | 68840142 | [0x55266d75D1a14E4572138116aF39863Ed6596E7F](https://explorer.testnet.frame.xyz/address/0x55266d75D1a14E4572138116aF39863Ed6596E7F) | | Klaytn | 8217 | [0x55266d75D1a14E4572138116aF39863Ed6596E7F](https://www.klaytnfinder.io/account/0x55266d75D1a14E4572138116aF39863Ed6596E7F) | | Klaytn Baobab | 1001 | [0x55266d75D1a14E4572138116aF39863Ed6596E7F](https://baobab.klaytnfinder.io/account/0x55266d75D1a14E4572138116aF39863Ed6596E7F) | #### Tokenbound Account Implementation[](/contracts/deployments#tokenbound-account-implementation) _Use this address as the `implementation` parameter when calling `initialize` on a newly created account_ | EVM Network | Chain ID | Account Implementation Address | | --- | --- | --- | | Goerli | 5 | [0x41C8f39463A868d3A88af00cd0fe7102F30E44eC](https://goerli.etherscan.io/address/0x41C8f39463A868d3A88af00cd0fe7102F30E44eC) | | Mumbai | 80001 | [0x41C8f39463A868d3A88af00cd0fe7102F30E44eC](https://mumbai.polygonscan.com/address/0x41C8f39463A868d3A88af00cd0fe7102F30E44eC) | | OP Goerli | 420 | [0x41C8f39463A868d3A88af00cd0fe7102F30E44eC](https://goerli-optimism.etherscan.io/address/0x41C8f39463A868d3A88af00cd0fe7102F30E44eC) | | Base Goerli | 84531 | [0x41C8f39463A868d3A88af00cd0fe7102F30E44eC](https://goerli.basescan.org/address/0x41C8f39463A868d3A88af00cd0fe7102F30E44eC) | | Linea Goerli | 59140 | [0x41C8f39463A868d3A88af00cd0fe7102F30E44eC](https://goerli.lineascan.build/address/0x41C8f39463A868d3A88af00cd0fe7102F30E44eC) | | Ethereum | 1 | [0x41C8f39463A868d3A88af00cd0fe7102F30E44eC](https://etherscan.io/address/0x41C8f39463A868d3A88af00cd0fe7102F30E44eC) | | Polygon | 137 | [0x41C8f39463A868d3A88af00cd0fe7102F30E44eC](https://polygonscan.com/address/0x41C8f39463A868d3A88af00cd0fe7102F30E44eC) | | Optimism | 10 | [0x41C8f39463A868d3A88af00cd0fe7102F30E44eC](https://optimistic.etherscan.io/address/0x41C8f39463A868d3A88af00cd0fe7102F30E44eC) | | Base | 8453 | [0x41C8f39463A868d3A88af00cd0fe7102F30E44eC](https://basescan.org/address/0x41C8f39463A868d3A88af00cd0fe7102F30E44eC) | | Linea | 59144 | [0x41C8f39463A868d3A88af00cd0fe7102F30E44eC](https://lineascan.build/address/0x41C8f39463A868d3A88af00cd0fe7102F30E44eC) | | Frame Sepolia | 68840142 | [0x41C8f39463A868d3A88af00cd0fe7102F30E44eC](https://explorer.testnet.frame.xyz/address/0x41C8f39463A868d3A88af00cd0fe7102F30E44eC) | | Klaytn | 8217 | [0x41C8f39463A868d3A88af00cd0fe7102F30E44eC](https://www.klaytnfinder.io/account/0x41C8f39463A868d3A88af00cd0fe7102F30E44eC) | | Klaytn Baobab | 1001 | [0x41C8f39463A868d3A88af00cd0fe7102F30E44eC](https://baobab.klaytnfinder.io/account/0x41C8f39463A868d3A88af00cd0fe7102F30E44eC) | --- # Tokenbound iFrame - Tokenbound Documentation [Skip to content](/iframe#vocs-content) Search [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Sun Moon [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [ERC-6551](https://eips.ethereum.org/EIPS/eip-6551) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Menu Installation On this page Chevron Right By using an `animation_url` developers may embed a web app as the media for NFT on OpenSea, and some other platforms. This allows users to view detailed information about the tokenbound account (TBA) of NFTs directly within the marketplace interface. This basic iframe implementation lets users explore their NFT's tokenbound accounts and view information such as: * Contents of the NFT's tokenbound account: ERC-721, ERC-1155, ether and ERC-20 tokens * Whether or not any ERC-721, or ERC-1155 tokens have global or token level approvals. This information provides context for users who are looking to buy an NFT and the contents within it's TBA, since tokens with pending approvals have the potential be transferred before the transaction for the parent NFT is finalized. * Whether the status of the TBA is `locked` or `unlocked`. A `locked` state allows users to confidently purchase an NFT, knowing that none of the contents of the TBA will be transferred for the specified time period. ### URL Implementation[](/iframe#url-implementation) The `URL` method is recommended for NFT projects using static images for their artwork, and/or existing projects and wish to show their NFT's Tokenbound account. This method requires updating the `animation_url` of your NFT's metadata to match this pattern: { "animation_url": "https://iframe-tokenbound.vercel.app///" } `contractAddress`: the contract address of the NFT collection you wish to display `tokenId`: the token ID of the individual NFT to be rendered in the iframe `chainId`: the chain ID of where your NFT collection resides. The following tables shows currently supported chains. | Network | Chain ID | | --- | --- | | Ethereum Mainnet | 1 | | Ethereum Goerli | 5 | | Ethereum Sepolia | 11155111 | | Polygon Mainnet | 137 | | Polygon Mumbai | 80001 | | Optimism Mainnet | 420 | For example, using `token ID 1` from the `Sapienz` collection on mainnet `1`: [https://iframe-tokenbound.vercel.app/0x26727ed4f5ba61d3772d1575bca011ae3aef5d36/1/1](https://iframe-tokenbound.vercel.app/0x26727ed4f5ba61d3772d1575bca011ae3aef5d36/1/1) This iframe implementation relies on Alchemy's indexer to render the NFT's media. If your project uses a custom API to render the NFT's media, use the custom implementation below. ### Custom Implementation[](/iframe#custom-implementation) Fork and clone the iframe repo -------------------------------- git clone git@github.com:githubUser/iframe.git Setup environment variables ----------------------------- cat .env.example > .env.local Create an Alchemy account and API key --------------------------------------- Navigate to [https://dashboard.alchemy.com/](https://dashboard.alchemy.com/) and create a new app Update your environment variables with your Alchemy NEXT_PUBLIC_ALCHEMY_KEY="" NEXT_PUBLIC_PROVIDER_ENDPOINT="https://..." Create a Graph studio account and API key ------------------------------------------- Navigate to [https://thegraph.com/studio/](https://thegraph.com/studio/) and create an API key (used for checking token approvals) You will need to fund your account with GRT tokens. Update `NEXT_PUBLIC_GRAPH_API_KEY` with your sub graph credentials. NEXT_PUBLIC_GRAPH_API_KEY="" Use in your custom api endpoint to fetch your NFT's media ----------------------------------------------------------- The application expects the endpoint to be: `string | string[]`, where the string is a url link to your NFT's assets. It should dynamically have a route for each tokenId. For example the `NEXT_PUBLIC_NFT_ENDPOINT` env variable is `https://nft-api.com/nft`. The application will then take the tokenId from the URL and make a fetch to that endpoint: `https://nft-api.com/nft/`. ... NEXT_PUBLIC_NFT_ENDPOINT="..." Host your application ----------------------- Host your application on a service provider of your choice and set your metadata server with that host. { "animation_url": "https://iframe-tokenbound.vercel.app///" } ### Options[](/iframe#options) Add the query param `?disableloading=true` to not have Tokenbound logo animation before the iframe starts. --- # Query TBA address for an NFT - Tokenbound Documentation [Skip to content](/guides/read-a-tba#vocs-content) Search [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Sun Moon [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [ERC-6551](https://eips.ethereum.org/EIPS/eip-6551) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Menu Query TBA address for an NFT On this page Chevron Right The Tokenbound SDK is compatible with both [viem](https://viem.sh/) and [Ethers](https://docs.ethers.org/v6/) . viem is a core SDK dependency, so we recommend using viem except for legacy Ethers projects. The following Tutorial uses [`create-wagmi` ↗️](https://wagmi.sh/cli/create-wagmi) boilerplate ![demo screenshot](https://i.imgur.com/z7a17B3.png) [Demo](https://tb-sdk-demo-create-wagmi.vercel.app/) [Source Code](https://github.com/anggxyz/tb-sdk-demo-create-wagmi) ### Install dependencies[](/guides/read-a-tba#install-dependencies) $ npm init wagmi This is the config used for the demo: ![](https://i.imgur.com/Ubustim.png) next, we install the `tokenbound/sdk` $ npm install @tokenbound/sdk ### Create a Form to input NFT contract address and token Id[](/guides/read-a-tba#create-a-form-to-input-nft-contract-address-and-token-id) We want a component that allows entering NFT contract address and Token Id. And another component that allows viewing the associated Tokenbound account ![](https://i.imgur.com/znpEUZw.png) The `src/app/page.tsx` is pre-populated with some helpful components that wagmi provides with the boilerplate. We can remove them for now. Feel free to remove everything from that file and add this: // src/app/page.tsx export default function Page() { return (

Check tokenbound account for an NFT

) } We create a new component inside `src/components` called `tba.tsx` 'use client' // src/components/tba.tsx ... ... export default function TBA() { return (
) } We can now import this component in our home page inside `src/app/page.tsx`: // src/app/page.tsx import TBA from '../components/tba' export default function Page() { return (

Check tokenbound account for an NFT

) } we first define global functions and objects in `tba.tsx` component: // src/components/tba.tsx import { useWalletClient } from 'wagmi' import { mainnet } from 'viem/chains' import { TokenboundClient } from '@tokenbound/sdk' import { type TBAccountParams } from "@tokenbound/sdk/dist/src/TokenboundClient"; const DEFAULT_ACCOUNT: TBAccountParams = { tokenContract: "0xe7134a029cd2fd55f678d6809e64d0b6a0caddcb", tokenId: "9" } then state variables and helper functions: // src/components/tba.tsx // ... // ... export default function TBA() { const { data: walletClient, isError, isLoading } = useWalletClient(); const tokenboundClient = new TokenboundClient({ walletClient, chainId: CHAIN_ID }) const [retrievedAccount, setRetrievedAccount] = useState(""); const [TBAccount, setTBAccount] = useState(DEFAULT_ACCOUNT) const getAccount = () => { try { const account = tokenboundClient.getAccount(TBAccount) setRetrievedAccount(account); } catch(err) { // ... } } const resetAccount = () => { setRetrievedAccount(""); setTBAccount(DEFAULT_ACCOUNT); // ... } // ... // ... // ... // ... } Inside this component, we return with a basic structure of the component, before adding a form in the next step: // src/components/tba.tsx export default function TBA() { // ... // ... // ... return (

Check tokenbound account for any NFT

{/* components go here */}
) } and finally we create a form like: // src/components/tba.tsx export default function TBA() { // ... // ... // ... return ( <> // ... // ... // ...
setTBAccount({ ...TBAccount, tokenContract: event.target.value as TBAccountParams["tokenContract"] })} value={TBAccount.tokenContract} /> setTBAccount({ ...TBAccount, tokenId: event.target.value })} value={TBAccount.tokenId} />
// ... // ... // ... ) } ### Display data[](/guides/read-a-tba#display-data) Next, we display the data we stored in state variables in the previous step inside our TBA component ![](https://i.imgur.com/wCExmiv.png) we now just display all the state variables we defined // src/components/tba.tsx
        {JSON.stringify({...TBAccount, retrievedAccount}, null, 2)}
      
### That's it! 🎉[](/guides/read-a-tba#thats-it-) View the codebase for this example app [here](https://github.com/anggxyz/tb-sdk-demo-create-wagmi) . --- # Deploy the ERC-6551 Registry - Tokenbound Documentation [Skip to content](/guides/deploy-registry#vocs-content) Search [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Sun Moon [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [ERC-6551](https://eips.ethereum.org/EIPS/eip-6551) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Menu Deploy the ERC-6551 Registry On this page Chevron Right The ERC-6551 Registry contract has already been deployed across several EVM networks. A list of deployed addresses can be found [here](/contracts/deployments) . Install Foundry ----------------- $ curl -L https://foundry.paradigm.xyz | bash $ foundryup Clone the Reference repository -------------------------------- $ git clone https://github.com/erc6551/reference.git $ git checkout tags/v0.3.1 Run the tests and build the contracts --------------------------------------- $ forge test $ forge build Compute the Registry address ------------------------------ This is to make sure it matches with `0x000000006551c19487814612e58FE06813775758` $ forge script script/ComputeRegistryAddress.s.sol:ComputeRegistryAddress The output should be: [⠒] Compiling... No files changed, compilation skipped Script ran successfully. Gas used: 24925 == Logs == 0x000000006551c19487814612e58FE06813775758 Deploy the Registry --------------------- Before we can deploy we need to provide `MAINNET_PRIVATE_KEY` env variable - set this to your test account’s private key $ forge script --fork-url script/DeployRegistry.s.sol --broadcast Replace `` with your chain's RPC endpoint --- # Connect to dapps as an NFT - Tokenbound Documentation [Skip to content](/guides/connect-with-nft#vocs-content) Search [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Sun Moon [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [ERC-6551](https://eips.ethereum.org/EIPS/eip-6551) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Menu Connect to dapps as your TBA On this page Chevron Right Your Tokenbound account is a smart contract wallet that's paired with your NFT, giving it the ability to do anything a wallet can. That means you can use your NFT to connect to websites and DApps using WalletConnect and perform actions on behalf of your NFT. Here's a quick guide on how to do it. On the site you want to connect to, open the connect wallet tool and tap WalletConnect. Then copy the WC connection details using the blue copy button on the top right: ![Connect Wallet](/walletconnect/connect-wallet-modal.png) On your NFT's page on **tokenbound.org**, click `Connect with NFT`: ![Connect Button](/walletconnect/connect-button.png) The **Log in as your NFT** modal should appear, and the connection code should be pre-populated in the field. Paste the code you copied, if needed, then click Connect: ![Login Modal](/walletconnect/login-modal.png) Your wallet should open and prompt you to sign a message to log in: ![Signature](/walletconnect/signature.png) Success! Now you can interact with DApps as your NFT. Any assets added to your NFT's Tokenbound account will be shown on its page on **tokenbound.org** --- # Interact with your Tokenbound Account (TBA) on local blockchain using nodejs - Tokenbound Documentation [Skip to content](/guides/interact-with-tba#vocs-content) Search [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Sun Moon [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [ERC-6551](https://eips.ethereum.org/EIPS/eip-6551) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Menu Execute TBA transactions using SDK On this page Chevron Right This guide walks you through transferring ETH to and from from a TBA you own, using nodejs scripts for a TBA on your local blockchain node. Below are the steps we’ll be following: Prep: 1. spin up a local test node (anvil) — you should be able to follow the same steps using an EVM compatible chain’s RPC url as well. 1. Deploy the registry contract on the canonical address 2. Deploy an account implementation contract 2. Deploy a test NFT contract 3. Mint a token to an address you have the private key for Walkthrough with scripts: 1. Initialise the SDK with the NFT’s contract address and token id you just minted 2. Transfer ETH from your wallet to the associated TBA of your NFT contract + token ID (a TBA is always associated with a (nft contract, token id) pair) 3. Deploy the Tokenbound account for this NFT contract + token id 4. Transfer ETH from the TBA to your wallet [Source Code](https://github.com/anggxyz/tb-deploy-demo) Setup ------- Clone the repository $ gh repo clone anggxyz/tb-deploy-demo $ cd tb-deploy-demo/contracts/erc6551-reference && forge build && cd ../test-nft && forge build && cd ../../ Spin up a local test node (anvil) ----------------------------------- $ anvil Deploy NFT contract --------------------- $ cd contracts/test-nft Set an account’s private key in .env with key `PRIVATE_KEY` and RPC url with key `RPC_URL` $ forge create NFT --rpc-url=$RPC_URL --private-key=$PRIVATE_KEY --constructor-args "test" "TEST" The output should look something like ❯ ... [⠒] Compiling... [⠃] Compiling 5 files with 0.8.10 [⠊] Solc 0.8.10 finished in 243.92ms Compiler run successful! Deployer: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 Deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3 Transaction hash: 0x04ff2f73f02b130516afabd60a42be636cb8febf0d2a04481fc80c645d1aa306 Mint an NFT ------------- Set own account address in .env with key `ACCOUNT_ADDRESS` $ cast send --rpc-url=$RPC_URL --private-key=$PRIVATE_KEY CONTRACT_ADDRESS "mintTo(address)" $ACCOUNT_ADDRESS Deploy the Registry contract ------------------------------ $ cd ../erc6551-reference $ cast rpc anvil_setCode 0x4e59b44847b379578588920ca78fbf26c0b4956c 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3 make sure you have RPC url set in the .env with key `RPC_URL` forge script --fork-url=$RPC_URL script/DeployRegistry.s.sol Setup tokenbound client ------------------------- We’ll be storing all the constants in a file called `constants.ts` // constants.ts export const CONSTANTS = { "NFT_CONTRACT": NFT_CONTRACT_ADDRESS, "NFT_ID": "1", "CHAIN_ID": 31337, "RPC":"http://127.0.0.1:8545", "ACCOUNT_IMPLEMENTATION": ACCOUNT_IMPLEMENTATION_CONTRACT /** (remove this key if using an EVM compatible chain, this key is only required for local/fresh chain) **/ } Create a file called `client.ts` and initialise and export `tokenboundClient` and `tokenboundAccount` // client.ts import { TokenboundClient } from "@tokenbound/sdk"; import { JsonRpcProvider, Wallet, formatEther } from "ethers"; import { CONSTANTS } from "./constants" import { TBAccountParams } from "@tokenbound/sdk/dist/src/TokenboundClient"; const { CHAIN_ID, NFT_CONTRACT, NFT_ID, RPC, ACCOUNT_IMPLEMENTATION } = CONSTANTS; export const provider = new JsonRpcProvider(RPC); if (!process.env.TEST_ACCOUNT) { console.error ("TEST_ACCOUNT private key undefined in .env"); process.exit(); } export const wallet = new Wallet(process.env.TEST_ACCOUNT, provider); const tokenboundClient = new TokenboundClient({ signer: wallet, chainId: CHAIN_ID, implementationAddress: ACCOUNT_IMPLEMENTATION as `0x${string}` }); export const tokenBoundAccount = tokenboundClient.getAccount({ tokenContract: NFT_CONTRACT as TBAccountParams["tokenContract"], tokenId: NFT_ID, }); // util function to display balance const displayBalance = async (address: string) => { const balance = await provider.getBalance(address); console.log(`balance of ${address}: ${formatEther(balance)}`) } export default tokenboundClient; Transfer ETH from your wallet to the associated TBA ----------------------------------------------------- Transfer ETH from your wallet to the associated TBA of your NFT contract + token ID (a TBA is always associated with a (nft contract, token id) pair) We create a new script named 1-transfer.ts, this would transfer funds from wallet → TBA // 1-transfer.ts import { formatEther, parseEther } from "ethers"; import { wallet, provider, tokenBoundAccount, displayBalance } from "./client"; // transfer eth from Wallet -> TBA (async () => { console.log(`sender:`, wallet.address); await displayBalance(wallet.address); const amount = parseEther("1"); console.log(`sending ${formatEther(amount)} ETH from ${wallet.address} to ${tokenBoundAccount}`); await wallet.sendTransaction({ to: tokenBoundAccount, value: amount }) await displayBalance(wallet.address); await displayBalance(tokenBoundAccount); })() Deploy the Tokenbound account for this NFT contract + token id ---------------------------------------------------------------- Before we can interact with the TBA to transfer funds to and from the account, we would need to deploy the account on the deterministic address that was retrieved in the first step when we executed the function getAccount from the SDK To deploy the account, we create a new script named 2-deploy.ts with the following code: // 2-deploy.ts import { CONSTANTS } from "./constants" import { TBAccountParams } from "@tokenbound/sdk/dist/src/TokenboundClient"; const { NFT_CONTRACT, NFT_ID } = CONSTANTS; import client, {tokenBoundAccount} from "./client"; (async () => { console.log(`Tokenbound Address ${tokenBoundAccount} for NFT: ${NFT_CONTRACT} and NFT ID: ${NFT_ID}`); console.log(`deploying account...`); const account = await client.createAccount({ tokenContract: NFT_CONTRACT as TBAccountParams["tokenContract"], tokenId: NFT_ID, }); console.log(account); })() Transfer ETH from the TBA to your wallet ------------------------------------------ Now that the account is deployed we can transfer ETH from the TBA back to the wallet. Creating a new script called `3-transfer.ts` // 3-transfer.ts import { formatEther, parseEther } from "ethers"; import { TBAccountParams } from "@tokenbound/sdk/dist/src/TokenboundClient"; import client, {wallet, provider, tokenBoundAccount, displayBalance} from "./client"; // transfer eth from B -> A (async () => { console.log(`wallet: ${wallet.address}`); await displayBalance(wallet.address); console.log(`TBA address: ${tokenBoundAccount}`) displayBalance(tokenBoundAccount) const amount = parseEther("1"); console.log(`sending ${formatEther(amount)} ETH from ${tokenBoundAccount} to ${wallet.address}`); const executedCall = await client.executeCall({ account: tokenBoundAccount, to: wallet.address as TBAccountParams["tokenContract"], value: amount, data: "", }); console.log("\n---\n",executedCall,"\n---\n"); await provider.waitForTransaction(executedCall); await displayBalance(wallet.address); await displayBalance(tokenBoundAccount); })() --- # Account - Tokenbound Documentation [Skip to content](/contracts/account#vocs-content) Search [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Sun Moon [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [ERC-6551](https://eips.ethereum.org/EIPS/eip-6551) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Menu Account On this page Chevron Right Tokenbound provides an opinionated, flexible, and audited ERC-6551 account implementation. The full source code of the Tokenbound ERC-6551 account implementation can be found in the [`tokenbound/contracts` repo](https://github.com/tokenbound/contracts/blob/main/src/AccountV3.sol) . --- # Deploy a custom account implementation - Tokenbound Documentation [Skip to content](/guides/deploy-account-implementation#vocs-content) Search [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Sun Moon [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [ERC-6551](https://eips.ethereum.org/EIPS/eip-6551) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Menu Deploy a custom account implementation On this page Chevron Right ERC-6551 (the proposal that introduces a new standard to the Ethereum chain, that enables Tokenbound accounts) introduces a _new relationship,_ **not** a new standard for ERC721 tokens and the token owners. The components include a Registry contract - specific to the chain and an account implementation contract - a common interface offered by Tokenbound that ensures the accounts are deployed to the same address across all chains. It is possible to use your own custom implementation contract as well and that is what this guide will walk you through 🚶‍♀️ ![erc6551 diagram](https://i.imgur.com/alujCO4.png) Setup ------- Clone the reference repository $ gh repo clone erc6551/reference Build the contracts $ forge build Deploy -------- set an account’s private key in .env with key `PRIVATE_KEY` and RPC url with key `RPC_URL` forge create src/examples/simple/SimpleERC6551Account.sol:SimpleERC6551Account --rpc-url=$RPC_URL --private-key=$PRIVATE_KEY The output should look something like: ❯ ... [⠢] Compiling... No files changed, compilation skipped Deployer: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 Deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3 Transaction hash: 0xb6c98880b4c92d2f5b2dc329f34b9d431e14a6a8648bb3a3f7dde2c454df4a79 Now whenever you initialise the SDK, you can override the default token implementation by specifying your implementation’s contract address instead: import { TokenboundClient } from "@tokenbound/sdk"; export const provider = new JsonRpcProvider(RPC); export const wallet = new Wallet(process.env.TEST_ACCOUNT, provider); const tokenboundClient = new TokenboundClient({ signer: wallet, chainId: 31337, implementationAddress: ACCOUNT_IMPLEMENTATION as `0x${string}` }); --- # Registry - Tokenbound Documentation [Skip to content](/contracts/registry#vocs-content) Search [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Sun Moon [![Logo](/tokenbound-light.svg)![Logo](/tokenbound-dark.svg)](/) [ERC-6551](https://eips.ethereum.org/EIPS/eip-6551) [GitHub](https://github.com/tokenbound) [X](https://twitter.com/tokenbound_) [Telegram](https://t.me/tokenbound) Menu Registry On this page Chevron Right The ERC-6551 registry is responsible for calculating account addresses for each ERC-721 token, as well as deploying the account at that address. The full source code of the ERC-6551 registry can be found in the [reference implementation](https://github.com/erc6551/reference/blob/main/src/ERC6551Registry.sol) . --- # Unknown The page could not be found NOT\_FOUND iad1::tlgx7-1737646423899-0c79df9a1d22 ---