Adding a delegated key to your wallet allows you to give a third party the possibility to transact on your wallet, while you maintain control over what that key can do. This guide will walk you through the process of creating a delegated key and explain the available permissions.

For a more detailed explanation of how to work with delegated keys, see the Delegated Keys guide.

Delegated keys are only available on EVM and Solana smart wallets

Prerequisites

Ensure you have a wallet created. You can follow the Quickstart for server wallets to prepare one. You will need:

  • API Key: Ensure you have an API key with the scopes: wallets.create, wallets.read, and wallets:signatures.create
  • Wallet Address: The locator of the wallet
  • Admin Signer Key: The private key of the admin signer.

Step-by-Step Guide

  1. Create a New Key: We need to create a new key for the third party. This key will be associated with the delegated signer’s permissions.

    import { generatePrivateKey, privateKeyToAccount } from "viem";
    
    const agentKey = generatePrivateKey();
    const agentSigner = privateKeyToAccount(agentKey);
    console.log(agentSigner.address);
    // > "0x569"
    
  2. Generate a Delegated Key: The creator of the key sends a POST request to the /signers endpoint:

    const walletLocator = "0x...";
    const apiKey = "sk_staging...";
    const signerAddress = "0x569...";
    
    async function createDelegatedKey() {
        const response = await fetch(`https://api.crossmint.com/2022-06-09/wallets/${walletLocator}/signers`, {
            method: "POST",
            headers: {
                "Content-Type": "application/json",
                "X-API-KEY": apiKey,
            },
            body: JSON.stringify({
                chain: "base-sepolia",
                signer: `evm-keypair:${signerAddress}`,
                expiresAt: 1735845180080, // timestamp in ms since Unix epoch
            }),
        });
    
        const data = await response.json();
        console.log(data);
    }
    
    createDelegatedKey().catch(console.error);
    

expiresAt

The expiresAt property specifies the expiration date and time for the delegated key. It is defined as a timestamp in milliseconds since the Unix epoch. Once the delegated key reaches the expiration date and time, it will no longer be valid and cannot be used to perform any actions.

Available Permissions

  1. Native Token Transfers:

    • Type: native-token-transfer
    • Description: Allows the transfer of native blockchain tokens like ETH.
    • Data:
      • allowance: The maximum amount of native tokens that can be transferred, specified in a decimal string.
    {
        "type": "native-token-transfer",
        "data": {
            "allowance": "12340000000" // Maximum amount in decimal string
        }
    }
    
  2. ERC20 Token Transfers:

    • Type: erc20-token-transfer
    • Description: Permits the transfer of ERC20 tokens, which are fungible tokens on the Ethereum blockchain.
    • Data:
      • address: The contract address of the ERC20 token.
      • allowance: The maximum amount of ERC20 tokens that can be transferred, specified in a decimal string.
    {
        "type": "erc20-token-transfer",
        "data": {
            "address": "0x...", // Token contract address
            "allowance": "12340000000" // Maximum amount in decimal string
        }
    }
    
  3. ERC721 Token Transfers:

    • Type: erc721-token-transfer
    • Description: Enables the transfer of ERC721 tokens, which are non-fungible tokens (NFTs) on the Ethereum blockchain.
    • Data:
      • address: The contract address of the ERC721 token.
      • tokenId: The specific token ID to be transferred.
    {
        "type": "erc721-token-transfer",
        "data": {
            "address": "0x...", // Token contract address
            "tokenId": "1234" // Specific token ID
        }
    }
    
  4. ERC1155 Token Transfers:

    • Type: erc1155-token-transfer
    • Description: Allows the transfer of ERC1155 tokens, which can be both fungible and non-fungible.
    • Data:
      • address: The contract address of the ERC1155 token.
      • tokenId: The specific token ID to be transferred.
      • amount: The amount of tokens to be transferred.
    {
        "type": "erc1155-token-transfer",
        "data": {
            "address": "0x...", // Token contract address
            "tokenId": "1234", // Specific token ID
            "amount": "10" // Amount of tokens
        }
    }
    
  5. Gas Limit Controls:

    • Type: gas-limit
    • Description: Sets a cap on the gas that can be used for transactions, helping to manage transaction costs.
    • Data:
      • limit: The maximum gas limit for transactions, specified in a decimal string.
    {
        "type": "gas-limit",
        "data": {
            "limit": "1000000" // Maximum gas in decimal string
        }
    }
    
  6. Total Call Limits:

    • Type: call-limit
    • Description: Restricts the number of calls that can be made, providing control over transaction frequency.
    • Data:
      • count: The maximum number of calls that can be made.
    {
        "type": "call-limit",
        "data": {
            "count": number // Max number of calls
        }
    }
    
  7. Rate Limiting:

    • Type: rate-limit
    • Description: Controls the rate of transactions by limiting the number of calls within a specified time frame.
    • Data:
      • count: The number of calls allowed.
      • interval: The time window in seconds.
    {
        "type": "rate-limit",
        "data": {
            "count": number,   // Number of calls allowed
            "interval": number // Time window in seconds
        }
    }