見出し画像

【マシンガンガールズ】応援用のおひねりNFTガチャ作ってみた話【ERC-1155×ランダム実装】

おふぁんてぃ〜🫶✨
メタバースアイドルグループ、マシンガンガールズNo.16 KEIこと、まっぷるけーです。

もふ姐の元気が出るオネエボイスが付いてるNFTガチャを作ったので、宣伝も兼ねてランダムにNFTをミントする仕組みを紹介・解説しちゃいます!

マシンガンズDAOのDiscordサーバーはこちら


もふ姐のおひねりNFTガチャとは

ミントするまで何が出るかはお楽しみ!
10種類 + 1種類(シークレット)で、もふ姐の元気が出るボイス付きのガチャ形式NFTコレクションです。

あーたもスキね❤️

1個1MATICで格安なのでコンプも目指しやすく、かぶっているものをリストしたり、持っていないものを2次で拾ったりオファーしたりできます。

応援のおひねり × ちょっとしたゲーム要素 × NFTという、けっこう革新的な構造になってます・・・うえしんさん天才!

ミントサイトはこちら
OpenSeaのコレクションページはこちら

コントラクトの仕組み

ここからコントラクトの仕組みの解説となりますが、以下の前提知識が必要となります。

  • NFTをミントしたことがある

  • ERC-721とERC-1155の違いがなんとなく分かる

  • 独学含めちょっとでもプログラミング経験がある

・・・ゑ、敷居高くない?

確かに思いましたが・・・
なるべく分かりやすく書こうと思ったのですが、非エンジニアの方が分かるレベルで噛み砕くのに限界がありました、お許しください😂

ということで、難しいな・・・と感じる方は、ふわふわっと、雰囲気だけでも感じ取ってもらえればと思います🙇

ERC-1155のおさらい

ERC-1155で知っておきたい重要な関数は、なんといってもミント関数になります。
まずはこちらをご覧ください。

ERC-1155のミント関数

ERC-1155のミント関数の一つに、_mintBatchという名前の関数があります。
こちらは指定した複数IDのNFTを指定した枚数分だけまとめてミントできるという、とても便利な機能になります。

カッコの中には4つパラメータが入っており、

  • 1つ目: ミントを実行しているウォレット (msg.sender)

  • 2つ目: ミント対象となるNFTのID (ids[])

  • 3つ目: ミント対象となるNFTのIDにおけるミント枚数 (amounts[])

  • 4つ目: 今回は重要ではないので解説しません

図に示した例では、3番を1枚、6番を2枚、9番を1枚、11番を1枚まとめてミントすることになります。

このように、もふ姐ガチャでは購入者が指定したミント総数に応じて、ランダムにids / amountsが設定されるように実装することがゴールとなります。

コードの全体像

もふ姐ガチャでは、11種類のIDをランダムに取得するところ以外は、至って通常のERC-1155実装となります。
そのため、核となるアルゴリズムは以下に示す30行に満たないコードブロックとなります。

コードの羅列にアレルギー起こしちゃう方はごめんなさい・・・今から身体かゆくなります😂

モフ姐ガチャNFTのコントラクト (polygon scan)

当初、解説する予定も無かったのでコメント0です。ごめんなさい😂

さて、大きく分けて3つのループ処理に集約されます。

  1. ID: 1〜11の値を所定の確率で1個ずつ、ミント総数分だけ選択する

  2. ユニークなIDの個数をカウントする (たとえば5個ミントして3, 6, 6, 9, 11番を引いた場合は重複が排除されたユニーク数は4となる)

  3. ユニークなIDの個数分を大きさとした配列を2つ (ids[], amounts[]) 用意し、対応するIDと個数をそれぞれ代入する

順を追って解説していきます。

1. IDごとの出現確率をどのように実装するか

IDごとの出現確率を実装している部分は以下になります。

for (uint256 i=0; i<_mintAmount; i++) {
    uint256 time = block.timestamp;
    bytes32 randomValue = keccak256(abi.encodePacked(msg.sender, "-", time, "-", i));
    uint256 tokenSeed = uint256(randomValue) % 21 + 1;
            
    if (tokenSeed == 11) mintAmountEachTokens[tokenSeed - 1]++;
    else if (tokenSeed % 10 == 0) mintAmountEachTokens[10 - 1]++;
    else mintAmountEachTokens[tokenSeed % 10 - 1]++;
}

もふ姐ガチャの要件として、特定のIDだけシークレット要因として出現確率を下げることになりました。

  • No.01〜10 (ノーマル): 9.52% (2/21)

  • No.11 (シークレット): 4.76% (1/21)

No.11のみ、他のIDと比べて相対的に出現確率が半分になるような仕様です。
要件をもとに効率的でシンプルなアルゴリズムを考えた結果、以下のようになりました。

乱数のシード値(種)とIDの割り振り

まずは1〜21の範囲で乱数を発生させ、乱数に対応するようにIDを割り当てます。

No.01〜10は、それぞれ乱数のうち2個に割り当てされています。
一方、No.11は1個だけです。

これらを実現するには、3行の分岐で事足ります。(もっと良い方法あるかも)

シード値からのID割り当て式

最後の式は、シード値を10で割った余りを表しています(13なら3, など)。

繰り返しになりますが、こうすることでNo.01〜10は2/21の確率、No.11のみ1/21の確率で選択されるようになります。
上述した式と図を見比べて確認してみてください。

さて、次の問題はどのようにして1〜21の範囲の乱数を発生させるか、ということになります。
考え得る方法は無数にありますが、ブロックチェーン記述言語のSolidityで簡単に擬似的な乱数が作れるハッシュ関数「keccak256」を採用しました。

bytes32 randomValue = keccak256(abi.encodePacked(msg.sender, "-", time, "-", i));

「keccak256」を簡単に説明すると、この関数に特定の文字列をぶち込むとそれに対応した78桁 (16進数だと64桁) というおびただしい長さの数が返されます。

  • keccak256("aaaaa") -> 5aff1592…

  • keccak256("aaaab") -> 6e91ec6b…

特徴として、上記のように1個でも入力値となる文字が異なると、全っっっく違う数が返ってきます。
この特徴が擬似的な乱数生成として非常に有用なので、よく使われます。

これを踏まえて、今回の実装をまとめると以下のような図になります。

乱数生成のロジック図解
  • ウォレットアドレス・ミントが実行された時間・ミント個数をつなげた文字列をもとに乱数を生成 (randomValue)

  • randomValueを21で割った余りに1を足し、1〜21の範囲に納める (tokenSeed)

あとはtokenSeedをもとに、ID割り当て式に代入することでIDが決定できます。

2. ユニークなIDの個数をカウントする

ミントするIDのみを格納する配列 (ids[]) のサイズを得るために、ユニークなIDの個数をカウントしておく必要があります。

for (uint256 i=0; i<mintAmountEachTokens.length; i++) {
    if (mintAmountEachTokens[i] > 0) countIds++;
}

このとき、mintAmountEachTokens[]には全てのIDに対応したミント数が格納されています。

mintAmountEachTokens[]に格納された値の一例

ミント数が0ではないIDの個数をカウントしておき、ids[], amounts[]の配列の大きさを定義するために利用します。
※上記例ではcountIds=4となる

3. _mintBatchに代入する配列(ids[], amounts[])を作る

mintAmountEachTokens[]から、ミント数が0でないIDを抽出し、ids[], amounts[]を作ります。

uint256[] memory ids = new uint256[](countIds);
uint256[] memory amounts = new uint256[](countIds);
uint256 idx;

for (uint256 i=0; i<mintAmountEachTokens.length; i++) {
    if (mintAmountEachTokens[i] > 0) {
        ids[idx] = i + 1;
        amounts[idx] = mintAmountEachTokens[i];
        idx++;
    }
}

図にすると、こんな感じ。

あとはamounts[], ids[]を_mintBatch関数に代入して実行すれば、ミント実行者のもとにもふ姐が届きます💋💄

まとめ

もふ姐NFTガチャの仕組み (アルゴリズムの考案から実装まで) を解説してみました。

雰囲気だけでも、どんな風にして確率を決定したり最終的にミントされたりしているかを感じていただけたら幸いです。
またエンジニア希望の方は、この発想をもとに自分のNFTガチャを作ってみたり、改良したりして成長の糧にしてくれると大変嬉しいです✨

マシンガンガールズのファンクラブパスについても記事を書いているので、ぜひこちらも見てみてください!
フルオンチェーンの豪華なパス型NFTです。

【マシンガンガールズ】会員パスNFTをリリースしました


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