Skip to content

XC-20概述

概览

跨共识信息格式(XCM)定义了两条互操作区块链之间传递信息的方式。此格式为Moonbeam/Moonriver与中继链或是其他波卡/Kusama生态内平行链之间打开了传递信息和资产的大门。

Substrate资产具有原生可互操作性。然而,开发者需要使用Substrate API与其交互。而这使开发者的体验感降低,尤其是来自以太坊生态的开发者。因此,为了协助开发者上手波卡和Kusama提供的原生互操作性,Moonbeam引入了XC-20概念。

XC-20为Moonbeam上独特的资产类别,其结合了Substrate资产的优点(原生可互操作性)但又使开发者能够通过预编译合约(以太坊API)使用熟悉的ERC-20接口与之交互。在EVM方面,XC-20具有ERC-20接口,因此智能合约和用户可以轻松地与其交互 ,并且无需了解 Substrate。这最终为开发人员在处理这些类型的资产时提供了更大的灵活性,并允许与基于EVM的智能合约(例如DEX和借贷平台等)无缝集成。 此外,开发人员可以将XC-20与常规的以太坊开发框架或dApp集成,并使用此类资产创建互连合约策略。此外,随着RT2301的引入,所有ERC-20都已支持XCM,这意味着它们也可以作为XC-20。

Moonbeam XC-20 XCM Integration With Polkadot

此页面涵盖了XC-20的基本概念,如果您想要了解如何与之交互或转移XC-20,请参考与XC-20交互使用X-Tokens Pallet发送XC-20教程。

XC-20类型

目前有两种XC-20类型:本地XC-20和外部XC-20。

什么是本地XC-20?

本地XC-20是EVM上存在的所有ERC-20,可以通过XCM跨链传输。为了将本地XC-20转移到另一个平行链,资产需要在该链上注册。转移本地XC-20时,实际的Token存在于Moonbeam上目标链的主权账户中。本地XC-20必须遵循本教程中ERC-20接口部分,它们不能自定义ERC-20。 更具体地说,transfer函数的函数选择器必须如EIP-20中所述:

function transfer(address _to, uint256 _value) public returns (bool success)

如果transfer函数的函数选择器偏离标准,则跨链转账将会失败。

什么是外部XC-20?

外部XC-20是从其他平行链或中继链转移到Moonbeam的原生跨链资产。这些资产的核心是Substrate资产。当转移外部XC-20时,实际的Token存在于每条链的Moonbeam主权账户中。所有的外部XC-20资产使用_xc_作为其名称的前缀与其他资产类别进行区分。

本地XC-20与外部XC-20的区别

与其他Substrate资产一样,两种类型的XC-20都可以通过以太坊和Substrate API轻松发送到生态系统中的其他平行链。 但是,使用Substrate API进行XCM转移将为本地XC-20发出EVM日志,但不会为外部XC-20发出EVM日志。建议使用以太坊API,通过基于EVM的浏览器(例如Moonscan)提供对XCM操作的更多可见性。

在 Moonbeam上,本地XC-20只能通过其常规ERC-20接口进行转移。 相反,外部XC-20可以通过两个接口(Substrate和ERC-20)进行转移。如果外部XC-20通过Substrate API转移,则基于EVM的区块浏览器将看不到该交易。只有通过以太坊API完成的交易才能通过此类浏览器可见。

两种资产类型的主要区别在于本地XC-20时EVM ERC-20,其具有XCM功能,然而外部XC-20是Substrate资产,顶部具有ERC-20接口。

XC-20的跨链资产转移可以通过X-Tokens Pallet完成。要了解如何使用X-Tokens Pallet转移XC-20s,您可以参考使用X-Tokens Pallet发送XC-20s的教程。

当前可用的外部XC-20列表

每个网络当前可用的外部XC-20资产列表如下所示:

来源 符号 XC-20地址
Polkadot xcDOT 0xFfFFfFff1FcaCBd218EDc0EbA20Fc2308C778080
Acala xcaSEED 0xfFfFFFFF52C56A9257bB97f4B2b6F7B2D624ecda
Acala xcACA 0xffffFFffa922Fef94566104a6e5A35a4fCDDAA9f
Acala xcLDOT 0xFFfFfFffA9cfFfa9834235Fe53f4733F1b8B28d4
Astar xcASTR 0xFfFFFfffA893AD19e540E172C10d78D4d479B5Cf
Bifrost xcBNC 0xffffffff7cc06abdf7201b350a1265c62c8601d2
Bifrost xcBNCS 0xfFfffffF6aF229AE7f0F4e0188157e189a487D59
Bifrost xcFIL 0xfFFfFFFF6C57e17D210DF507c82807149fFd70B2
Bifrost xcvASTR 0xFffFffff55C732C47639231a4C4373245763d26E
Bifrost xcvDOT 0xFFFfffFf15e1b7E3dF971DD813Bc394deB899aBf
Bifrost xcvFIL 0xFffffFffCd0aD0EA6576B7b285295c85E94cf4c1
Bifrost xcvGLMR 0xFfFfFFff99dABE1a8De0EA22bAa6FD48fdE96F6c
Bifrost xcvMANTA 0xFFfFFfFfdA2a05FB50e7ae99275F4341AEd43379
Centrifuge xcCFG 0xFFfFfFff44bD9D2FFEE20B25D1Cf9E78Edb6Eae3
Composable xcIBCMOVR 0xFfFfffFF3AFcd2cAd6174387df17180a0362E592
Composable xcIBCPICA 0xfFFFFfFFABe9934e61db3b11be4251E6e869cf59
Composable xcIBCIST 0xfFfFffff6A3977d5B65D1044FD744B14D9Cef932
Composable xcIBCBLD 0xFffFffff9664be0234ea4dc64558F695C4f2A9EE
Composable xcIBCTIA 0xFFFfFfff644a12F6F01b754987D175F5A780A75B
Composable xcIBCATOM 0xffFFFffF6807D5082ff2f6F86BdE409245e2D953
Darwinia xcRING 0xFfffFfff5e90e365eDcA87fB4c8306Df1E91464f
Equilibrium xcEQ 0xFffFFfFf8f6267e040D8a0638C576dfBa4F0F6D6
Equilibrium xcEQD 0xFFffFfFF8cdA1707bAF23834d211B08726B1E499
HydraDX xcHDX 0xFFFfFfff345Dc44DDAE98Df024Eb494321E73FcC
Interlay xcIBTC 0xFFFFFfFf5AC1f9A51A93F5C527385edF7Fe98A52
Interlay xcINTR 0xFffFFFFF4C1cbCd97597339702436d4F18a375Ab
Manta xcMANTA 0xfFFffFFf7D3875460d4509eb8d0362c611B4E841
Nodle xcNODL 0xfffffffFe896ba7Cb118b9Fa571c6dC0a99dEfF1
OriginTrail Parachain xcOTP 0xFfffffFfB3229c8E7657eABEA704d5e75246e544
Parallel xcPARA 0xFfFffFFF18898CB5Fe1E88E668152B4f4052A947
Pendulum xcPEN 0xffffffff2257622f345e1acde0d4f46d7d1d77d0
Phala xcPHA 0xFFFfFfFf63d24eCc8eB8a7b5D0803e900F7b6cED
Polkadex xcPDEX 0xfFffFFFF43e0d9b84010b1b67bA501bc81e33C7A
Polkadot Asset Hub xcPINK 0xfFfFFfFf30478fAFBE935e466da114E14fB3563d
Polkadot Asset Hub xcUSDC 0xFFfffffF7D2B0B761Af01Ca8e25242976ac0aD7D
Polkadot Asset Hub xcUSDT 0xFFFFFFfFea09FB06d082fd1275CD48b191cbCD1d
Subsocial xcSUB 0xffffffff43b4560bc0c451a3386e082bff50ac90
Zeitgeist xcZTG 0xFFFFfffF71815ab6142E0E20c7259126C6B40612

*您可以在Polkadot.js Apps上查看每个资产ID

来源 符号 XC-20地址
Relay Chain Alphanet xcUNIT 0xFfFFfFff1FcaCBd218EDc0EbA20Fc2308C778080

*您可以在Polkadot.js Apps上查看每个资产ID

检索外部XC-20列表与原数据信息

要获取当前可用的外部XC-20列表以及其关联的元数据,您可以使用Polkadot.js API查询链状态。为此,您可以遵循以下步骤:

  1. 为您想要获取其资产列表的网络创建一个API提供商。 您可以为每个网络使用以下WSS端点:

    wss://wss.api.moonbeam.network
    
    wss://wss.api.moonriver.moonbeam.network
    
    wss://wss.api.moonbase.moonbeam.network
    
  2. 查询所有资产的assets pallet

  3. 迭代资产列表以获取所有资产ID及其关联的元数据
import { ApiPromise, WsProvider } from '@polkadot/api'; // Version 9.13.6

const getXc20s = async () => {
  // 1. Create API provider
  const substrateProvider = new WsProvider(
    'wss://wss.api.moonbase.moonbeam.network'
  );
  const api = await ApiPromise.create({ provider: substrateProvider });

  // 2. Query the assets pallet for all assets
  const assets = await api.query.assets.asset.entries();

  // 3. Get metadata for each asset using the ID
  assets.forEach(
    async ([
      {
        args: [id],
      },
    ]) => {
      const metadata = await api.query.assets.metadata(id);
      console.log(`Asset ID: ${id}`);
      console.log(`Metadata: ${metadata.toHuman()}`);
      console.log('-----');
    }
  );

  api.disconnect();
};

getXc20s();

结果将显示资产ID以及所有已注册外部XC-20的一些附加信息。

获取本地XC-20元数据信息

在Moonbeam上本地XC-20s为ERC-20s,它们无法通过XCM传输至其他平行链,您可以将本地XC-20s当作ERC-20来交互。如果您有ERC-20的地址与ABI,您可以通过使用ERC-20标准接口来获取元数据信息,包括它的名字,符号以及小数点位数。

以下实例展示了如何在Moonbase Alpha上获取Jupiter token的元数据:

import { ethers } from 'ethers';

const providerRPC = {
  moonbase: {
    name: 'moonbase',
    rpc: 'https://rpc.api.moonbase.moonbeam.network', // Insert your RPC URL here
    chainId: 1287, // 0x507 in hex,
  },
};

const provider = new ethers.JsonRpcProvider(providerRPC.moonbase.rpc, {
  chainId: providerRPC.moonbase.chainId,
  name: providerRPC.moonbase.name,
});

// Replace with the address of the ERC-20 token
const tokenAddress = '0x9Aac6FB41773af877a2Be73c99897F3DdFACf576';
const tokenABI = [
  'function name() view returns (string)',
  'function symbol() view returns (string)',
  'function decimals() view returns (uint8)',
];

const tokenContract = new ethers.Contract(tokenAddress, tokenABI, provider);
async function getTokenMetadata() {
  try {
    const [name, symbol, decimals] = await Promise.all([
      tokenContract.name(),
      tokenContract.symbol(),
      tokenContract.decimals(),
    ]);
    console.log(`Name: ${name}`);
    console.log(`Symbol: ${symbol}`);
    console.log(`Decimals: ${decimals}`);
  } catch (error) {
    console.error('Error fetching token metadata:', error);
  }
}
getTokenMetadata();
import { Web3 } from 'web3';

// Insert your RPC URL here
const web3 = new Web3('https://rpc.api.moonbase.moonbeam.network');

// Replace with the address of the ERC-20 token
const tokenAddress = '0x9Aac6FB41773af877a2Be73c99897F3DdFACf576';
const tokenABI = [
  // ERC-20 ABI
  {
    constant: true,
    inputs: [],
    name: 'name',
    outputs: [{ name: '', type: 'string' }],
    payable: false,
    stateMutability: 'view',
    type: 'function',
  },
  {
    constant: true,
    inputs: [],
    name: 'symbol',
    outputs: [{ name: '', type: 'string' }],
    payable: false,
    stateMutability: 'view',
    type: 'function',
  },
  {
    constant: true,
    inputs: [],
    name: 'decimals',
    outputs: [{ name: '', type: 'uint8' }],
    payable: false,
    stateMutability: 'view',
    type: 'function',
  },
];
const tokenContract = new web3.eth.Contract(tokenABI, tokenAddress);
async function getTokenMetadata() {
  try {
    const [name, symbol, decimals] = await Promise.all([
      tokenContract.methods.name().call(),
      tokenContract.methods.symbol().call(),
      tokenContract.methods.decimals().call(),
    ]);
    console.log(`Name: ${name}`);
    console.log(`Symbol: ${symbol}`);
    console.log(`Decimals: ${decimals}`);
  } catch (error) {
    console.error('Error fetching token metadata:', error);
  }
}
getTokenMetadata();
from web3 import Web3

web3 = Web3(Web3.HTTPProvider("https://rpc.api.moonbase.moonbeam.network"))

# Replace with the address of the ERC-20 token
token_address = "0x9Aac6FB41773af877a2Be73c99897F3DdFACf576"
token_abi = [  # ERC-20 ABI
    {
        "constant": True,
        "inputs": [],
        "name": "name",
        "outputs": [{"name": "", "type": "string"}],
        "payable": False,
        "stateMutability": "view",
        "type": "function",
    },
    {
        "constant": True,
        "inputs": [],
        "name": "symbol",
        "outputs": [{"name": "", "type": "string"}],
        "payable": False,
        "stateMutability": "view",
        "type": "function",
    },
    {
        "constant": True,
        "inputs": [],
        "name": "decimals",
        "outputs": [{"name": "", "type": "uint8"}],
        "payable": False,
        "stateMutability": "view",
        "type": "function",
    },
]
token_contract = web3.eth.contract(address=token_address, abi=token_abi)


def get_token_metadata():
    try:
        name = token_contract.functions.name().call()
        symbol = token_contract.functions.symbol().call()
        decimals = token_contract.functions.decimals().call()
        print(f"Name: {name}")
        print(f"Symbol: {symbol}")
        print(f"Decimals: {decimals}")
    except Exception as e:
        print(f"Error fetching token metadata: {e}")


get_token_metadata()
Last update: February 14, 2024
| Created: January 4, 2022