Menjadi arbiter OpenFiat
Arbiter memutus sengketa dengan OPEN mereka sendiri dipertaruhkan, bukan reputasi. Ini menelusuri bond, menemukan sebuah kasus, dan memberikan suara commit-lalu-reveal yang benar-benar membayar.
Yang Anda butuhkan
- Sebuah dompet Solana dengan setidaknya 10.000 OPEN — min_stake_arbitrator dari konfigurasi staking yang di-deploy, yang dapat diubah tata kelola — bond ia lewat halaman Stake di openfiat-app, atau lewat instruksi di bawah jika Anda membangun klien Anda sendiri
- Sebuah dompet yang dapat menandatangani pesan, yang dilakukan setiap dompet Solana yang relevan — halaman Arbitrate di openfiat-app menjalankan seluruh kasus di browser, dan SDK tersedia jika Anda lebih suka memprogram
- Akses jaringan ke endpoint JSON-RPC setidaknya satu node OpenFiat, milik Anda atau yang publik
Menangani sebuah kasus
Kerjakan langkah-langkah ini secara berurutan, satu kasus setiap kali. Tiap langkah membawa perintah atau kode yang dibutuhkannya.
- 01
Bond OPEN untuk membuka kunci pool arbitrase
Arbiter harus men-stake sebelum dapat melihat bukti satu kasus — itulah yang membuat menyuap salah satunya sia-sia (Anda tak tahu kasus mana yang harus dibidik) dan memberi jaringan sesuatu untuk di-slash jika Anda memilih melawan konsensus terungkap. Konfigurasi devnet yang di-deploy menetapkan minimum arbiter di 10.000 OPEN, sepuluh kali 1.000 yang disetor setiap peran lain.
stake.tsimport { PublicKey, Transaction } from "@solana/web3.js"; import { getAssociatedTokenAddressSync, TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; import { onchain } from "@openfiat/sdk"; // Role.Arbitrator = 1 — same instruction pair openfiat-app's Stake page // submits when you connect a wallet and bond there directly. const from = getAssociatedTokenAddressSync(mint, owner, false, TOKEN_2022_PROGRAM_ID); const amount = 10_000n * 1_000_000_000n; // OPEN has 9 decimals (OFS-4100 §1) const instructions = [ onchain.staking.initializeStakeAccountIx(owner, onchain.Role.Arbitrator), onchain.staking.stakeIx(owner, mint, onchain.Role.Arbitrator, from, amount), ]; const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash(); const tx = new Transaction({ feePayer: owner, blockhash, lastValidBlockHeight }).add(...instructions); const { signature } = await wallet.signAndSendTransaction(tx); - 02
Temukan sebuah kasus terbuka
Arbiter memilih sengketa mana yang dikerjakan — tak ada yang menugaskan satu kepada Anda. Kueri node mana pun untuk kasus yang belum mencapai jumlah arbiter yang diwajibkan.
shell# Any node will do — arbitrators pick a case, nobody assigns one. curl -s -X POST http://localhost:7080/rpc -H 'content-type: application/json' \ -d '{"jsonrpc":"2.0","id":1,"method":"getDisputes","params":{}}' # Filter the result for status: "Open" and arbitrators.length < required_arbitrators - 03
Bergabung sebelum dapat melihat bukti
Bergabung adalah yang membuka kunci sebuah kasus bagi Anda: pengajuan milik pembeli dan penjual sendiri, konfirmasi pembayaran, dan log pesan transaksi mereka. Begitu sebuah kasus memiliki jumlah arbiter lengkapnya, ia terkunci dan fase commit dimulai.
join.rsuse openfiat_disputes::events::ArbitratorJoin; use openfiat_sdk::wallet::Keypair; use openfiat_sdk::{Client, ClientConfig}; // Joining is what unlocks the case's evidence for you — buyer/seller // submissions and the trade's own message log become visible once you're // in `dispute.arbitrators`. let client = Client::new(ClientConfig { endpoint: node_url, ..Default::default() }); client .send_arbitrator_join( ArbitratorJoin { dispute_id: dispute.id.clone(), arbitrator: peer_id(&keypair), arbitrator_public_key: keypair.public_key(), timestamp: Timestamp::now(), }, &keypair, ) .await?; - 04
Komitkan suara Anda — dua kali
Dua pemungutan suara commit-reveal berjalan berdampingan: satu off-chain yang tercatat di jejak audit dan reputasi milik kasus itu sendiri, dan satu on-chain terhadap akun DisputeCase milik openfiat-escrow yang benar-benar memutuskan hasil yang dibobot stake. Gunakan keputusan dan salt yang sama untuk keduanya — tetapi enum khusus tiap sisi, bukan angka yang sama: Invalid off-chain adalah 2, InvalidDispute on-chain adalah 3, karena MutualSettlement menempati 2 on-chain. Hash byte yang salah dan Anda berkomitmen pada sesuatu yang tak pernah dapat Anda ungkap, yang persis membuat seorang arbiter di-slash.
commit.rs + commit.ts// Off-chain (marketplace record + reputation) — Rust SDK let secret: [u8; 32] = rand::random(); let commitment = openfiat_disputes::commitment::compute(vote, &secret); // sha256(vote || secret) client.send_vote_commit(VoteCommit { dispute_id, arbitrator: peer_id(&keypair), commitment, timestamp: Timestamp::now() }, &keypair).await?; // keep `secret` — you need it again at reveal, and it must never be guessable before then // On-chain (the stake-weighted vote that actually pays out) — TypeScript SDK import { onchain } from "@openfiat/sdk"; import { createHash } from "node:crypto"; // onchain.DisputeOutcome, NOT the off-chain Vote byte: the two enums // diverge from Invalid onwards (see this file's header). Hash the wrong // one and the commitment can never be opened. const commitment = createHash("sha256").update(Buffer.from([onchain.DisputeOutcome.BuyerWins])).update(salt).digest(); const ix = onchain.escrow.commitDisputeVoteIx(arbitrator, reservationId, commitment); - 05
Ungkap begitu jendelanya terbuka
Ungkap hasil dan salt Anda di kedua tempat begitu jendela commit tertutup. On-chain, di sinilah pula suara Anda memperoleh bobot sejatinya: instruksi reveal membaca akun stake peran Arbitrator Anda secara langsung, jadi dompet tanpa stake arbiter tak dapat memberikan yang valid.
reveal.rs + reveal.ts// Off-chain — Rust SDK client.send_vote_reveal(VoteReveal { dispute_id, arbitrator: peer_id(&keypair), vote, secret, timestamp: Timestamp::now() }, &keypair).await?; // On-chain — reads your Arbitrator StakeAccount directly (no CPI) to weight this vote import { onchain } from "@openfiat/sdk"; const [arbitratorStake] = onchain.staking.stakeAccountPda(arbitrator, onchain.Role.Arbitrator); const ix = onchain.escrow.revealDisputeVoteIx( arbitrator, reservationId, onchain.DisputeOutcome.BuyerWins, salt, arbitratorStake, ); - 06
Hasilnya mengeksekusi dirinya sendiri
Begitu tiap arbiter mengungkap, atau jendela reveal tertutup, siapa pun — Anda, pembeli, penjual, atau bot yang tak terkait — dapat memanggil execute_dispute_outcome. Ia hanya menghitung suara yang sudah tercatat on-chain. Desainnya lalu membayar mayoritas sebagian biaya kasus dan menyita sebagian stake dari yang mengungkap melawannya — tetapi baik imbalan maupun penalti belum diimplementasikan, jadi hari ini penghitungan menggerakkan dana trader dan tak lebih.
resolve.tsimport { onchain } from "@openfiat/sdk"; // Permissionless — it only tallies votes the reveal step above already // recorded on-chain, so anyone (the buyer, the seller, either arbitrator, // or an unrelated crank bot) can call it once the reveal window closes. const ix = onchain.escrow.executeDisputeOutcomeIx(mint, seller, reservationId, destinations);