🍊

【Solidity】Context.solを読む

2022/11/16に公開

ERC721で継承しているContextとは何者なのか?と疑問に思ったので読んでみました。
備忘録を兼ねて記事にしております。

リンク集

ERC721

最初にContextを継承しています。

ERC721.sol
import "./IERC721.sol";
import "./IERC721Receiver.sol";
import "./extensions/IERC721Metadata.sol";
import "../../utils/Address.sol";
import "../../utils/Context.sol";
import "../../utils/Strings.sol";
import "../../utils/introspection/ERC165.sol";

/**
 * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
 * the Metadata extension, but not including the Enumerable extension, which is available separately as
 * {ERC721Enumerable}.
 */
contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {

Context

とても短いので全文を載せました。

  • msg.sender
  • msg.data

のラッパーのようですが、何に使うのでしょうか?
コメントをDeepLで翻訳をかけてみました。

現在の実行コンテキストに関する情報を提供する。
トランザクションの送信者とそのデータなど、現在の実行コンテキストに関する情報を提供します。これらは一般に、msg.sender と msg.data を介して利用可能ですが、このような直接的な方法でアクセスするべきではありません。
メタ・トランザクションを扱う場合、トランザクションを送信するアカウントと実行の代金を支払うアカウントが異なることがあるからです。
メタ・トランザクションを扱う場合、送信と実行の支払いを行うアカウントは、 (アプリケーションから見て)実際の送信者であるとは限りません。
このコントラクトは、中間的な、ライブラリのようなコントラクトにのみ必要とされる。

基本的にはmsg.senderと同じ機能を果たしますが、メタトランザクションを使用する場合は_msgSender()をoverrideする必要がありそうです。

Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

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

_msgSender()をoverrideしてる例

overrideしてる例もありましたので、紹介しておきます。

https://ethereum.stackexchange.com/questions/92618/what-is-the-value-add-of-msgsender-helper-in-openzeppelin

※コメントをDeepLで翻訳

Contextの関数をオーバーライドする。
RelayHubから呼び出された場合、送信者とデータの前処理が必要。実際の送信者は呼び出しデータの末尾に格納され、そのデータを処理する際にはそこから削除する必要があることを意味する。
msg.sender の代替となるものです。通常のトランザクションの場合はmsg.sender、GSNリレーコールの場合はエンドユーザー(msg.senderは実際にはRelayHub)を返します。
重要:{GSNRecipient}から派生したコントラクトは決して msg.sender を使用せず、代わりに {_msgSender} を使用する必要があります。

  // Overrides for Context's functions: when called from RelayHub, sender and
    // data require some pre-processing: the actual sender is stored at the end
    // of the call data, which in turns means it needs to be removed from it
    // when handling said data.

    /**
     * @dev Replacement for msg.sender. Returns the actual sender of a transaction: msg.sender for regular transactions,
     * and the end-user for GSN relayed calls (where msg.sender is actually `RelayHub`).
     *
     * IMPORTANT: Contracts derived from {GSNRecipient} should never use `msg.sender`, and use {_msgSender} instead.
     */
    function _msgSender() internal view virtual override returns (address payable) {
        if (msg.sender != getHubAddr()) {
            return msg.sender;
        } else {
            return _getRelayedCallSender();
        }
    }

まとめ

理解した上で使うべきではありますが、基本的には_msgSender()を使用しておくのがいいと思います。

Discussion