跳到主要内容

CrossSpaceCall 合约

Conflux eSpace 和 Core Space 是两个独立的 space,您不能直接将 CFX 从 base32 地址发送到十六进制地址。 您只能使用 Confluxhub Space Bridge 在 eSpace 和 Core Space 之间转移 CFX。

在底层,Core Space 中有一个名为 CrossSpaceCall 的内置合约,用于在 eSpace 和 Core Space 之间转移 CFX。 通过CrossSpaceCall,在Core Space内直接与eSpace合约进行互动成为可能。 这个合约是由 CIP-90 引入的。

CrossSpaceCall 接口

这个合约在 Core Space 中可用,地址为:

以下是这个合约的接口:

interface CrossSpaceCall {
/**
* @dev 在 eSpace 中部署一个合约
* @param init bytes - 合约初始化字节码
* @return bytes20 - 部署合约的十六进制地址
*/
function createEVM(bytes calldata init) external payable returns (bytes20);
/* 跨空间 CFX 转移的方法 */

/**
* @dev 将 CFX 从 Core space 转移到 eSpace 指定地址。转移金额由交易值指定。
* @param to bytes20 - 接收方在 eSpace 的十六进制地址
* @return output bytes - 交易输出
*/
function transferEVM(bytes20 to) external payable returns (bytes memory output);

/**
* @dev 从 eSpace 映射账户余额中提取 CFX
* @param value uint256 - 需要提取的 CFX 数量
*/
function withdrawFromMapped(uint256 value) external;

/**
* @dev 查询 eSpace 映射账户的 CFX 余额
* @param addr address - 需要查询的 core 地址
* @return uint256 - 余额
*/
function mappedBalance(address addr) external view returns (uint256);

/**
* @dev 查询 eSpace 映射账户的 nonce
* @param addr address - 需要查询的 core 地址
* @return uint256 - Nonce 值
*/
function mappedNonce(address addr) external view returns (uint256);

/* 其他跨空间操作的方法 */

/**
* @dev 从 Core space 调用 eSpace 合约方法
* @param to bytes20 - eSpace 中合约的十六进制地址
* @param data bytes - 合约方法调用数据
* @return output bytes - 方法调用结果
*/
function callEVM(bytes20 to, bytes calldata data) external payable returns (bytes memory output);

/**
* @dev 从 Core space 静态调用 eSpace 合约方法
* @param to bytes20 - eSpace 中合约的十六进制地址
* @param data bytes - 合约方法调用数据
* @return output bytes - 方法调用结果
*/
function staticCallEVM(bytes20 to, bytes calldata data) external view returns (bytes memory output);
}

在 eSpace 和 Core Space 之间转移 CFX

通过调用 CrossSpaceCall 内置合约的相关方法,可以实现在 eSpace 和 Core Space 之间转移 CFX。

注意,CrossSpaceCall(如同其他内置合约一样)只能在 Conflux Core Space 中访问。

从 Core Space 到 eSpace

从 Core 到 eSpace:要将 CFX 从 Conflux Core 转移到 Conflux eSpace,需要调用该合约的 transferEVM(bytes20 to) 方法。 此转移的目的地址由方法参数 to 指定。 跨空间转移将在一个单一的原子步骤中执行。

function transferEVM(bytes20 to) external payable returns (bytes memory output);

JS 示例

const { Conflux, Drip } = require('js-conflux-sdk');

const conflux = new Conflux({
url: 'https://main.confluxrpc.com',
chainId: 1029,
});

const account = conflux.wallet.addPrivateKey(process.env.PRIVATE_KEY);

const crossSpaceCall = conflux.InternalContract('CrossSpaceCall');

async function main() {
const eSpaceAddress = '0x3D69D968e3673e188B2D2d42b6a385686186258f';

const receipt = await crossSpaceCall.transferEVM(eSpaceAddress)
.sendTransaction({
from: account,
value: Drip.fromCFX(1), // 转移 1 CFX,金额由 value 指定
}).executed();

console.log(`转移到 ${eSpaceAddress} ${receipt.outcomeStatus === 0 ? 'succeed' : 'failed'}`);
}

main();

从 eSpace 到 Core Space

跨空间操作中的映射地址

要将 CFX 从 eSpace 转移到 Core Space,需要一个映射地址。 Core Space 中的每个地址在 eSpace 中都有一个 映射地址 (hex40)。 只有 Core space 地址可以从其映射地址提取 CFX。

有关映射地址的详细信息,请参阅映射地址

转移步骤

要将 CFX 从 Conflux eSpace 转移到 Conflux Core,需要两个步骤。

  1. 将 CFX 转移到属于 Core 目标地址的 eSpace 映射地址。 这个操作需要一个 eSpace 交易。
  2. 调用 CrossSpaceCall 内部合约的 withdrawFromMapped(uint256 value) 方法。 这个调用将把 CFX 从映射账户转回到相应的目标地址。 另一个方法 mappedBalance 可用于查询一个 core 地址的映射地址余额。
function withdrawFromMapped(uint256 value) external;

// 参数 addr 是一个 core 账户地址
function mappedBalance(address addr) external view returns (uint256);

JS 示例

步骤 1: 使用 js-conflux-sdk 的地址工具方法获取 Core Space 目标账户的映射地址。

const { address } = require('js-conflux-sdk');

const base32Address = 'cfx:aak2rra2njvd77ezwjvx04kkds9fzagfe6ku8scz91';

const mappedAddress = address.cfxMappedEVMSpaceAddress(base32Address);

// 0x12Bf6283CcF8Ad6ffA63f7Da63EDc217228d839A

步骤 2: 通过钱包或 ethers.js 在 eSpace 中向映射地址转移 CFX

步骤 3: 在 Core Space 中调用 CrossSpaceCall 内部合约的 withdrawFromMapped 方法,从映射地址提取 CFX。

const { Conflux, Drip, address } = require('js-conflux-sdk');

const conflux = new Conflux({
url: 'https://main.confluxrpc.com',
chainId: 1029,
});

const account = conflux.wallet.addPrivateKey(process.env.PRIVATE_KEY);

const crossSpaceCall = conflux.InternalContract('CrossSpaceCall');

async function main() {
const receipt = await crossSpaceCall.withdrawFromMapped(Drip.fromCFX(1))
.sendTransaction({
from: account,
}).executed();

console.log(`从 eSpace 提取 ${receipt.outcomeStatus === 0 ?' succeed' : 'failed'}`);
}

main();

从 Core Space 调用 eSpace 合约

通过 CrossSpaceCall 合约,可以从 Core Space 读取或写入 eSpace 合约的状态。 我们将给出一个简单的示例,展示如何从 Core Space 调用 eSpace 合约。

以下是在 eSpace 中部署的合约,地址为 0x8c2a2b6b4c3b6e7e7d3b5e8b4b6b6b6b6b6b6b6b

contract SimpleStore {
uint256 public value;

function setValue(uint256 _value) public {
value = _value;
}
}

以下是在 Core Space 中部署的合约:


contract CrossCallExample {

CrossSpace public crossSpaceCall = CrossSpace(0x0888000000000000000000000000000000000006);

function readValue() public returns (uint256) {
bytes20 to = bytes20(0x8c2a2b6b4c3b6e7e7d3b5e8b4b6b6b6b6b6b6b6b);
bytes memory num = crossSpaceCall.staticCallEVM(to, abi.encodeWithSignature("value()"));
return abi.decode(num, (uint256));
}

function setValue(uint256 _value) public {
bytes20 to = bytes20(0x8c2a2b6b4c3b6e7e7d3b5e8b4b6b6b6b6b6b6b6b);
bytes memory data = abi.encodeWithSignature("setValue(uint256)", 100);
crossSpaceCall.callEVM(to, data);
}
}

其他资源