Saltar al contenido principal

06 · Configuración de entornos y aceptación

Parámetros de red, activo de demostración, ejemplos de consulta y lista de aceptación para los entornos públicos.

6.1 Entornos

ElementoPruebasDemostración mainnet
UsoDesarrollo, integración, aceptaciónVerificación de capacidades
RedBohr TestnetBOT Mainnet
EstadoDisponibleSuite desplegada
Chain ID968677
RPChttps://rpc.bohr.lifehttps://rpc.botchain.ai
Exploradorhttps://scan.bohr.lifehttps://scan.botchain.ai
GasBOT de pruebaBOT

Direcciones, saldos, identidades y Claims son independientes.

6.2 Estructura recomendada

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',
},
};
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',
},
};

No retroceda automáticamente a testnet si mainnet falta o falla. JSON mainnet.

6.3 Activo público

ElementoValor
Nombre / símbolo / decimalesProject Real World Asset / PRWA / 6
TopicKYC_APPROVED
Valor Topic7151541257903274562366177585585886223835338030660388602590463654390840817671
Scheme1
Países156, 702

6.3.1 Bohr Testnet

ContratoDirección
Token0x922835859623d6F3b99a2742D585E093bBA0a740
IdentityRegistry0x17e33C394Ab783D6786011d01681D8Ad540C5F53
IdentityRegistryStorage0xB834C4FEEADC24A9c5B873e8887CD9b54C40E98D
ClaimTopicsRegistry0xbf8adD07A8722d06c218A3A7DD4Bb44d3a90948A
TrustedIssuersRegistry0x94ffe710F64AB382274A53C8b10003a3287E621D
ModularCompliance0x1E2e2a848b611C121C86F77C703B8DD32DCdE37A
Token ONCHAINID0x551676B9061b5324676BBbB5587433454EE54521
CompartidoDirección
ONCHAINID Gateway0x3B0FE2CD501534cbcbD1F97ec823Da535fc0224f
IdFactory0xb4E03AB303f4c42dbced87b65e1d9f5788EAb369
ClaimIssuer0x67EC753196D6Cd1B65a29b6ff9c1bE41E554a5a7
TREXGateway0x82e1Fa8022BA1dcFC05061E0A1CE828C189108A9
Country Allowlist0x532bFc29B0D9a281084203303a8E687259D57149

6.3.2 BOT Mainnet

ContratoDirección
Token0x9115A020821fDFdf265Eea8788a500d17557c370
IdentityRegistry0x7752dd107CDec2dF5feD585BCC70457c5312021a
IdentityRegistryStorage0xD54fD1381c970F19366cb7c50072295045ff5516
ClaimTopicsRegistry0x645E33c8c67D3Ea478F87b70d76711E110953FB9
TrustedIssuersRegistry0x4d96f4Bb96795a3EFeb3Cea43459E2ee4C5ad439
ModularCompliance0xB8A4b2aFd8318e61cDbaEC07559B49bE6bBE20D5
Token ONCHAINID0x3677B0F87892B10F1341DB3348dFEcb9CE039146
CompartidoDirección
ONCHAINID Gateway0xa6B4E53128915E0f980DD455De9F70B6Dc61E1ee
IdFactory0x124ED389600870D1a5f86f657896Add3E623ca9e
ClaimIssuer0x3950eB42733b3eF6744E8788C741788CCF6c84b3
TREX ImplementationAuthority0x3E19c7f1e6E53125fF205591fc516e25541d21ff
ONCHAINID ImplementationAuthority0x992CCAC1A33EFdb58b9cfD49CF510d5db15Fc249
IAFactory0xf3BdD013eb6c49C23f5b8E70bE5F6C8c98c76028
TREXFactory0xf622AbFDf470912CCb86A54d52D2430951a3e956
TREXGateway0x3c209A13fc9E91B060C7672874895E117a1A3Ab5
Country Allowlist0xA41A626bcBF57B3695539f6516E3D482dCFAEDEC

Country Allowlist no ha completado una auditoría de producción. La Suite es solo de demostración técnica y no debe portar activos reales.

JSON testnet · JSON mainnet

6.4 Carteras públicas

EjemploCarteraONCHAINID testnetPaísVerificado
Alice0xb450970Eece71044acF7cB7f53Ee51e3BC2EA9220xfAB41B1DfD098F439D75cEA0cb48f70B46052544156true
Bob0xfc996C5378fe0cd03Fd4296075abc07B16b2B12F0xd3b816e7494e918297E3553d65488a7E0682C6A3702true
Cathy0x2b981b025397AE1AFca6f8DC7A2f5C7A868dEe780xb7522A6649a20A0820E292D8D0f35aB792812011156true

No se proporcionan claves privadas. Para escritura, use una cartera propia.

EjemploCarteraONCHAINID mainnetPaísVerificado
Alice0xb450970Eece71044acF7cB7f53Ee51e3BC2EA9220x95d0ae16d03A26BA6a0dA844938C5c50e16e407C156true
Bob0xfc996C5378fe0cd03Fd4296075abc07B16b2B12F0x3F5059a5eadc24c27809f481e97Bef4834DB4272702true
Cathy0x2b981b025397AE1AFca6f8DC7A2f5C7A868dEe780x29E0cb659BEd6baF5a6Dc19C50cB41dbBdd41194156true

Para negativos, use una cartera propia no registrada: contains == false, isVerified == false.

6.5 Validar red y contrato

Ejemplos con ethers.js v5:

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');
}

Valide Chain ID antes de escribir.

6.6 Leer el activo

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});

Acepte cuando nombre/símbolo, decimals, IR y MC coincidan con la publicación.

6.7 Saldo y elegibilidad

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});

Las muestras deben devolver contains y verified verdaderos.

6.8 Eventos

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),
});
}

Consulte por tramos y checkpoints.

6.9 Escrituras

OperaciónFirmanteRequisito
Crear ONCHAINIDCartera inversorGas
addClaimGestor ONCHAINIDFirma Claim
registerIdentityIR AgentSoporte del emisor
mint / burnToken AgentSoporte del emisor
transferTitularElegibilidad y reglas

Nunca transfiera claves privadas. Los PRWA públicos están pausados; transfer solo funciona después de unpause().

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');
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);
await (await token.connect(ownerSigner).approve(spender, amount)).wait();
await (await token.connect(spenderSigner)
.transferFrom(ownerAddress, recipient, amount)).wait();

El recibo determina el resultado final.

6.10 Lista de aceptación

Entorno

  • Configuración independiente;
  • Chain ID estricto;
  • Datos de publicación oficial;
  • Sin fallback de mainnet a testnet.

Contratos y transacciones

  • Nombre, símbolo, decimals, IR y MC correctos;
  • Bytecode y ABI correctos;
  • parseUnits / formatUnits;
  • Estados enviado/confirmado/fallido;
  • Sin actualización final tras fallo ni mint/burn duplicado.

Identidad y seguridad

  • IR del activo correcto;
  • Diferenciar contains e isVerified;
  • KYC claro fuera de cadena;
  • Mensajes de rechazo comprensibles;
  • Sin claves en frontend/repositorio/logs;
  • Firmas controladas, proxies y avisos de seguridad.

6.11 Diagnóstico

1. Chain ID
2. RPC
3. Bytecode
4. Token.name / decimals / identityRegistry
5. balance / paused / isFrozen
6. contains / isVerified
7. compliance.canTransfer
8. Rol firmante
9. callStatic / estimateGas
10. Recibo y eventos

Si testnet funciona y mainnet falla, compare red, direcciones, cualificaciones y reglas.

Anterior: 05 · Interfaces y eventos · Inicio