欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

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

引言

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

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

前置知識(shí)概述

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

Hash

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

ECDSA

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

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

你不應(yīng)該將ECDSA與用來(lái)對(duì)數(shù)據(jù)進(jìn)行加密的AES(高級(jí)加密標(biāo)準(zhǔn))相混淆。ECDSA不會(huì)對(duì)數(shù)據(jù)進(jìn)行加密、或阻止別人看到或訪問(wèn)你的數(shù)據(jù),它可以防止的是確保數(shù)據(jù)沒(méi)有被篡改。

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

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

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

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

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

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

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

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

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

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

此分析針對(duì) 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 實(shí)現(xiàn)的一個(gè) solidity 庫(kù),它實(shí)現(xiàn)了從 hash 值中恢復(fù)錢(qián)包地址的方法,將它應(yīng)用在 bytes32 上,就可以直接在 bytes32 上調(diào)用 recover 方法。recover 函數(shù)簽名:function recover(bytes32 hash, bytes memory signature) internal pure returns (address) 。

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

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

mapping(address => uint256) private _nonces;

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

為了避免雙花攻擊,在智能合約中維護(hù) 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ù),我們知道,要將錢(qián)包地址恢復(fù),至少需要經(jīng)過(guò) ECDSA 的簽名以及用于簽名的原始數(shù)據(jù),而此處,ECDSA 簽名的原始數(shù)據(jù)就是經(jīng)過(guò) abi 編碼的 keccak256(abi.encode(_TYPEHASH, req.from, req.to, req.value, req.gas, req.nonce, keccak256(req.data))) ForwardRequest 結(jié)構(gòu)體數(shù)據(jù)的哈希值。再通過(guò)調(diào)用 ECDSA 庫(kù)中的 recover 函數(shù),傳入簽名,就能夠恢復(fù)得到簽名者的錢(qián)包地址。

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

接下來(lái)看,如何執(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 方法的時(shí)候,根據(jù)元交易參數(shù),指定了 call 的 gas 與 value 值。需要注意的是,這里并不直接將元交易的 data 字段當(dāng)作 call 操作的 data,而是將 data 與 from 進(jìn)行 abi 編碼后一起作為 call 操作的參數(shù),這在目標(biāo)合約(也就是 req.to)中會(huì)被解析,從而得到交易的發(fā)送者,在下面會(huì)詳細(xì)講解。

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

ERC2771

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

abstract contract ERC2771Context is Context

ERC2771Context 繼承了 Context,而 Context 中簡(jiǎn)單封裝了從 msg.sender 與 msg.data ,以便規(guī)范這兩個(gè)功能的使用,且能夠讓其在子合約中修改其行為。要求使用 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();
	}
}

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

元交易使用概覽

讓我們來(lái)嘗試簡(jiǎn)單使用元交易合約,要支持元交易,你所編寫(xiě)的合約必須繼承 ERC2771Context。在這里簡(jiǎn)單實(shí)現(xiàn)一個(gè) 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();
    }
}

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

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

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

你可能感興趣的文章

更多

熱門(mén)幣種

  • 幣名
    最新價(jià)格
    24H漲幅
  • bitcoin BTC 比特幣

    BTC

    比特幣

    $ 96880.57¥ 687667.97
    -5.94%
  • ethereum ETH 以太坊

    ETH

    以太坊

    $ 3163.07¥ 22451.78
    -9.47%
  • tether USDT 泰達(dá)幣

    USDT

    泰達(dá)幣

    $ 0.9996¥ 7.0952
    -0.01%
  • ripple XRP 瑞波幣

    XRP

    瑞波幣

    $ 2.2831¥ 16.2056
    -8.66%
  • binance-coin BNB 幣安幣

    BNB

    幣安幣

    $ 912.48¥ 6476.87
    -5.06%
  • solana SOL Solana

    SOL

    Solana

    $ 140.98¥ 1000.69
    -9.16%
  • usdc USDC USD Coin

    USDC

    USD Coin

    $ 1.0005¥ 7.1016
    +0.04%
  • tron TRX 波場(chǎng)

    TRX

    波場(chǎng)

    $ 0.2926¥ 2.0769
    -1.88%
  • dogecoin DOGE 狗狗幣

    DOGE

    狗狗幣

    $ 0.1623¥ 1.152
    -7.15%
  • cardano ADA 艾達(dá)幣

    ADA

    艾達(dá)幣

    $ 0.5161¥ 3.6633
    -8.65%

幣圈快訊

  • 主流PerpDEX一覽:Lighter連續(xù)3日霸榜,Hyperliquid、Aster交易量回升至百億

    2025-11-14 18:30
    據(jù)Defilama數(shù)據(jù),主流PerpDEX交易量較昨日均有不同程度上漲,合約持倉(cāng)量變化較小。Lighter成交穩(wěn)定現(xiàn)居榜首,Hyperliquid、Aster、Pacifica的交易量上漲超40%。當(dāng)前部分PerpDEX交易量如下: Lighter24小時(shí)交易量約127.8億美元,TVL約11.87億美元,未平倉(cāng)合約15.6億美元; Hyperliquid24小時(shí)交易量約125.8億美元,TVL約45.47億美元,未平倉(cāng)合約80.1億美元; Aster24小時(shí)交易量約111.7億美元,TVL約14.32億美元,未平倉(cāng)合約23.5億美元; EdgeX24小時(shí)交易量約82億美元,TVL約4.89億美元,未平倉(cāng)合約7.8億美元; ApeX24小時(shí)交易量約28億美元,TVL約5079萬(wàn)美元,未平倉(cāng)合約3932萬(wàn)美元; Paradex24小時(shí)交易量約10.3億美元,TVL約1.41億美元,未平倉(cāng)合約3.7億美元; Pacifica24小時(shí)交易量約16.6億美元,TVL約3990萬(wàn)美元,未平倉(cāng)合約4889萬(wàn)美元。
  • 若ETH突破3,345美元,主流CEX累計(jì)空單清算強(qiáng)度將達(dá)14.88億美元

    2025-11-14 18:30
    據(jù)Coinglass數(shù)據(jù)顯示,若ETH突破3,345美元,主流CEX累計(jì)空單清算強(qiáng)度將達(dá)14.88億美元。反之,若ETH跌破3,028美元,主流CEX累計(jì)多單清算強(qiáng)度將達(dá)7.39億美元。
  • 若BTC突破101,806美元,主流CEX累計(jì)空單清算強(qiáng)度將達(dá)24.23億美元

    2025-11-14 18:30
    據(jù)Coinglass數(shù)據(jù)顯示,若BTC突破101,806美元,主流CEX累計(jì)空單清算強(qiáng)度將達(dá)24.23億美元。反之,若BTC跌破92,124美元,主流CEX累計(jì)多單清算強(qiáng)度將達(dá)11.79億美元。
  • JDVance回應(yīng)競(jìng)選下屆總統(tǒng)可能:中期選舉后會(huì)和特朗普談?wù)?/p>

    2025-11-14 18:28
    JDVance在接受Fox新聞專訪中談及2028年可能競(jìng)選總統(tǒng):“我們會(huì)贏得中期選舉。我們會(huì)竭盡全力贏得中期選舉。之后,我會(huì)和美國(guó)總統(tǒng)坐下來(lái)談?wù)勥@件事。”
  • 橋水三季度持倉(cāng)出爐減持英偉達(dá)

    2025-11-14 18:18
    北京時(shí)間11月14日凌晨,全球最大對(duì)沖基金橋水截至今年三季度末的持倉(cāng)報(bào)告出爐。報(bào)告顯示,截至今年三季度末,橋水持有251萬(wàn)股英偉達(dá),數(shù)量相較于二季度末的723萬(wàn)股降低65.3%。值得一提的是,在今年二季度,橋水對(duì)英偉達(dá)加倉(cāng)幅度高達(dá)154.37%。這一減倉(cāng)舉動(dòng)顯示出橋水對(duì)英偉達(dá)的后市表現(xiàn)趨于謹(jǐn)慎。
  • 查看更多