BitcoinuNameSyncL1

Description:

Smart contract deployed on Ethereum with Factory features.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "contracts/BitcoinuNameSyncL1.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

// Optimism Stack用のクロスチェーンメッセージング
interface ICrossDomainMessenger {
    function sendMessage(
        address _target,
        bytes calldata _message,
        uint32 _gasLimit
    ) external;
    function xDomainMessageSender() external view returns (address);
}

/**
 * @title BitcoinuNameSyncL1
 * @dev イーサリアムメインネット側の名前同期コントラクト
 * L2からのリクエストに応答してトークン名を送信
 * トークンのブリッジ機能は標準ブリッジに任せる
 */
contract BitcoinuNameSyncL1 {
    
    // L1トークンコントラクト
    address public immutable l1Token;
    
    // L2名前同期コントラクトごとの情報
    struct L2SyncInfo {
        bool approved;                          // 承認されているか
        address messenger;                       // 対応するL1メッセンジャーアドレス
    }
    
    // L2名前同期コントラクトアドレス => L2情報
    mapping(address => L2SyncInfo) public l2SyncInfo;
    
    // L2コントラクトの配列(管理用)
    address[] public l2SyncList;
    
    // オーナー
    address public owner;
    
    event L2SyncContractAdded(address indexed l2Contract, address indexed messenger);
    event L2SyncContractRemoved(address indexed l2Contract);
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    
    // ガスリミット設定
    uint32 public constant NAME_UPDATE_GAS_LIMIT = 100000;
    
    event NameSyncRequested(
        string newName,
        string newSymbol,
        uint256 timestamp
    );
    
    modifier onlyOwner() {
        require(msg.sender == owner, "Only owner can call");
        _;
    }
    
    /**
     * @dev コンストラクタ
     * @param _l1Token L1トークンアドレス(Bitcoinuコントラクト)
     */
    constructor(address _l1Token) {
        require(_l1Token != address(0), "Invalid L1 token");
        
        l1Token = _l1Token;
        owner = msg.sender;
        
        // L1トークンのname()とsymbol()が呼び出せることを確認
        (bool successName, ) = _l1Token.staticcall(
            abi.encodeWithSignature("name()")
        );
        (bool successSymbol, ) = _l1Token.staticcall(
            abi.encodeWithSignature("symbol()")
        );
        
        require(
            successName && successSymbol,
            "L1 token must implement name() and symbol()"
        );
    }
    
    /**
     * @dev オーナーを変更
     * @param newOwner 新しいオーナーアドレス
     */
    function transferOwnership(address newOwner) external onlyOwner {
        require(newOwner != address(0), "Invalid address");
        address oldOwner = owner;
        owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
    
    /**
     * @dev L2名前同期コントラクトを追加
     * @param _l2SyncContract 追加するL2名前同期コントラクトアドレス
     * @param _l1Messenger そのL2に対応するL1メッセンジャーアドレス
     */
    function addL2SyncContract(address _l2SyncContract, address _l1Messenger) external onlyOwner {
        require(_l2SyncContract != address(0), "Invalid L2 contract");
        require(_l1Messenger != address(0), "Invalid messenger");
        require(!l2SyncInfo[_l2SyncContract].approved, "Contract already added");
        
        l2SyncInfo[_l2SyncContract] = L2SyncInfo({
            approved: true,
            messenger: _l1Messenger
        });
        l2SyncList.push(_l2SyncContract);
        
        emit L2SyncContractAdded(_l2SyncContract, _l1Messenger);
    }
    
    /**
     * @dev L2名前同期コントラクトのメッセンジャーアドレスを更新
     * @param _l2SyncContract L2コントラクトアドレス
     * @param _l1Messenger 新しいL1メッセンジャーアドレス
     */
    function updateL2Messenger(address _l2SyncContract, address _l1Messenger) external onlyOwner {
        require(l2SyncInfo[_l2SyncContract].approved, "Contract not found");
        require(_l1Messenger != address(0), "Invalid messenger");
        
        l2SyncInfo[_l2SyncContract].messenger = _l1Messenger;
    }
    
    /**
     * @dev L2名前同期コントラクトを削除
     * @param _l2SyncContract 削除するL2コントラクトアドレス
     */
    function removeL2SyncContract(address _l2SyncContract) external onlyOwner {
        require(l2SyncInfo[_l2SyncContract].approved, "Contract not found");
        
        delete l2SyncInfo[_l2SyncContract];
        
        // 配列から削除
        for (uint256 i = 0; i < l2SyncList.length; i++) {
            if (l2SyncList[i] == _l2SyncContract) {
                l2SyncList[i] = l2SyncList[l2SyncList.length - 1];
                l2SyncList.pop();
                break;
            }
        }
        
        emit L2SyncContractRemoved(_l2SyncContract);
    }
    
    /**
     * @dev 承認されたL2コントラクトの数を取得
     */
    function getL2SyncCount() external view returns (uint256) {
        return l2SyncList.length;
    }
    
    /**
     * @dev L2からのリクエストに応答してトークン名を送信
     * L2名前同期コントラクトからのクロスチェーンメッセージでのみ呼び出し可能
     * @param requestingL2Contract リクエスト元のL2コントラクトアドレス
     */
    function respondWithTokenInfo(address requestingL2Contract) external {
        // リクエスト元のL2コントラクトが承認されているか確認
        require(
            l2SyncInfo[requestingL2Contract].approved,
            "L2 contract not approved"
        );
        
        // 対応するメッセンジャーからのメッセージか確認
        address expectedMessenger = l2SyncInfo[requestingL2Contract].messenger;
        require(
            msg.sender == expectedMessenger,
            "Only corresponding messenger can call"
        );
        
        // メッセンジャーを通じてメッセージが送られてきたか確認
        ICrossDomainMessenger messenger = ICrossDomainMessenger(expectedMessenger);
        require(
            messenger.xDomainMessageSender() == requestingL2Contract,
            "Invalid message sender"
        );
        
        // L1トークンコントラクトから現在の名前を取得
        (bool successName, bytes memory dataName) = l1Token.staticcall(
            abi.encodeWithSignature("name()")
        );
        (bool successSymbol, bytes memory dataSymbol) = l1Token.staticcall(
            abi.encodeWithSignature("symbol()")
        );
        
        require(successName && successSymbol, "Failed to read token info");
        
        string memory tokenName = abi.decode(dataName, (string));
        string memory tokenSymbol = abi.decode(dataSymbol, (string));
        
        // L2に名前とシンボルを返信
        bytes memory message = abi.encodeWithSignature(
            "receiveTokenInfo(string,string)",
            tokenName,
            tokenSymbol
        );
        
        messenger.sendMessage(
            requestingL2Contract,
            message,
            NAME_UPDATE_GAS_LIMIT
        );
        
        emit NameSyncRequested(tokenName, tokenSymbol, block.timestamp);
    }
}"
    }
  },
  "settings": {
    "evmVersion": "paris",
    "optimizer": {
      "enabled": false,
      "runs": 200
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    }
  }
}}

Tags:
Factory|addr:0x67c72faf5d772f01b6dc6f5c43b1bf95232c08ff|verified:true|block:23733136|tx:0x72dba3dd4603b0aeaaf74ec0f9440eadbb3c9b97cb2b2429b0f0ded64728f945|first_check:1762349863

Submitted on: 2025-11-05 14:37:44

Comments

Log in to comment.

No comments yet.