06 · 環境設定と受入検証
公開環境へ接続するためのネットワークパラメータ、デモ資産、照会例、受入チェックリストを提供します。
6.1 環境情報
| 項目 | テスト環境 | メインネットデモ環境 |
|---|---|---|
| 用途 | 開発、結合テスト、受入 | BOT Mainnet 機能検証 |
| ネットワーク | Bohr Testnet | BOT Mainnet |
| 状態 | 利用可能 | デモ Suite デプロイ済み |
| Chain ID | 968 | 677 |
| RPC | https://rpc.bohr.life | https://rpc.botchain.ai |
| Explorer | https://scan.bohr.life | https://scan.botchain.ai |
| ネイティブ gas 資産 | Test BOT | BOT |
Bohr Testnet と BOT Mainnet のコントラクトアドレス、Token 残高、ID、Claim は共有されません。
6.2 推奨設定構造
環境ごとに独立した設定ファイルまたは環境変数を使用します。
type RwaEnvironment = {
chainId: number;
rpcUrl: string;
explorerUrl: string;
contracts: {
token: string;
identityRegistry: string;
onchainIdGateway?: string;
idFactory?: string;
claimIssuer?: string;
};
};
テスト環境:
const rwaTestnet = {
chainId: 968,
rpcUrl: 'https://rpc.bohr.life',
explorerUrl: 'https://scan.bohr.life',
contracts: {
token: '0x922835859623d6F3b99a2742D585E093bBA0a740',
identityRegistry: '0x17e33C394Ab783D6786011d01681D8Ad540C5F53',
onchainIdGateway: '0x3B0FE2CD501534cbcbD1F97ec823Da535fc0224f',
idFactory: '0xb4E03AB303f4c42dbced87b65e1d9f5788EAb369',
claimIssuer: '0x67EC753196D6Cd1B65a29b6ff9c1bE41E554a5a7',
},
};
BOT Mainnet 機能デモ:
const rwaMainnet = {
chainId: 677,
rpcUrl: 'https://rpc.botchain.ai',
explorerUrl: 'https://scan.botchain.ai',
contracts: {
token: '0x9115A020821fDFdf265Eea8788a500d17557c370',
identityRegistry: '0x7752dd107CDec2dF5feD585BCC70457c5312021a',
onchainIdGateway: '0xa6B4E53128915E0f980DD455De9F70B6Dc61E1ee',
idFactory: '0x124ED389600870D1a5f86f657896Add3E623ca9e',
claimIssuer: '0x3950eB42733b3eF6744E8788C741788CCF6c84b3',
},
};
メインネット設定が不足または検証失敗した場合、テストネットアドレスへ自動 fallback してはいけません。メインネット JSON を参照してください。
6.3 公開デモ資産
| 項目 | 値 |
|---|---|
| 名称 | Project Real World Asset |
| シンボル | PRWA |
| Decimals | 6 |
| 適格性 Topic | KYC_APPROVED |
| Topic 値 | 7151541257903274562366177585585886223835338030660388602590463654390840817671 |
| Claim scheme | 1 |
| 許可国コード | 156, 702 |
6.3.1 Bohr Testnet アドレス
| コントラクト | アドレス |
|---|---|
Token | 0x922835859623d6F3b99a2742D585E093bBA0a740 |
IdentityRegistry | 0x17e33C394Ab783D6786011d01681D8Ad540C5F53 |
IdentityRegistryStorage | 0xB834C4FEEADC24A9c5B873e8887CD9b54C40E98D |
ClaimTopicsRegistry | 0xbf8adD07A8722d06c218A3A7DD4Bb44d3a90948A |
TrustedIssuersRegistry | 0x94ffe710F64AB382274A53C8b10003a3287E621D |
ModularCompliance | 0x1E2e2a848b611C121C86F77C703B8DD32DCdE37A |
| Token ONCHAINID | 0x551676B9061b5324676BBbB5587433454EE54521 |
| 共有コントラクト | アドレス |
|---|---|
ONCHAINID Gateway | 0x3B0FE2CD501534cbcbD1F97ec823Da535fc0224f |
IdFactory | 0xb4E03AB303f4c42dbced87b65e1d9f5788EAb369 |
ClaimIssuer | 0x67EC753196D6Cd1B65a29b6ff9c1bE41E554a5a7 |
TREXGateway | 0x82e1Fa8022BA1dcFC05061E0A1CE828C189108A9 |
| Country Allowlist | 0x532bFc29B0D9a281084203303a8E687259D57149 |
6.3.2 BOT Mainnet デモアドレス
| コントラクト | アドレス |
|---|---|
Token | 0x9115A020821fDFdf265Eea8788a500d17557c370 |
IdentityRegistry | 0x7752dd107CDec2dF5feD585BCC70457c5312021a |
IdentityRegistryStorage | 0xD54fD1381c970F19366cb7c50072295045ff5516 |
ClaimTopicsRegistry | 0x645E33c8c67D3Ea478F87b70d76711E110953FB9 |
TrustedIssuersRegistry | 0x4d96f4Bb96795a3EFeb3Cea43459E2ee4C5ad439 |
ModularCompliance | 0xB8A4b2aFd8318e61cDbaEC07559B49bE6bBE20D5 |
| Token ONCHAINID | 0x3677B0F87892B10F1341DB3348dFEcb9CE039146 |
| 共有プラットフォーム | アドレス |
|---|---|
ONCHAINID Gateway | 0xa6B4E53128915E0f980DD455De9F70B6Dc61E1ee |
IdFactory | 0x124ED389600870D1a5f86f657896Add3E623ca9e |
ClaimIssuer | 0x3950eB42733b3eF6744E8788C741788CCF6c84b3 |
TREX ImplementationAuthority | 0x3E19c7f1e6E53125fF205591fc516e25541d21ff |
ONCHAINID ImplementationAuthority | 0x992CCAC1A33EFdb58b9cfD49CF510d5db15Fc249 |
IAFactory | 0xf3BdD013eb6c49C23f5b8E70bE5F6C8c98c76028 |
TREXFactory | 0xf622AbFDf470912CCb86A54d52D2430951a3e956 |
TREXGateway | 0x3c209A13fc9E91B060C7672874895E117a1A3Ab5 |
| Country Allowlist | 0xA41A626bcBF57B3695539f6516E3D482dCFAEDEC |
BOT Mainnet デモ Suite の Country Allowlist モジュールは本番監査を完了していません。技術機能検証専用であり、実資産を直接載せてはいけません。
Bohr Testnet JSON · BOT Mainnet JSON
6.4 公開照会ウォレット
| サンプル | ウォレット | Testnet ONCHAINID | 国 | 適格性 |
|---|---|---|---|---|
| Alice | 0xb450970Eece71044acF7cB7f53Ee51e3BC2EA922 | 0xfAB41B1DfD098F439D75cEA0cb48f70B46052544 | 156 | true |
| Bob | 0xfc996C5378fe0cd03Fd4296075abc07B16b2B12F | 0xd3b816e7494e918297E3553d65488a7E0682C6A3 | 702 | true |
| Cathy | 0x2b981b025397AE1AFca6f8DC7A2f5C7A868dEe78 | 0xb7522A6649a20A0820E292D8D0f35aB792812011 | 156 | true |
秘密鍵は提供されません。write 操作には自分のウォレットを使用してください。
| サンプル | ウォレット | BOT Mainnet ONCHAINID | 国 | isVerified |
|---|---|---|---|---|
| Alice | 0xb450970Eece71044acF7cB7f53Ee51e3BC2EA922 | 0x95d0ae16d03A26BA6a0dA844938C5c50e16e407C | 156 | true |
| Bob | 0xfc996C5378fe0cd03Fd4296075abc07B16b2B12F | 0x3F5059a5eadc24c27809f481e97Bef4834DB4272 | 702 | true |
| Cathy | 0x2b981b025397AE1AFca6f8DC7A2f5C7A868dEe78 | 0x29E0cb659BEd6baF5a6Dc19C50cB41dbBdd41194 | 156 | true |
negative test には自分が管理する未登録ウォレットを使用します。期待値は contains == false、isVerified == false です。ゼロアドレスを実業務ウォレットに使用しないでください。
6.5 第 1 段階:ネットワークとコントラクトを検証
例は ethers.js v5 を使用します。v6 では JsonRpcProvider、formatUnits、parseUnits の v6 import を使用してください。
const { ethers } = require('ethers');
const provider = new ethers.providers.JsonRpcProvider('https://rpc.bohr.life');
const network = await provider.getNetwork();
if (network.chainId !== 968) {
throw new Error(`Wrong network: expected 968, got ${network.chainId}`);
}
const TOKEN = '0x922835859623d6F3b99a2742D585E093bBA0a740';
const IR = '0x17e33C394Ab783D6786011d01681D8Ad540C5F53';
if (await provider.getCode(TOKEN) === '0x') {
throw new Error('Token contract not found on current network');
}
write 操作の前に毎回 Chain ID を検証します。
6.6 第 2 段階:資産情報を読み取る
const token = new ethers.Contract(TOKEN, [
'function name() view returns (string)',
'function symbol() view returns (string)',
'function decimals() view returns (uint8)',
'function totalSupply() view returns (uint256)',
'function identityRegistry() view returns (address)',
'function compliance() view returns (address)',
'function paused() view returns (bool)',
], provider);
const [name, symbol, decimals, supply, registry, compliance, paused] =
await Promise.all([
token.name(), token.symbol(), token.decimals(), token.totalSupply(),
token.identityRegistry(), token.compliance(), token.paused(),
]);
console.log({
name, symbol, decimals,
totalSupply: ethers.utils.formatUnits(supply, decimals),
registry, compliance, paused,
});
名称・シンボルが公開情報と一致し、decimals を読み取れ、identityRegistry() と compliance() がアドレス表に一致することを確認します。
6.7 第 3 段階:残高と適格性を照会
const wallet = '0xb450970Eece71044acF7cB7f53Ee51e3BC2EA922';
const ir = new ethers.Contract(IR, [
'function contains(address) view returns (bool)',
'function isVerified(address) view returns (bool)',
'function identity(address) view returns (address)',
'function investorCountry(address) view returns (uint16)',
], provider);
const [rawBalance, contains, verified, identity, country] =
await Promise.all([
token.balanceOf(wallet), ir.contains(wallet), ir.isVerified(wallet),
ir.identity(wallet), ir.investorCountry(wallet),
]);
console.log({
balance: ethers.utils.formatUnits(rawBalance, decimals),
contains, verified, identity, country,
});
公開テストウォレットでは contains と verified が true で、ID と国コードが表に一致する必要があります。
6.8 第 4 段階:イベントを照会
const latest = await provider.getBlockNumber();
const logs = await token.queryFilter(
token.filters.Transfer(), Math.max(0, latest - 5000), latest
);
for (const log of logs) {
console.log({
txHash: log.transactionHash,
blockNumber: log.blockNumber,
from: log.args.from,
to: log.args.to,
value: ethers.utils.formatUnits(log.args.value, decimals),
});
}
長時間稼働するインデクサーは範囲を分割し、checkpoint から再開して過大なリクエストを避けます。
6.9 write 操作の結合テスト
| 操作 | 署名者 | 前提 |
|---|---|---|
| ONCHAINID 作成 | 投資家テストウォレット | test gas |
addClaim | ONCHAINID 管理ウォレット | test Claim 署名 |
registerIdentity | test IR Agent | 発行者またはプラットフォームの支援 |
mint / burn | test Token Agent | 発行者またはプラットフォームの支援 |
transfer | Token 保有者 | 両当事者が適格性とルールを満たす |
通常の開発者は Agent 秘密鍵を必要としません。Agent 権限操作は対象資産の発行者が実行します。投資家操作には自分のウォレットを使用し、秘密鍵を送信しないでください。
公開 PRWA デモ資産は現在 pause 中です。通常 transfer は Token Agent が unpause() を呼び出した後にのみ実行できます。
transfer の事前検査と送信
const recipient = '0xfc996C5378fe0cd03Fd4296075abc07B16b2B12F';
const senderAddress = await signer.getAddress();
const amount = ethers.utils.parseUnits('10', decimals);
if (await token.paused()) {
throw new Error('Token transfers are currently paused');
}
if (!await ir.isVerified(recipient)) {
throw new Error('Recipient is not verified for this asset');
}
const compliance = new ethers.Contract(
await token.compliance(),
['function canTransfer(address,address,uint256) view returns (bool)'],
provider
);
if (!await compliance.canTransfer(senderAddress, recipient, amount)) {
throw new Error('Transfer rejected by compliance rules');
}
const receipt =
await (await token.connect(signer).transfer(recipient, amount)).wait();
console.log(receipt.transactionHash);
approve + transferFrom
await (await token.connect(ownerSigner).approve(spender, amount)).wait();
await (await token.connect(spenderSigner)
.transferFrom(ownerAddress, recipient, amount)).wait();
事前検査後も状態は変化し得るため、レシートが最終結果です。
6.10 ローンチ受入チェックリスト
環境
- Testnet と Mainnet の設定が独立している。
- 起動時に Chain ID を厳密に検証する。
- RPC、Explorer、コントラクトアドレスは公式リリース情報を使用する。
- Mainnet 設定が Testnet アドレスへ自動 fallback しない。
コントラクト読み取り
- Token の名称、シンボル、
decimalsが正しい。 - Token に紐づく IR と MC がアドレス表に一致する。
- アドレスにコントラクト bytecode がある。
- ABI がデプロイ済みバージョンと一致する。
金額とトランザクション
- 全金額で
parseUnits/formatUnitsを使用する。 - write 操作で submitted、confirmed、failed を区別する。
- tx hash が正しい Explorer を指す。
- 失敗時に最終業務状態を更新しない。
- retry が mint または burn を重複送信しない。
ID とコンプライアンス
- 対象資産の IR で適格性を照会する。
containsとisVerifiedを区別する。- 複数資産で誤った IR を再利用しない。
- KYC 平文はオフチェーンに保持する。
- コンプライアンス拒否理由を明確に表示する。
セキュリティ
- 秘密鍵をフロントエンド、リポジトリ、ログに置かない。
- Agent と Claim Signer は管理された署名方式を使う。
- プロキシアドレスのみを使用する。
- アップグレードとセキュリティ通知を購読する。
6.11 トラブルシューティング順序
1. Chain ID を確認
2. RPC の利用可否を確認
3. 現在のネットワークでアドレスに bytecode があるか確認
4. Token.name / decimals / identityRegistry を読み取り
5. balance / paused / isFrozen を照会
6. 受取人 contains / isVerified を照会
7. compliance.canTransfer を照会
8. 署名者ロールを確認
9. callStatic / estimateGas で revert 理由を取得
10. 送信後にレシートとイベントを照会
Testnet で成功し Mainnet で失敗する場合は、ネットワーク、コントラクトアドレス、資産適格要件、コンプライアンスルールを比較してください。同一設定と仮定してはいけません。