最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

當前位置:主頁 > 區(qū)塊鏈 > 區(qū)塊鏈技術(shù) > 元交易合約如何實現(xiàn)

元交易合約如何實現(xiàn)?智能合約開發(fā)實戰(zhàn):元交易(Metatransaction)系列二

2021-12-15 15:59:09 | 來源: | 作者:佚名
這篇文章主要介紹了元交易合約如何實現(xiàn)?智能合約開發(fā)實戰(zhàn):元交易(Metatransaction)系列二的相關(guān)資料,希望小編的這篇關(guān)于元交易合約如何實現(xiàn)的文章,能夠幫助各位投資者對元交易有一個更加全面透徹的了解。

引言

上文中提到,普通的 ETH 交易并不能夠做到讓用戶無需 gas 費,需要交易中嵌套一個交易,即元交易,來實現(xiàn)免 gas 費。

本文將分析開源庫 OpenZeppelin/openzeppelin-contracts 中的元交易合約的實現(xiàn),讓你能夠快速入門元交易實現(xiàn)細節(jié),從而能夠自己對后續(xù)更多的相關(guān)技術(shù)深入探索。

前置知識概述

元交易會涉及到 ECDSA 與 EIP712 等知識,如果你是熟手,可以跳過此節(jié)內(nèi)容,直接瀏覽具體實現(xiàn)分析部分。

Hash

也稱哈希、散列、數(shù)字摘要。通過哈希函數(shù),可以將長短不一的信息轉(zhuǎn)化為一段長度任意但可預測的(確定性的)結(jié)果。這是一類神奇的函數(shù),可以將一大堆信息轉(zhuǎn)變成一串短的,可作為摘要的數(shù)據(jù) “指紋”。對于一個給定的輸入而言,生成的 “指紋” 始終一致。如果你的原始數(shù)據(jù)中有任何細微的改動,生成的哈希值將大不相同。以太坊中采用的是 Keccak-256 算法。

ECDSA

在密碼學中,ECDSA(Elliptic Curve Digital Signature Algorithm,橢圓曲線數(shù)字簽名算法)是使用橢圓曲線密碼學的數(shù)字簽名算法(DSA)的一個變種。

主要用于對數(shù)據(jù)(比如一個文件)創(chuàng)建數(shù)字簽名,以便于你在不破壞它的安全性的前提下對它的真實性進行驗證??梢詫⑺胂蟪梢粋€實際的簽名,你可以識別部分人的簽名,但是你無法在別人不知道的情況下偽造它。

你不應(yīng)該將ECDSA與用來對數(shù)據(jù)進行加密的AES(高級加密標準)相混淆。ECDSA不會對數(shù)據(jù)進行加密、或阻止別人看到或訪問你的數(shù)據(jù),它可以防止的是確保數(shù)據(jù)沒有被篡改。

如圖所示,在以太坊中,ECDSA 用于對原始數(shù)據(jù)的 hash 值進行簽名及恢復。
 

元交易合約如何實現(xiàn)?智能合約開發(fā)實戰(zhàn):元交易(Metatransaction)系列二

將原始數(shù)據(jù)通過 hash 函數(shù)得到它的 hash 值后,用戶 A 用自己的私鑰對該 hash 值進行簽名,得到 Signature(簽名)。有了該簽名與 hash 值,任何人都能夠從中恢復出簽名人的錢包地址,在這里用戶 B 則恢復得到了用戶 A 的錢包地址。

EIP712
Ethereum Improvement Proposals (EIPs),你可以在這里查看所有的 EIPs。EIP712 (Ethereum typed structured data hashing and signing)以太坊類型的結(jié)構(gòu)化數(shù)據(jù)哈希與簽名。

如果我們只關(guān)心字節(jié)字符串的話,簽名數(shù)據(jù)是一個已經(jīng)解決了的問題。但不幸的是,在現(xiàn)實世界中,我們關(guān)心的是復雜而有意義的信息,對結(jié)構(gòu)化數(shù)據(jù)進行哈希是非常重要的,錯誤會導致系統(tǒng)安全屬性的丟失。

此 EIP 旨在提高鏈上使用的鏈下消息簽名的可用性。我們看到越來越多的人采用鏈下消息簽名,因為它節(jié)省了 gas 費,減少了區(qū)塊鏈上的交易數(shù)量。當前簽名消息是一個不透明的十六進制字符串,顯示給用戶,關(guān)于組成消息的項目的上下文很少。
 

元交易合約如何實現(xiàn)?智能合約開發(fā)實戰(zhàn):元交易(Metatransaction)系列二

EIP712 概述了一個編碼數(shù)據(jù)及其結(jié)構(gòu)的方案,該方案允許在簽名時將數(shù)據(jù)顯示給用戶進行驗證。下面是一個用戶在簽署 EIP712 消息時顯示的示例。

元交易合約如何實現(xiàn)?智能合約開發(fā)實戰(zhàn):元交易(Metatransaction)系列二

元交易合約的實現(xiàn)

此分析針對 openzeppelin-contracts v4.3.2 版本。

contract MinimalForwarder is EIP712 {
    using ECDSA for bytes32;

    struct ForwardRequest {
        address from;
        address to;
        uint256 value;
        uint256 gas;
        uint256 nonce;
        bytes data;
    }

	constructor() EIP712("MinimalForwarder", "0.0.1") {}
}

ECDSA 是 openzeppelin 實現(xiàn)的一個 solidity 庫,它實現(xiàn)了從 hash 值中恢復錢包地址的方法,將它應(yīng)用在 bytes32 上,就可以直接在 bytes32 上調(diào)用 recover 方法。recover 函數(shù)簽名:function recover(bytes32 hash, bytes memory signature) internal pure returns (address) 。

ForwardRequest 結(jié)構(gòu)體定義了一個交易中用于簽名的基本組成成分。與以太坊交易不同的是沒有 gasPrice,因為智能合約的執(zhí)行只關(guān)心 gas 的消耗。ForwardRequest 中 的 nonce 概念與以太坊類似,都是為了避免雙花攻擊,但這里的 nonce 僅由智能合約維護,跟普通的以太坊交易中的 nonce 無關(guān)。

構(gòu)造函數(shù)中直接使用 EIP712 的構(gòu)造函數(shù)進行初始化,EIP712 的構(gòu)造函數(shù)簽名為:constructor(string memory name, string memory version) ,其中 name 是合約名稱,version 是合約版本,這將作為 EIP712 簽名驗證的一部分,它在部署時,將自動獲取合約的地址、chainId 等信息。意味著,即便有相同的 ForwardRequest 結(jié)構(gòu)體數(shù)據(jù),但合約地址或區(qū)塊鏈網(wǎng)絡(luò)不同,也會導致簽名無效。
 

mapping(address => uint256) private _nonces;

function getNonce(address from) public view returns (uint256) {
	return _nonces[from];
}

為了避免雙花攻擊,在智能合約中維護 nonce 是必要的。

bytes32 private constant _TYPEHASH =
	keccak256("ForwardRequest(address from,address to,uint256 value,uint256 gas,uint256 nonce,bytes data)");

function verify(ForwardRequest calldata req, bytes calldata signature) public view returns (bool) {
	address signer = _hashTypedDataV4(
            keccak256(abi.encode(_TYPEHASH, req.from, req.to, req.value, req.gas, req.nonce, keccak256(req.data)))
    ).recover(signature);
	return _nonces[req.from] == req.nonce && signer == req.from;
}

看到 verify 函數(shù),我們知道,要將錢包地址恢復,至少需要經(jīng)過 ECDSA 的簽名以及用于簽名的原始數(shù)據(jù),而此處,ECDSA 簽名的原始數(shù)據(jù)就是經(jīng)過 abi 編碼的 keccak256(abi.encode(_TYPEHASH, req.from, req.to, req.value, req.gas, req.nonce, keccak256(req.data))) ForwardRequest 結(jié)構(gòu)體數(shù)據(jù)的哈希值。再通過調(diào)用 ECDSA 庫中的 recover 函數(shù),傳入簽名,就能夠恢復得到簽名者的錢包地址。

通過 _nonces[req.from] == req.nonce 來確保交易的調(diào)用是順序的,且不會遭受雙花攻擊。signer == req.from 避免簽名者與實際元交易發(fā)送者不匹配。

接下來看,如何執(zhí)行元交易。
 

function execute(ForwardRequest calldata req, bytes calldata signature)
	public
	payable
	returns (bool, bytes memory)
{
	require(verify(req, signature), "MinimalForwarder: signature does not match request");
	_nonces[req.from] = req.nonce + 1;

	(bool success, bytes memory returndata) = req.to.call{gas: req.gas, value: req.value}(
		abi.encodePacked(req.data, req.from)
	);
	// Validate that the relayer has sent enough gas for the call.
	// See https://ronan.eth.link/blog/ethereum-gas-dangers/
	assert(gasleft() > req.gas / 63);

	return (success, returndata);
}

在使用 Address.call 方法的時候,根據(jù)元交易參數(shù),指定了 call 的 gas 與 value 值。需要注意的是,這里并不直接將元交易的 data 字段當作 call 操作的 data,而是將 data 與 from 進行 abi 編碼后一起作為 call 操作的參數(shù),這在目標合約(也就是 req.to)中會被解析,從而得到交易的發(fā)送者,在下面會詳細講解。

assert(gasleft() > req.gas / 63) 簡單理解為避免中繼器(代為執(zhí)行元交易的人)惡意地或無意地使用足夠低的 gas 使得交易執(zhí)行成功,而元交易執(zhí)行失敗。詳情可以在 ethereum gas dangers 中學習。

ERC2771

要支持元交易,僅實現(xiàn)元交易智能合約是不夠的,因為目標合約無法知道實際的元交易 from 是誰。如果沒有額外的措施,它將只能夠從 msg.sender 中獲取,由于在元交易合約實現(xiàn)中,是通過 Address.call 調(diào)用的,因此將得到的發(fā)送者是元交易合約的地址。ERC2771 則解決了該問題。
 

abstract contract ERC2771Context is Context

ERC2771Context 繼承了 Context,而 Context 中簡單封裝了從 msg.sender 與 msg.data ,以便規(guī)范這兩個功能的使用,且能夠讓其在子合約中修改其行為。要求使用 Context 合約獲取 msg 相關(guān)的數(shù)據(jù),而不是直接使用 msg.sender 等。
 

abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

ERC2771Context 就修改了 Context 合約的方法。

function _msgSender() internal view virtual override returns (address sender) {
	if (isTrustedForwarder(msg.sender)) {
		// The assembly code is more direct than the Solidity version using `abi.decode`.
		assembly {
		sender := shr(96, calldataload(sub(calldatasize(), 20)))
		}
	} else {
		return super._msgSender();
	}
}

先通過 isTrustedForwarder(msg.sender) 驗證元交易的調(diào)用方是期望的元交易合約地址。assembly 代碼將上文的元交易合約中 req.to.call{...}(abi.encodePacked(req.data, req.from)) 編碼進的 data 部分內(nèi)容的 req.from 獲取到,然后再返回該值。

元交易使用概覽

讓我們來嘗試簡單使用元交易合約,要支持元交易,你所編寫的合約必須繼承 ERC2771Context。在這里簡單實現(xiàn)一個 NFT 合約,在部署它之前,你必須先部署元交易合約,將元交易合約地址作為參數(shù)傳遞給 NFT 合約構(gòu)造函數(shù)。
 

// SPDX-License-Identifier: GPL3.0
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/metatx/ERC2771Context.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

contract NFT is ERC2771Context, ERC721 {
    using SafeMath for uint256;

    uint256 private _currentTokenId = 0;

    constructor(
        string memory name,
        string memory symbol,
        address trustedForwarder
    ) ERC721(name, symbol) ERC2771Context(trustedForwarder) {}

    function safeMint() public virtual {
        safeMint("");
    }

    function safeMint(bytes memory _data) internal virtual {
        uint256 tokenId = _getNextTokenId();
        _incrementTokenId();
        _safeMint(_msgSender(), tokenId, _data);
    }
    
    function getCurrTokenId() public virtual view returns (uint256) {
        return _currentTokenId;
    }

    /**
     * @dev calculates the next token ID based on value of _currentTokenId
     * @return uint256 for the next token ID
     */
    function _getNextTokenId() internal virtual view returns (uint256) {
        return _currentTokenId.add(1);
    }

    /**
     * @dev increments the value of _currentTokenId
     */
    function _incrementTokenId() internal virtual {
        _currentTokenId++;
    }

    function _msgSender() internal view virtual override(Context, ERC2771Context) returns (address) {
        return ERC2771Context._msgSender();
    }

    function _msgData() internal view virtual override(Context, ERC2771Context) returns (bytes calldata) {
        return ERC2771Context._msgData();
    }
}

在這個示例中,如果 Alice 沒有足夠的 ETH 支付 gas 費,來鑄造一個 NFT,她可以簽署一個元交易,元交易的 data 是由 abi.encodeWithSignature(functionSelector, parmas...) 得到的,將該元交易遞交給具有足夠 ETH 的 Bob,Bob 調(diào)用元交易合約 MinimalForwarder.execute(req, signature),從而讓 Alice 的元交易成功執(zhí)行。

以上就是元交易合約如何實現(xiàn)?智能合約開發(fā)實戰(zhàn):元交易(Metatransaction)系列二的詳細內(nèi)容,更多關(guān)于元交易合約實現(xiàn)的資料請關(guān)注腳本之家其它相關(guān)文章!

免責聲明:本文只為提供市場訊息,所有內(nèi)容及觀點僅供參考,不構(gòu)成投資建議,不代表本站觀點和立場。投資者應(yīng)自行決策與交易,對投資者交易形成的直接或間接損失,作者及本站將不承擔任何責任。!

你可能感興趣的文章

幣圈快訊

  • 管理資產(chǎn)超20億美元的BIND等阿根廷銀行集團開發(fā)比索穩(wěn)定幣

    2026-07-28 16:32
    管理資產(chǎn)超20億美元的銀行控股集團BINDGroup正通過旗下虛擬資產(chǎn)服務(wù)提供商BEN開發(fā)與阿根廷比索掛鉤的穩(wěn)定幣,面向機構(gòu)提供可編程貨幣服務(wù)。BINDGroup還宣布與Circle合作,為BEN客戶提供符合當?shù)乇O(jiān)管要求的機構(gòu)級支付和資金管理服務(wù)。PetersenGroup也正通過一家子公司推進第二項比索穩(wěn)定幣計劃,并獲得加密即服務(wù)公司Lirium支持。該產(chǎn)品名為DIPE,已形成白皮書;Lirium為BancoGalicia和Brubank提供相關(guān)解決方案。上述項目均由銀行集團支持的公司推進,而非銀行集團直接提供服務(wù)。阿根廷中央銀行自2022年5月起禁止私人銀行向客戶提供加密相關(guān)服務(wù)。這些產(chǎn)品主要面向機構(gòu)場景,用例包括資金管理、基于鏈上事件觸發(fā)的支付以及抵押信貸管理。3月,阿根廷證券監(jiān)管機構(gòu)曾認定與比索掛鉤的穩(wěn)定幣argt屬于證券,且未按規(guī)定合規(guī)發(fā)行。
  • 美股光通信概念盤前繼續(xù)集體下跌邁威爾、康寧跌超3%

    2026-07-28 16:14
    7月28日,延續(xù)昨日跌勢,美股市場光通信概念股今日盤前繼續(xù)集體下跌。其中,AXTInc、AsteraLabs、ViaviSolutions跌超4%,AppliedOptoelectronics、Coherent、邁威爾科技、康寧、MaxLinear、Tower半導體、GlobalFoundries、CredoTechnology跌超3%,Lumentum跌近3%。
  • 美股iShares半導體ETF下跌3.7%

    2026-07-28 16:13
    據(jù)Gate行情數(shù)據(jù)顯示,美股iShares半導體ETF下跌3.7%。
  • 港股收盤恒指漲0.41%老鋪黃金跌超23.5%

    2026-07-28 16:10
    據(jù)Gate行情數(shù)據(jù)顯示,港股收盤,恒生指數(shù)收漲0.41%,科技指數(shù)收漲0.61%。老鋪黃金(06181.HK)跌幅超過23.5%,智譜(02513.HK)跌幅超過18.5%,MiniMax(00100.HK)跌幅超過14%
  • 美股商業(yè)航天股盤前走低SpaceX和RocketLab跌超2%

    2026-07-28 16:09
    據(jù)Gate行情數(shù)據(jù)顯示,美股商業(yè)航天股盤前走低,SpaceX(SPCX.O)和RocketLab(RKLB.O)均跌超2%
  • 查看更多
更多

熱門幣種

  • 幣種
    最新價格
    24H漲跌幅
  • bitcoin BTC 比特幣

    BTC

    比特幣

    $ 63570.24¥ 430268.81
    -2.72%
  • ethereum ETH 以太坊

    ETH

    以太坊

    $ 1883.52¥ 12748.41
    -4.15%
  • tether USDT 泰達幣

    USDT

    泰達幣

    $ 0.9989¥ 6.7609
    -0.02%
  • binance-coin BNB 幣安幣

    BNB

    幣安幣

    $ 565.79¥ 3829.49
    -1.53%
  • usdc USDC USD Coin

    USDC

    USD Coin

    $ 1.0009¥ 6.7744
    +0.01%
  • ripple XRP 瑞波幣

    XRP

    瑞波幣

    $ 1.0563¥ 7.1494
    -4.67%
  • solana SOL Solana

    SOL

    Solana

    $ 73.2662¥ 495.89
    -4.26%
  • tron TRX 波場

    TRX

    波場

    $ 0.3252¥ 2.201
    -1.9%
  • hyperliquid HYPE Hyperliquid

    HYPE

    Hyperliquid

    $ 55.3412¥ 374.57
    -7.79%
  • dogecoin DOGE 狗狗幣

    DOGE

    狗狗幣

    $ 0.070386¥ 0.4764
    -3.48%
科技| 嵊泗县| 高清| 罗源县| 饶阳县| 永春县| 凤凰县| 香格里拉县| 永寿县| 龙门县| 宣化县| 靖西县| 海城市| 邹平县| 肃宁县| 平泉县| 金塔县| 德钦县| 团风县| 神池县| 芷江| 雷波县| 麻阳| 宁陵县| 洪洞县| 金乡县| 平潭县| 乡宁县| 澄江县| 永康市| 固安县| 石景山区| 墨江| 秀山| 昌乐县| 上蔡县| 仙桃市| 乡宁县| 田东县| 嵩明县| 青浦区|