ETH決済とPLT決済の実装上の違いとは?

お知らせ
Table of Contents

フロントエンドチーム小林です。
HashPortでは、パレットチェーンというブロックチェーンを運営し、パレットトークン(PLT)というトークンを発行しています。
PLTは、社内外のプロジェクトで広く使われるようになってきており、私自身もPLTの決済の実装プロジェクトに関わりました。イーサリアムベースでの開発フローについては十分理解しているつもりでしたが、PLTでの実装は色々工夫が必要な点が多かったです。その気づきをまとめていきます。

ETH決済とPLT決済の違いについて

ETH決済もPLT決済も送金するという意味では似ています。
大きな違いとしては、使うウォレットが異なることと、PLTはトークンであり、スマートコントラクトベースでやりとりする必要があるという点があります。

ウォレット 単位 種類
ETH決済 Metamask など ETH 基軸通貨
PLT決済 PLTウォレット PLT ERC20(トークン)

作るもの


・ETHWallet接続ボタンを押すと、Metamaskが反応し接続できます。
・ETH送付ボタンを押すと、Metamaskが反応し0.02ETH送付できます。
・PLTWallet接続ボタンを押すと、バーコードが表示され、PLTウォレットで読み取ると接続できます。
・PLT送付ボタンを押すと、PLTWalletが反応し0.02PLT送付できます。

ETH


PLT


実装

フロントエンドの準備

フレームワークはVue3を使います。

cd ~
npm init vue@latest

選択肢はそれぞれ下記のように選択します。

✔ Project name: … <your-project-name>
plteth_frontend
✔ Add TypeScript? … No / Yes
Yes
✔ Add JSX Support? … No / Yes
No
✔ Add Vue Router for Single Page Application development? … No / Yes
No
✔ Add Pinia for state management? … No / Yes
No
✔ Add Vitest for Unit testing? … No / Yes
No
✔ Add Cypress for both Unit and End-to-End testing? … No / Yes
No
✔ Add ESLint for code quality? … No / Yes
Yes
✔ Add Prettier for code formatting? … No / Yes
Yes
  cd plteth_frontend
  npm install
  npm run dev

http://localhost:3000/
にアクセスして、表示されることを確認します。

サンプル

下記が、ETH決済とPLT決済の両方を試すことができるサンプルです。
後のセクションで解説します。

App.vue

<script setup lang="ts">
import Web3 from "web3/dist/web3.min.js";
import detectEthereumProvider from "@metamask/detect-provider";
import { ref } from "vue";
import PLTContractAbi from "@/abi/PLTContract.json";
import type { AbiItem } from "web3-utils";
import type { PLTContract } from "@/abi/PLTContract";
import WalletConnectProvider from "@walletconnect/web3-provider/dist/umd/index.min.js";

const web3 = ref();
const account = ref();
const provider = ref();
const PLTCONTRACT_ADDRESS = "0x****************************************";

const connectETHWallet = async () => {
  provider.value = await detectEthereumProvider();
  web3.value = new Web3(provider.value);
  const ethereum = (window as any).ethereum;
  const accounts = await ethereum.request({ method: "eth_requestAccounts" });
  account.value = accounts[0];
  console.log(account.value);
};

const ethTransfer = async () => {
  const value = web3.value.utils.toWei("0.002", "ether");
  const receipt = await web3.value.eth.sendTransaction({
    from: account.value,
    to: "0x****************************************",
    value: value,
  });
  console.log(receipt);
};

const connectPLTWallet = async () => {
  const chainID = 12345678;
  const paletteRPC = "https://**************";

 // WalletConnectに接続
  provider.value = new WalletConnectProvider({
    rpc: {
      chainID: paletteRPC,
    },
  });
  await provider.value.enable();
  web3.value = new Web3(provider.value);

  // アカウントを取得
  const accounts = await web3.value.eth.getAccounts();
  account.value = accounts[0];
  console.log(account.value);
};

const pltTransfer = async () => {
  const PLTContract = new web3.value.eth.Contract(
    PLTContractAbi as AbiItem[],
    PLTCONTRACT_ADDRESS
  ) as PLTContract;
  const value = web3.value.utils.toWei("0.002", "ether");
  const data = PLTContract.methods
    .transfer("0x****************************************", value)
    .encodeABI();
  const receipt = await web3.value.eth.sendTransaction({
    from: account.value,
    to: PLTCONTRACT_ADDRESS,
    value,
    data,
    gasPrice: 0,
    gas: 0,
  });
  console.log(receipt);
};
</script>

<template>
  <h1>ETH送付</h1>
  <button @click="connectETHWallet">ETHWallet接続</button>
  <button @click="ethTransfer">ETH送付</button>
  <br />
  <h1>PLT送付</h1>
  <button @click="connectPLTWallet">PLTWallet接続</button>
  <button @click="pltTransfer">PLT送付</button>
</template>

ライブラリ(npm)

web3
@metamask/detect-provider
typechain

ライブラリ(グローバル)

solc

ETH決済の実装方法

ウォレットへ接続

Metamaskに接続し、得られたproviderをもとにweb3オブジェクトを生成します。
その後、アカウントの情報も取得します。Metamaskへの接続方法については、下記リンクを参照ください。
https://docs.metamask.io/guide/getting-started.html#basic-considerations

const connectETHWallet = async () => {
  provider.value = await detectEthereumProvider();
  web3.value = new Web3(provider.value);
  const ethereum = (window as any).ethereum;
  const accounts = await ethereum.request({ method: "eth_requestAccounts" });
  account.value = accounts[0];
  console.log(account.value);
};

ETH送付

0.02etherを0x****************************************というアドレスに送ります。

const ethTransfer = async () => {
  const value = web3.value.utils.toWei("0.002", "ether");
  const receipt = await web3.value.eth.sendTransaction({
    from: account.value,
    to: "0x****************************************",
    value: value,
  });
  console.log(receipt);
};

PLT決済の実装方法

ABIの保存

PLTContractのABIを src/abi/PLTContract.json と保存します。

ABIの型生成

Typescriptを使うため、typechainを用いて、src/abi/PLTContract.jsonから型を生成します。

npm install --save-dev typechain

package.jsonのscriptsの箇所にtypechainの記述を加えて、npmから使えるようにします。

"scripts": {
    "dev": "vite",
    "build": "run-p type-check build-only",
    "preview": "vite preview --port 4173",
    "build-only": "vite build",
    "type-check": "vue-tsc --noEmit",
    "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
    "typechain": "typechain --target=web3-v1 $npm_config_filepath --outDir $npm_config_distpath"
  },

typechainを用いて型生成をします。src/abi/PLTContract.d.ts のように生成されます。

npm run typechain --filepath="src/abi/PLTContract.json" --distpath="src/abi"

ウォレットへ接続

現状PLTウォレットへ接続するためには、WalletConnectを介する必要があります。WalletConnectについては下記を参照してください。
https://docs.walletconnect.com/quick-start/dapps/web3-provider
provider.enable()でWalletConnectを有効化すると、QRコードが表示されます。
それをPLTウォレットで読み取ると接続できます。
接続には、イーサリアムとは異なるchainID, RPCを用います。
今回は、テスト用のchainID, RPCを使っています。

const connectPLTWallet = async () => {
  const chainID = 12345678;
  const paletteRPC = "https://**************";

  // WalletConnectに接続
  provider.value = new WalletConnectProvider({
    rpc: {
      chainID: paletteRPC,
    },
  });
  await provider.value.enable();
  web3.value = new Web3(provider.value);

  // アカウントを取得
  const accounts = await web3.value.eth.getAccounts();
  account.value = accounts[0];
  console.log(account.value);
};

PLT送付

0.02PLTを0x**************************************** というアドレスに送ります。
まずは、PLTContractをABIとコントラクトアドレスをもとに生成します。
PLTContractからtransfer関数を呼ぶという処理をdataとして保存し、sendTransaction時に一緒に渡します。

const pltTransfer = async () => {
  const PLTContract = new web3.value.eth.Contract(
    PLTContractAbi as AbiItem[],
    PLTCONTRACT_ADDRESS
  ) as PLTContract;
  const value = web3.value.utils.toWei("0.002", "ether");
  const data = PLTContract.methods
    .transfer("0x****************************************", value)
    .encodeABI();
  const receipt = await web3.value.eth.sendTransaction({
    from: account.value,
    to: PLTCONTRACT_ADDRESS,
    value: value,
    data,
    gasPrice: 0,
    gas: 0,
  });
  console.log(receipt);
};

まとめ

今回は、ETH決済とPLT決済を実装し、比較を行いました。
PLT決済では、スマートコントラクトとやりとりする必要があるため、ABIやコントラクトアドレスが必要で、実装がワンステップ増え、工夫する必要があります。

タイトルとURLをコピーしました