ERC-3643 es un estándar de tokens de Ethereum para la emisión regulada y permisionada — añade comprobaciones de elegibilidad (KYC/AML), restricciones de transferencia y capacidades de transferencia forzosa/congelación sobre un contrato de token fungible.
Características clave
- Verificación de elegibilidad: Solo se permiten transferencias entre titulares que hayan completado las comprobaciones KYC/AML.
- Cumplimiento normativo: Las listas blancas/negras, los límites de inversores y las normas jurisdiccionales se aplican a nivel de protocolo.
- Aplicación y control: Las transferencias no autorizadas se bloquean, y un emisor puede transferir o quemar tokens de forma forzosa para cumplir obligaciones regulatorias del mundo real.
El equivalente en EmpoorioChain: pallet-emp-rwa
La suite de cumplimiento de EmpoorioChain incluye pallet-emp-rwa, un pallet nativo diseñado específicamente para tokens permisionados al estilo de activos del mundo real (RWA). Convive junto a pallet-emp-assets en lugar de requerir contratos de cumplimiento por token — la lógica de elegibilidad, congelación y transferencia forzosa la aplica el propio runtime para cualquier activo registrado bajo él.
Capacidades clave (verifica los nombres exactos de los extrínsecos en la referencia de pallets actual aquí)
- Aprobación de titulares: Una autoridad de cumplimiento aprueba o revoca titulares elegibles on-chain, controlando las transferencias a nivel de runtime.
- Congelación de cuentas: Una autoridad de cumplimiento puede congelar a un titular concreto, bloqueando nuevas transferencias sin tocar la lógica central del activo.
- Transferencia forzosa / recuperación: La autoridad de cumplimiento puede ejecutar una transferencia forzosa para cumplir órdenes judiciales o recuperar tokens de una cuenta comprometida o fraudulenta.
- Auditabilidad: Cada acción de cumplimiento (aprobación, congelación, transferencia forzosa) es un extrínseco on-chain, lo que ofrece a los auditores un historial de transacciones nativo en lugar de depender de registros off-chain.
¿Cómo se compara con una implementación personalizada en Solidity?
En Ethereum, el cumplimiento al estilo ERC-3643 normalmente se construye como Solidity a medida — un contrato de token con sus propios mapeos de KYC, un mapeo de congelación y un rol privilegiado de autoridad de cumplimiento, todo escrito y auditado por proyecto.
En EmpoorioChain, la lógica equivalente ya existe como un pallet compartido, auditado una sola vez. Un equipo no escribe ni despliega lógica de cumplimiento por token — registra un activo bajo pallet-emp-rwa y llama a los extrínsecos ya existentes del pallet para gestionar los titulares elegibles.
pragma solidity ^0.8.28;
interface IEmpAssets {
function transfer(address to, address mintAddress, uint256 amount) external;
function getTokenAccount(address owner, address token) external view returns (uint256 balance, bool isFrozen);
function mintTokens(address to, address mintAddress, uint256 amount) external;
}
contract PermissionedAsset {
IEmpAssets public immutable empAssets;
address public immutable mintAddress;
mapping(address => bool) public isKYCApproved;
mapping(address => bool) public frozen;
address public complianceAuthority;
address public transferHookProgram;
event KYCApproved(address indexed user, bool status);
event AccountFrozen(address indexed user, bool status);
event TransferHookSet(address indexed hookProgram);
event ForcedTransfer(address indexed from, address indexed to, uint256 value);
event Transfer(address indexed from, address indexed to, uint256 value);
constructor(address _empAssets, address _mint, address authority) {
empAssets = IEmpAssets(_empAssets);
mintAddress = _mint;
complianceAuthority = authority;
}
modifier onlyComplianceAuth() {
require(msg.sender == complianceAuthority, "not compliance auth");
_;
}
function approveKYC(address user, bool approved) external onlyComplianceAuth {
isKYCApproved[user] = approved;
emit KYCApproved(user, approved);
}
function freezeAccount(address user, bool freeze) external onlyComplianceAuth {
frozen[user] = freeze;
emit AccountFrozen(user, freeze);
}
function setTransferHook(address hookProgram) external onlyComplianceAuth {
transferHookProgram = hookProgram;
emit TransferHookSet(hookProgram);
}
function setComplianceAuthority(address newAuthority) external onlyComplianceAuth {
complianceAuthority = newAuthority;
}
function transfer(address to, uint256 amount) external {
require(!frozen[msg.sender] && !frozen[to], "account frozen");
require(isKYCApproved[msg.sender] && isKYCApproved[to], "KYC required");
if (transferHookProgram != address(0)) {
bool ok = ITransferHook(transferHookProgram).onTransfer(msg.sender, to, amount);
require(ok, "blocked by hook");
}
empAssets.transfer(to, mintAddress, amount);
emit Transfer(msg.sender, to, amount);
}
function forceTransfer(address from, address to, uint256 amount) external onlyComplianceAuth {
// temporarily unfreeze to bypass EmpAssets.transfer require(msg.sender == owner)
frozen[from] = false;
empAssets.transfer(to, mintAddress, amount);
frozen[from] = true;
emit ForcedTransfer(from, to, amount);
}
}
interface ITransferHook {
function onTransfer(address from, address to, uint256 amount) external returns (bool);
}
Elegibilidad de titulares
Solo las cuentas explícitamente aprobadas por la autoridad de cumplimiento pueden enviar o recibir el activo — algo que el pallet aplica antes de ejecutar una transferencia, la misma garantía que ofrece la comprobación de elegibilidad de ERC-3643 en Ethereum.
Aplicación de la congelación
Una autoridad de cumplimiento puede congelar la capacidad de transferir de un titular concreto a nivel de pallet — sin necesidad de lógica de contrato personalizada, con el mismo resultado que la función de congelación de cuentas de ERC-3643.
Punto de aplicación
Mientras que las implementaciones de ERC-3643 suelen ejecutar un callback de tipo transfer-hook en cada transferencia, pallet-emp-rwa realiza las comprobaciones equivalentes de elegibilidad/congelación de forma nativa dentro del extrínseco de transferencia del pallet, antes de que la transferencia se aplique. En la práctica, eso significa:
- Las cuentas no elegibles o congeladas se rechazan antes de que cambie el estado
- No hay un contrato hook independiente que desplegar o configurar por activo
- La lógica de cumplimiento forma parte del pallet auditado, no es código personalizado por proyecto
Esto ofrece la misma aplicación a nivel de protocolo que proporcionan los transfer hooks de ERC-3643, sin un contrato hook independiente por token.
Transferencia forzosa (autoridad de anulación)
La autoridad de cumplimiento puede ejecutar una transferencia forzosa entre dos cuentas elegibles cualesquiera — el equivalente en EmpoorioChain de la capacidad de delegado permanente / transferencia forzosa de ERC-3643, utilizada para órdenes judiciales o recuperación de fraudes.
Cómo usar pallet-emp-rwa
1. Mapa conceptual
| Función de ERC-3643 | Equivalente en pallet-emp-rwa |
|---|---|
| Lista blanca KYC | Almacenamiento de titulares aprobados, controlado por la autoridad de cumplimiento |
| Congelación de cuenta | Extrínseco nativo de congelación |
| Transferencia forzosa / recuperación | Extrínseco nativo de transferencia forzosa |
| Lógica personalizada en la transferencia | Integrada en el extrínseco de transferencia del pallet, no es un hook independiente |
| Administrador de cumplimiento | Un AccountId32 designado (u origen controlado por gobernanza) |
2. Flujo de extremo a extremo (simplificado)
User → pallet-emp-assets (transfer) ↘
pallet-emp-rwa eligibility check → OK / ERR
↘
pallet-emp-assets (balance change applied)
Una transferencia de un activo registrado en pallet-emp-rwa es un único extrínseco; el runtime comprueba la elegibilidad y el estado de congelación de ambas cuentas como parte de su ejecución. Si alguna comprobación falla, se rechaza todo el extrínseco y no cambia el estado — reflejando la aplicación on-chain de ERC-3643, sin una llamada hook independiente.
3. Ejemplo mínimo de cliente
El código cliente para las acciones de cumplimiento es una llamada normal de @polkadot/api: firmar y enviar un extrínseco de aprobación o congelación de titular desde la cuenta de la autoridad de cumplimiento, y enviar transferencias ordinarias desde las cuentas de los titulares. No hay ningún programa independiente que escribir, compilar o desplegar para la propia lógica de cumplimiento.
// EmpoorioChain does not need a separate "transfer hook" contract for this —
// pallet-emp-rwa (part of the emp-compliance-suite) enforces eligibility and
// freeze rules natively at the runtime level, before a transfer is applied.
// The client side simply calls its extrinsics via @polkadot/api; there is no
// program to write, build, or deploy for the compliance logic itself.
import { ApiPromise, WsProvider, Keyring } from "@polkadot/api";
const api = await ApiPromise.create({
provider: new WsProvider("wss://rpc.testnet.empooriochain.org"),
});
const keyring = new Keyring({ type: "sr25519" });
const complianceAdmin = keyring.addFromUri("//compliance-admin-seed-here");
const assetId = 1;
// Whitelist a holder after off-chain KYC/AML has cleared them.
async function approveHolder(accountId) {
const hash = await api.tx.empRwa
.approveHolder(assetId, accountId)
.signAndSend(complianceAdmin);
return hash.toString();
}
// Freeze/unfreeze an account — enforced natively, no custom logic required.
async function freezeHolder(accountId) {
const hash = await api.tx.empRwa
.freezeHolder(assetId, accountId)
.signAndSend(complianceAdmin);
return hash.toString();
}
4. Guía rápida de emp-cli (ilustrativa)
Un flujo típico: registrar un nuevo activo permisionado bajo pallet-emp-rwa como administrador de cumplimiento, aprobar a cada titular una vez que el KYC/AML off-chain lo autoriza, y después las transferencias entre titulares aprobados se realizan automáticamente, mientras que las transferencias que involucran a una cuenta no aprobada o congelada son rechazadas por el propio runtime. Los nombres exactos de los comandos deben comprobarse en la documentación actual de emp-cli.
# emp-cli quickstart (illustrative — see EmpoorioChain CLI docs for the
# exact subcommands and flags, which evolve alongside the pallet).
# 1. Register a new permissioned asset under pallet-emp-rwa
emp-cli assets create --admin $COMPLIANCE_ADMIN
# 2. Approve holders after off-chain KYC/AML
emp-cli emp-rwa approve-holder --asset-id 1 --account $HOLDER
# 3. Transfers between approved holders succeed automatically;
# transfers involving a non-approved or frozen account are rejected
# by the runtime itself, not by client-side validation.
emp-cli assets transfer --asset-id 1 --to $HOLDER --amount 10


