You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Near链使用AssemblyScript调用Aurora合约时如何编码参数

问题场景

在NEAR区块链上使用AssemblyScript开发的合约,需要调用部署在Aurora上的EVM合约时,Aurora合约抛出ERR_BORSH_DESERIALIZE panic错误,原实现代码如下:

import { BorshSerializer } from '@serial-as/borsh'

@serializable
class FunctionCallArgs {
  contract: Uint8Array;
  input: Uint8Array;
}

export function myFunction(): void {
  const args: FunctionCallArgs = {
    contract: util.stringToBytes(contractAddress),
    input: util.stringToBytes(abiEncodedFn),
  };
  const argsBorsh = BorshSerializer.encode(args);

  ContractPromise.create("aurora", "call", argsBorsh, 100);
}
错误根因
  • 字段类型不匹配:Aurora引擎合约call方法的第一个参数contract是固定长度20字节的EVM地址原始字节数组,Borsh对固定长度数组不会写入长度前缀;原代码将其定义为动态长度Uint8Array,序列化时会额外写入4字节小端序长度值,和Aurora预期的序列化结构完全错位,直接触发反序列化失败。
  • 字节转换逻辑错误:util.stringToBytes是将字符串按UTF-8编码转成字节流,传入hex格式的地址/ABI调用数据时,会把每个十六进制字符的ASCII码作为字节值(比如字符'0'会被转为0x30,而非十六进制对应的0x00),完全不符合参数的字节要求。
  • Gas配置不足:原代码传入的100单位gas远低于跨合约调用+Aurora EVM执行的最低要求,即使参数序列化正确也会后续执行失败(该问题不会触发反序列化报错,但属于必踩的坑)。
正确实现代码

直接手动按Borsh规则序列化参数,避免第三方序列化库的类型标注、字段顺序不匹配问题,同时修正字节转换逻辑:

/**
 * 将hex格式字符串转为原始字节数组
 * 自动处理带0x前缀/不带前缀的输入
 */
function hexToBytes(hex: string): Uint8Array {
  const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
  assert(cleanHex.length % 2 === 0, "Invalid hex string length");
  const res = new Uint8Array(cleanHex.length / 2);
  for (let i = 0; i < res.length; i++) {
    const byteStr = cleanHex.slice(i * 2, i * 2 + 2);
    res[i] = u8(parseInt(byteStr, 16));
  }
  return res;
}

/**
 * 按Aurora call方法的Borsh序列化规则编码参数
 * 结构:[20字节固定EVM地址][4字节小端序input长度][input原始字节]
 */
function serializeAuroraCallArgs(targetEvmAddr: Uint8Array, callInput: Uint8Array): Uint8Array {
  assert(targetEvmAddr.length === 20, "EVM address must be 20 bytes");
  const args = new Uint8Array(20 + 4 + callInput.length);
  // 写入固定长度20字节地址
  memory.copy(args.dataStart, targetEvmAddr.dataStart, 20);
  // 写入input长度(小端u32)
  store<u32>(args.dataStart + 20, callInput.length as u32);
  // 写入input内容
  memory.copy(args.dataStart + 24, callInput.dataStart, callInput.length);
  return args;
}

export function myFunction(): void {
  // 替换为实际目标Aurora合约的EVM地址(hex格式)
  const targetContract = "0x你的合约地址";
  // 替换为实际ABI编码后的EVM调用数据(hex格式)
  const abiEncodedCallData = "0x你的ABI编码调用数据";

  const contractBytes = hexToBytes(targetContract);
  const inputBytes = hexToBytes(abiEncodedCallData);
  const serializedArgs = serializeAuroraCallArgs(contractBytes, inputBytes);

  // 附加Gas建议不低于30Tgas,可根据实际调用复杂度上调
  const attachedGas = 30_000_000_000_000;
  ContractPromise.create("aurora", "call", serializedArgs, attachedGas);
}
注意事项
  • 不要依赖通用Borsh序列化库处理Aurora调用参数,必须确认序列化结构和Aurora合约定义完全一致:固定长度字段无长度前缀,动态长度字段前置4字节小端序长度。
  • 所有链上传递的EVM地址、ABI编码数据都必须是原始字节,不能直接把hex字符串用UTF-8编码转字节。
  • Aurora跨调用需要预留足够的Gas,避免因Gas不足导致交易失败。

内容的提问来源于stack exchange,提问作者Gwin Pin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 10:51:35