关联交易
中继交易(或元交易)是由所谓的中继者付费的交易。换句话说,如果中继者愿意为交互付费,与智能合约交互的地址不一定要有任何 EGLD 来付费。
更多细节和规格可以在Elrond规格上找到。
转发交易类型
目前,有两个版本的中继交易:v1 和 v2。最后,它们都有相同的效果,但 v2 在气体使用方面进行了优化,这是我们的推荐。
转述交易版本 1
中继交易版本 1 依赖于将内部交易 JSON 序列化并作为参数提供给relayedTx
协议函数。
它看起来像是:
RelayedV1Transaction {
Sender: <Relayer address>
Receiver: <Address that signed the inner transaction>
Value: 0
GasLimit: <move_balance_cost> + length(Data) * <gas_per_data_byte> + <inner transaction gas limit>
Data: "relayedTx" +
"@" + <JSON serialized inner transaction in hexadecimal encoding>
}
内部交易可以具有如下格式:
RelayedV1InnerTransaction {
Sender: <Receiver of the relayed transaction>
Receiver: <Smart Contract address>
Value: 0
GasLimit: <to be determined for each case>
Data: "functionName" +
"@" + <argument in hexadecimal encoding>
...
}
然而,与常规交易的 JSON 序列化不同,必须签名的内部交易具有不同的结构:
type Transaction struct {
Nonce uint64
Value *math_big.Int
ReceiverAddress []byte
SenderAddress []byte
GasPrice uint64
GasLimit uint64
Data []byte
ChainID []byte
Version uint32
Signature []byte
Options uint32
}
请注意,与常规的前端 交易结构相比,存在一些差异,例如:
SenderAddress
和ReceiverAddress
必须是字节数组,而不是 bech32 字符串地址Value
必须是大整数,而不是字符串ChainID
必须是字节数组而不是字符串Signature
必须是字节数组,而不是它的十六进制版本
准备使用 erdjs 中继 v1 交易
erdjs
通过使用一个允许用户准备这种交易的构建器,内置了对中继交易版本 1 的支持。
资源:
举例
下面是一个中继 v1 交易的示例。其意图是:
erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx
将调用合约erd1qqqqqqqqqqqqqpgqrchxzx5uu8sv3ceg8nx8cxc0gesezure5awqn46gtd
的函数add
,而erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th
将支付计算费用
{
"nonce":2627,
"value":"0",
"receiver":"erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx",
"sender":"erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th",
"gasPrice":1000000000,
"gasLimit":61040000,
"data":"cmVsYXllZFR4QDdiMjI2ZTZmNmU2MzY1MjIzYTMxMzkzODJjMjI3MzY1NmU2NDY1NzIyMjNhMjI2NzQ1NmU1NzRmNjU1NzZkNmQ0MTMwNjMzMDZhNmI3MTc2NGQzNTQyNDE3MDdhNjE2NDRiNDY1NzRlNTM0ZjY5NDE3NjQzNTc1MTYzNzc2ZDQ3NTA2NzNkMjIyYzIyNzI2NTYzNjU2OTc2NjU3MjIyM2EyMjQxNDE0MTQxNDE0MTQxNDE0MTQxNDE0NjQxNDIzNDc1NTk1MjcxNjMzNDY1NDQ0OTM0Nzk2NzM4N2E0ODc3NjI0NDMwNWE2ODZiNTg0MjM1NzAzMTc3M2QyMjJjMjI3NjYxNmM3NTY1MjIzYTMwMmMyMjY3NjE3MzUwNzI2OTYzNjUyMjNhMzEzMDMwMzAzMDMwMzAzMDMwMzAyYzIyNjc2MTczNGM2OTZkNjk3NDIyM2EzNjMwMzAzMDMwMzAzMDMwMmMyMjY0NjE3NDYxMjIzYTIyNTk1NzUyNmIyMjJjMjI3MzY5Njc2ZTYxNzQ3NTcyNjUyMjNhMjI0ZTMwNzIzMTcwNmYzNzZiNzY0ZjU0NGI0OTQ3NDcyZjc1NmI2NzcyMzg1YTYyNTc2NDU4NjczMTY2NTEzMDc2NmQ3NTYyMzU3OTM0NGY3MzUzNDE3MTM0N2EyZjU5Mzc2YzQ2NTI3OTU3NzM2NzM0NGUyYjZmNGE2OTQ5NDk1Nzc3N2E2YjZkNmM2YTQ5NDE3MjZkNjkzMTY5NTg0ODU0NzkzNDRiNjc0MTQxM2QzZDIyMmMyMjYzNjg2MTY5NmU0OTQ0MjIzYTIyNTY0MTNkM2QyMjJjMjI3NjY1NzI3MzY5NmY2ZTIyM2EzMTdk",
"chainID":"T",
"signature": "44889e788581c8913a00e03f711f9ed3522119030a48fe6c1b3434656670b4b93867213f7a7b5453eafe0884f7447361e1154d26c6e7b2cfa40510159e0e1008",
"version":1
}
数据字段(从 base64 解码为字符串后)转换为:
relayedTx@7b226e6f6e6365223a3139382c2273656e646572223a2267456e574f65576d6d413063306a6b71764d354241707a61644b46574e534f69417643575163776d4750673d222c227265636569766572223a22414141414141414141414146414234755952716334654449347967387a48776244305a686b5842357031773d222c2276616c7565223a302c226761735072696365223a313030303030303030302c226761734c696d6974223a36303030303030302c2264617461223a225957526b222c227369676e6174757265223a224e307231706f376b764f544b4947472f756b6772385a625764586731665130766d75623579344f73534171347a2f59376c465279577367344e2b6f4a69494957777a6b6d6c6a4941726d69316958485479344b6741413d3d222c22636861696e4944223a2256413d3d222c2276657273696f6e223a317d
此外,内部交易很容易被解码(十六进制字符串到字符串),导致:
{
"nonce":198,
"sender":"gEnWOeWmmA0c0jkqvM5BApzadKFWNSOiAvCWQcwmGPg=",
"receiver":"AAAAAAAAAAAFAB4uYRqc4eDI4yg8zHwbD0ZhkXB5p1w=",
"value":0,
"gasPrice":1000000000,
"gasLimit":60000000,
"data":"YWRk",
"signature":"N0r1po7kvOTKIGG/ukgr8ZbWdXg1fQ0vmub5y4OsSAq4z/Y7lFRyWsg4N+oJiIIWwzkmljIArmi1iXHTy4KgAA==",
"chainID":"VA==",
"version":1
}
解码 base64 字段,我们将得到:
- 发送者:T0
- 接收者:
erd1qqqqqqqqqqqqqpgqrchxzx5uu8sv3ceg8nx8cxc0gesezure5awqn46gtd
- 数据:
add
- 链 ID:
T
- 签名:
374af5a68ee4bce4ca2061bfba482bf196d67578357d0d2f9ae6f9cb83ac480ab8cff63b9454725ac83837ea09888216c33926963200ae68b58971d3cb82a000
关于中继交易的气体限制,让我们检查一下数学。
gasLimit = <move_balance_cost> + length(Data) * <gas_per_data_byte> + <inner transaction gas limit>
gasLimit = 50_000 + 660 * 1500 + 60_000_000
gasLimit = 61040000 // just like the gas limit set in the relayed transaction
转述交易版本 2
与版本 1 相比,中继交易版本 2 仅具有包含在数据字段中的内部交易的某些字段,使得有效载荷更小,因此 tx 费用更小。它还消除了在中继和内部交易之间计算匹配气体限值的需要。
它看起来像是:
RelayedV1Transaction {
Sender: <Relayer address>
Receiver: <Address that signed the inner transaction>
Value: 0
GasLimit: <move_balance_cost> + length(Data) * <gas_per_data_byte> + <gas needed for the inner transaction>
Data: "relayedTxV2" +
"@" + <Smart Contract address to be called in hexadecimal encoding>
"@" + <nonce of the receiver in hexadecimal encoding>
"@" + <data field (function name + args) in hexadecimal encoding>
"@" + <the signature of the inner transaction in hexadecimal encoding>
}
注
注意到所需的参数,内部交易有一些限制:它不能有看涨价值或自定义油价。
因此,当想要建立这样的交易时,步骤应该是:
- 创建内部交易(确保
gasLimit
设置为 0) - 签名吧
- 获取接收者、nonce、数据和签名字段,并在中继的交易中使用它们
准备使用 erdjs 中继 v2 交易
erdjs
通过使用一个允许用户准备这种交易的构建器,内置了对中继交易版本 2 的支持。
资源:
举例
下面是一个中继 v2 交易的示例。其意图是:
erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx
将调用合约erd1qqqqqqqqqqqqqpgqrchxzx5uu8sv3ceg8nx8cxc0gesezure5awqn46gtd
的函数add
,而erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th
将支付计算费用
{
"nonce":37,
"value":"0",
"receiver":"erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx",
"sender":"erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th",
"gasPrice":1000000000,
"gasLimit":60372500,
"data":"cmVsYXllZFR4VjJAMDAwMDAwMDAwMDAwMDAwMDA1MDAxZTJlNjExYTljZTFlMGM4ZTMyODNjY2M3YzFiMGY0NjYxOTE3MDc5YTc1Y0AwZkA2MTY0NjRAOWFiZDEzZjRmNTNmM2YyMzU5Nzc0NGQ2NWZjNWQzNTFiYjY3NzNlMDVhOTU0YjQxOWMwOGQxODU5M2QxYzY5MjYyNzlhNGQxNjE0NGQzZjg2NmE1NDg3ODAzMTQyZmNmZjBlYWI2YWQ1ODgyMDk5NjlhY2I3YWJlZDIxMDIwMGI=",
"chainID":"T",
"signature":"2a448b92c16a564a0b1dc8d02fb3a73408decc0aa47d0780a4faa108234d767dc262057b376a9f3c4d9283018c90cb751b55d27c42f59d63cce3ca6213a5ac0a",
"version":1
}
解码数据字段(base64 到 string)后,我们将得到:
relayedTxV2@000000000000000005001e2e611a9ce1e0c8e3283ccc7c1b0f4661917079a75c@0f@616464@9abd13f4f53f3f23597744d65fc5d351bb6773e05a954b419c08d18593d1c6926279a4d16144d3f866a5487803142fcff0eab6ad588209969acb7abed210200b
解码论点(这里有用的资源)我们会得到:
- 第一个参数:
000000000000000005001e2e611a9ce1e0c8e3283ccc7c1b0f4661917079a75c
= >erd1qqqqqqqqqqqqqpgqrchxzx5uu8sv3ceg8nx8cxc0gesezure5awqn46gtd
(要调用的 sc 地址) - 第二个参数:
0f
= >15
(内部交易的 nonce) - 第三个参数:
616464
= >add
(要调用的函数——本例中不需要参数) - 第四个参数:
9abd13f4f53f3f23597744d65fc5d351bb6773e05a954b419c08d18593d1c6926279a4d16144d3f866a5487803142fcff0eab6ad588209969acb7abed210200b
(内部交易签名)