Files
bro-sdk/docs/add-evm-token-support.md
2025-05-23 11:59:37 +02:00

7.0 KiB

How to Add Support for a new EVM Token

This document explains the process for adding support for a new EVM token in the SDK.

Overview

Adding support for a new EVM token requires modifying the following files:

  1. src/utils/types/knownIds.ts - Add the new Token ID
  2. src/evmUtils/contractHelpers.ts - Add the token to the contract configuration
  3. src/stacksUtils/stxContractAddresses.ts - Add contract addresses for the corresponding token on the Stacks chain

Important Notice for Developers and AI Assistants

CRITICAL: The following values MUST be obtained from contract deployers or development team and should NEVER be generated by developers or AI tools:

  1. The exact ONCHAIN_CONFIG_KEY value for the token (e.g., TOKEN_NEW_TOKEN)
  2. The contract addresses in stxTokenContractAddresses_legacy
  3. The token name/identifier (the actual token name like "ETH", "BTC", etc.)

These values are determined by the contract deployers and must match the deployed contract configurations.

NAMING CONVENTIONS:

  • KnownTokenId.EVM.TOKEN_NAME and KnownTokenId.Stacks.TOKEN_NAME typically use the same name (e.g., both would be "ETH" for ETH)
  • However, ONCHAIN_CONFIG_KEY.TOKEN_NAME is NOT directly related to these names and is determined by how it's defined in the smart contract (e.g., "TOKEN_ETH" for ETH)
  • Always confirm the exact naming for ONCHAIN_CONFIG_KEY with the contract deployers, as it must match what's in the contract

Detailed Steps

1. Add the Token ID in knownIds.ts

In the src/utils/types/knownIds.ts file, add the new Token ID to the appropriate sections in the KnownTokenId namespace:

export namespace KnownTokenId {
  export namespace EVM {
    // Add the new EVM Token ID here - use the exact token name provided by the team
    // For example, ETH for Ethereum
    export const TOKEN_NAME = tokenId("evm-tokenname")
  }
  
  // If Stacks support is needed, also add it to the Stacks namespace
  // Use the same token name as above
  export namespace Stacks {
    export const TOKEN_NAME = tokenId("stx-tokenname")
  }
}

2. Update Contract Configuration in contractHelpers.ts

In the src/evmUtils/contractHelpers.ts file, you need to update the following sections:

  1. Add a new token key to the ONCHAIN_CONFIG_KEY enum:
enum ONCHAIN_CONFIG_KEY {
  // Other token keys...
  // IMPORTANT: Use the exact key provided by the contract deployers
  // This key format is usually different from the token name itself
  // For example, TOKEN_ETH for Ethereum
  TOKEN_KEY = "TOKEN_KEY", // This must match what's configured in the smart contract
}
  1. Add the new token key to the getConfigs call in the _getOnChainConfigsImpl function:
const configs = await readContract(client, {
  abi: BridgeConfigAbi,
  address: configContractAddress,
  functionName: "getConfigs",
  args: [
    [
      // Other token keys...
      ONCHAIN_CONFIG_KEY.TOKEN_KEY, // Use the key added in the enum above
    ],
  ],
})
  1. Add the token mapping to the return object in the same function:
return {
  // Other mappings...
  // Note: EVMToken.TOKEN_NAME uses the same name as in KnownTokenId.EVM
  // while ONCHAIN_CONFIG_KEY.TOKEN_KEY uses the contract-specific key
  [EVMToken.TOKEN_NAME]: maybeAddress(configs[INDEX_POSITION]),
}

Important: The INDEX_POSITION should match the position of your token key in the getConfigs args array. For example, if your token is the 21st item in the array, use configs[20] (zero-indexed).

3. Add Stacks Contract Addresses in stxContractAddresses.ts

Add the corresponding contract addresses in the src/stacksUtils/stxContractAddresses.ts file:

export const stxTokenContractAddresses_legacy: Record<
  // ...
> = {
  // Other tokens...
  // Use the same token name as in KnownTokenId.Stacks
  [KnownTokenId.Stacks.TOKEN_NAME]: {
    [KnownChainId.Stacks.Mainnet]: wrapContractAddress("mainnet", {
      // IMPORTANT: Use the exact addresses provided by the contract deployers
      deployerAddress: contractsMultisigMainnet,
      contractName: "token-name", // This contract name must be obtained from the team
    }),
    [KnownChainId.Stacks.Testnet]: wrapContractAddress("testnet", {
      // IMPORTANT: Use the exact addresses provided by the contract deployers
      deployerAddress: contractsMultisigTestnet,
      contractName: "token-name", // This contract name must be obtained from the team
    }),
  },
}

Example: Adding ETH Token Support

Here's a real example of adding support for the ETH token:

  1. Adding to knownIds.ts:

    export const ETH = tokenId("evm-eth")  // In EVM namespace
    export const ETH = tokenId("stx-eth")  // In Stacks namespace - same name as EVM
    
  2. Updating contractHelpers.ts:

    // Add to enum - this key was provided by the contract deployers
    // Note that this is TOKEN_ETH, not just ETH
    enum ONCHAIN_CONFIG_KEY {
      // ...other tokens
      TOKEN_ETH = "TOKEN_ETH",
    }
    
    // Add to getConfigs call
    ONCHAIN_CONFIG_KEY.TOKEN_ETH,
    
    // Add to return object mapping
    // Here we use EVMToken.ETH (the token name), not TOKEN_ETH
    [EVMToken.ETH]: maybeAddress(configs[20]),
    
  3. Adding to stxContractAddresses.ts:

    [KnownTokenId.Stacks.ETH]: {
      [KnownChainId.Stacks.Mainnet]: wrapContractAddress("mainnet", {
        deployerAddress: contractsMultisigMainnet,
        contractName: "token-eth", // This name was provided by the team
      }),
      [KnownChainId.Stacks.Testnet]: wrapContractAddress("testnet", {
        deployerAddress: contractsMultisigTestnet,
        contractName: "token-eth", // This name was provided by the team
      }),
    },
    

Important Considerations

  1. After adding a new token, ensure that all related cross-chain routing and validation logic works correctly
  2. Maintain consistency with array indices - ensure the index position in the configs array matches the position of your token in the getConfigs args array
  3. If the contract address is read from on-chain configuration, make sure the on-chain contract has the correct token address configured
  4. After adding a new token, perform comprehensive testing to ensure all functionality works as expected

For Automated Tools (AI Assistants)

When adding a new token, follow these exact steps:

  1. DO NOT generate any values on your own - always ask for the official token name, ONCHAIN_CONFIG_KEY, and contract addresses
  2. Identify the next available index position for the token in the getConfigs call
  3. Add the token ID with the appropriate prefix pattern (e.g., "evm-tokenname" and "stx-tokenname")
  4. Add the token to all three files mentioned above
  5. Ensure the index position in the return mapping matches the position in the args array
  6. Follow the existing naming conventions for contract names as specified by the contract deployers
  7. Remember that KnownTokenId names typically match in EVM and Stacks namespaces, but ONCHAIN_CONFIG_KEY uses a different format defined by the contract