Renesis
Renesis
成功事例
BlockChain

発行額1億円突破記念!スマートコントラクトで広がるJPYC活用術― 技術者向け(Solidity・Hardhat・Polygon)

日本円ステーブルコインJPYCをスマートコントラクトに組み込む、Polygon上でのSolidityハンズオンチュートリアル。

R

Renesis Tech

2025年11月17日12 min read
日本国旗と円マーク金貨を持つ手、JPYCロゴ——日本円連動型ステーブルコイン。
日本国旗と円マーク金貨を持つ手、JPYCロゴ——日本円連動型ステーブルコイン。

PYCは日本円に連動したステーブルコインで、2025年10月27日にローンチされました。日本のWeb3分野では急速に存在感を高めており、発行額は公開からわずか6日で1億円を突破しています。

これまで日本でdAppsを構築する場合、価格変動が大きいETHやMATICに依存するか、USDCなどの海外ステーブルコインを使わざるを得ず、円ベースでサービスを組み立てるのは簡単ではありませんでした。

しかし、JPYCの登場によって状況は大きく変わります。JPYCは日本の決済サービス法のもと**正式に「電子決済手段」**として認可されており、これによりユーザーにとって自然で、円に馴染んだWeb3体験を実現できます。本ガイドでは、スマートコントラクトからJPYCとやり取りする方法を、実際のコードスニペットを交えて解説します。手数料が安く高速なPolygonを利用し、HardhatとSolidityを使って「JPYCの入金・出金が可能な基本コントラクト」を構築していきます。

バージョンに関する注意

本記事の内容は2025年11月6日時点で検証しています。Web3のツール群は更新が非常に早いため、将来的にバージョン差異による不具合が発生する可能性があります。以下のバージョンで動作確認済みです。

  • Hardhat: 2.22.4
  • @nomicfoundation/hardhat-toolbox: 5.0.0
  • @openzeppelin/contracts: 5.0.2
  • dotenv: 16.4.5

これらをpackage.jsonに追加し、npm installを実行して環境を揃えてください。

Node.js(v18以上推奨)
VS Codeなどのコードエディタ
MetaMaskウォレット拡張機能(事前にアカウント設定済みのもの)
Polygonネットワーク上でのデプロイや取引に必要なMATIC(ガス代用)
テスト用の少額のJPYC — 公式サイトの「JPYC EX」から数百円分を入手し、PolygonネットワークのMetaMaskウォレットへ送金してください

ターミナルを開き、作業用フォルダーを作成したうえで、Hardhatプロジェクトを初期化します。

mkdir jpyc-sc-tutorial
cd jpyc-sc-tutorial
npx hardhat

copy

プロンプトには次のように回答してください:

  • 何をしますか? → JavaScriptプロジェクトを作成する
  • Hardhatプロジェクトのルート: → そのまま Enter(デフォルト)
  • .gitignore を追加しますか? → はい
  • npmで依存関係をインストールしますか? → はい

その後、以下のパッケージを追加でインストールしてください。

npm install @openzeppelin/contracts@5.0.2 dotenv@16.4.5

copy

ルートディレクトリに .env ファイルを作成し、以下の内容を記述してください。

POLYGON_RPC_URL="YOUR_ALCHEMY_OR_INFURA_POLYGON_RPC_URL"
PRIVATE_KEY="YOUR_METAMASK_PRIVATE_KEY"

copy

Alchemy もしくは Infura から取得した Polygon の RPC URL をここに設定してください。

MetaMask の秘密鍵もこの欄に入力しますが、絶対に他人と共有しないよう注意してください。

続いて、hardhat.config.js を次のように更新してください。

require("@nomicfoundation/hardhat-toolbox");
require("dotenv").config();

module.exports = {
solidity: "0.8.20",
networks: {
polygon: {
url: process.env.POLYGON_RPC_URL || "",
accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : [],
},
},
};

copy

contractsフォルダ内のサンプル Lock.sol を削除し、代わりに JPYCHandler.sol を新規作成します。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract JPYCHandler is Ownable {
IERC20 public immutable jpycToken;

event Deposit(address indexed user, uint256 amount);
event Withdraw(address indexed owner, uint256 amount);

address constant JPYC_POLYGON_ADDRESS = 0x431D5dfF03120AFA4bDf332c61A6e1766eF37BDB;

constructor() Ownable(msg.sender) {
jpycToken = IERC20(JPYC_POLYGON_ADDRESS);
}

/**
* @dev Lets a user deposit JPYC into the contract.
* @param _amount Amount of JPYC (with 18 decimals in mind).
* Note: User needs to approve this contract first to spend their JPYC.
*/
function depositJPYC(uint256 _amount) external {
require(_amount > 0, "Amount must be greater than zero");
uint256 allowance = jpycToken.allowance(msg.sender, address(this));
require(allowance >= _amount, "Check the token allowance");
bool success = jpycToken.transferFrom(msg.sender, address(this), _amount);
require(success, "Transfer failed");
emit Deposit(msg.sender, _amount);
}

/**
* @dev Owner can pull out all JPYC from the contract.
*/
function withdrawAllJPYC() external onlyOwner {
uint256 balance = getContractBalance();
require(balance > 0, "No JPYC to withdraw");
jpycToken.transfer(owner(), balance);
emit Withdraw(owner(), balance);
}

/**
* @dev Check the contract's JPYC balance.
* @return Balance in wei-like units.
*/
function getContractBalance() public view returns (uint256) {
return jpycToken.balanceOf(address(this));
}
}

copy

それでは、このコントラクトを実際にオンチェーンへデプロイしてテストしてみましょう。

デプロイ用スクリプトとして、scripts/deploy.js を次のように編集します。

const hre = require("hardhat");

async function main() {
const jpycHandler = await hre.ethers.deployContract("JPYCHandler");
await jpycHandler.waitForDeployment();
console.log(`JPYCHandler deployed to: ${jpycHandler.target}`);
}

main().catch((error) => {
console.error(error);
process.exitCode = 1;
});

copy

次のコマンドを実行します:

npx hardhat run scripts/deploy.js --network polygon

copy

コンソールに表示されたデプロイ先アドレスを控えておいてください。

次に、コントラクトとやり取りするためのスクリプトとして、scripts/interact.js を新しく作成します。

const { ethers } = require("hardhat");

// CONFIG
const JPYC_HANDLER_ADDRESS = "YOUR_DEPLOYED_CONTRACT_ADDRESS";
const JPYC_TOKEN_ADDRESS = "0x431D5dfF03120AFA4bDf332c61A6e1766eF37BDB";
const DEPOSIT_AMOUNT = ethers.parseUnits("10", 18); // JPYC has 18 decimals

async function main() {
const [signer] = await ethers.getSigners();
console.log("Using wallet:", signer.address);

const jpycHandler = await ethers.getContractAt("JPYCHandler", JPYC_HANDLER_ADDRESS, signer);
const jpycToken = await ethers.getContractAt("IERC20", JPYC_TOKEN_ADDRESS, signer);

console.log("\\nApproving spend...");
const approveTx = await jpycToken.approve(JPYC_HANDLER_ADDRESS, DEPOSIT_AMOUNT);
await approveTx.wait();
console.log("Approved. Tx:", approveTx.hash);

console.log("\\nDepositing...");
const depositTx = await jpycHandler.depositJPYC(DEPOSIT_AMOUNT);
await depositTx.wait();
console.log("Deposited. Tx:", depositTx.hash);

const contractBalance = await jpycHandler.getContractBalance();
console.log("\\nCheck balance:", ethers.formatUnits(contractBalance, 18) + " JPYC");
}

main().catch((error) => {
console.error(error);
process.exitCode = 1;
});

copy

契約アドレスを差し替えたら、次のコマンドを実行してください。

npx hardhat run scripts/interact.js --network polygon

copy

承認と入金の処理が正しく完了し、最終的に 10 JPYC の残高が表示されていれば成功です。


まとめと今後のステップ

これで、スマートコントラクト内でJPYCを扱うための基本的な流れを一通り理解できたはずです。
とくに approve → transferFrom のパターンは、あらゆるERC20トークンを扱う際の定番手順なので、この段階で慣れておくと後がとても楽になります。

今回のシンプルな構成は、少し手を加えるだけで、次のようなさまざまなユースケースに応用できます。

  • ECサイト向けの決済システム
  • ブログやメディアでのクリエイター向けチップ機能
  • Web3ゲームで利用できる安定したゲーム内通貨

JPYCの登場によって、「円」をベースにしたWeb3プロジェクトの可能性は大きく広がりました。
今回のコードを土台に、自分のユースケースに合わせてカスタマイズし、面白いプロダクトづくりに挑戦してみてください。

このガイドは、JPYCを使って開発を始めるための“確実に動くスタート地点”としてまとめたものです。
Web3開発は、環境やバージョンの違いによって予期せぬ問題が起きやすく、なかなかクセのある分野でもあります。

もし、手順どおり進めてもエラーが出たり、コードについて疑問があれば、
いつでも https://renesistech.jp/ からご連絡ください。喜んでサポートいたします。

それでは、楽しいビルドライフを!

シェア

コメント (0)

まだコメントはありません。最初のコメントを投稿しましょう。

コメントを投稿