跳转至

智能合约调用数据格式

原文:https://docs.elrond.com/developers/sc-calls-format

除了常规的移动余额交易(地址 A 将金额 X 发送到地址 B,同时可选地在data字段中包含注释),Elrond交易可以触发智能合约调用,或内置函数调用

这可能发生在下列情况下:

  • 交易的接收者是智能合约地址,数据字段以合约的有效功能开始。
  • 交易的数据字段以有效的内置函数名开始。

对Elrond上的智能合约函数(或内置函数)的调用具有以下格式:

ScCallTransaction {
    Sender: <account address of the sender>
    Receiver: <account address of the receiver> # can be a SC, or other address in case of built in functions
    Value: X # to be determined for each case
    GasLimit: Y # to be determined for each case
    Data: "functionName" +
          "@" + <optional first argument in hexadecimal encoding> +
          "@" + <optional second argument in hexadecimal encoding> +
          ...
} 

每个函数的参数数量都是特定的。

举例。我们有一个地址为erd1qqqqqqqqqqqqqpgqrchxzx5uu8sv3ceg8nx8cxc0gesezure5awqn46gtd的智能合约 A。合约有一个函数add(numberToAdd numeric),它将numberToAdd添加到内部管理的金额中。如果我们想调用该函数,并将15添加到内部总和中,则交易看起来会像这样:

ExampleScCallTransaction {
    Sender: <account address of the sender>
    Receiver: erd1qqqqqqqqqqqqqpgqrchxzx5uu8sv3ceg8nx8cxc0gesezure5awqn46gtd
    Value: 0 # no value needed for this call
    GasLimit: 1_000_000 # let's suppose we need this much gas for calling the function
    Data: "add@0f" # call the function add with the argument 15, hex-encoded
} 

约束

仅关注智能合约调用/内置函数调用的数据字段,对于函数名称和参数有一些限制:

  • function name必须是要调用的函数的纯文本名称。
  • arguments必须用一个偶数个字符进行十六进制编码(eq: 7 -无效,07 -有效;f6f -无效,6f6b -有效)。
  • function namearguments必须用@字符隔开。

这一页的下一节将集中在不同的数据类型如何被编码以符合期望的格式。

如何为智能合约调用转换参数

有多种方法可以将参数从原始格式转换为十六进制编码。

对于手动创建的交易,可以使用在线工具对参数进行编码。比如hex to stringhex to decimal等等。

对于以编程方式创建的交易,可以通过使用我们的 SDK 之一(erdjserdpyerdgoerdjava等等)或者通过使用内置组件或创建交易所用语言的其他库来对参数进行编码。

格式化数据字段有多种方式:

  • 手动转换每个参数,然后通过@字符在参数旁边加入函数名。
  • 使用预定义的参数序列化程序,比如 erdjs 中的
  • 使用 erdjs 的合约调用
  • 使用 erdcpp 的合约调用
  • 等等

转换 bech32 地址(erd1)

Elrond使用 HRP erdbech32地址。因此,地址应该是这样的:

erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th

警告

将一个 bech32 地址转换成十六进制编码不是一个简单的string to hex操作,而是需要专门的

工具或助手。

有许多智能合约调用(或内置函数调用)接收地址作为其参数之一。显然,它们必须是十六进制编码的。

例子

bech32 ->

erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th 
--> 
0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1

erd1cux02zersde0l7hhklzhywcxk4u9n4py5tdxyx7vrvhnza2r4gmq4vw35r
-->
c70cf50b238372fffaf7b7c5723b06b57859d424a2da621bcc1b2f317543aa36 

使用在线工具转换地址

有多种(非官方或社区支持的)工具可以用来将地址转换为十六进制编码:

使用 erdpy 转换地址

确保你已经安装了erdpy

erdpy wallet bech32 --decode erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th 

会输出0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1

此外,十六进制地址可以转换为 bech32,如下所示:

erdpy wallet bech32 --encode 0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1 

会输出erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th

处理这些转换的编码算法可以在这里找到。

使用 erdjs 转换地址

点击了解更多关于erdjs 的信息。

import { Address } from "@elrondnetwork/erdjs";
...

const address = Address.fromBech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th");
console.log(address.hex()); 

会输出0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1

此外,十六进制地址可以转换为 bech32,如下所示:

import { Address } from "@elrondnetwork/erdjs";
...

const address = Address.fromHex("0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1");
console.log(address.bech32()); 

会输出erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th

处理这些转换的编码算法可以在这里找到。

使用 erdgo 转换地址

点击了解更多关于erdgo 的信息。

import (
    ...
    "github.com/ElrondNetwork/elrond-sdk-erdgo/data"
    ...
)

addressObj, err := data.NewAddressFromBech32String("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th")
if err != nil {
    return err
}

fmt.Println(hex.EncodeToString(addressObj.AddressBytes())) 

会输出0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1

此外,十六进制地址可以转换为 bech32,如下所示:

import (
    ...
    "github.com/ElrondNetwork/elrond-sdk-erdgo/data"
    ...
)

addressBytes, err := hex.DecodeString("0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1")
if err != nil {
    return err
}
addressObj := data.NewAddressFromBytes(addressBytes) 
fmt.Println(addressObj.AddressAsBech32String()) 

会输出erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th

处理这些转换的编码算法可以在这里找到。

使用 erdjava 转换地址

点击了解更多关于erdjava 的信息。

System.out.println(Address.fromBech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th").hex()); 

会输出0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1

此外,十六进制地址可以转换为 bech32,如下所示:

System.out.println(Address.fromHex("0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1").bech32()); 

会输出erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th

处理这些转换的编码算法可以在这里找到。

转换字符串值

对于智能合约调用需要字符串参数的情况,可以通过使用内置库将它们转换为十六进制格式来简单地获得字符串参数。

重要

确保结果包含偶数个字符。

下面你可以找到一些例子:

绝不是说,这些代码片段提供了编码指南;它们更多的是关于如何执行必要操作的简单示例。

例子

字符串->十六进制

ok          --> 6f6b
MEX-455c57  --> 4d45582d343535633537 

用 javascript 转换字符串值

console.log(Buffer.from("ok").toString("hex"));  // 6f6b 

要将十六进制编码的字符串转换为常规字符串:

console.log(Buffer.from("6f6b", "hex").toString()); // ok 

用 java 转换字符串值

String inputHex = Hex.encodeHexString("ok".getBytes(StandardCharsets.UTF_8));
if (inputHex.length() % 2 != 0) {
   inputHex = "0" + inputex;
}

System.out.println(inputHex);  // 6f6b 

要将十六进制编码的字符串转换为常规字符串:

byte[] bytes = Hex.decodeHex("6f6b".toCharArray());

String result = new String(bytes, StandardCharsets.UTF_8); // ok 

在 go 中转换字符串值

fmt.Println(hex.EncodeToString([]byte("ok"))) // 6f6b 

要将十六进制编码的字符串转换为常规字符串:

decodedInput, err := hex.DecodeString("6f6b")
if err != nil {
    return err
}

fmt.Println(string(decodedInput)) // ok 

转换数值

对于智能合约调用需要数字参数的情况,可以通过使用内置库将它们转换为十六进制格式来简单地获得数字参数。

重要

确保结果包含偶数个字符。

下面你可以找到一些例子。他们使用大整数/数字库来确保代码也适用于大数值:

绝不是说,这些代码片段提供了编码指南;它们更多的是关于如何执行必要操作的简单示例。

例子

数字->十六进制

7  --> 07
10 --> 0a
35 --> 25 

在 javascript 中转换数值

const intValue = 37;
const bn = new BigNumber(intValue, 10);
let bnStr = bn.toString(16);
if(bnStr.length % 2 != 0) {
    bnStr = "0" + bnStr;
}
console.log(bnStr);  // 25 

要将十六进制编码的字符串转换为常规数字:

const hexValue = "25";
let bn = new BigNumber(hexValue, 16);
console.log(bn.toString());  // 37 

另外,erdjs包括一些实用函数,用于填充结果。

在 go 中转换数值

inputNum := int64(37)

bi := big.NewInt(inputNum)
fmt.Println(hex.EncodeToString(bi.Bytes())) // 25 

用于将十六进制编码的数字转换为常规数字:

hexString := "25"

decodedHex, err := hex.DecodeString(hexString)
if err != nil {
    return err
}
bi := big.NewInt(0).SetBytes(decodedHex)
fmt.Println(bi.String()) // 37 


回到顶部