Menulis aturan Cedar

Halaman ini menjelaskan cara menulis aturan kebijakan Cedar untuk memvalidasi transaksi di Multi-Party Compute (MPC) Policy Engine.

Policy Engine mendekode payload transaksi yang masuk di dalam Trusted Execution Environment (TEE) yang aman dan memproyeksikan atribut intent transaksi ke konteks evaluasi Cedar.

Struktur aturan Cedar

Saat menulis aturan Cedar untuk Policy Engine, Anda menentukan aturan menggunakan kumpulan kondisi bertingkat:

  • Akun utama: Identitas logis pemohon transaksi (penginisiasi transaksi) dalam ruang kerja Multi-Party Compute (misalnya, User::"alice"), bukan Google Cloud identitas IAM (pengguna atau akun layanan) yang memanggil API.
  • Tindakan: Tindakan kriptografis yang diminta (misalnya, Action::"sign_transaction").
  • Resource: Aset target atau class operasi yang sedang dioperasikan (misalnya, Resource::"mpc_operation").
  • Context: Parameter dan metadata transaksi yang diuraikan (dapat diakses di bagian context.transaction).

Referensi skema transaksi Ethereum

Framework agnostik protokol memungkinkan aturan untuk mengabaikan pemeriksaan skema agar tetap dapat digunakan kembali di berbagai jaringan blockchain. Namun, untuk secara eksplisit membatasi aturan ke payload transaksi Ethereum, periksa: context.transaction.schema == "ethereum.transaction.v2".

Atribut berikut didukung di dalam data context.transaction:

Atribut Jenis Deskripsi
schema String Skema format. Untuk transaksi Ethereum, nilai ini selalu "ethereum.transaction.v2".
operation String Jenis operasi transaksi. Nilai yang didukung:
  • "NATIVE_TRANSFER": Transfer langsung mata uang blockchain utama (seperti ETH).
  • "TOKEN_TRANSFER": Transfer token ERC-20 (seperti USDC, USDT, DAI).
  • "TOKEN_APPROVE": Persetujuan token ERC-20 untuk mengizinkan kontrak membelanjakan token.
  • "CONTRACT_CALL": Interaksi smart contract generik (seperti staking atau swapping).
chain_id String ID jaringan blockchain target (misalnya, "1" untuk Mainnet Ethereum atau "11155111" untuk Testnet Sepolia).
asset_symbol String Simbol ticker token yang ditransfer (misalnya, "ETH", "USDC", "DAI", atau "WBTC"). Token yang tidak terdaftar akan menampilkan "UNKNOWN".
asset_contract_address String Alamat smart contract token ERC-20 (dalam format checksum EIP-55 huruf besar/kecil). Ini di-resolve ke string kosong ("") untuk transfer ETH standar.
recipient String Alamat penerima tujuan (dalam format checksum EIP-55 huruf besar/kecil). Untuk persetujuan token, ini mewakili alamat pembelanja.
spend_amount_scaled Long Jumlah transfer token dinormalisasi ke presisi 9 desimal tetap (format nanocoin), sehingga tidak perlu melacak desimal token yang bervariasi (seperti 6, 8, atau 18) saat menulis aturan.

Cara menghitung: Kalikan jumlah aset yang dapat dibaca manusia (misalnya, 1,5 ETH atau 5.000 USDC) dengan 1.000.000.000 (109) untuk mendapatkan nilai aturan Anda:
  • 0.1 ETH → 100000000 (0,1 × 109)
  • 1.0 aset apa pun → 1000000000 (1,0 × 109)
  • 5,000 USDC → 5000000000000 (5.000 × 109)
spend_amount_dust Long Sisa jumlah transaksi yang berada di bawah nilai minimum presisi 9 desimal. Untuk aset dengan lebih dari 9 desimal (seperti ETH, yang memiliki 18 desimal), kolom ini berisi nilai sub-Gwei yang tidak diskalakan (Wei yang tersisa). Nilai ini selalu 0 untuk aset dengan 9 desimal atau kurang (seperti USDC atau WBTC).
max_fee_atomic Long Batas biaya transaksi total maksimum (diskalakan sebesar 109, yang mewakili Gwei).
gas_limit Long Jumlah gas maksimum yang dialokasikan untuk eksekusi transaksi.
destination_type String Klasifikasi alamat penerima. Nilai yang didukung: "EOA" (wallet pengguna standar), "CONTRACT" (smart contract), atau "INTERNAL_TREASURY" (vault internal).
temporal_validity Long Nonce akun transaksi (digunakan untuk mencegah serangan replay transaksi).

Referensi skema transaksi Bitcoin

Untuk secara eksplisit membatasi aturan pada payload transaksi PSBT Bitcoin BIP 174, periksa: context.transaction.schema == "bitcoin.transaction.v2".

Atribut berikut didukung di dalam data context.transaction:

Atribut Jenis Deskripsi
schema String Skema format. Untuk transaksi Bitcoin, nilai ini selalu "bitcoin.transaction.v2".
operation String Jenis operasi transaksi. Nilai yang didukung:
  • "NATIVE_TRANSFER": Transfer langsung Bitcoin (BTC).
  • "OP_RETURN": Output data null / penautan data yang tidak dapat dibelanjakan.
chain_id String Bagian yang Dapat Dibaca Manusia (HRP) Bech32 jaringan target: "bc" (Mainnet Bitcoin), "tb" (Testnet / Testnet4), atau "bcrt" (Regtest).
asset_symbol String Simbol ticker aset: "BTC".
recipient String Alamat tujuan utama. Untuk transaksi OP_RETURN, nilainya adalah "unaddressable". Untuk pembersihan konsolidasi internal (perubahan 100%), ini akan di-resolve ke alamat perubahan pertama.
spend_amount_scaled Long Jumlah transfer keluar bersih yang dinormalisasi ke presisi 9 desimal tetap (unit 10-9). Karena 1 satoshi sama dengan 10 unit nanocoin (1 sat = 10 unit, 1 BTC = 109 unit), jumlah kembalian internal tidak disertakan. Untuk transaksi sweep internal / perubahan 100%, nilai ini dievaluasi menjadi 0.
max_fee_atomic Long Batas biaya penambang yang dihitung dinormalisasi ke presisi 9 desimal: (∑ Input − ∑ Output) × 10.
destination_type String Klasifikasi skrip penerima. Nilai yang didukung: "P2WPKH" (Native SegWit), "P2TR" (Taproot), "P2PKH" (Legacy), "P2SH" (Nested SegWit / Script Hash), "TREASURY_CHANGE" (internal change sweep), atau "".
temporal_validity Long Kolom nLockTime transaksi.
outputs Set<Record> Set yang dinormalisasi dari semua output transaksi: [{ address: String, amount_scaled: Long, is_change: Bool }].

Konsep kebijakan inti Bitcoin

  1. Matematika Penskalaan 9 Desimal Universal: Jumlah dalam kebijakan Bitcoin menggunakan presisi nanocoin 9 desimal yang dinormalisasi (1 sat = 10 unit, 1 BTC = 109 unit):

    Jumlahdiskalakan = Satoshis × 10 = BTC × 109

    • 0.0005 BTC (50.000 satoshi) → 500000 (50.000 × 10)
    • 0.0025 BTC (250.000 satoshi) → 2500000 (250.000 × 10)
    • 1.0 BTC (100.000.000 satoshi) → 1000000000 (100.000.000 × 10)
  2. Pemisahan Output Perubahan: Parser memeriksa jalur derivasi BIP-32 (m/.../1/*) dan menghubungkan skrip input untuk mengidentifikasi output perubahan internal secara otomatis. Jumlah kembalian tidak termasuk dalam spend_amount_scaled, sehingga memastikan bahwa kebijakan batas pembelanjaan dievaluasi secara ketat terhadap nilai keluar bersih yang ditransfer ke pihak ketiga.

  3. Aturan Penerima Tunggal Non-Perubahan: Untuk mencegah serangan perutean multi-penerima yang ambigu, transaksi yang berisi beberapa penerima pihak ketiga eksternal yang berbeda akan gagal ditutup (ErrUnsupportedTx).


Contoh aturan Cedar

Contoh berikut menunjukkan cara mengonfigurasi daftar yang diizinkan, aturan batas, dan batas replay menggunakan Cedar untuk transaksi Ethereum dan Bitcoin.

Contoh Ethereum

Aturan berikut mengilustrasikan pola kebijakan umum untuk transaksi Ethereum dan ERC-20.

1. Batas transfer ETH langsung

Aturan ini mengizinkan Alice mentransfer ETH rantai dasar, dengan memeriksa bahwa jumlah transfer yang diskalakan tidak melebihi 1,0 ETH (1.000.000.000 unit Gwei yang diskalakan).

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. Aturan daftar yang diizinkan untuk token ERC-20

Aturan ini mengizinkan transfer token USDC hingga 5.000 USDC. Tindakan ini membatasi transfer ke alamat penerima dalam daftar yang diizinkan. Perhatikan bahwa karena string Cedar peka huruf besar/kecil, alamat penerima harus cocok dengan format EIP-55 yang menggunakan huruf besar dan kecil.

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. Fallback panggilan smart contract dan DeFi

Aturan ini mengizinkan interaksi kontrak umum (seperti staking atau penukaran) tanpa batasan jumlah, asalkan bukan operasi transfer pengeluaran aset.

permit (
    principal == User::"alice",
    action == Action::"sign_transaction",
    resource == Resource::"mpc_operation"
)
when {
    context.transaction.operation == "CONTRACT_CALL"
};

4. Perlindungan replay yang ketat (batas ID Rantai)

Untuk mencegah serangan replay transaksi, yaitu payload yang ditandatangani untuk rantai testnet dikirim ulang di mainnet produksi, Anda dapat mencakupkan aturan ke ID Rantai tertentu (misalnya, 11155111 untuk Sepolia).

permit (
    principal == User::"alice",
    action == Action::"sign_transaction",
    resource == Resource::"mpc_operation"
)
when {
    context.transaction.chain_id == "11155111"
};

Contoh Bitcoin

Aturan berikut mengilustrasikan pola kebijakan umum untuk transaksi PSBT Bitcoin.

1. Batas pembelanjaan dan batas biaya penambang

Aturan ini mengizinkan transfer Bitcoin (BTC) langsung dengan jumlah transfer keluar bersih tidak melebihi 0,0025 BTC (250.000 satoshi → 2.500.000 unit berskala) dan biaya penambang tidak melebihi 10.000 satoshi (100.000 unit atom).

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. Daftar yang diizinkan untuk alamat SegWit (P2WPKH) dan Taproot (P2TR)

Aturan ini membatasi transfer Bitcoin ke alamat tujuan SegWit atau Taproot yang disetujui.

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. Konsolidasi UTXO dan treasury sweep

Aturan ini mengizinkan pembersihan konsolidasi UTXO internal, dengan semua output dikembalikan ke alamat kembalian internal (destination_type == "TREASURY_CHANGE" dan spend_amount_scaled == 0), sekaligus membatasi biaya konsolidasi.

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. Pemeriksaan set output

Aturan ini memvalidasi bahwa set output transaksi berisi output dan jumlah tujuan tertentu.

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. Cakupan jaringan (Mainnet versus Testnet)

Aturan ini membatasi otorisasi untuk transaksi Bitcoin Testnet (tb), sehingga mencegah eksekusi di 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. Penambatan data OP_RETURN

Aturan ini mengizinkan transaksi penautan data OP_RETURN yang tidak dapat dibelanjakan (spend_amount_scaled == 0 dan recipient == "unaddressable"), dengan menerapkan batas biaya yang ketat.

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

Pertahanan keamanan parser

Untuk mengamankan operasi transaksi di lingkungan produksi, Policy Engine mengurai payload secara ketat dan menolak struktur yang tidak valid di lapisan gateway sebelum mengevaluasi aturan Cedar apa pun:

  • Penerapan mata uang dasar bernilai nol: Parser secara eksplisit menolak operasi transfer token Ethereum (TOKEN_TRANSFER) yang juga mencoba menggabungkan aset transfer dasar yang tidak bernilai nol. Hal ini mencegah payload berbahaya mentransfer nilai aset dasar standar sekaligus menampilkan transaksi sebagai transfer token standar.
  • Verifikasi UTXO dan Witness: Untuk transaksi PSBT Bitcoin, parser memvalidasi bahwa semua input menyediakan data witness_utxo yang valid, sehingga mencegah spoofing penghitungan biaya atau penandatanganan yang tidak diverifikasi.
  • Verifikasi Skrip Output Perubahan: Output perubahan internal harus cocok dengan pubkey skrip input atau jalur perubahan BIP-32 yang diketahui (m/.../1/*). Payload yang mencoba memalsukan output perubahan ke alamat pihak ketiga akan gagal ditutup.
  • Penerapan Penerima Eksternal Tunggal: Payload Bitcoin yang berisi beberapa alamat tujuan non-perubahan eksternal akan gagal ditutup (ErrUnsupportedTx) untuk mencegah otorisasi kebijakan multi-penerima yang ambigu.
  • Perlindungan Integer Overflow dan Underflow: Nonce, locktime, batas gas atau biaya, dan jumlah yang melebihi batas keamanan (MaxInt64) atau menghasilkan underflow (seperti total nilai output yang melebihi total nilai input) akan langsung ditolak.
  • Tidak Ada Verifikasi Biaya: Transaksi yang gagal menentukan biaya penambang atau parameter gas yang tepat akan otomatis gagal ditutup.