発行額1億円突破記念!スマートコントラクトで広がるJPYC活用術― 技術者向け(Solidity・Hardhat・Polygon)
日本円ステーブルコインJPYCをスマートコントラクトに組み込む、Polygon上でのSolidityハンズオンチュートリアル。

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-tutorialnpx 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: MITpragma 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");// CONFIGconst JPYC_HANDLER_ADDRESS = "YOUR_DEPLOYED_CONTRACT_ADDRESS";const JPYC_TOKEN_ADDRESS = "0x431D5dfF03120AFA4bDf332c61A6e1766eF37BDB";const DEPOSIT_AMOUNT = ethers.parseUnits("10", 18); // JPYC has 18 decimalsasync 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)
まだコメントはありません。最初のコメントを投稿しましょう。
