lesson-3_ネームサービスを作成して登録し てみよう
前回、hardhatを用いて簡単なスマートコントラクトをデプロイすることができました。
ここから、ネームサービスの中身を作成していきましょう。
💽 ドメインデータをブロックチェーンに保存する
ネームサービスのポイントは、人々がインターネット上のあなた固有の名前に便利にアクセスすることができるということです。
google.comと入力してGoogleにアクセスするのと同じように、ユーザーはあなたのドメインネームを頼りにあなたの情報にアクセスすることができます。
したがって、最初に必要なのは、ドメインを登録するための関数と、登録したドメインを格納する場所になります。
Domains.sol
に向かいます。
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;
import "hardhat/console.sol";
contract Domains {
// "mapping"でstring型の各keyとaddress型の各データを紐付けにして格納します。そのmappingをここでは"domains"として定義しています。
mapping(string => address) public domains;
constructor() {
console.log("THIS IS MY DOMAIN CONTRACT. NICE.");
}
// register関数はnameとアドレスを紐付けます。
function register(string calldata name) public {
domains[name] = msg.sender;
console.log("%s has registered a domain!", msg.sender);
}
// nameに対応するaddressを返すゲッター関数を定義しておきます。
function getAddress(string calldata name) public view returns (address) {
return domains[name];
}
}
上のコードではいくつかの関数を追加し、domains
mapping変数も追加しました。
マッピングは、2つの値を「マッピング」する 単純なデータ型です。 この例では、文字列(ドメイン名)をウォレットアドレスと紐付けしています。
この変数は「状態変数」と呼ばれるため特別であり、スマートコントラクトのストレージに永続的に保存されます。
ここではregister
関数を実行すると、ドメインに関連するデータが永続的に保存されます。
また、ここではmsg.sender
を使用しています。
これは、関数を呼び出した人のウォレットアドレスです。
いわゆる認証のようなものです。
スマートコントラクトを呼び出すには、有効なウォレットを使用してトランザクションに署名する必要があるため、誰が関数を呼び出したかを正確に把握する必要があります。
msg.sender
は今後もよく目にすることになるでしょう。
今後、特定のウォレットアドレスのみが呼び出せる関数を作成できるようになります。
たとえば、関数を変更して、ドメインを所有するウォレットのみがそれらを更新できるようにすることができます。
getAddress
関数はまさにそれを行います-ドメイン所有者のウォレットアドレスを取得します。
上の関数定義においてポイントがあるので、それらを見てみましょう。
-
calldata
これはname
引数が格納されるべき場所を示します。ブロックチェーンでデータを処理するには実際の費用がかかるため、Solidityでは参照データを格納する場所を指定できます。calldata
は一時的なデータで不変です。ガスの消費量は最も少ないです。(cf.memory
一時的で可変) -
public
これはアクセスに関する修飾子です。 他のコントラクトを含め、どこからでもアクセスできます。 -
view
これは、関数がコントラクトのデータのみを表示し、変更しないことを意味します。まさに見る(view)だけです。 -
returns(string)
コントラクトは呼び出されたときに文字列変数を返します。
✅ run.js を更新する
run.js
でテストを行うため変更を加えましょう。
domainContractFactory.deploy()
でコントラクトをブロックチェーンにデプロイします。
関数でpublicを指定したため、どこからでも呼び出すことができるようになります。
APIに詳しい方ならパブリックなAPIのエンドポイントのように考えるとわかりやすいでしょう。
では具体的にテストしたいと思います。
const main = async () => {
const [owner, randomPerson] = await hre.ethers.getSigners();
const domainContractFactory = await hre.ethers.getContractFactory("Domains");
const domainContract = await domainContractFactory.deploy();
await domainContract.deployed();
console.log("Contract deployed to:", domainContract.address);
console.log("Contract deployed by:", owner.address);
const txn = await domainContract.register("doom");
await txn.wait();
const domainOwner = await domainContract.getAddress("doom");
console.log("Owner of domain:", domainOwner);
};
const runMain = async () => {
try {
await main();
process.exit(0);
} catch (error) {
console.log(error);
process.exit(1);
}
};
runMain();
🤔 動作を確認しよう
順番に見ていきましょう。
const [owner, randomPerson] = await hre.ethers.getSigners();
ブロックチェーンに何かをデプロイするには、ウォレットアドレスが必要です。
ここではコントラクトオーナーのウォレットアドレスを取得し、さらにランダムなウォレットアドレスを取得してrandomPerson
としました。これはあとで解説します。
コントラクトをデプロイした人のアドレスを出力します。
console.log("Contract deployed by:", owner.address);
最後にこれを追加しています。
const txn = await domainContract.register("doom");
await txn.wait();
const domainOwner = await domainContract.getAddress("doom");
console.log("Owner of domain:", domainOwner);
まず、doom
を引数としてregister
関数を呼び出します。
さらに同じくgetAddress
関数を呼び出します。
これらを実行してみましょう。
ターミナル上で、下記を実行してみましょう。
yarn contract run:script
次のような画面になります。
Compiled 1 Solidity file successfully
THIS IS MY DOMAIN CONTRACT. NICE.
Contract deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3
Contract deployed by: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266 has registered a domain!
Owner of domain: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266