物理資産・在庫
資産の識別情報と権利を結び付け、発行・移転・保有を扱う。
← 実装パターン一覧設備1台に紐づく権利を発行し、保有者を管理する
配送ロボット A-001に関する契約上の権利を1,000単位で表し、そのうち10単位を取引先へ割り当てる構成です。設備そのものの情報は資産台帳に保存し、発行数や保有数はトークンで管理します。
資産IDを指定すると、対応するトークン、現在の保有者・保有数、割当や移転の履歴を同じ画面で確認できます。
システム構成と役割
資産管理画面
設備情報、契約、割当先と数量を表示します。
Web UI業務API・資産台帳
資産IDとトークンの対応、操作権限、処理の受付IDを管理します。
Application API / DB権利の発行・移転
発行上限と保有残高を管理し、許可された移転を実行します。
FlexibleTokenHelper履歴の同期
確定した取引を台帳に反映し、稼働や点検の記録と紐づけます。
Transaction receipts / Events
データモデル例
業務DBに保存する情報と、チェーンやAPIで管理する情報を対応づけます。フィールド名とサンプル値は、この構成で使うアプリケーション側の設計例です。
| 項目・値の例 | 管理する場所 | 役割・対応関係 |
|---|---|---|
assetIdROBOT-A-001 | 業務DB | 実物設備を識別する固定ID。機体番号や台帳番号との対応を保存します。 |
agreementIdAGR-2027-001 | 業務DB | トークンが表す権利の契約と版。原本や個人情報はアクセス制御した場所に保存します。 |
chainId + tokenAddresschainId / 0x… | DBとチェーン | 同じアドレスでもチェーンが異なれば別のコントラクトです。必ず組で保存します。 |
cap / decimals1000 / 0 | チェーン | この例は小数を使わず、1単位を1として扱います。発行上限は初期化時に設定します。 |
holder / balancepartnerWallet / 10 | チェーン | 保有数の正はチェーン。DB側の一覧はイベントから作る検索用データです。 |
operationId / transactionHashALLOC-001 / 0x… | 業務DB | 受付・送信・確定の状態と取引を対応づけ、再送による二重発行を防ぎます。 |
処理の流れ
設備と権利を登録する
A-001と契約AGR-2027-001を台帳に登録します。設備1台につき1コントラクトを使う構成なら、トークンの保有数をその設備に関する権利の数量として扱えます。
Application DB: assetId → agreementId → tokenAddressトークンを初期化する
FlexibleTokenを発行上限1,000、小数桁0で用意します。発行者にMINTER_ROLEを付与し、譲渡可否や必要なホワイトリストを設定します。
FlexibleTokenHelper.deploy / attach取引先に10単位を割り当てる
割当申請を保存してからmintを呼び出します。確定したreceiptのハッシュを申請に紐づけ、残高を取得します。発行済みの単位を渡す場合は、保有者の署名でtransferを使用します。
mint(recipient, amount) → balanceOf(recipient)保有者の一覧を更新する
Transferイベントを取り込み、chainId・transactionHash・logIndexを一意キーにして反映します。画面表示用のDBと、チェーンの残高を定期的に照合します。
Transfer events / balanceOf運用記録を重ねる
稼働時間、点検、故障などはassetIdで台帳に紐づけます。権利の移転と設備の引渡しは別の状態として記録し、現物の確認が必要な処理は業務側で管理します。
Application DB: operating_records.assetId
コードを利用する前の準備
- 初期化済みFlexibleTokenのアドレスと、対象チェーンに接続した発行者のSignerを用意します。
- この例では発行上限1,000・小数桁0を使用します。unitsには表示上の数量を文字列で渡します。
- 発行者のMINTER_ROLE、Pauseの状態、割当先に必要な参加条件を確認します。
npm install --save-exact @hazbase/kit@0.9.0 ethers@6.16.0以下はアプリケーションから呼び出すTypeScriptの関数です。接続先・権限・対象データを引数として渡します。UI、DBへの保存、処理の再開は、上記の構成に沿って業務側へ組み込めます。
設備IDを残して、10単位を割り当てる
allocateAssetへassetId、tokenAddress、recipient、units: "10"、issuerを渡します。DBへの保存処理は返された値を使用して、業務API側に組み込めます。
import { FlexibleTokenHelper } from '@hazbase/kit';
import { parseUnits } from 'ethers';
type Signer = Parameters<typeof FlexibleTokenHelper.deploy>[1];
export async function allocateAsset(input: {
assetId: string;
tokenAddress: string;
recipient: string;
units: string;
issuer: Signer;
}) {
if (!input.issuer.provider) throw new Error('A connected signer is required.');
// Requires an initialized token and a signer with MINTER_ROLE.
const token = FlexibleTokenHelper.attach(input.tokenAddress, input.issuer);
const amount = parseUnits(input.units, await token.decimals());
if (amount <= 0n) throw new Error('Units must be positive.');
const receipt = await token.mint(input.recipient, amount);
const balance = await token.balanceOf(input.recipient);
const network = await input.issuer.provider.getNetwork();
// Persist this mapping in your asset register after confirmation.
return {
assetId: input.assetId,
chainId: network.chainId.toString(),
tokenAddress: input.tokenAddress,
holder: input.recipient,
allocatedAtomic: amount.toString(),
balanceAtomic: balance.toString(),
transactionHash: receipt.hash,
blockNumber: receipt.blockNumber,
};
}
実行結果と、アプリケーションへの反映
保有数が0だった割当先ではbalanceAtomicが"10"になります。transactionHashとblockNumberを操作履歴へ保存します。mintは追加発行なので、画面の再読込や通信の再試行から無条件に呼び直さない構成にします。
実装で押さえておきたい点
数量の単位
小数桁が18のトークンへ10をそのまま渡すと、表示上の10単位にはなりません。コードではdecimalsを読み、parseUnitsで最小単位へ変換します。
取引成功後にDB保存が失敗した場合
チェーン上の発行は取り消されません。受付IDと送信時の取引ハッシュを保存できる送信処理を用意し、イベントから確定結果を回収します。
資産ごとに異なる権利
同じトークンの数量は同質として扱われます。設備ごとに条件が違う場合は別コントラクト、個体を1つずつ識別する場合はPrivilegeNFTなどの構成が候補です。
用途に合わせた拡張
在庫・保管物品への応用
assetIdを保管ロットへ置き換え、ロット内で同質の物品を単位化できます。引渡し完了時の消込は、倉庫側の確認とトークンのburnを対応づけます。
RWA Opsとの組み合わせ
設備の定義、発行、割当、運用記録をまとめて扱う場合はRWA Opsも利用できます。独自画面や既存台帳との接続は、API・SDKによる構成と比較できます。