見出し画像

NounsDAOの動作解説と、Web3/NFTの開発現場

シンギュラリティソサイエティ(以下「SS」)では、代表の中島が NounsDAO のNouner になってからWeb3のブームが来ています。
DAOやSolidityに触れてまだ1ヶ月しか経ってないエンジニア達ですが、爆速で勉強中です。
前回の記事が好評だったため、今回はSSのエンジニア達がどんな会話をしながら開発を進めているのか一部公開します。

中島:ようやく、Nouns のソースコードを読み始めました。

中島:色々と勉強になります。

  • オークションでbidした際には、そのお金は一時的に address(this) に transfer される。コントラクトのアドレスもウォレットの役目を果たすのですね。これで、どうしてバグによって「誰にも取り出すことが出来ないお金」が出来てしまうのか理解できました。

  • オークションに失敗(誰も bid しない場合)は、burn するようになっている。

  • オークションハウスのコントラクトをEtherscan で見ると、現時点での bid 額が balance として表示される。https://etherscan.io/address/0x830bd73e4184cef73443c15111a1df14e495c706#readProxyContract

  • Etherscan で auction とか duration などに格納された値をリアルタイムで見ることも出来る。

  • Dapp (web3 app) において、スマートコントラクトは、インテリジェントなModelの役割を果たしているとも言える。データの生合成、排他制御、ビジネスロジックなどは、すべてスマートコントラクトが行い、アプリ側(View + Controller)は、それと人間の橋渡しをするだけ。なので、Controller にバグがあっても、データの生合成が壊れたりすることはない。私が嫌いな “Fat Controller” と正反対の美しいアーキテクチャ

  • オークションの締め切り間際に bid が入った場合、締め切り時間を伸ばすという「ルール」になっているけど、そのルールはスマートコントラクト上で実装されている。この手の「ルール」(ビジネスロジックと呼んでも良い)を web アプリ側ではなく、スマートコントラクト側で実装することにより、ハックを不可能にしているし、web アプリ側のバグによる誤動作を排除している。

  • NounsSeeder コントラクト内の、generateSeed 関数が、ミントする Noun の見た目(Seed)を決めている。ロジックは、keccak256(abi.encodePacked(blockhash(block.number - 1), nounId))、ブロックチェーンのハッシュ値を利用して、疑似乱数を生成している。

  • なので、TwitterID から生成したいのであれば、この generateSeed を TwitterID をパラメータとして受ける関数に置き換える必要がある。

  • NounsのSVGイメージを作る仕組みを読みましたが、100% on-chain でやろうという部分に凄い意気込みを感じました。しかし、pixel 画像を SVG 化しているからこそデータ量が増えている部分もあるのも事実です(一列ごとに rectangle 化しています)。なので、パーツを最初から SVG で作れば、データ量も少なくてすむし、カーブも使えるのでバライティが増します。

有本:オークション部分などはミスが有ると大変ですから、これを実装して運営するのは大変でしょうね。なのでてきるだけ実績がある実装をベースに使うのが良いですね。コンストラクタのサイズに制限があるのと、実行やデータ保存にコストがかかるのでFat Controllerにならないですね。コアなロジックだけスマコンで実装される。

竹原:Auction 自体もSmartContractでロジックとデータが制御されているんですね!とても勉強になります。createBid() payable… になっているということは bid した時点でBlockに追記されるので、ガス代がかかるということですよね。そして、そのときのガス代はbidの msg.senderが支払うと理解しました。

有本:そんなに量はないので、ここのNounsXXX.solは見ておくと良いです。

有本:デプロイの流れはここ。

有本:投票もスマコンかとおもったら、投票はないのですね。どっかで見た気がしたのですが、OpenZeppelinかCompoundだったのかな。

有本:Solidityの処理でrequireの条件のtransactionを失敗した場合、ブロックチェーンにエラーが残るのですね。
へんなアタックしたら、全部記録が残りますね。https://rinkeby.etherscan.io/tx/0xaed766b1215d0ee45b117f101da6576d4de47abb073a494146e9b32eb1a0001a

竹原:sender側をプログラム化してリトライ処理などいれてしまい バグがあると、ガス代が延々と消費されていくんですね..。SmartContract間連携などでも気をつけないとエラーの無限ループがおきそう。

有本:無限ループにはならないしくみはあるようです。何でカウントするかは忘れましたが、計算量が多いと処理が止まるようです。じゃないと、簡単にDoS攻撃ができてしまいます。SmartContract間連携でもGas代の上限があるので、相互に呼び出しても上限に達するはず。なので、おそらく重い処理もできないですよね。100万件のデータがあって、それを全部処理するなどは。
transferに関してはオーナーか、もしくは許可しているcontractのみが可能なので、別コンストラクタが必要だということがわかりました。NounsAuctionHouseをみたところ、isApprovedForAllを使っているのではなくAuctionHouseがnounを所有しているのでtransferは普通にできるのですね。

有本:う。バグって、payableでmintしても他人所有のNFTがmintされるものができてしまった。。。。(NounsTokenを改良して遊んでいます)

中島:スマートコントラクトのコンパイルとデプロイは、何を使ってますか?

有本:truffleです。hardhatのほうが今は主流のようですね。
たまたまみたサンプルがtruffleだったので、というくらいの理由です。nouns-contractsのsmart contract(hardhat)を、truffleでコンパイルしているのですが、importの挙動が少し違うようなので、そこで少しハマりました。

有本:hardhat

import { PausableUpgradeable } from '@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol';

有本:truffle

import '@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol';

中島:この記事を読んでみます。


有本:
うーーーん。記事を読みましたが、両方使ってみないと評価しづらいですね。Truffle だと、テストするのに Ganacheが必要ですが、Hardhatは単体でできるようなので、そのあたりの使いやすさが決めてになりそうですね。普通にコンパイル&デプロイするだけならどっちでも一緒な気がします。もしくは、nounsに合わせてHardhatにするか。

中島:Nouns の discord には hardhat の方が良く出てきますね。

有本:Nounsが使っていますからね。

中島:上の記事に、Open Zeppelin も hardhat を使っていると出ていますね。

有本:はい。Truffleのほうが古いので、記事などではよく使われていますね。が、おそらくhardhatのほうが新しくて便利なのかもしれませんね。現状であれば、私もswitchするコストは低いので、hardhatを統一して使ってみる、というのでも良いです。

中島:そうしましょうか。ちなみに、hardhat は local install が標準のようです。バージョンのことを考えたら、その方が安全かも。

有本:そうですね。hardhatの記事をいくつかみたところ、たしかにテストなどはしやすそうですね。

中島:ローカルで走るブロックチェーンがあるようですね。

有本:gethが動くのかな?

有本:Hardhat Networkってのがあるのですね。https://github.com/NomicFoundation/hardhat/blob/master/docs/hardhat-network/README.md

有本:Mainnet forkingもできるのですね。これは良いかも。これでテストをしておけば、mainnetにデプロイして動かない、というのを防げますね。
これを試してみると、すぐに使えますね。

有本:あとは、vue側でlocalに接続するようにすればテストもできそうです。abiは、artifacts/contracts/Greeter.sol/Greeter.jsonですね。いまのvueのStartupKitでweb3のライブラリを使うと、Webpackのバージョン問題でこれにあたりますので注意を。

有本:localhostのethネットへの接続時にこのエラーがでます。エラーの回避方法はあったはずなので、後で共有します。
このチケットにあるようにagent-baseをいれて、vue.config.jsに追加かな。

yarn add agent-base

をして、vue.config.jsのconfigureWebpack->resolve->fallbackを

"http": 'agent-base',
"https": 'agent-base',

に変更ですね。これで、localのethを叩いてテストできました。localに繋ぐ場合、web3.jsでは、

const web3 = new Web3('http://localhost:8545');

有本:hardHatブランチでhelloというオンチェーンのmethodを叩くサンプルをpushしています(mintTestWeb)。
現在作っているものをhardHatで開発するには、少し変更が必要になるので、これだけはtruffleで進めて行きます。余裕ができたらhardhatにいれる。

と、いろいろ寄り道するとリリースにたどり着かなそうなので、まずは最短でリリースを目標とします。


おわりに
シンギュラリティ・ソサエティでは、テクノロジーがどのように社会に影響を与えるか、様々な議論をしています。 DAOなどに代表されるブロックチェーンやスマートコントラクトのテクノロジーは、社会や経済の仕組みをコード化し、透明且つ効率に仕組みに刷新する可能性を秘めています。
現在、シンギュラリティ・ソサエティでは、DAOやDeFi、Smart Contractなどの勉強や開発、NounsDAOへのプロポーザルプロジェクトなど、Web3の活動も行っています。今後もこれらに関する記事を発信していきますのでお楽しみに!

この記事が気に入ったらサポートをしてみませんか?