En esta página, se describe cómo crear reglas de políticas de Cedar para validar transacciones en el motor de políticas de computación multipartita (MPC).
El Policy Engine decodifica las cargas útiles de las transacciones entrantes dentro de un entorno de ejecución confiable (TEE) seguro y proyecta los atributos de la intención de la transacción en el contexto de evaluación de Cedar.
Estructura de las reglas de Cedar
Cuando escribes reglas de Cedar para Policy Engine, especificas una regla con un conjunto de condiciones anidadas:
- Principal: Es la identidad lógica del solicitante de la transacción (el iniciador de la transacción) dentro del espacio de trabajo de computación multipartita (por ejemplo,
User::"alice"), en lugar de la identidad de IAM de Google Cloud (usuario o cuenta de servicio) que llama a la API. - Acción: Es la acción criptográfica solicitada (por ejemplo,
Action::"sign_transaction"). - Recurso: Es la clase de recurso o de operación de destino sobre la que se opera (por ejemplo,
Resource::"mpc_operation"). - Context: Son los metadatos y los parámetros analizados de la transacción (accesibles en
context.transaction).
Referencia del esquema de transacciones de Ethereum
El framework independiente del protocolo permite que las reglas omitan la verificación del esquema para que se puedan reutilizar en diferentes redes de cadena de bloques. Sin embargo, para restringir de forma explícita una regla a las cargas útiles de transacciones de Ethereum, verifica lo siguiente: context.transaction.schema == "ethereum.transaction.v2".
Se admiten los siguientes atributos dentro del registro context.transaction:
| Atributo | Tipo | Descripción |
|---|---|---|
schema |
String | Es el esquema de formato. En el caso de las transacciones de Ethereum, siempre es "ethereum.transaction.v2". |
operation |
String |
Es el tipo de operación de transacción. Valores admitidos:
|
chain_id |
String | Es el ID de la red de cadena de bloques de destino (por ejemplo, "1" para la red principal de Ethereum o "11155111" para la red de prueba de Sepolia). |
asset_symbol |
String | Es el símbolo de cotización del token que se transfiere (por ejemplo, "ETH", "USDC", "DAI" o "WBTC"). Los tokens que no cotizan en bolsa devuelven "UNKNOWN". |
asset_contract_address |
String | La dirección del contrato inteligente del token ERC-20 (en formato de suma de comprobación EIP-55 con mayúsculas y minúsculas). Esto se resuelve en una cadena vacía ("") para las transferencias de ETH estándar. |
recipient |
String | Es la dirección del destinatario (en formato de suma de comprobación EIP-55 con mayúsculas y minúsculas). En el caso de las aprobaciones de tokens, representa la dirección del gastador. |
spend_amount_scaled |
Largo |
Es el importe de la transferencia de tokens normalizado a una precisión fija de 9 decimales (formato de nanocoin), lo que elimina la necesidad de hacer un seguimiento de los decimales de tokens variables (como 6, 8 o 18) cuando se escriben reglas.
Cómo calcularlo: Multiplica el importe del activo legible por humanos (p.ej., 1.5 ETH o 5,000 USDC) por 1,000,000,000 (109) para obtener el valor de tu regla:
|
spend_amount_dust |
Largo | Es el resto del importe de la transacción que está por debajo del umbral de precisión de 9 decimales. Para los activos con más de 9 decimales (como ETH, que tiene 18), este contiene el valor de sub-Gwei sin escalar (el Wei restante). Este valor siempre es 0 para los activos con 9 decimales o menos (como USDC o WBTC). |
max_fee_atomic |
Largo | Es el límite máximo de la comisión total por transacción (escalado por 109, que representa Gwei). |
gas_limit |
Largo | Es la cantidad máxima de gas asignada para la ejecución de la transacción. |
destination_type |
String | Es la clasificación de la dirección del destinatario. Valores admitidos: "EOA" (billetera de usuario estándar), "CONTRACT" (contrato inteligente) o "INTERNAL_TREASURY" (bóveda interna). |
temporal_validity |
Largo | Es el nonce de la cuenta de transacción (se usa para evitar ataques de reproducción de transacciones). |
Referencia del esquema de transacciones de Bitcoin
Para restringir de forma explícita una regla a las cargas útiles de transacciones de PSBT de BIP 174 de Bitcoin, verifica lo siguiente: context.transaction.schema == "bitcoin.transaction.v2".
Se admiten los siguientes atributos dentro del registro context.transaction:
| Atributo | Tipo | Descripción |
|---|---|---|
schema |
String | Es el esquema de formato. En el caso de las transacciones de Bitcoin, siempre es "bitcoin.transaction.v2". |
operation |
String |
Es el tipo de operación de transacción. Valores admitidos:
|
chain_id |
String | La parte legible por humanos (HRP) de Bech32 de la red de destino: "bc" (red principal de Bitcoin), "tb" (red de prueba / red de prueba 4) o "bcrt" (red de regresión). |
asset_symbol |
String | El símbolo de cotización del activo: "BTC". |
recipient |
String | Es la dirección de destino principal. Para las transacciones de OP_RETURN, es "unaddressable". En el caso de los barridos de consolidación interna (cambio del 100%), esto se resuelve en la primera dirección de cambio. |
spend_amount_scaled |
Largo |
Es el importe neto de la transferencia saliente normalizado a una precisión fija de 9 decimales (unidades de 10-9). Dado que 1 satoshi equivale a 10 unidades de nanocoin (1 sat = 10 unidades, 1 BTC = 109 unidades), se excluyen los importes de cambio internos. En el caso de las transacciones de barrido interno o de cambio del 100%, este valor se evalúa como 0.
|
max_fee_atomic |
Largo | Es el límite de la comisión del minero calculada, normalizada con una precisión de 9 decimales: (∑ Entradas − ∑ Salidas) × 10. |
destination_type |
String | La clasificación de la secuencia de comandos receptora. Valores admitidos: "P2WPKH" (SegWit nativo), "P2TR" (Taproot), "P2PKH" (heredado), "P2SH" (SegWit anidado / hash de secuencia de comandos), "TREASURY_CHANGE" (barrido de cambio interno) o "". |
temporal_validity |
Largo | El campo nLockTime de la transacción. |
outputs |
Set<Record> | Es el conjunto normalizado de todos los resultados de la transacción: [{ address: String, amount_scaled: Long, is_change: Bool }]. |
Conceptos básicos de la política de Bitcoin
Matemática de escalamiento universal de 9 decimales: Los importes en las políticas de Bitcoin usan una precisión normalizada de nanocoins de 9 decimales (1 sat = 10 unidades, 1 BTC = 109 unidades):
Amountscaled = Satoshis × 10 = BTC × 109
0.0005BTC (50,000 satoshis) →500000(50,000 × 10)0.0025BTC (250,000 satoshis) →2500000(250,000 × 10)1.0BTC (100,000,000 satoshis) →1000000000(100,000,000 × 10)
Separación de salidas de cambio: El analizador inspecciona las rutas de derivación BIP-32 (
m/.../1/*) y correlaciona las secuencias de comandos de entrada para identificar automáticamente las salidas de cambio internas. Los importes de cambio se excluyen despend_amount_scaled, lo que garantiza que las políticas de límite de inversión se evalúen estrictamente en función del valor neto de salida transferido a terceros.Regla de destinatario único sin cambio: Para evitar ataques ambiguos de enrutamiento de varios destinatarios, las transacciones que contienen varios destinatarios externos distintos de terceros fallan de forma cerrada (
ErrUnsupportedTx).
Ejemplos de reglas de Cedar
En los siguientes ejemplos, se muestra cómo configurar listas de entidades permitidas, reglas de límite y límites de repetición con Cedar para transacciones de Ethereum y Bitcoin.
Ejemplos de Ethereum
Las siguientes reglas ilustran patrones de políticas comunes para las transacciones de Ethereum y ERC-20.
1. Límite de transferencia directa de ETH
Esta regla permite que Alice transfiera ETH de la cadena base, verificando que el importe de la transferencia escalado no supere 1.0 ETH (1,000,000,000 de unidades de Gwei escaladas).
permit (
principal == User::"alice",
action == Action::"sign_transaction",
resource == Resource::"mpc_operation"
)
when {
context.transaction.operation == "NATIVE_TRANSFER" &&
context.transaction.asset_symbol == "ETH" &&
context.transaction.spend_amount_scaled <= 1000000000
};
2. Regla de lista de tokens ERC-20 permitidos
Esta regla permite transferencias de tokens de USDC de hasta 5,000 USDC. Restringe las transferencias a una dirección de destinatario que se encuentre en una lista de entidades permitidas. Ten en cuenta que, como las cadenas de Cedar distinguen mayúsculas de minúsculas, la dirección del destinatario debe coincidir con el formato EIP-55 que combina mayúsculas y minúsculas.
permit (
principal == User::"alice",
action == Action::"sign_transaction",
resource == Resource::"mpc_operation"
)
when {
context.transaction.operation == "TOKEN_TRANSFER" &&
context.transaction.asset_symbol == "USDC" &&
context.transaction.recipient == "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B" &&
context.transaction.spend_amount_scaled <= 5000000000000
};
3. Resguardos de llamadas de contratos inteligentes y DeFi
Esta regla permite interacciones generales con contratos (como staking o intercambio) sin restricciones de importe, siempre que no sean operaciones de transferencia que impliquen el gasto de activos.
permit (
principal == User::"alice",
action == Action::"sign_transaction",
resource == Resource::"mpc_operation"
)
when {
context.transaction.operation == "CONTRACT_CALL"
};
4. Protección estricta contra la repetición (límite de ID de cadena)
Para evitar ataques de reproducción de transacciones en los que se vuelve a enviar una carga útil firmada para una cadena de testnet en mainnets de producción, puedes limitar el alcance de tu regla a un ID de cadena específico (p.ej., 11155111 para Sepolia).
permit (
principal == User::"alice",
action == Action::"sign_transaction",
resource == Resource::"mpc_operation"
)
when {
context.transaction.chain_id == "11155111"
};
Ejemplos de Bitcoin
Las siguientes reglas ilustran patrones de políticas comunes para las transacciones de PSBT de Bitcoin.
1. Límite de inversión y límite de tarifa de minero
Esta regla permite transferencias directas de Bitcoin (BTC) en las que el importe neto de la transferencia saliente no supere los 0.0025 BTC (250,000 satoshis → 2,500,000 unidades escaladas) y la comisión del minero no supere los 10,000 satoshis (100,000 unidades atómicas).
permit (
principal == User::"alice",
action == Action::"sign_transaction",
resource == Resource::"mpc_operation"
)
when {
context.transaction.operation == "NATIVE_TRANSFER" &&
context.transaction.asset_symbol == "BTC" &&
context.transaction.spend_amount_scaled <= 2500000 &&
context.transaction.max_fee_atomic <= 100000
};
2. Lista de entidades permitidas de direcciones de SegWit (P2WPKH) y Taproot (P2TR)
Esta regla restringe las transferencias de Bitcoin a una dirección de destino aprobada de SegWit o Taproot.
permit (
principal == User::"alice",
action == Action::"sign_transaction",
resource == Resource::"mpc_operation"
)
when {
context.transaction.schema == "bitcoin.transaction.v2" &&
(context.transaction.destination_type == "P2WPKH" || context.transaction.destination_type == "P2TR") &&
context.transaction.recipient == "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh"
};
3. Consolidación de UTXO y barrido de tesorería
Esta regla permite barridos de consolidación de UTXO internos en los que todos los resultados se devuelven a direcciones de cambio internas (destination_type == "TREASURY_CHANGE" y spend_amount_scaled == 0), a la vez que se limita la comisión de consolidación.
permit (
principal == User::"alice",
action == Action::"sign_transaction",
resource == Resource::"mpc_operation"
)
when {
context.transaction.schema == "bitcoin.transaction.v2" &&
context.transaction.destination_type == "TREASURY_CHANGE" &&
context.transaction.spend_amount_scaled == 0 &&
context.transaction.max_fee_atomic <= 50000
};
4. Inspección del conjunto de resultados
Esta regla valida que el conjunto de salidas de la transacción contenga una salida de destino y un importe específicos.
permit (
principal == User::"alice",
action == Action::"sign_transaction",
resource == Resource::"mpc_operation"
)
when {
context.transaction.outputs.contains({
address: "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
amount_scaled: 500000,
is_change: false
})
};
5. Alcance de la red (Mainnet frente a Testnet)
Esta regla limita la autorización a las transacciones de Bitcoin Testnet (tb), lo que evita la ejecución en Bitcoin Mainnet (bc).
permit (
principal == User::"alice",
action == Action::"sign_transaction",
resource == Resource::"mpc_operation"
)
when {
context.transaction.schema == "bitcoin.transaction.v2" &&
context.transaction.chain_id == "tb"
};
6. Anclaje de datos de OP_RETURN
Esta regla permite transacciones de anclaje de datos OP_RETURN no gastables (spend_amount_scaled == 0 y recipient == "unaddressable"), lo que aplica un límite estricto de tarifas.
permit (
principal == User::"alice",
action == Action::"sign_transaction",
resource == Resource::"mpc_operation"
)
when {
context.transaction.operation == "OP_RETURN" &&
context.transaction.recipient == "unaddressable" &&
context.transaction.spend_amount_scaled == 0 &&
context.transaction.max_fee_atomic <= 10000
};
Defensas de seguridad del analizador
Para proteger las operaciones de transacciones en los entornos de producción, Policy Engine analiza las cargas útiles de forma estricta y rechaza las estructuras no válidas en la capa de la puerta de enlace antes de evaluar cualquier regla de Cedar:
- Aplicación de la moneda base con valor cero: El analizador rechaza de forma explícita las operaciones de transferencia de tokens de Ethereum (
TOKEN_TRANSFER) que también intentan agrupar activos de transferencia base que no sean cero. Esto evita que las cargas útiles maliciosas transfieran valores de activos base estándar mientras presentan la transacción como una transferencia de tokens estándar. - Verificación de UTXO y testigo: En el caso de las transacciones de PSBT de Bitcoin, el analizador valida que todas las entradas proporcionen datos de
witness_utxoválidos, lo que evita la falsificación del cálculo de tarifas o la firma no verificada. - Verificación de la secuencia de comandos de salida de cambio: Las salidas de cambio internas deben coincidir con una clave pública de la secuencia de comandos de entrada o con una ruta de cambio BIP-32 conocida (
m/.../1/*). Las cargas útiles que intentan falsificar las salidas de cambio a direcciones de terceros fallan de forma segura. - Aplicación de un único destinatario externo: Las cargas útiles de Bitcoin que contienen varias direcciones de destino externas que no son de cambio fallan de forma cerrada (
ErrUnsupportedTx) para evitar la autorización ambigua de políticas de varios destinatarios. - Protección contra desbordamiento de enteros positivo y negativo: Se rechazan de inmediato los nonces, los tiempos de bloqueo, los límites de gas o tarifas, y los importes que superan los límites de seguridad (
MaxInt64) o producen desbordamientos negativos (como un valor de salida total que supera el valor de entrada total). - Verificación de tarifas faltantes: Las transacciones que no definen las tarifas de minero o los parámetros de gas adecuados fallan y se cierran automáticamente.