# Overview

What is DelegateRegistry, who's using it, and how you can use it

[**delegate.xyz**](https://delegate.xyz) is the best solution to secure valuable onchain assets while still participating in NFT airdrop claims, ERC20 token governance, and more. Users link cold wallets with hot wallets, and then the hot wallet can act on behalf of the cold wallet, like crypto power-of-attorney.\
\
It can be incorporated into login flows, token-gated minting & claiming, gaming actions, DAO governance, and more. By integrating the registry, your product improves by (1) derisking new user acquisition from those who have already delegated; (2) making it safer and easier for existing users to interact with your app from hot/mobile wallets without risking security. Get in touch if you're interested in using!

## Who's Using It?

We've seen 150+ project integrations onchain, and even more offchain. This is a list of highlights, not comprehensive. Analytics nerds can dive even deeper by looking at registry code integrations on [Codeslaw](https://www.codeslaw.app/search?chain=ethereum\&q=IDelegationRegistry). Unique usecases are bolded on their first appearance in the list.

<figure><img src="https://3301342738-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKMp3PwjpKKfLzakTeUUs%2Fuploads%2FeEbJgTpjNUDSX0BqO5rR%2FScreenshot%202023-09-23%20at%2012.10.53%20PM.png?alt=media&amp;token=642572ab-3ad0-4a69-aebc-e29a80d14b81" alt=""><figcaption></figcaption></figure>

<table><thead><tr><th width="222">Project</th><th>Summary</th><th>Description</th><th>Link</th></tr></thead><tbody><tr><td>Azuki</td><td><strong>Allowlisted minting</strong></td><td>Directly enabled ~2000+ Elementals mints</td><td><a href="https://twitter.com/0xfoobar/status/1673426478636183554">https://twitter.com/0xfoobar/status/1673426478636183554</a></td></tr><tr><td>OpenSea</td><td><strong>Theft prevention</strong></td><td>Introduced 3-hour hold period on transferred assets, using Delegate to wallet ownership</td><td><a href="https://twitter.com/opensea/status/1621276759932149761">https://twitter.com/opensea/status/1621276759932149761</a></td></tr><tr><td>Yuga Labs HV-MTL</td><td><strong>Gaming access</strong></td><td>Mint HV-MTL from a hotwallet, then delegate gameplay rights to other addresses</td><td><a href="https://twitter.com/ParaX_ai/status/1674221397424603137">https://twitter.com/ParaX_ai/status/1674221397424603137</a></td></tr><tr><td>Yuga Labs SewerPass</td><td>Gaming access</td><td>Mint Sewerpass from a hotwallet, then delegate gameplay rights to other addresses</td><td><a href="https://twitter.com/0xfoobar/status/1615392203152424973">https://twitter.com/0xfoobar/status/1615392203152424973</a></td></tr><tr><td>Opepen</td><td><strong>Tokengated reveal</strong></td><td>Opepen holders can opt into a new set reveal with delegated wallet</td><td><a href="https://twitter.com/jalil_eth/status/1653382501916655623">https://twitter.com/jalil_eth/status/1653382501916655623</a></td></tr><tr><td>Tokenproof</td><td><strong>Event ticketing</strong></td><td>Their offchain integration lets people claim event tickets/QR codes with a delegated wallet</td><td><a href="https://twitter.com/tokenproof/status/1596291355176628224">https://twitter.com/tokenproof/status/1596291355176628224</a></td></tr><tr><td>EthPass/Moonpay</td><td>Event ticketing</td><td>Their offchain integration lets people claim event tickets/QR codes with a delegated wallet</td><td><a href="https://twitter.com/ethpass/status/1626255759876169728">https://twitter.com/ethpass/status/1626255759876169728</a></td></tr><tr><td>ArtBlocks</td><td><strong>Allowlisting platform minting</strong></td><td>Their core drop allowlisting mechanic lets artists and friends mint using delegated wallets</td><td><a href="https://etherscan.io/address/0x0711a9767a41290d7f52714204618345c584f450#code">https://etherscan.io/address/0x0711a9767a41290d7f52714204618345c584f450#code</a></td></tr><tr><td>Manifold</td><td>Allowlisting platform minting</td><td>Proves ownership of an allowlisted address</td><td><a href="https://twitter.com/manifoldxyz/status/1628875214988926979">https://twitter.com/manifoldxyz/status/1628875214988926979</a></td></tr><tr><td>Premint</td><td>Allowlisting platform minting</td><td>Proves ownership of an allowlisted address</td><td><a href="https://twitter.com/premint/status/1625284660782850048">https://twitter.com/premint/status/1625284660782850048</a></td></tr><tr><td>Braindrops</td><td>Allowlisting platform minting</td><td>Their core drop allowlisting mechanic lets artists and friends mint using delegated wallets</td><td><a href="https://etherscan.io/address/0x5ec433aaf1d0ea1f7a22f5bf02ab00bdbd5c2ccc">https://etherscan.io/address/0x5ec433aaf1d0ea1f7a22f5bf02ab00bdbd5c2ccc</a></td></tr><tr><td>ForgottenRunes</td><td><strong>NFT airdrop</strong></td><td>Their Trick-Or-Treat experience gave an airdrop to cryptopunks, bored apes, and more</td><td><a href="https://etherscan.io/address/0xD52c79d897a24c275729112C3C5ea813b5703f88#code">https://etherscan.io/address/0xD52c79d897a24c275729112C3C5ea813b5703f88#code</a></td></tr><tr><td>Nouns</td><td><strong>Onchain governance</strong></td><td>Users can pool nouns and take voting actions from a delegated wallet</td><td><a href="https://etherscan.io/address/0xbe5e6de0d0ac82b087baaa1d53f145a52efe1642">https://etherscan.io/address/0xbe5e6de0d0ac82b087baaa1d53f145a52efe1642</a></td></tr><tr><td>InvisibleFriends</td><td>NFT airdrop</td><td>Their 3D drop gave a free claim to holders of the original collection</td><td><a href="https://etherscan.io/address/0x49c36afa15c7fdbd57ce3d61d80f39b6615a76ef#code">https://etherscan.io/address/0x49c36afa15c7fdbd57ce3d61d80f39b6615a76ef#code</a></td></tr><tr><td>Phaver</td><td><strong>Social media access control</strong></td><td>Users can login to their crypto social with delegated wallets</td><td><a href="https://twitter.com/phaverapp/status/1687445533151870976">https://twitter.com/phaverapp/status/1687445533151870976</a></td></tr><tr><td>Friendship Bracelets</td><td>NFT airdrop</td><td>Their airdrop gave a 2x free claim to artblocks holders</td><td><a href="https://etherscan.io/address/0x942bc2d3e7a589fe5bd4a5c6ef9727dfd82f5c8a">https://etherscan.io/address/0x942bc2d3e7a589fe5bd4a5c6ef9727dfd82f5c8a</a></td></tr><tr><td>BendDAO</td><td><strong>Utility access while in lending platform</strong></td><td>Users keep utility access (discord chats, airdrop claims, etc) while using their NFT as collateral</td><td><a href="https://twitter.com/BendDAO/status/1689317782226182160">https://twitter.com/BendDAO/status/1689317782226182160</a></td></tr><tr><td>ParaSpace</td><td>Utility access while in lending platform</td><td>Users keep utility access (discord chats, airdrop claims, etc) while using their NFT as collateral</td><td><a href="https://twitter.com/Xeer/status/1644613530363269124">https://twitter.com/Xeer/status/1644613530363269124</a></td></tr><tr><td>Arcade</td><td>Utility access while in lending platform</td><td>Users keep utility access (discord chats, airdrop claims, etc) while using their NFT as collateral</td><td><a href="https://twitter.com/Arcade_xyz/status/1620524688094154753">https://twitter.com/Arcade_xyz/status/1620524688094154753</a></td></tr><tr><td>Bitcoin Ordinals</td><td><strong>Tokengated minting</strong></td><td>Prove token ownership before using an ETH-BTC bridge to mint an ordinal version</td><td><a href="https://etherscan.io/address/0x165f848f980309f6147b8adfc8589cc35c587ca7#code">https://etherscan.io/address/0x165f848f980309f6147b8adfc8589cc35c587ca7#code</a></td></tr><tr><td>Nakamigos</td><td>NFT airdrop</td><td>Free Cloaks to Nakamigos holders</td><td><a href="https://twitter.com/delegatedotxyz/status/1704902425276989831">https://twitter.com/delegatedotxyz/status/1704902425276989831</a></td></tr><tr><td>CollabLand</td><td><strong>Discord access</strong></td><td>Connect a hot wallet to access tokengated Discord channels</td><td><a href="https://twitter.com/Collab_Land_/status/1623087015289040896">https://twitter.com/Collab_Land_/status/1623087015289040896</a></td></tr><tr><td>Vulcan</td><td>Discord access</td><td>Connect a hot wallet to access tokengated Discord channels</td><td><a href="https://twitter.com/VulcanAuth/status/1623813363229761536">https://twitter.com/VulcanAuth/status/1623813363229761536</a></td></tr></tbody></table>

<figure><img src="https://3301342738-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKMp3PwjpKKfLzakTeUUs%2Fuploads%2FAQ7V2K8Xci4SOx0E0hme%2FScreenshot%202022-12-06%20at%203.37.33%20PM.png?alt=media&amp;token=383939e3-128b-4848-b66f-dae4e3a788c9" alt=""><figcaption></figcaption></figure>

## What are the Features?

* **Fully Onchain**

  There are no offchain signatures floating around a hidden relay network. This gives users important assurances that what you see is what you get. Attack vectors like the OpenSea [stale listings problem](https://support.opensea.io/hc/en-us/articles/4415742560403-What-is-an-inactive-listing-) are prevented.
* **Fully Enumerable**

  We provide onchain methods to get a complete list of all delegations for both cold and hot wallets. No event parsing needed. This greatly simplifies integration efforts for both smart contract and frontend developers.
* **Fully Independent**

  There are zero external dependencies or admin/governance control, so the attack surface is locked down and the registry can deployed on any EVM chain of your choice.
* **Fully Immutable**

  There are zero admin powers. Because governance is an attack vector, there should be none of it in a neutral trustless delegation standard. The standard is designed to be as flexible as possible, but upgrades are always possible by deploying a new registry with different functionality.
* **Fully Verifiable**

  By using vanity addresses for CREATE2 deployment, the contract can be permissionlessly deployed at the same 14-leading-zeros address across multiple chains. This makes it easier for end users to verify that they’re interacting with the correct contract.

## How does it work for normal crypto users?

**You’ll use** [**https://delegate.xyz/**](https://delegate.xyz/) **to assign a hotwallet delegate for your coldwallet vault - that's it.** The delegate has permission to claim airdrops or other utility on behalf of the vault, but it cannot touch anything within the vault. The granular permissioning lets you assign a delegate for either (1) everything; (2) a specific contract; (3) a specific token. For fungible ERC20/1155 tokens you'll be prompted to enter a specific token amount to delegate; for nonfungible ERC721/1155 tokens you'll be prompted to enter a specific token id to delegate.

<figure><img src="https://3301342738-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKMp3PwjpKKfLzakTeUUs%2Fuploads%2FlQIzCzfj65tRwLV4Di6q%2FScreenshot%202023-09-23%20at%209.55.57%20AM.png?alt=media&amp;token=a2b84ce9-7101-489f-bdf1-6ea2f46b4783" alt=""><figcaption></figcaption></figure>

## How about smart contract wallets like Gnosis Safe or 4337?

Since the registry does not rely on offchain signatures and instead exclusively uses \`msg.sender\` for authentication, it works just as well for smart contract wallets as it does for externally-owned-accounts (EOAs) like Metamask/Rabby/Rainbow.

For Gnosis Safe, [follow the instructions here](https://help.safe.global/en/articles/40849-walletconnect-safe-app) for using WalletConnect. WalletConnect should also work for other smart contract wallet types.

## How does it work for smart contract devs?

Writing a smart contract? Follow the instructions in [Smart Contract Examples](/integrate-in-your-project/smart-contract-examples). Import the the [IDelegateRegistry.sol](/technical-documentation/delegate-registry/idelegateregistry.sol) interface to interact with the deployed registry address found in [Contract Addresses](/technical-documentation/delegate-registry/contract-addresses). You'll query the registry to see if a delegated address has permissions to act on behalf of another.

<figure><img src="https://3301342738-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKMp3PwjpKKfLzakTeUUs%2Fuploads%2FGq3arRpNNJmBMmG57Ncp%2Fcarbon(12).png?alt=media&amp;token=38768351-12b3-42c6-885b-66781db69afe" alt=""><figcaption><p>Sample smart contract integration</p></figcaption></figure>

## How does it work for frontend devs?

Use the JavaScript SDK or HTTP REST API found in [Setup](/technical-documentation/javascript-sdk/setup) to fetch a list of incoming and outgoing delegations for a connected wallet.

## Comparison with Status Quo

<figure><img src="https://3301342738-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKMp3PwjpKKfLzakTeUUs%2Fuploads%2FPL3voi6gdBl5STAodaN2%2FScreenshot%202023-07-31%20at%2012.48.49%20PM.png?alt=media&amp;token=03257c6c-4487-47f2-a0f8-5786e412f6bf" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3301342738-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKMp3PwjpKKfLzakTeUUs%2Fuploads%2FDUOlcwvMoxDCF84lxZ8R%2Fflow.jpg?alt=media&amp;token=38f44cfd-7f88-4ec8-a2c8-f11ffabbd725" alt=""><figcaption><p>Contract interaction with DelegateRegistry for Solidity devs</p></figcaption></figure>


# Delegating a wallet

Click the searchbar or the "Delegate assets" link on the main page to get started. It'll open up this modal window.

<figure><img src="https://3301342738-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKMp3PwjpKKfLzakTeUUs%2Fuploads%2FlQIzCzfj65tRwLV4Di6q%2FScreenshot%202023-09-23%20at%209.55.57%20AM.png?alt=media&amp;token=a2b84ce9-7101-489f-bdf1-6ea2f46b4783" alt=""><figcaption></figcaption></figure>

**What if I already delegated on Registry V1?**

If you already delegated using V1, that data is in the V1 contract. Over time, projects will migrate to V2 and it's important you migrate your delegation to V2 if you want it to be recognized by these newer projects. The default delegation on the portal is now V2.

You can migrate your delegation by clicking on the migration banner when you connect your wallet if you have existing V1 delegations in place.

<figure><img src="https://3301342738-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKMp3PwjpKKfLzakTeUUs%2Fuploads%2FqzniymCusi97C0MEjjKC%2Fmigrate.jpg?alt=media&amp;token=fbd59480-a917-4576-914b-ab738d2ce909" alt=""><figcaption></figcaption></figure>

Clicking the migrate button will populate all your V1 delegations into one V2 batch call so you can easily re-delegate in the more powerful V2 contract to ensure projects which support the latest contract will recognize the delegation.

**What is the difference between Wallet, Contact, and Asset delegation?**

We offer several permissioning options to customize what parts of your wallet you want to delegate. Most users delegate their entire wallet or a specific contract, but we enable more powerful granularity for those who need it.

* **Wallet:** This will delegate your entire wallet, all contracts and assets within it.
* **Contract:** Will only delegate a specific contract. Other contracts/assets remain undelegated.
* **Asset:** Will only delegate a specific tokenId and/or amount of tokens on a specific contract. Autodetects whether a contract address is ERC20, ERC721, or ERC1155. For ERC20 you delegate an amount, for ERC721 you delegate a tokenId, for ERC1155 you delegate a tokenId and amount.

<figure><img src="https://3301342738-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKMp3PwjpKKfLzakTeUUs%2Fuploads%2FTV9KPkHYNuHxgWRwxQjy%2FScreenshot%202023-09-23%20at%202.24.27%20PM.png?alt=media&amp;token=4b0ecf32-d227-48b2-9fef-8c394e252cc7" alt=""><figcaption></figcaption></figure>

These work from a top down approach. For example, if you delegate your entire wallet, when someone checks if you have a specific contract or token delegated, it will return `true`.&#x20;

Same thing for delegating a specific contract. When you check if a specific token is delegated, it will return `true` as well.


# Comparison with Others

Snapshot [has](https://etherscan.io/address/0x469788fe6e9e9681c6ebf3bf78e7fd26fc015446) a very single one-to-one delegation contract used for their offchain voting system. Simple enough to work for offchain stuff, but not much uptake in onchain composability. As governance moves onchain we'll need tooling to delegate a specific amount of fungible tokens, to delegate them for specific purposes, etc. \~50k contract interactions here, but limited onchain usage.

WarmXYZ [was](https://etherscan.io/address/0xc3aa9bc72bd623168860a1e5c6a4530d3d80456c) the first delegation solution to come to market, but is overly simplistic and ruggable. It doesn't support contract- or token-level delegations, and is an upgradeable proxy that can change at any time. Nor is it built to be natively multichain. \~20k contract interactions.

EternalProxy [tries](https://etherscan.io/address/0x888888888888660f286a7c06cfa3407d09af44b2) to eliminate the need to visit a delegation website by impersonating an ERC20 token and having magic value transfers represent a delegation. This is the worst of both worlds, hard to understand, hard to compose, and hard to use without a friendly UI. Stands at 3500 lines of code in a single contract, compared to 500 for ours. <1k contract interactions here.&#x20;

Double Protocol is approaching the NFT rental market with their own EIP standard, but unfortunately it's not backwards compatible with the vast majority of ERC721s and thus only works on a small segment of gaming NFTs. Whereas we've built Delegate Market to work for any token, even if it was deployed years in the past.


# FAQ

**Is Delegate multichain?**

Yes, we're deployed on 17 different EVM chains, including Ethereum, Polygon, BSC, Avalanche, Arbitrum, Optimism, and Base. There are also two testnet deployments on Goerli and Sepolia.

**Is Delegate crosschain?**

No, each chain's deployment is self-contained with no dependencies or bridge risk. This means if a user wants to use a delegated wallet on both Ethereum and Polygon, they will need to delegate once on each chain. We're investigating options for crosschain messaging but given the novel risks this is not live today.


# Audits

Code4rena audited both the V2 Registry and Delegate Marketplace contracts in Nov 2023. [Full report here](https://code4rena.com/reports/2023-09-delegate). Zero criticals, zero highs, all medium vulnerabilities remediated prior to launch.


# Smart Contract Examples

Specific examples and general principles for integrating DelegateRegistry into your Solidity smart contract

**Sample Token-Gated Mint w/ Delegate**

Here the constant `ORIGINAL_CONTRACT` would be the one with the original tokens whose holders are being allowlisted. The constant`DELEGATE_REGISTRY` address would be `0x00000000000000447e69651d841bD8D104Bed493`.

```solidity
/** 
 * @notice For example, bored ape holders minting their mutant apes
 * @param originalTokenIds The ids of tokens being used to mint something new
 */
function tokengatedMint(uint256[] calldata originalTokenIds) external {
    for (uint256 i = 0; i < originalTokenIds.length; ++i) {
        uint256 tokenId = originalTokenIds[i];
        address tokenOwner = ORIGINAL_CONTRACT.ownerOf(tokenId);
        // Mint if tokenOwner is msg.sender or tokenOwner delegated to msg.sender
        if (msg.sender == tokenOwner ||
            IDelegateRegistry(DELEGATE_REGISTRY).checkDelegateForERC721(
                msg.sender,
                tokenOwner,
                address(ORIGINAL_CONTRACT),
                tokenId,
                ""
            )
        ) {
            // Can mint to either the vaulted wallet or msg.sender, project's choice
            // Can also use an `address recipient` function parameter for flexibility
            _mint(tokenOwner, tokenId);
        }
    }
}
```

**Sample Merkle Tree Claim w/ Delegate**

This is based off what [Nakamigos CLOAKS](https://etherscan.io/token/0x0c56f29b8d90eea71d57cadeb3216b4ef7494abc#code) used, where if users held a Nakamigo they were eligible for a free mint of a cloak. To save gas they used a merkle tree claim, this is compatible with Delegate.

```solidity
    /**
     * @notice Claim tokens from your allowlist quota
     * @param tokenOwner If using delegate.xyz, the address that features in the
     *  allowlist. Set this to 0x000..000 if not using delegation
     * @param numberOfTokens The number of tokens to claim
     * @param tokenQuota The total quota of tokens for the claiming address
     * @param proof The merkle proof for this claimer
     */
    function mintAllowList(
        address tokenOwner,
        uint256 numberOfTokens,
        uint256 tokenQuota,
        bytes32[] calldata proof
    ) external payable {
        // Set address of the wallet that appears on the allowlist
        address claimer = msg.sender;
        
        // --- DELEGATE INTEGRATION HERE ---

        // Check for delegation
        if (tokenOwner != address(0) && tokenOwner != msg.sender) {
            if (IDelegateRegistry(_DELEGATE_REGISTRY).checkDelegateForAll(msg.sender, tokenOwner, "")) {
                claimer = vault;
            }
        }
        
        // --- END DELEGATE INTEGRATION ---

        // Check if the claimer has tokens remaining in their quota
        if (getAllowListMinted(claimer) + numberOfTokens > tokenQuota) {
            revert ExceedsAllowListQuota();
        }

        // Check if the claimer is on the allow list
        if (!onAllowList(claimer, tokenQuota, 69000000000000000000, proof)) {
            revert NotOnAllowList();
        }

        if (msg.value != numberOfTokens * pricePerToken) {
            revert WrongETHValueSent();
        }
        
        // Claim tokens
        _setAllowListMinted(claimer, numberOfTokens);
        _safeMint(msg.sender, numberOfTokens, "");
    }
```

## General Principles

Whether you're building a mint or claim function, solidity additions to your contract are an important part of securing who is and isn't allowed to mint on behalf of a wallet.

Typically, a mint or claim function looks like this:

```solidity
function claim() public returns (uint256 tokenId) {
  // 1. Check if `msg.sender` is allowed to claim
  // Maybe using merkle tree, etc
  
  // 2. Check if `msg.sender` has already claimed
  
  // 3. Your claim code below using `msg.sender`
  _claim(msg.sender)
}
```

To integrate delegate.cash into your solidity contract, we will add a small code block to the above step. We will also pass an optional `_vault` address into the claim function.

<pre class="language-solidity" data-line-numbers><code class="lang-solidity">address constant public <a data-footnote-ref href="#user-content-fn-1">NFT_CONTRACT</a> = 0x0000000000000000000000000000000000000001;


function claim(address <a data-footnote-ref href="#user-content-fn-2">_</a>cold) public returns (uint256 tokenId) {
  address requester = msg.sender;
  
  // Check if msg.sender is a permitted delegate of the cold storage address
  // If so, then we'll move ahead and mint on behalf of the cold wallet
  // Rather than msg.sender
  if (_vault != address(0)) { 
    bool isDelegateValid = REGISTRY.checkDelegateForContract(msg.sender, _cold, NFT_CONTRACT, "");
    require(isDelegateValid, "delegation does not exist");
    requester = _cold;
  }
  
  // 1. Check if `requester` is allowed to claim
  // Maybe using merkle tree, etc
  
  // 2. Check if `requester` has already claimed
  
  // 3. Your claim code below using `requester`
  _claim(`requester`)
}
</code></pre>

Let's break down what we added.

#### (line 1) Passing an optional `_cold` address variable into the contraction.

When delegating, a <mark style="color:orange;">**hot wallet**</mark> (`msg.sender`) is the one making the request on behalf of a <mark style="color:blue;">**cold wallet**</mark> (`_cold`). When there is a `_cold` variable passed through the contract function, we know the <mark style="color:orange;">**hot wallet**</mark> is minting on someone else's behalf.

#### (line 2) Using a new `requester` variable

In a typical mint contract, `msg.sender` is used throughout the contract as the user who holds the NFT and processes the transaction. Now, since `msg.sender` may be minting on behalf of someone else, we use `requester` to know if that is the case or not. `requester` will either be `msg.sender` or the <mark style="color:blue;">**cold wallet**</mark>.

#### (line 4-8) Checking the DelegateRegistry for the valid pairings

If the transaction includes a <mark style="color:blue;">**cold wallet**</mark>, this line of code will make sure that there is a vault<>delegate pairing with the cold and hot wallet; which is the act of someone going to delegate.cash and delegating their hot wallet with their cold wallet.

[^1]: The NFT Contract of the project

[^2]: This is typically the cold wallet that holds the NFT that `msg.sender` is delegating on behalf of.


# Token Ownership Claiming

Explains the recommended user experience for how a user should claim something based on ownership.

In this example, let's assume a user wants to claim a Ticket to an event based on ownership of a NFT. Your goal is to:

* List out all NFTs that have been delegated to a particular wallet
* Process that NFT Token ID as claimed by:
  * Checking ownership of that NFT
  * If the wallet does not own the NFT, check to make sure the NFT has been delegated to that user
* Give the wallet the Ticket

### User experience steps

1. The first step is to get all the incoming delegations from the wallet that wants to claim the ticket. You can do this the following ways:<br>

   **Contract/Javascript SDK:** [`getIncomingDelegations(address)`](/technical-documentation/javascript-sdk/fetch-delegations)

   **REST API:** [Delegations by wallet](/technical-documentation/rest-api/v2#delegations-by-wallet) where `to` is the wallet address in question<br>

2. Filter out these delegations to only include the NFT Contract you are looking to claim tickets for.<br>

   <pre class="language-javascript"><code class="lang-javascript">// A rough example
   <strong>const filteredDelegations = incomingDelegations.filter(delegation => {
   </strong>    return delegation.type === "ALL" ||
       delegation.type === "CONTRACT" &#x26;&#x26; delegation.contract === NFT_CONTRACT ||
       delegation.type === "ERC721"  &#x26;&#x26; delegation.contract === NFT_CONTRACT
   })
   </code></pre>

3. Get all the NFT's of each unique `from` address in the above list.<br>

   ```javascript
   const delegatedWallets = [...new Set(filteredDelegations.map(delegation => delegation.from))];
   ```

4. For each `delegatedWallet`, list all of their NFT's that are from the contract you are claiming for. Then the user can decide which Token ID to claim the ticket for.\
   \
   There are many external API's to accomplish this. Alchemy offers a simple solution here called [getNFTsForOwner](https://docs.alchemy.com/reference/getnftsforowner-v3).<br>

5. Once the user has selected a token they want to claim a ticket for, the user will most likely send this selection to a backend request. We need to double check that the user has actually delegated this token to the wallet or that the wallet owns this NFT token.
   * Make sure the token id has not been claimed before.
   * Does the wallet submitting the request own this NFT? You can do this by checking the `ownerOf(tokenId)` on the contract level.
   * If not, double check that the wallet who delegated this token owns the NFT
   * If so, double check that this specific token id has been delegated to the requestor. \
     \
     **Contract/Javascript SDK:** Use the `checkDelegateForERC721` in the SDK or contract\
     **REST API:** Use the [v2/check/erc721](/technical-documentation/rest-api/v2#delegation-checks) endpoint<br>

6. Process the ticket! You'll want to mark this specific token id as claimed so no one else can claim this token.


# V2 is a Separate Contract

The V1 registry is immutable by design and can be found at address [0x00000000000076A84feF008CDAbe6409d2FE638B](https://etherscan.io/address/0x00000000000076a84fef008cdabe6409d2fe638b) across a variety of EVM chains.

The V2 registry is also immutable by design and can be found at address [0x00000000000000447e69651d841bD8D104Bed493](https://etherscan.io/address/0x00000000000000447e69651d841bd8d104bed493) across a variety of EVM chains.

So the connotations of a centralized admin unilaterally pushing new code into a proxy contract do not apply here. V1 registry will continue to live on, it cannot be stopped. However V2 is far more powerful, gas-efficient, and user-friendly. The Delegate Market is also built on top of V2 not V1. The delegate.xyz frontend will offer users a one-click batch migration option to port their data from V1 into V2, and will focus its flows on V2.&#x20;

Apps are encouraged to update their integrations as soon as possible, please reach out with any questions while following the instructions in [V1 → V2 migration](/upgrade-to-v2/v1-v2-migration).

## Gas Benchmarking Improvements

<table><thead><tr><th width="288">Method</th><th>Registry V1</th><th>Registry V2</th><th>Improvement</th></tr></thead><tbody><tr><td>multicall (all+contract+erc721)</td><td>662,728</td><td>355,751</td><td>46.4% cheaper</td></tr><tr><td>delegateAll</td><td>211,709</td><td>140,425</td><td>33.7% cheaper</td></tr><tr><td>delegateContract</td><td>232,298</td><td>124,201</td><td>46.5% cheaper</td></tr><tr><td>delegateERC721</td><td>218,721</td><td>146,829</td><td>32.9% cheaper</td></tr><tr><td>delegateERC20</td><td>n/a</td><td>146,290</td><td></td></tr><tr><td>delegateERC1155</td><td>n/a</td><td>168,850</td><td></td></tr><tr><td>checkDelegateForAll</td><td>7,588</td><td>3,002</td><td>60.5% cheaper</td></tr><tr><td>checkDelegateForContract</td><td>7,786</td><td>5,491</td><td>29.5% cheaper</td></tr><tr><td>checkDelegateForERC721</td><td>11,186</td><td>7,932</td><td>20.1% cheaper</td></tr><tr><td>checkDelegateForERC20</td><td>n/a</td><td>7,882</td><td></td></tr><tr><td>checkDelegateForERC1155</td><td>n/a</td><td>7,932</td><td></td></tr></tbody></table>


# V1 → V2 migration

Registry V2 brings two key new features: batch delegation and subdelegations, all while reducing gas costs by 30-60%. Batch delegation lets users create multiple delegations in a single transaction. Subdelegation lets users split up the rights associated with a single token, for example pointing airdrop claiming to wallet B and governance rights to wallet C.

These are expansions on the core featureset of V1; if you simply wish to continue using V1-esque features then a direct migration table is provided below.&#x20;

## Migration

### **Delegating your wallet**

**v1**

```solidity
delegateForAll(delegate, value)
```

**v2**

```solidity
delegateAll(delegate, "", value)
```

> We've added the ability to use subdelegations which is what `""` is for.

### **Delegating a contract**

**v1**

```solidity
delegateForContract(delegate, contract_, value)
```

**v2**

```solidity
delegateContract(delegate, contract_, "", value)
```

> We've added the ability to use sub-delegations which is what `""` is for.

### Delegating Tokens

**v1**

```solidity
delegateForToken(delegate, contract_, tokenId, value)
```

**v2**

In v2, we've added support for fungible tokens and split up the token calls into 3 seperate functions.

**v2 - ERC721**

```solidity
delegateERC721(delegate, contract_, tokenId, "", value)
```

**v2 - Fungibles**

```solidity
delegateERC20(delegate, contract_, "", amount)
delegateERC1155(delegate, contract_, tokenId, "", amount)
```

> Users can now specify an amount when delegating fungible tokens

### Revoke Calls

**v1**

```solidity
revokeAllDelegates()
revokeDelegate(delegate)
revokeSelf(vault)
```

**v2**

These functions are removed in favor of using the delegate functions and providing `false` as the value.

**Fetching Incoming Delegations**

**v1**

```solidity
getDelegationsByDelegate(delegate)
```

**v2**

```solidity
getIncomingDelegations(delegate)
```

> All enumeration methods now return the same struct, no matter the delegation type

### Fetching Outgoing Delegations

**v1**

```solidity
getDelegatesForAll()
getDelegatesForContract()
getDelegatesForToken()
getContractLevelDelegations()
getTokenLevelDelegations()
```

**v2**

```solidity
getOutgoingDelegations(vault)
```

> These methods have all been rolled into one single enumeration that returns a list of all delegations a vault has issued

### Checking Wallet Delegations

**v1**

```solidity
checkDelegateForAll(delegate, vault)
```

**v2**

```solidity
checkDelegateForAll(delegate, vault, "")
```

### Checking Contract Delegations

**v1**

```solidity
checkDelegateForContract(delegate, vault, contract_)
```

**v2**

```solidity
checkDelegateForContract(delegate, vault, contract_, "")
```

### Checking Token Delegations

**v1**

```solidity
checkDelegateForToken(delegate, vault, contract_, tokenId, "")
```

**v2**

**v2 - ERC721**

```solidity
checkDelegateForERC721(delegate, vault, contract_, tokenId, "")
```

**v2 - Fungibles**

```solidity
checkDelegateForERC20(delegate, vault, contract_, "")
checkDelegateForERC1155(delegate, vault, contract_, tokenId, "")
```

> Fungible token queries return a uint256 instead of a boolean representing the amount delegated


# Batching

The `multicall()` method in V2 registry lets users queue up multiple delegations and submit them all in a single transaction. This is more gas-efficient and saves user time.

The function is simple, use a frontend library to pack each method call into its bytes representation then submit an array of byte function calls. This can be used for both writes and reads.

```
function multicall(bytes[] calldata data) external payable override returns (bytes[] memory results) {
    results = new bytes[](data.length);
    bool success;
    unchecked {
        for (uint256 i = 0; i < data.length; ++i) {
            //slither-disable-next-line calls-loop,delegatecall-loop
            (success, results[i]) = address(this).delegatecall(data[i]);
            if (!success) revert MulticallFailed();
        }
    }
}
```


# Subdelegations

There is a new `bytes32 rights` parameter associated with each delegation, that did not exist in V1. This is used for **subdelegations**, or splitting up the rights associated with a wallet/token and pointing them towards distinct receiver wallets. For example, an NFT may grant airdrop rights, governance rights, event ticketing rights, gameplay rights, IP licensing rights, and access to a tokengated chat.

You can either continue aggregating these rights and pointing them to a single wallet, or choosing a more granular approach that points different rights to different wallets.&#x20;

## Simple Approach

To delegate all rights, pass an empty bytestring as the rights param. This can be done in most programming languages with the empty string: `""`. This encompasses all rights and any specific rights check will return true. Most users should do this unless specifically directed otherwise until app adoption paths become clear.

## Complex Approach

Apps can choose to check a specific bytestring if they would like users to opt into more granular control. For example, an onchain governance protocol could call `checkDelegateForERC20(to, from, contract_, "governance")` which would encompass both users who made the default simple approach and users who specifically delegated `"governance"` rights. The delegate.xyz frontend will eventually assist in grouping users into simple lowercased english words in conjunction with integration partners to avoid fragmentation. Please reach out if interested!


# Shadow Delegation

Implement non-custodial NFT delegation using Delegate Registry v2 and the shadow delegation pattern, enforced via Yuga Labs’ ExclusiveDelegateResolver.

### In Production: How Yuga Uses Shadow Delegation

Yuga Labs uses shadow delegation to let holders of Ape NFTs on Ethereum delegate access to a wallet on ApeChain. This allows users to verify ownership and participate in ApeChain experiences **without bridging or moving their Apes**.

By combining `Delegate Registry v2` and `ExclusiveDelegateResolver`, Yuga enables onchain delegation that’s:

* **Non-custodial**: the NFT stays in the original wallet
* **Cross-chain**: access is granted to a different wallet on another chain
* **Exclusive**: only one delegate per token is valid at a time

{% embed url="<https://x.com/yugalabs/status/1914363571280159172?s=46&t=jXxAznseRvMWhHxSBWZ72A>" %}

### Infinite Use Cases

`Delegate Registry v2` provides the primitives for onchain NFT access control, forming the base layer upon which **shadow delegation** builds customizable, scoped, and enforceable delegation logic.

Use cases include:

* Assign agents to act on behalf of wallets across chains
* Enable wearables, emotes, or other metadata-bound behaviors
* Grant permissions in identity systems, social graphs, or gaming avatars
* Build composable avatars and modular inventories
* Enforce execution rights on specific chains or applications

***

### Core Concepts

#### 1) Delegate Registry v2

Delegate Registry v2 is an onchain registry that allows users to grant permission to other addresses to act on their behalf. It serves as a data layer, returning a boolean for whether a delegation exists.

Delegations can be scoped:

* to specific tokens via `checkDelegateForERC721`
* to particular contracts `checkDelegateForContract`
* across all tokens and contracts `checkDelegateForAll`

The registry does not enforce rules like exclusivity, expiration, or precedence. It simply stores data.\
**`ExclusiveDelegateResolver`**, developed by Yuga Labs, is responsible for interpreting that data and enforcing logic.

#### 2) Resolver Contracts ([ExclusiveDelegateResolver](https://github.com/yuga-labs/ExclusiveDelegateResolver))

Resolver contracts apply custom logic to interpret delegation records by answering:

> "Who currently has the right to act on this token, under these rules?"

Yuga Labs’ `ExclusiveDelegateResolver` is used in production (e.g. Otherside, ApeChain) to enforce exclusive, scoped, onchain delegation, letting one wallet act on behalf of another without moving the NFT. It scans delegations scoped to a `rightsNamespace` and applies specificity rules (**token > contract > all-assets**) to return the active delegate.

#### 3) The Shadow Delegation Pattern

Shadow delegation is a design pattern that combines `Delegate Registry v2` with a resolver like `ExclusiveDelegateResolver` to enable non-custodial, exclusive delegation, scoped by use case and enforced onchain.

In this pattern:

* Only one delegation per token (or namespace) should be valid at a time
* Previous delegates must be explicitly revoked before a new one is assigned
* Asset ownership remains with the original holder; no escrow or transfers

This pattern works by combining scoped delegation rights with onchain resolution logic, illustrated below.

### How to Implement It

Shadow delegation follows a simple 3-step flow:

<figure><img src="https://3301342738-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKMp3PwjpKKfLzakTeUUs%2Fuploads%2FIyaEy5xZUaTJqFYy4UF2%2F3step.png?alt=media&amp;token=890aea76-237f-4a0c-9a57-d7faebe19255" alt="" width="375"><figcaption></figcaption></figure>

1. **Delegate** access to a token using `delegateERC721()`
2. **Resolve** the active delegate using `ExclusiveDelegateResolver`
3. **Enforce** the delegation with an onchain check (e.g. `require(msg.sender == delegate)`)

#### Step 1: Delegate an NFT via Delegate Registry v2

The owner calls `delegateERC721()` on the registry to assign a delegate for a specific NFT:

```solidity
delegateERC721(
  address delegate,
  address contract_,
  uint256 tokenId,
  bytes32 rights,
  bool value
);
```

* `delegate`: The address receiving the delegation.
* `contract_`: The NFT contract address.
* `tokenId`: The specific token ID to delegate.
* `rights`: A `bytes32` value representing delegation scope.
* `value`: Set to `true` to enable, or `false` to revoke.

In the shadow delegation pattern, you must scope delegation to a unique chain or context by computing a `rights` value. Use the following utility:

```tsx
import { encodeAbiParameters, keccak256 } from 'viem';

function computeShadowRights(shadowChainId?: number): string {
    if (!isShadowDelegation) return '';
    if (!shadowChainId) return '0x000000000000000000000000000000000000000000000000000000ffffffffff';

    const encodedData = encodeAbiParameters([{ type: 'uint' }], [BigInt(shadowChainId)]);
    const hash = keccak256(encodedData);
    const namespace = hash.slice(0, 50);
    const padding = '000000';
    const maxRights = (BigInt(2) ** BigInt(40) - BigInt(1)).toString(16).padStart(10, '0');
    const rights = namespace + padding + maxRights;
		
    return rights;
  }
```

{% hint style="warning" %}
⚠️ **Revoke Before Reassigning**\
If you're delegating the same token (and rights) to a new address, you must first revoke the previous delegate using `delegateERC721(..., false)`. Otherwise, the storage slot is overwritten, and the resolver may return an outdated result.

💡 **Use `multicall()` to Minimize UX & Gas**\
Apps can batch the revocation and reassignment into a single transaction using the registry’s [`multicall()`](https://docs.delegate.xyz/upgrade-to-v2/batching) method to reduce friction and cost.

🛠️ **See It Live**\
Yuga Labs uses this pattern in production. See how their [Shadow Beacon contract](https://apescan.io/address/0x00000000000087c6dbadc090d39bc10316f20658#code) performs explicit revocation before reassignment (lines 933–991).
{% endhint %}

**How Rights are Constructed and Resolved**

The `rights` field is a 32-byte (`bytes32`) value that encodes the scope and expiry of a delegation. This is how the resolver knows **what context the delegation applies to**, **how specific it is**, and **whether it’s still valid**.

<table><thead><tr><th width="85.38671875">Bytes</th><th width="239.328125">Purpose</th><th>Notes</th></tr></thead><tbody><tr><td>0–23</td><td><code>rightsNamespace</code></td><td>Used to scope delegations (e.g., by chain or feature)</td></tr><tr><td>24–28</td><td>Reserved padding (<code>000000</code>)</td><td>Required by resolver formatting</td></tr><tr><td>29–33</td><td><code>uint40 expiry</code></td><td>Unix timestamp after which delegation is invalid</td></tr></tbody></table>

**Resolver Behavior:**

* **Chain-specific scoping**: Namespaces are typically derived from `keccak256(chainId)` so you can delegate the same token to different wallets on different chains. These are resolved independently.
* **Global fallback delegation**: If the **first 24 bytes are zero**, i.e., `0x000...000`, the delegation is considered **global,** valid across all chains or apps. These are **ranked lowest in specificity** and only take effect if no scoped delegation exists.
* **Automatic expiry**: The final 5 bytes of `rights` encode an **expiry timestamp** (`uint40`). When the current block time exceeds this value, the delegation is considered invalid.\
  If you don't want an expiry, use the max value: `0xffffffffff`.

This layered resolution system allows you to combine **scoped**, **exclusive**, **expiring**, and **cross-chain** delegation behavior.

#### Step 2: Use the ExclusiveDelegateResolver

Once delegation is recorded, you can resolve it using `ExclusiveDelegateResolver`, which applies namespace-based resolution logic (token > contract > all-assets) and scopes based on the first 24 bytes of the `rights` field. This means a token-level delegation takes priority over a contract-level one under the same namespace.

Resolver interface:

```solidity
function exclusiveOwnerByRights(
  address nftContract,
  uint256 tokenId,
  bytes24 rightsNamespace
) external view returns (address);
```

Example usage:

```solidity
bytes24 rightsNamespace = bytes24(keccak256(abi.encode(shadowChainId)));

address delegate = IExclusiveDelegateResolver(resolverAddress).exclusiveOwnerByRights(
  nftContractAddress,
  tokenId,
  rightsNamespace
);
```

This reinforces the resolver concept from Core Concept #2. The registry stores raw data and the resolver interprets it according to a rule set (in this case, exclusivity via specificity).

#### Step 3: Enforce Delegation in Your App or Smart Contract

Whenever your application or NFT/game logic needs to check control, replace `ownerOf(tokenId)` or raw ownership checks with delegation resolution:

```solidity
require(msg.sender == delegate, "Not authorized delegate");
```

This enforces **non-custodial, exclusive access** via the resolver logic, honoring only the delegate for the scoped rights.

***

### Resources

* Delegate Registry v2: <https://github.com/delegatexyz/delegate-registry-v2>
* ApeChain Shadow Delegations: <https://docs.apechain.com/start-building/NFT-Shadows>
* Yuga’s Exclusive Resolver: <https://github.com/yuga-labs/ExclusiveDelegateResolver>

***

### Summary

`Shadow delegation` with `Delegate Registry v2` and `ExclusiveDelegateResolver` enables:

* Fully onchain delegation logic
* Exclusive, non-custodial access
* Use case-specific scoping via `rightsNamespace`

Developers can build on this pattern by customizing how delegations are scoped and managed, without needing to deploy their own resolver contract.


# Overview

The next NFT primitive: tradeable delegation rights

| Contract Name        | Address (Ethereum and Goerli)              |
| -------------------- | ------------------------------------------ |
| Delegate Registry V2 | 0x00000000000000447e69651d841bD8D104Bed493 |
| Delegate Token       | 0xC2E257476822377dFB549f001B4cb00103345e66 |
| Principal Token      | 0xC73dFD486BC155b8126a366F68A4fefe05CE1dCD |
| Create Offerer       | 0xf4c9581E2F2CE9d7E07a20b81e1B46aA95C8b6f4 |
| Market Metadata      | 0xBa93c25cD7db01b5d8f4b74aE4e3F5e048144834 |

**Liquid delegates (LDs) wrap delegation rights into a tradeable NFT.** This gives you a **trustless way to trade airdrop claims** and more. It grants **no-liquidation, no-risk NFT rentals** automatically compatible with all standard ERC721s.

<figure><img src="https://3301342738-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKMp3PwjpKKfLzakTeUUs%2Fuploads%2FMLTBys3MFsAxUx8UamWc%2Fimage.png?alt=media&amp;token=08c31e52-56cf-43f6-bbb0-918ac9dd8da2" alt=""><figcaption><p>An impressive array of Goerli NFTs deposited by Liquid Delegate beta testers</p></figcaption></figure>

How does it work? The Liquid Delegate creator chooses two parameters: an NFT they own and the timeframe to delegate it for. For example, I might delegate Azuki #578 for one month. I would then deposit the Azuki into an escrow contract that will manage the delegation, and I receive a Liquid Delegate NFT in return.&#x20;

<figure><img src="https://3301342738-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKMp3PwjpKKfLzakTeUUs%2Fuploads%2FdbeKdW4E2QHRIhY4Cvr5%2FUntitled.png?alt=media&amp;token=c0ee1760-fbd9-482b-bf7b-440cf6ded033" alt=""><figcaption></figcaption></figure>

Liquid Delegate NFTs have the following properties:

* *they are tradeable on NFT marketplaces*
* *holder will automatically receive delegation rights*
* *holder has exclusive rights to atomically flashloan the escrowed token*
* *holder can burn it to return the escrowed NFT to the depositor*

Why are these features important? Tradeability opens up an entirely new liquid market for NFT utility, whereas beforehand they were mostly done in handshake deals behind closed doors. Automatic delegation rights makes it simple to use that utility. Exclusive flashloan rights provide backstop functionality to ensure compatibility with projects that don’t support delegation yet. The burn function opens up an avenue to retrieve the escrowed token before expiration if the depositor changes their mind.

Once a Liquid Delegate expiration timestamp hits, anyone may burn the Liquid Delegate and return the escrowed NFT to the depositor. Eager depositors may wish to call this trigger themselves, or automated bots could burn expired NFTs on demand.

## What are the Use Cases?

#### 1. Airdrop Claim Rights

Some people don’t have the free time to be glued to their screens 24/7/365 with notifications on across Discord/Twitter/Telegram to claim free stuff. Of course they’d like to maximize profits, but not at the expense of other important priorities. Or maybe there’s a DAO which finds it difficult to run proper governance across all the onchain activites necessary. Liquid Delegate lets you put those airdrop rights up for sale and let someone else do the dirty work. And LD buyers can batch up their work to make it worth the time.

#### 2. Alpha Pass Rentals, Event Ticketing, IP Rights

Want to give somebody a taste of a token-gated discord? You could rent your NFT to them for a week (for a small fee, of course) taking advantage of the fact that delegatecash has native support in both Vulcan and CollabLand. Or maybe you have an ApeFest ticket but can’t go in-person yourself? Previously you might give it to a friend, or negotiate some sketchy OTC deal with a Twitter anon. Now you can just rent out your token utility for a week or two, and get paid in an upfront way for it. It would also be fascinating to structure IP rights agreements around Liquid Delegates.

#### 3. Lockup Incentives

NFT projects want to reward their most loyal diamond-handed believers. But what does that even mean - discord activity, twitter pfps, follower count, something else? Now projects can directly incentivize long-term alignment by purchasing Liquid Delegates from holders who lock up for extended time periods. Could veToken-esque incentive programs be built on top of this? We’ll see!

<figure><img src="https://3301342738-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKMp3PwjpKKfLzakTeUUs%2Fuploads%2F7C96UupGM8ccdZ8LpM3W%2Fimage.png?alt=media&amp;token=5fb52c0e-9fe1-442f-8497-670b6619eb82" alt=""><figcaption><p>Liquid Delegate lets you tokenize a SewerPass’ ability to play DookeyDash</p></figcaption></figure>

Are there other protocols tackling each of these usecases? Of course. But none of them roll up so many different possibilities into a unified interface with simple time expirations and comprehensive asset protection. Standardization attracts liquidity.


# FAQ

**How do I create a Delegate Token?**

Go to <https://delegate.xyz/marketplace/ethereum>, click on the "List an Item" button, then choose an NFT to deposit and the expiration time.

<figure><img src="https://3301342738-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKMp3PwjpKKfLzakTeUUs%2Fuploads%2Fh5nPVAPy9O2HdmGlGpU5%2FScreenshot%202023-10-26%20at%205.41.01%20PM.png?alt=media&amp;token=4c349b1a-c72a-4d9a-adf6-e1883f4cdcac" alt=""><figcaption><p>The frontend flow to list on Delegate Market (and optionally create a Delegate Token).</p></figcaption></figure>

**What can I do with my Delegate Token?**

You can sell it on NFT marketplaces, including our native one!

**How do I get my NFT back?**

When the Delegate Token expires, you get your NFT back. Since it's stored in trustless escrow, there's no counterparty risk!

**Why would someone buy my Delegate Token?**

Owning a Delegate Token means that the holder has all delegation rights. So this could be valuable if you want an airdrop claim, access to a token-gated discord, or so on.

**Do I need to connect my vault to use Delegate Market?**

The NFT is stored in escrow when you mint a Delegate Token, to prevent people from selling or transferring the underlying NFT while its rights are delegated. So you'll need to connect whichever wallet holds the NFT.

**Is Delegate Market safe?**

Audit results can be found on Code4rena. All core smart contracts are immutable with the exception of some metadata parameters.


# Delegate for Gaming

Delegate offers two key features to speed up crypto gaming: **asset security** and a **native marketplace.**

## Asset Security

Ironically, sometimes toughest problem for novel crypto primitives isn't developing the logic, but gaining user trust. When retail users read stories of daily six- and seven-figure phishing attacks, it makes sense to hunker down. Use a CEX, Uniswap, Opensea, and little else. Even for experienced cryptonatives, the mental overhead of verifying every site, every smart contract, and every transaction takes the fun out of gaming.

Delegate fixes this. The core innovation is that assets can be held in a cold wallet (a hardware device, a multisig, etc) and dangerous actions like sales or transfers are locked down, while still enabling a hot wallet (browser extension, mobile app, etc) to play on its behalf. This reduces the attack surface by 10x-100x, where users don't have to worry any more.

A great example was the Yuga Labs' DookeyDash game, where bored apes could both let their families play without putting assets at risk, or hire premiere gamers to run up highscores for them. Tropofarmer demo-ed the most startling example of how powerful this primitive is by delegating to an empty hot wallet, then publishing the private key on Twitter! Others could play for him, but the delegation security was so strong that his 4-figure asset was never at risk.

{% embed url="<https://twitter.com/tropoFarmer/status/1617598151011237890>" %}

## Native Marketplace

The Liquid Delegate marketplace is also a powerful default for games with valuable in-game items. Users who don't have the time or skill or desire to play daily can rent out their assets by creating Delegate Tokens, which are ERC-721 representations of a delegation right. Then these can be sold on our native marketplace to earn a little extra money. \
\
This is a completely different value prop than all rental marketplaces live today, because Liquid Delegates are backwards compatible with standard ERC-721 and ERC-1155 tokens, even if deployed years ago. And where others have failed due to excessive liquidity fragmentation, the Liquid Delegate marketplace brings in a variety of usecases into a unified interface. And of course, it's built on best-in-class Seaport tech, the same framework that powers OpenSea.


# Delegate Registry


# Contract Addresses

The full registry interface is in [IDelegateRegistry.sol](/technical-documentation/delegate-registry/idelegateregistry.sol)

<table><thead><tr><th width="214">Mainnet Chain (EVM)</th><th>Address</th></tr></thead><tbody><tr><td>Ethereum</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Apechain</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Arbitrum One</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Arbitrum Nova</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Avalanche</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Base</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Blast</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>BNB Chain</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Canto</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Celo</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Fantom</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Gnosis</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Hychain</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Linea</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Mantle</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Moonbeam</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Moonriver</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Optimism</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Polygon</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Polygon zkEVM</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Plume</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Ronin</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Sanko</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Scroll</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Sei</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Shape</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Taiko</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>XAI</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>ZetaChain</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Zora</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr></tbody></table>

<table><thead><tr><th width="237">Mainnet Chain (ZKSync)</th><th>Address</th><th data-hidden></th></tr></thead><tbody><tr><td>Abstract</td><td>0x0000000059A24EB229eED07Ac44229DB56C5d797</td><td></td></tr><tr><td>ZKSync Era</td><td>0x0000000059A24EB229eED07Ac44229DB56C5d797</td><td></td></tr><tr><td>Treasure</td><td>0x0000000059A24EB229eED07Ac44229DB56C5d797</td><td></td></tr></tbody></table>

<table><thead><tr><th width="209">Testnet Chain</th><th>Address</th></tr></thead><tbody><tr><td>Ethereum (Sepolia)</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Ethereum (Holesky)</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Abstract (Sepolia)</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Base (Sepolia)</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Berachain bArtio</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Monad</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr><tr><td>Ronin</td><td>0x00000000000000447e69651d841bD8D104Bed493</td></tr></tbody></table>


# IDelegateRegistry.sol

IDelegateRegistry.sol

```solidity
// SPDX-License-Identifier: CC0-1.0
pragma solidity >=0.8.13;

/**
 * @title IDelegateRegistry
 * @custom:version 2.0
 * @custom:author foobar (0xfoobar)
 * @notice A standalone immutable registry storing delegated permissions from one address to another
 */
interface IDelegateRegistry {
    /// @notice Delegation type, NONE is used when a delegation does not exist or is revoked
    enum DelegationType {
        NONE,
        ALL,
        CONTRACT,
        ERC721,
        ERC20,
        ERC1155
    }

    /// @notice Struct for returning delegations
    struct Delegation {
        DelegationType type_;
        address to;
        address from;
        bytes32 rights;
        address contract_;
        uint256 tokenId;
        uint256 amount;
    }

    /// @notice Emitted when an address delegates or revokes rights for their entire wallet
    event DelegateAll(address indexed from, address indexed to, bytes32 rights, bool enable);

    /// @notice Emitted when an address delegates or revokes rights for a contract address
    event DelegateContract(address indexed from, address indexed to, address indexed contract_, bytes32 rights, bool enable);

    /// @notice Emitted when an address delegates or revokes rights for an ERC721 tokenId
    event DelegateERC721(address indexed from, address indexed to, address indexed contract_, uint256 tokenId, bytes32 rights, bool enable);

    /// @notice Emitted when an address delegates or revokes rights for an amount of ERC20 tokens
    event DelegateERC20(address indexed from, address indexed to, address indexed contract_, bytes32 rights, uint256 amount);

    /// @notice Emitted when an address delegates or revokes rights for an amount of an ERC1155 tokenId
    event DelegateERC1155(address indexed from, address indexed to, address indexed contract_, uint256 tokenId, bytes32 rights, uint256 amount);

    /// @notice Thrown if multicall calldata is malformed
    error MulticallFailed();

    /**
     * -----------  WRITE -----------
     */

    /**
     * @notice Call multiple functions in the current contract and return the data from all of them if they all succeed
     * @param data The encoded function data for each of the calls to make to this contract
     * @return results The results from each of the calls passed in via data
     */
    function multicall(bytes[] calldata data) external payable returns (bytes[] memory results);

    /**
     * @notice Allow the delegate to act on behalf of `msg.sender` for all contracts
     * @param to The address to act as delegate
     * @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights
     * @param enable Whether to enable or disable this delegation, true delegates and false revokes
     * @return delegationHash The unique identifier of the delegation
     */
    function delegateAll(address to, bytes32 rights, bool enable) external payable returns (bytes32 delegationHash);

    /**
     * @notice Allow the delegate to act on behalf of `msg.sender` for a specific contract
     * @param to The address to act as delegate
     * @param contract_ The contract whose rights are being delegated
     * @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights
     * @param enable Whether to enable or disable this delegation, true delegates and false revokes
     * @return delegationHash The unique identifier of the delegation
     */
    function delegateContract(address to, address contract_, bytes32 rights, bool enable) external payable returns (bytes32 delegationHash);

    /**
     * @notice Allow the delegate to act on behalf of `msg.sender` for a specific ERC721 token
     * @param to The address to act as delegate
     * @param contract_ The contract whose rights are being delegated
     * @param tokenId The token id to delegate
     * @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights
     * @param enable Whether to enable or disable this delegation, true delegates and false revokes
     * @return delegationHash The unique identifier of the delegation
     */
    function delegateERC721(address to, address contract_, uint256 tokenId, bytes32 rights, bool enable) external payable returns (bytes32 delegationHash);

    /**
     * @notice Allow the delegate to act on behalf of `msg.sender` for a specific amount of ERC20 tokens
     * @dev The actual amount is not encoded in the hash, just the existence of a amount (since it is an upper bound)
     * @param to The address to act as delegate
     * @param contract_ The address for the fungible token contract
     * @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights
     * @param amount The amount to delegate, > 0 delegates and 0 revokes
     * @return delegationHash The unique identifier of the delegation
     */
    function delegateERC20(address to, address contract_, bytes32 rights, uint256 amount) external payable returns (bytes32 delegationHash);

    /**
     * @notice Allow the delegate to act on behalf of `msg.sender` for a specific amount of ERC1155 tokens
     * @dev The actual amount is not encoded in the hash, just the existence of a amount (since it is an upper bound)
     * @param to The address to act as delegate
     * @param contract_ The address of the contract that holds the token
     * @param tokenId The token id to delegate
     * @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights
     * @param amount The amount of that token id to delegate, > 0 delegates and 0 revokes
     * @return delegationHash The unique identifier of the delegation
     */
    function delegateERC1155(address to, address contract_, uint256 tokenId, bytes32 rights, uint256 amount) external payable returns (bytes32 delegationHash);

    /**
     * ----------- CHECKS -----------
     */

    /**
     * @notice Check if `to` is a delegate of `from` for the entire wallet
     * @param to The potential delegate address
     * @param from The potential address who delegated rights
     * @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only
     * @return valid Whether delegate is granted to act on the from's behalf
     */
    function checkDelegateForAll(address to, address from, bytes32 rights) external view returns (bool);

    /**
     * @notice Check if `to` is a delegate of `from` for the specified `contract_` or the entire wallet
     * @param to The delegated address to check
     * @param contract_ The specific contract address being checked
     * @param from The cold wallet who issued the delegation
     * @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only
     * @return valid Whether delegate is granted to act on from's behalf for entire wallet or that specific contract
     */
    function checkDelegateForContract(address to, address from, address contract_, bytes32 rights) external view returns (bool);

    /**
     * @notice Check if `to` is a delegate of `from` for the specific `contract` and `tokenId`, the entire `contract_`, or the entire wallet
     * @param to The delegated address to check
     * @param contract_ The specific contract address being checked
     * @param tokenId The token id for the token to delegating
     * @param from The wallet that issued the delegation
     * @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only
     * @return valid Whether delegate is granted to act on from's behalf for entire wallet, that contract, or that specific tokenId
     */
    function checkDelegateForERC721(address to, address from, address contract_, uint256 tokenId, bytes32 rights) external view returns (bool);

    /**
     * @notice Returns the amount of ERC20 tokens the delegate is granted rights to act on the behalf of
     * @param to The delegated address to check
     * @param contract_ The address of the token contract
     * @param from The cold wallet who issued the delegation
     * @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only
     * @return balance The delegated balance, which will be 0 if the delegation does not exist
     */
    function checkDelegateForERC20(address to, address from, address contract_, bytes32 rights) external view returns (uint256);

    /**
     * @notice Returns the amount of a ERC1155 tokens the delegate is granted rights to act on the behalf of
     * @param to The delegated address to check
     * @param contract_ The address of the token contract
     * @param tokenId The token id to check the delegated amount of
     * @param from The cold wallet who issued the delegation
     * @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only
     * @return balance The delegated balance, which will be 0 if the delegation does not exist
     */
    function checkDelegateForERC1155(address to, address from, address contract_, uint256 tokenId, bytes32 rights) external view returns (uint256);

    /**
     * ----------- ENUMERATIONS -----------
     */

    /**
     * @notice Returns all enabled delegations a given delegate has received
     * @param to The address to retrieve delegations for
     * @return delegations Array of Delegation structs
     */
    function getIncomingDelegations(address to) external view returns (Delegation[] memory delegations);

    /**
     * @notice Returns all enabled delegations an address has given out
     * @param from The address to retrieve delegations for
     * @return delegations Array of Delegation structs
     */
    function getOutgoingDelegations(address from) external view returns (Delegation[] memory delegations);

    /**
     * @notice Returns all hashes associated with enabled delegations an address has received
     * @param to The address to retrieve incoming delegation hashes for
     * @return delegationHashes Array of delegation hashes
     */
    function getIncomingDelegationHashes(address to) external view returns (bytes32[] memory delegationHashes);

    /**
     * @notice Returns all hashes associated with enabled delegations an address has given out
     * @param from The address to retrieve outgoing delegation hashes for
     * @return delegationHashes Array of delegation hashes
     */
    function getOutgoingDelegationHashes(address from) external view returns (bytes32[] memory delegationHashes);

    /**
     * @notice Returns the delegations for a given array of delegation hashes
     * @param delegationHashes is an array of hashes that correspond to delegations
     * @return delegations Array of Delegation structs, return empty structs for nonexistent or revoked delegations
     */
    function getDelegationsFromHashes(bytes32[] calldata delegationHashes) external view returns (Delegation[] memory delegations);

    /**
     * ----------- STORAGE ACCESS -----------
     */

    /**
     * @notice Allows external contracts to read arbitrary storage slots
     */
    function readSlot(bytes32 location) external view returns (bytes32);

    /**
     * @notice Allows external contracts to read an arbitrary array of storage slots
     */
    function readSlots(bytes32[] calldata locations) external view returns (bytes32[] memory);
}

```


# Javascript SDK


# Installation / Importing

Adding [@delegatexyz/sdk](https://github.com/delegatexyz/delegate-javascript-sdk) to your project is just a single command.

```bash
npm install @delegatexyz/sdk viem
```

## Importing

{% code title="ES6 or Typescript" %}

```javascript
import { http } from "viem"
import { DelegateV1, DelegateV2 } from "@delegatexyz/sdk";
```

{% endcode %}

{% code title="NodeJS require" %}

```javascript
const { http } = require("viem");
const { DelegateV1, DelegateV2 } = require("@delegatexyz/sdk");
```

{% endcode %}


# Setup

### Installation

Adding [@delegatexyz/sdk](https://github.com/delegatexyz/delegate-javascript-sdk) to your project is just a single command.

```bash
npm install @delegatexyz/sdk viem
```

### Importing

{% code title="ES6 or Typescript" %}

```javascript
import { http } from "viem"
import { DelegateV1, DelegateV2 } from "@delegatexyz/sdk";
```

{% endcode %}

{% code title="NodeJS require" %}

```javascript
const { http } = require("viem");
const { DelegateV1, DelegateV2 } = require("@delegatexyz/sdk");
```

{% endcode %}

### Setup

The v1 or v2 SDK require the same parameters:

* **transport**: a valid viem [Transport](https://viem.sh/docs/clients/intro.html#transports).
* **chain (optional)**: [chain](https://viem.sh/docs/glossary/terms.html#chain) from `viem/chains` (or [define your own](https://viem.sh/docs/clients/chains.html#custom-chains))
* **account (optional)**: A [wallet client](https://viem.sh/docs/clients/wallet.html)

*`account` is only required to use the write functions*.

```typescript
import { http } from "viem"
import { DelegateV1, DelegateV2 } from "@delegatexyz/sdk";

const RPC_URL = "";
const v1 = new DelegateV1(http(RPC_URL))
const v2 = new DelegateV2(http(RPC_URL))
```


# Check Delegations


# checkDelegateForAll

Check if \`to\` is a delegate of \`from\` for the entire wallet

**checkDelegateForAll**( `to`: <mark style="color:blue;">string</mark>, `from`: <mark style="color:blue;">string</mark>, `rights?`: <mark style="color:blue;">string</mark> ) ⇒ Promise< <mark style="color:blue;">boolean</mark> >

&#x20;       Returns `true` if delegate is granted to act on the from's behalf

<table data-header-hidden><thead><tr><th width="125"></th><th></th></tr></thead><tbody><tr><td><strong>to</strong></td><td>The delegated address to check</td></tr><tr><td><strong>from</strong></td><td>The potential address who delegated rights</td></tr><tr><td><strong>rights</strong> <em>(optional)</em></td><td>Specific rights to check for, pass nothing to ignore subdelegations and check full delegations only</td></tr></tbody></table>

#### Usage Example

<pre class="language-javascript"><code class="lang-javascript">const to = "0x0000000000000000000000000000000000000003";
const from = "0x0000000000000000000000000000000000000001";
const isDelegateForAll = await v2.checkDelegateForAll(to, from);

/* returns example

<strong>true
</strong><strong>
</strong>*/
</code></pre>


# checkDelegateForContract

Check if \`to\` is a delegate of \`from\` for the specified \`contract\` or the entire wallet

**checkDelegateForContract**( `to`: <mark style="color:blue;">string</mark>, `from`: <mark style="color:blue;">string</mark>, `contract`: <mark style="color:blue;">string</mark>, `rights?`: <mark style="color:blue;">string</mark> ) ⇒ Promise< <mark style="color:blue;">boolean</mark> >

&#x20;       Returns `true` if delegate is granted to act on from's behalf for entire wallet or that specific contract

<table data-header-hidden><thead><tr><th width="124"></th><th></th></tr></thead><tbody><tr><td><strong>to</strong></td><td>The delegated address to check</td></tr><tr><td><strong>from</strong></td><td>The potential address who delegated rights</td></tr><tr><td><strong>contract</strong></td><td>The address for the contract you're delegating</td></tr><tr><td><strong>rights</strong> <em>(optional)</em></td><td>Specific rights to check for, pass nothing to ignore subdelegations and check full delegations only</td></tr></tbody></table>

#### Usage Example

```javascript
const to = "0x0000000000000000000000000000000000000003";
const from = "0x0000000000000000000000000000000000000001";
const contract = "0x0000000000000000000000000000000000000002";
const isDelegateForContract = await v2.checkDelegateForContract(to, from, contract);

/* returns example

true

*/
```


# checkDelegateForERC721

Check if \`to\` is a delegate of \`from\` for the specific \`contract\` and \`tokenId\`, the entire \`contract\`, or the entire wallet

**checkDelegateForERC721**( `to`: <mark style="color:blue;">string</mark>, `from`: <mark style="color:blue;">string</mark>, `contract`: <mark style="color:blue;">string,</mark> `tokenId`: <mark style="color:blue;">number</mark>, `rights?`: <mark style="color:blue;">string</mark> ) ⇒ Promise< <mark style="color:blue;">boolean</mark> >

&#x20;       Returns `true` if delegate is granted to act on from's behalf for entire wallet, that contract, or that specific tokenId

<table data-header-hidden><thead><tr><th width="128"></th><th></th></tr></thead><tbody><tr><td><strong>to</strong></td><td>The delegated address to check</td></tr><tr><td><strong>from</strong></td><td>The potential address who delegated rights</td></tr><tr><td><strong>contract</strong></td><td>The address for the contract you're delegating</td></tr><tr><td><strong>tokenId</strong></td><td>The token id for the token you're delegating</td></tr><tr><td><strong>rights</strong> <em>(optional)</em></td><td>Specific rights to check for, pass nothing to ignore subdelegations and check full delegations only</td></tr></tbody></table>

#### Usage Example

```javascript
const to = "0x0000000000000000000000000000000000000003";
const from = "0x0000000000000000000000000000000000000001";
const contract = "0x0000000000000000000000000000000000000002";
const tokenId = 5;
const isDelegateForToken = await v2.checkDelegateForERC721(to, from, contract, tokenId);

/* returns example

true

*/
```


# checkDelegateForERC1155

Returns the amount of a ERC1155 tokens the delegate is granted rights to act on the behalf of

**checkDelegateForERC11555**( `to`: <mark style="color:blue;">string</mark>, `from`: <mark style="color:blue;">string</mark>, `contract`: <mark style="color:blue;">string,</mark> `tokenId`: <mark style="color:blue;">number</mark>, `rights?`: <mark style="color:blue;">string</mark> ) ⇒ Promise< <mark style="color:blue;">number</mark> >

&#x20;       Returns the delegated balance, which will be 0 if the delegation does not exist

<table data-header-hidden><thead><tr><th width="128"></th><th></th></tr></thead><tbody><tr><td><strong>to</strong></td><td>The delegated address to check</td></tr><tr><td><strong>from</strong></td><td>The potential address who delegated rights</td></tr><tr><td><strong>contract</strong></td><td>The address for the contract you're delegating</td></tr><tr><td><strong>tokenId</strong></td><td>The token id for the token you're delegating</td></tr><tr><td><strong>rights</strong> <em>(optional)</em></td><td>Specific rights to check for, pass nothing to ignore subdelegations and check full delegations only</td></tr></tbody></table>

#### Usage Example

```javascript
const to = "0x0000000000000000000000000000000000000003";
const from = "0x0000000000000000000000000000000000000001";
const contract = "0x0000000000000000000000000000000000000002";
const tokenId = 5;
const isDelegateForToken = await v2.checkDelegateForERC1155(to, from, contract, tokenId);

/* returns example

1

*/
```


# checkDelegateForERC20

Returns the amount of ERC20 tokens the delegate is granted rights to act on the behalf of

**checkDelegateForERC20**( `to`: <mark style="color:blue;">string</mark>, `from`: <mark style="color:blue;">string</mark>, `contract`: <mark style="color:blue;">string,</mark> `rights?`: <mark style="color:blue;">string</mark> ) ⇒ Promise< <mark style="color:blue;">boolean</mark> >

&#x20;       Returns the delegated balance, which will be 0 if the delegation does not exist

<table data-header-hidden><thead><tr><th width="128"></th><th></th></tr></thead><tbody><tr><td><strong>to</strong></td><td>The delegated address to check</td></tr><tr><td><strong>from</strong></td><td>The potential address who delegated rights</td></tr><tr><td><strong>contract</strong></td><td>The address for the contract you're delegating</td></tr><tr><td><strong>rights</strong> <em>(optional)</em></td><td>Specific rights to check for, pass nothing to ignore subdelegations and check full delegations only</td></tr></tbody></table>

#### Usage Example

```javascript
const to = "0x0000000000000000000000000000000000000003";
const from = "0x0000000000000000000000000000000000000001";
const contract = "0x0000000000000000000000000000000000000002";
const isDelegateForToken = await v2.checkDelegateForERC20(to, from, contract);

/* returns example

0

*/
```


# Fetch Delegations

**getIncomingDelegations**( `to`: <mark style="color:blue;">string</mark> ) ⇒ Promise< <mark style="color:blue;">V2Delegation\[]</mark> >

&#x20;       Returns an array of Delegation items

<table data-header-hidden><thead><tr><th width="97"></th><th></th></tr></thead><tbody><tr><td><strong>to</strong></td><td>The address to retrieve delegations for</td></tr></tbody></table>

**getOutgoingDelegations**( `from`: <mark style="color:blue;">string</mark> ) ⇒ Promise< <mark style="color:blue;">V2Delegation\[]</mark> >

&#x20;       Returns an array of Delegation items

<table data-header-hidden><thead><tr><th width="97"></th><th></th></tr></thead><tbody><tr><td><strong>from</strong></td><td>The address to retrieve delegations for</td></tr></tbody></table>

#### Usage Example

```javascript
const to = "0x0000000000000000000000000000000000000003";
const from = "0x0000000000000000000000000000000000000001";
const incoming = await v2.getIncomingDelegations(to);
const outgoing = await v2.getOutgoingDelegations(from);
```


# Delegate/Revoke

The standard functions that are used in the below subpages explain how to initiate transactions. However, if you want to save the transaction data to be called later, you can do so with the following functions.&#x20;

This is also useful if you'd like to do a `multicall`.

```typescript
import { 
    rawDelegateAll, 
    rawDelegateContract, 
    rawDelegateERC721, 
    rawDelegateERC1155,
    rawDelegateERC20,
    rawMulticall
} from "@delegatexyz/sdk";
```

Their usage is the same, however it is not asynchronous.


# delegateAll

Allow the delegate to act on behalf of \`msg.sender\` for all contracts

**delegateAll**( `to`: <mark style="color:blue;">string</mark>, `rights`: <mark style="color:blue;">string</mark>, `enable`: <mark style="color:blue;">boolean</mark> ) ⇒ Promise< <mark style="color:blue;">TransactionHash</mark> >

&#x20;       Returns the transaction hash of the submitted delegation.

<table data-header-hidden><thead><tr><th width="99"></th><th></th></tr></thead><tbody><tr><td><strong>to</strong></td><td>The address to act as delegate</td></tr><tr><td><strong>rights</strong></td><td>Specific subdelegation rights granted to the delegate, pass <code>""</code> to encompass all rights</td></tr></tbody></table>

#### Usage Example

```javascript
const to = "0x0000000000000000000000000000000000000003";
const from = "0x0000000000000000000000000000000000000001";
const tx = await v2.delegateAll(to, "", true);
```


# delegateContract

Allow the delegate to act on behalf of \`msg.sender\` for a specific contract

**delegateContract**( `to`: <mark style="color:blue;">string</mark>, `contract`: <mark style="color:blue;">string</mark>, `rights`: <mark style="color:blue;">string</mark>, `enable`: <mark style="color:blue;">boolean</mark> ) ⇒ Promise< <mark style="color:blue;">TransactionHash</mark> >

&#x20;       Returns the transaction hash of the submitted delegation.

<table data-header-hidden><thead><tr><th width="124"></th><th></th></tr></thead><tbody><tr><td><strong>to</strong></td><td>The address to act as delegate</td></tr><tr><td><strong>contract</strong></td><td>The contract whose rights are being delegated</td></tr><tr><td><strong>rights</strong></td><td>Specific subdelegation rights granted to the delegate, pass <code>""</code> to encompass all rights</td></tr></tbody></table>

#### Usage Example

```javascript
const to = "0x0000000000000000000000000000000000000003";
const from = "0x0000000000000000000000000000000000000001";
const contract = "0x0000000000000000000000000000000000000002";
await v2.delegateContract(to, contract, "", true);
```


# delegateERC721

Allow the delegate to act on behalf of \`msg.sender\` for a specific ERC721 token

**delegateERC721**( `to`: <mark style="color:blue;">string</mark>, `contract`: <mark style="color:blue;">string,</mark> `tokenId`: <mark style="color:blue;">number</mark>, `rights`: <mark style="color:blue;">string</mark>, `enable`: <mark style="color:blue;">boolean</mark> ) ⇒ Promise< <mark style="color:blue;">TransactionHash</mark> >

&#x20;       Returns the transaction hash of the submitted delegation.

<table data-header-hidden><thead><tr><th width="128"></th><th></th></tr></thead><tbody><tr><td><strong>to</strong></td><td>The address to act as delegate</td></tr><tr><td><strong>contract</strong></td><td>The contract whose rights are being delegated</td></tr><tr><td><strong>tokenId</strong></td><td>The token id for the token you're delegating</td></tr><tr><td><strong>rights</strong></td><td>Specific subdelegation rights granted to the delegate, pass <code>""</code> to encompass all rights</td></tr></tbody></table>

#### Usage Example

```javascript
const to = "0x0000000000000000000000000000000000000003";
const from = "0x0000000000000000000000000000000000000001";
const contract = "0x0000000000000000000000000000000000000002";
const tokenId = 5;
await v2.delegateERC721(to, contract, tokenId, "", true);
```


# delegateERC1155

Allow the delegate to act on behalf of \`msg.sender\` for a specific amount of ERC1155 tokens

**delegateERC1155**( `to`: <mark style="color:blue;">string</mark>, `contract`: <mark style="color:blue;">string,</mark> `tokenId`: <mark style="color:blue;">number</mark>, `rights`: <mark style="color:blue;">string</mark>, `amount`: <mark style="color:blue;">number</mark> ) ⇒ Promise< <mark style="color:blue;">TransactionHash</mark> >

&#x20;       Returns the transaction hash of the submitted delegation.

<table data-header-hidden><thead><tr><th width="128"></th><th></th></tr></thead><tbody><tr><td><strong>to</strong></td><td>The address to act as delegate</td></tr><tr><td><strong>contract</strong></td><td>The contract whose rights are being delegated</td></tr><tr><td><strong>tokenId</strong></td><td>The token id for the token you're delegating</td></tr><tr><td><strong>rights</strong></td><td>Specific subdelegation rights granted to the delegate, pass <code>""</code> to encompass all rights</td></tr><tr><td><strong>amount</strong></td><td>The amount of that token id to delegate, > 0 delegates and 0 revokes</td></tr></tbody></table>

#### Usage Example

```javascript
const to = "0x0000000000000000000000000000000000000003";
const from = "0x0000000000000000000000000000000000000001";
const contract = "0x0000000000000000000000000000000000000002";
const tokenId = 5;
const amount = 1;
await v2.delegateERC1155(to, contract, tokenId, "", amount);
```


# delegateERC20

Allow the delegate to act on behalf of \`msg.sender\` for a specific amount of ERC20 tokens

**delegateERC20**( `to`: <mark style="color:blue;">string</mark>, `contract`: <mark style="color:blue;">string,</mark> `rights`: <mark style="color:blue;">string</mark>, `amount`: <mark style="color:blue;">number</mark> ) ⇒ Promise< <mark style="color:blue;">TransactionHash</mark> >

&#x20;       Returns the transaction hash of the submitted delegation.

<table data-header-hidden><thead><tr><th width="128"></th><th></th></tr></thead><tbody><tr><td><strong>to</strong></td><td>The address to act as delegate</td></tr><tr><td><strong>contract</strong></td><td>The contract whose rights are being delegated</td></tr><tr><td><strong>rights</strong></td><td>Specific subdelegation rights granted to the delegate, pass <code>""</code> to encompass all rights</td></tr><tr><td><strong>amount</strong></td><td>The amount of that token id to delegate, > 0 delegates and 0 revokes</td></tr></tbody></table>

#### Usage Example

```javascript
const to = "0x0000000000000000000000000000000000000003";
const from = "0x0000000000000000000000000000000000000001";
const contract = "0x0000000000000000000000000000000000000002";
const amount = 1;
await v2.delegateERC20(to, contract, "", amount);
```


# REST API


# v2

**Supported Networks:** All networks on the main delegate.xyz website are supported

**Rate Limits:** 25 requests per 10 seconds.

To obtain an API key to remove rate limits, you can create one here: <https://delegate.xyz/developer/api-keys>

### Authentication

If you have an API Key, you can add it to the request headers like so:

```javascript
fetch(URL, { headers: { "X-API-KEY": "abc123" } }) 
```

### Delegations by wallet

## Get a list of incoming and outgoing delegations for a specific wallet.

<mark style="color:blue;">`GET`</mark> `https://api.delegate.xyz/registry/v2/:wallet`

#### Path Parameters

| Name                                     | Type    | Description                   |
| ---------------------------------------- | ------- | ----------------------------- |
| wallet<mark style="color:red;">\*</mark> | Address | The wallet to get delegations |

#### Query Parameters

| Name    | Type   | Description               |
| ------- | ------ | ------------------------- |
| chainId | number | Defaults to `1` (mainnet) |

{% tabs %}
{% tab title="200: OK Delegation\[]" %}

```typescript
type Delegation = {
    type: "NONE" | "ALL" | "CONTRACT" | "TOKEN";
    from: string;
    to: string;
    contract: string | null;
    tokenId: number | null;
};

// returns Delegation[]
```

{% endtab %}
{% endtabs %}

**Delegations by wallet Example**

```
curl https://api.delegate.xyz/registry/v2/0x0000000000000000000000000000000000000000
```

***

### Delegation Checks

## Returns true if delegate is granted to act on the from's behalf

<mark style="color:blue;">`GET`</mark> `https://api.delegate.xyz/registry/v2/check/all`

#### Query Parameters

| Name                                   | Type    | Description                               |
| -------------------------------------- | ------- | ----------------------------------------- |
| to<mark style="color:red;">\*</mark>   | Address | The hot wallet to act on your behalf      |
| from<mark style="color:red;">\*</mark> | Address | The cold wallet who issued the delegation |
| chainId                                | number  | Defaults to `1` (mainnet)                 |
| rights                                 | string  | bytes32 of rights string                  |

{% tabs %}
{% tab title="200: OK Boolean" %}

{% endtab %}
{% endtabs %}

**Check All Example**

```
curl https://api.delegate.xyz/registry/v2/check/all?to=0x0000000000000000000000000000000000000000&from=0x0000000000000000000000000000000000000001
```

***

## Returns true if delegate is granted to act on from's behalf for entire wallet or that specific contract

<mark style="color:blue;">`GET`</mark> `https://api.delegate.xyz/registry/v2/check/contract`

#### Query Parameters

| Name                                       | Type    | Description                                    |
| ------------------------------------------ | ------- | ---------------------------------------------- |
| from<mark style="color:red;">\*</mark>     | Address | The hot wallet to act on your behalf           |
| to<mark style="color:red;">\*</mark>       | Address | The cold wallet who issued the delegation      |
| contract<mark style="color:red;">\*</mark> | Address | The address for the contract you're delegating |
| chainId                                    | number  | Defaults to `1` (mainnet)                      |
| rights                                     | string  | bytes32 of rights string                       |

{% tabs %}
{% tab title="200: OK Boolean" %}

{% endtab %}
{% endtabs %}

**Check Contract Example**

```
curl https://api.delegate.xyz/registry/v2/check/contract?to=0x0000000000000000000000000000000000000000&from=0x0000000000000000000000000000000000000001&contract=0x0000000000000000000000000000000000000003
```

***

## Returns true if delegate is granted to act on from's behalf for entire wallet, that contract, or that specific tokenId

<mark style="color:blue;">`GET`</mark> `https://api.delegate.xyz/registry/v2/check/erc721`

#### Query Parameters

| Name                                       | Type    | Description                                    |
| ------------------------------------------ | ------- | ---------------------------------------------- |
| delegate<mark style="color:red;">\*</mark> | Address | The hot wallet to act on your behalf           |
| vault<mark style="color:red;">\*</mark>    | Address | The cold wallet who issued the delegation      |
| contract<mark style="color:red;">\*</mark> | Address | The address for the contract you're delegating |
| tokenId<mark style="color:red;">\*</mark>  | Number  | The token id for the token you're delegating   |
| chainId                                    | number  | Defaults to `1` (mainnet)                      |
| rights                                     | string  | bytes32 of rights string                       |

{% tabs %}
{% tab title="200: OK Boolean" %}

{% endtab %}
{% endtabs %}

**Check ERC721 Example**

```
curl https://api.delegate.xyz/registry/v2/check/contract?to=0x0000000000000000000000000000000000000000&from=0x0000000000000000000000000000000000000001&contract=0x0000000000000000000000000000000000000003&tokenId=1
```

***

## Returns the delegated balance, which will be 0 if the delegation does not exist

<mark style="color:blue;">`GET`</mark> `https://api.delegate.xyz/registry/v2/check/erc1155`

#### Query Parameters

| Name                                       | Type    | Description                                    |
| ------------------------------------------ | ------- | ---------------------------------------------- |
| delegate<mark style="color:red;">\*</mark> | Address | The hot wallet to act on your behalf           |
| vault<mark style="color:red;">\*</mark>    | Address | The cold wallet who issued the delegation      |
| contract<mark style="color:red;">\*</mark> | Address | The address for the contract you're delegating |
| tokenId<mark style="color:red;">\*</mark>  | Number  | The token id for the token you're delegating   |
| chainId                                    | number  | Defaults to `1` (mainnet)                      |
| rights                                     | string  | bytes32 of rights string                       |

{% tabs %}
{% tab title="200: OK Boolean" %}

{% endtab %}
{% endtabs %}

**Check ERC1155 Example**

```
curl https://api.delegate.xyz/registry/v2/check/erc1155?to=0x0000000000000000000000000000000000000000&from=0x0000000000000000000000000000000000000001&contract=0x0000000000000000000000000000000000000003&tokenId=1
```

***

## Returns the delegated balance, which will be 0 if the delegation does not exist

<mark style="color:blue;">`GET`</mark> `https://api.delegate.xyz/registry/v2/check/erc20`

#### Query Parameters

| Name                                       | Type    | Description                                    |
| ------------------------------------------ | ------- | ---------------------------------------------- |
| delegate<mark style="color:red;">\*</mark> | Address | The hot wallet to act on your behalf           |
| vault<mark style="color:red;">\*</mark>    | Address | The cold wallet who issued the delegation      |
| contract<mark style="color:red;">\*</mark> | Address | The address for the contract you're delegating |
| chainId                                    | number  | Defaults to `1` (mainnet)                      |
| rights                                     | string  | bytes32 of rights string                       |

{% tabs %}
{% tab title="200: OK Boolean" %}

{% endtab %}
{% endtabs %}

**Check ERC20 Example**

```
curl https://api.delegate.xyz/registry/v2/check/erc20?to=0x0000000000000000000000000000000000000000&from=0x0000000000000000000000000000000000000001&contract=0x0000000000000000000000000000000000000003
```


# v1

**Supported Networks:** All networks on the main delegate.xyz website are supported

**Rate Limits:** 25 requests per 10 seconds

### Delegations by wallet

## Get a list of incoming and outgoing delegations for a specific wallet.

<mark style="color:blue;">`GET`</mark> `https://api.delegate.xyz/registry/v1/:wallet`

#### Path Parameters

| Name                                     | Type    | Description                   |
| ---------------------------------------- | ------- | ----------------------------- |
| wallet<mark style="color:red;">\*</mark> | Address | The wallet to get delegations |

#### Query Parameters

| Name    | Type   | Description               |
| ------- | ------ | ------------------------- |
| chainId | number | Defaults to `1` (mainnet) |

{% tabs %}
{% tab title="200: OK Delegation\[]" %}

```typescript
type Delegation = {
    type: "NONE" | "ALL" | "CONTRACT" | "TOKEN";
    delegate: string;
    vault: string;
    contract: string | null;
    tokenId: number | null;
};

// returns Delegation[]
```

{% endtab %}
{% endtabs %}

**Delegations by wallet Example**

```shell
curl https://api.delegate.xyz/registry/v1/0x0000000000000000000000000000000000000000
```

### Delegation Checks

## Returns true if the address is delegated to act on the entire vault

<mark style="color:blue;">`GET`</mark> `https://api.delegate.cash/registry/v1/check/all`

#### Query Parameters

| Name                                       | Type    | Description                               |
| ------------------------------------------ | ------- | ----------------------------------------- |
| delegate<mark style="color:red;">\*</mark> | Address | The hot wallet to act on your behalf      |
| vault<mark style="color:red;">\*</mark>    | Address | The cold wallet who issued the delegation |
| chainId                                    | number  | Defaults to `1` (mainnet)                 |

{% tabs %}
{% tab title="200: OK Boolean" %}

{% endtab %}
{% endtabs %}

**Check All Example**

```sh
curl https://api.delegate.xyz/registry/v1/check/all?delegate=0x0000000000000000000000000000000000000000&vault=0x0000000000000000000000000000000000000001
```

## Returns true if the address is delegated to act on your behalf for a token contract or an entire vault

<mark style="color:blue;">`GET`</mark> `https://api.delegate.cash/registry/v1/check/contract`

#### Query Parameters

| Name                                       | Type    | Description                                    |
| ------------------------------------------ | ------- | ---------------------------------------------- |
| delegate<mark style="color:red;">\*</mark> | Address | The hot wallet to act on your behalf           |
| vault<mark style="color:red;">\*</mark>    | Address | The cold wallet who issued the delegation      |
| contract<mark style="color:red;">\*</mark> | Address | The address for the contract you're delegating |
| chainId                                    | number  | Defaults to `1` (mainnet)                      |

{% tabs %}
{% tab title="200: OK Boolean" %}

{% endtab %}
{% endtabs %}

**Check Contract Example**

```sh
curl https://api.delegate.xyz/registry/v1/check/contract?delegate=0x0000000000000000000000000000000000000000&vault=0x0000000000000000000000000000000000000001&contract=0x0000000000000000000000000000000000000003
```

## Returns true if the address is delegated to act on your behalf for a specific token, the token's contract or an entire vault

<mark style="color:blue;">`GET`</mark> `https://api.delegate.xyz/registry/v1/check/token`

#### Query Parameters

| Name                                       | Type    | Description                                    |
| ------------------------------------------ | ------- | ---------------------------------------------- |
| delegate<mark style="color:red;">\*</mark> | Address | The hot wallet to act on your behalf           |
| vault<mark style="color:red;">\*</mark>    | Address | The cold wallet who issued the delegation      |
| contract<mark style="color:red;">\*</mark> | Address | The address for the contract you're delegating |
| tokenId<mark style="color:red;">\*</mark>  | Number  | The token id for the token you're delegating   |
| chainId                                    | number  | Defaults to `1` (mainnet)                      |

{% tabs %}
{% tab title="200: OK Boolean" %}

{% endtab %}
{% endtabs %}

**Check Token Example**

```sh
curl https://api.delegate.xyz/registry/v1/check/contract?delegate=0x0000000000000000000000000000000000000000&vault=0x0000000000000000000000000000000000000001&contract=0x0000000000000000000000000000000000000003&tokenId=1
```


# Technical Documentation

The V1 registry address is [0x00000000000076A84feF008CDAbe6409d2FE638B](https://etherscan.io/address/0x00000000000076a84fef008cdabe6409d2fe638b). Also deployed on many other EVM chains at the same address.

Its source code is tagged on GitHub at <https://github.com/delegatexyz/delegate-registry/tree/2d1a158b012f1d3ac138335c719d45fda0fa1d29>.

It is immutable with \~30,000 delegations and will continue running forever, however we encourage new apps to integrate with V2 only. Users have a one-click migration option to port all of their delegations over on the site, so there is no loss of data.

Users who wish to continue managing their V1 registry delegations can do so by using the version selector in the top right corner of the delegation modal.

<figure><img src="https://3301342738-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKMp3PwjpKKfLzakTeUUs%2Fuploads%2FOI8HQRPLH8LZO5xvQtNB%2FiL8YLDBu.jpg?alt=media&amp;token=efd51921-7561-49c5-8455-c71071a0032d" alt=""><figcaption></figcaption></figure>

&#x20;

<figure><img src="https://3301342738-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKMp3PwjpKKfLzakTeUUs%2Fuploads%2FVBRkVcKp9Z5SbM1yXsG1%2FScreenshot%202023-09-23%20at%2010.06.40%20AM.png?alt=media&amp;token=83d49058-fdba-47f5-bb15-e047bb3c2120" alt=""><figcaption></figcaption></figure>

And for curiosity's sake, here's analytics about V1 registry usage from Sep 2022 to Sep 2023. Thanks for the great adoption, here's to V2 standing for a decade.

<figure><img src="https://3301342738-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKMp3PwjpKKfLzakTeUUs%2Fuploads%2FUTrAXYmuM6xlk12ZGZXh%2FScreenshot%202023-09-23%20at%2010.24.18%20AM.png?alt=media&amp;token=323a43c0-cc05-463e-bb5a-4d7e09bd9edb" alt=""><figcaption></figcaption></figure>


