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。
此页面涵盖了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资产列表如下所示:
*您可以在Polkadot.js Apps上查看每个资产ID
*您可以在Polkadot.js Apps上查看每个资产ID
来源 | 符号 | XC-20地址 |
---|---|---|
Relay Chain Alphanet | xcUNIT | 0xFfFFfFff1FcaCBd218EDc0EbA20Fc2308C778080 |
*您可以在Polkadot.js Apps上查看每个资产ID
检索外部XC-20列表与原数据信息¶
要获取当前可用的外部XC-20列表以及其关联的元数据,您可以使用Polkadot.js API查询链状态。为此,您可以遵循以下步骤:
-
为您想要获取其资产列表的网络创建一个API提供商。 您可以为每个网络使用以下WSS端点:
wss://wss.api.moonbeam.network
wss://wss.api.moonriver.moonbeam.network
wss://wss.api.moonbase.moonbeam.network
-
查询所有资产的
assets
pallet - 迭代资产列表以获取所有资产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()
| Created: January 4, 2022