GreenSnap TECH BLOG

GreenSnapのエンジニアチームの取り組みや使っている技術を紹介します

社内slackでスタンプを押したらブロックチェーンに記録するWeb3サービスをchatGPTに丸投げして作ってみた話

はじめに

この記事は、AIの自然言語生成モデルであるchatGPTによって作成されました。そのため、内容に誤りがある可能性があります。また一部人間によって訂正されたり、修正された場合があることをご了承ください。

web3とは

web3は、ブロックチェーンを利用するためのアプリケーションプログラミングインターフェース(API)を提供するものです。つまり、ブロックチェーンにアクセスするためのインターフェースを提供し、ブロックチェーンを利用するアプリケーションを作成するためのものです。

【補足】 ここでchatGPTが説明されているのは、javascriptのweb3ライブラリだと思われます。一般的なWeb3について質問し直したところ、以下のような回答が返ってきました。

Web3とは、インターネット上で動くアプリケーションのプラットフォームのことです。Web3は、Web 2.0よりも新しい技術を使用しており、Web 2.0が中心としているのはサーバーであるのに対し、Web3はブロックチェーンを中心としています。

ブロックチェーンとは、データを複数のコンピューター(ノード)に分散して保存する技術です。そのため、Web3アプリケーションは、データが一つのサーバーに保存されるのではなく、複数のコンピューターに分散して保存されるため、安全で信頼性が高く、偽の情報の挿入やデータの改ざんが困難です。

Web3は、仮想通貨やスマートコントラクトなど、さまざまな技術を採用しており、新しいビジネスモデルやサービスを創出するための潜在的なプラットフォームとして注目されています。

chatGPTとは

chatGPTは、OpenAIが開発した自然言語生成モデルです。入力された文章をもとに、自然な文章を生成することができます。このモデルは、自然言語処理タスクやチャットボットなどに利用されています。

実装手順

1. hardhatでローカルにブロックチェーン環境をたてる

chatGPTから、web3のおすすめのフレームワークであるhardhatをおすすめされました。hardhatは、Ethereumのブロックチェーンを利用するためのフレームワークです。

まずは、hardhatをローカル環境にインストールします。以下のコマンドを実行してください。

$ npm install hardhat

次に、ローカル環境でブロックチェーンを立ち上げます。以下のコマンドを実行してください。

$ npx hardhat node

立ち上げた際に、オーナーアドレスが表示されるので、このアドレスを保存しておきましょう。このアドレスを使用して、スマートコントラクトをデプロイしたり、トランザクションを送信することができます。

2. ブロックチェーン上にデータを記録するためのスマートコントラクトを作成する

スマートコントラクトを作成することで、ブロックチェーン上にデータを記録することができます。スマートコントラクトは、Ethereumブロックチェーン上で実行されるプログラムです。

今回は、社内のslackでスタンプを押したときに、そのスタンプを記録するスマートコントラクトを作成します。そのために、ThankYouStamp.solという名前のスマートコントラクトファイルを作成します。

以下は、ThankYouStamp.solのソースコードです。

pragma solidity ^0.8.9;

contract ThankYouStamp {
    // スタンプを送信するためのデータ構造
    struct Thanks {
        bytes32 sender;  // 送信者のslackユーザーIDをKeccak256でハッシュ化したもの
        bytes32 receiver;  // 受信者のslackユーザーIDをKeccak256でハッシュ化したもの
        uint256 timestamp;  // スタンプの送信日時をUNIX時間で保存
    }

    // 送信されたスタンプを保存するためのマップ
    mapping(bytes32 => Thanks) public thanks;

    // 送信者と受信者のslackユーザーIDをハッシュ化したものをキーに、送信されたスタンプ数を保存するためのマップ
    mapping(bytes32 => uint256) public thanksCount;

    // スタンプを送信する
    function sendThanks(string memory senderId, string memory receiverId, uint256 timestamp) public {
        // 送信者と受信者のslackユーザーIDをハッシュ化
        bytes32 sender = keccak256(abi.encodePacked(senderId));
        bytes32 receiver = keccak256(abi.encodePacked(receiverId));

        // 自分自身にスタンプを送信することはできない
        require(sender != receiver, "Cannot send a stamp to yourself");

        // スタンプを送信する
        thanks[sender] = Thanks(sender, receiver, timestamp);
        thanksCount[receiver]++;
    }

    // 特定のslackユーザーが受け取ったスタンプの累積数を取得する
    function getMyThanks(string memory userId) public view returns (uint256) {
        // slackユーザーIDをハッシュ化
        bytes32 key = keccak256(abi.encodePacked(userId));
        return thanksCount[key];
    }
}

このスマートコントラクトは、thanksCountという変数を定義しています。この変数は、各ユーザーが取得したスタンプの数を記録するものです。また、sendThanksという関数が定義されています。この関数を呼び出すことで、thanksCountを1増やすことができます。

3. スマートコントラクトをデプロイする

作成したスマートコントラクトをデプロイすることで、ブロックチェーン上に登録することができます。デプロイするためには、オーナーアドレスが必要になります。

デプロイスクリプトは、deploy.tsとして以下のように書いておきます。

import { ethers } from "hardhat";
import { ThankYouStamp } from "../typechain-types/ThankYouStamp";

async function main() {
  const ThankYouStamp = await ethers.getContractFactory("ThankYouStamp");
  // スマートコントラクトのインスタンスを生成
  const thankYouStamp = await ThankYouStamp.deploy();

  // デプロイされたスマートコントラクトのアドレスを表示
  console.log("ThankYouStamp deployed to: ", thankYouStamp.address);
}

// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

以下のコマンドを実行して、スマートコントラクトをデプロイします。

$ npx hardhat run scripts/deploy.ts --network localhost

デプロイが完了すると、スマートコントラクトのアドレスが表示されます。このアドレスを保存しておきましょう。

4. slack bolt経由でスマートコントラクトを呼び出す

次に、slack boltを使用して、スマートコントラクトを呼び出すようにします。slack boltは、slackアプリで利用するためのフレームワークです。

slacl boltの詳細については、公式サイト を参照ください。

次に、slack boltを使用して、slackでスタンプを押したときに、スマートコントラクトを呼び出す処理を記述します。

app.jsファイルを作成し、以下のように書いておきます。

const {App, ExpressReceiver} = require('@slack/bolt');
const request = require('request');
const Web3 = require('web3');

// Web3を初期化する
// URL for the Ethereum network
const networkUrl = "http://127.0.0.1:8545";

// ThankYouStampのABIをロードする
const thankYouStampABI = require('./ThankYouStamp.json').abi;

// ThankYouStampのアドレスをロードする
const thankYouStampAddress = require('./ThankYouStampAddress.json').address;

// Connect to the Ethereum network
const web3 = new Web3(networkUrl);

// ThankYouStampのコントラクトを初期化する
const thankYouStamp = new web3.eth.Contract(thankYouStampABI, thankYouStampAddress);

const TOKEN = "SLACK_API_TOKEN"
const SIGNING_SECRET = "YOUR_SIGNING_SECRET"

// ボットトークンとソケットモードハンドラーを使ってアプリを初期化します
const app = new App({
    token: TOKEN,
    signingSecret: SIGNING_SECRET
});

app.event('reaction_added', async ({event, say, client}) => {
    if (event.reaction === 'thankyou') {
        // スタンプを送信したuserIdを受け取る
        const senderId = event.user;
        // リアクションしたメッセージを送信したuserIdを受け取る
        const recipientId = event.item_user;
    
        // 自分自身に感謝スタンプを送ることはできないので、senderIdとrecipientIdが異なる場合のみ処理を行う
        if (senderId !== recipientId) {
          // スタンプの送受信をブロックチェーン上に記録する
          await thankYouStamp.methods.sendThanks(senderId, recipientId, Date.now()).send({ from: "OWNER_ADDRESS" });
    
          // ボットが日本語で返答する
          say(`<@${senderId}>さんから感謝スタンプが届きました。あなたの感謝スタンプは合計${await thankYouStamp.methods.getMyThanks(recipientId).call()}個になりました。`);
        }
    }
});

(async () => {
    // アプリを起動します
    await app.start(process.env.PORT || 3000);
    console.log('⚡️ Bolt app is running!');
})();

上記のコードでは、thankyouというスタンプが押されたときに、スマートコントラクトを呼び出す処理が記述されています。

上記コード内の、ThankYouStamp.jsonについては、手順3で生成されたものになります。また、ThankYouStampAddress.jsonについては、手順3でデプロイした際に生成されるコントラクトアドレスを記載しております。

また、OWNER_ADDRESSに関しては、手順1で保管しておいたオーナーアドレスになります。

5. slack Boltを起動して試す

最後に、slack boltを起動して、動作を確認します。以下のコマンドを実行してください。

node app.js

slack boltが起動したら、thankyouスタンプを押してみましょう。すると、スマートコントラクトが呼び出され、以下のようなメッセージが返ってくれば成功です。

slack thankyou

まとめ

今回は、社内slackでスタンプを押したらブロックチェーンに記録するweb3サービスをchatGPTに丸投げして作ってみた話をご紹介しました。スマートコントラクトを作成し、slack boltを使用してスマートコントラクトを呼び出すことで、簡単にブロックチェーンを利用するアプリケーションを作成することができました。

web3を使用することで、ブロックチェーンを利用するアプリケーションを作成することができます。また、chatGPTを使用することで、自然言語を生成することができるので、お手軽に文章を作成することができます。

今回は、スタンプを押したときに、スマートコントラクトを呼び出す処理を実装しましたが、web3を使用することで、様々なタイプのアプリケーションを作成することができます。是非、web3とchatGPTを試してみてください。

最後に

GreenSnapではエンジニアを募集中です。サーバーサイド、iOS、Androidエンジニアはもちろんのこと これから作成するデータ基盤とそれを活用できるデータサイエンティストの方も募集しています。
一人ひとりが幅広くいろんな技術領域を担当しているので、特定の技術だけを担当するより多くの技術に触れたい方や挑戦したい方は是非お声がけください。

www.wantedly.com

裏話

この記事に出てくるソースコードをchatGPTに書いてもらったときの質問内容がこちらです。

以下の要件を満たす社内の感謝スタンプシステムを作るために、下記の条件を満たすスマートコントラクトThankYouStamp.solのソースコードと、slackのAPIをハンドリングするapp.jsのソースコードを書いてください。

## 仕様

- 感謝スタンプはslackのスタンプを使います
- slack上のdevelopチャンネルの中でのメッセージにリアクションすることで感謝スタンプを送信できます
- 自分自身に感謝スタンプを送ることはできません

## 技術要件

- ThankYouStamp.solについて
    - solidityのバージョンは0.8.9です
    - ThankYouStamp.solというスマートコントラクトを定義します
    - string型は文字列比較できないことに注意します
    - ThankYouStampのなかで、sendThanks関数を定義します
        - sendThanks関数は、送信者のslackのユーザーIDと受信者のslackのユーザーIDとスタンプの送信日時を受け取り、ブロックチェーン上に保存します
    - ThankYouStampのなかで、getMyThanks関数を定義します
        - getMyThanks関数はslackのユーザーIDを受け取り、スタンプの合計取得数を返します

- app.jsについて
    - ThankYouStampのABIをThankYouStamp.jsonからロードします
    - ThankYouStampのアドレスをThankYouStampAddress.jsonからロードします
    - slackAppを初期化して変数appに格納します
    - reaction_addedイベントをハンドリングし、結果をevent, say, clientとして受け取ります
    - event.reactionの中身が「thankyou」の場合、スタンプを送信したuserIdと、リアクションしたメッセージを送信したuserIdを受け取ります
    - スタンプの送受信をブロックチェーン上に記録します
    - say()を使ってボットが日本語で返答します
        - 〇さんから感謝スタンプが届きました。あなたの感謝スタンプは合計△個になりました。
    - 上記の〇には感謝スタンプを押したユーザーのユーザーIDが@メンション付きで入り、△は感謝スタンプを受け取ったユーザーの累積のスタンプ数が入ります。

最初はかなり雑な質問をしていたので、手取り足取り教えてくれましたが、そこから実際にコードを書いて、動かなかったところが修正されるように質問内容を調整することで、このような質問にたどり着きました。質問の仕方次第で全く異なる回答が返ってきたりするので、ググり力ならぬ、chatGPTへの質問力みたいなものが、今後求められる時代が来るのかもしれません。