From e1fbeca7a14fe80e6038d5b8a0fa726998bbbf99 Mon Sep 17 00:00:00 2001 From: mooncitydev Date: Mon, 30 Mar 2026 23:24:20 +0900 Subject: [PATCH] fix readme program id and whitelist docs; reject zero payment amounts Made-with: Cursor --- README.md | 11 +----- programs/ble-revshare/src/constants.rs | 3 ++ programs/ble-revshare/src/errors.rs | 2 + .../src/instructions/execute_payment.rs | 9 +++-- tests/ble-revshare.ts | 39 +++++++++++++++++++ 5 files changed, 52 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 9469ed9..9b0fcd6 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,7 @@ This program implements a payment distribution system where payments can be spli ### Key Features -- Token whitelist management -- Payment execution with broadcaster revenue sharing (70/30 split) +- Payment execution with a 2% treasury cut; when a broadcaster co-signs, 30% of that cut goes to the broadcaster and 70% to treasury (see `constants.rs`) - Arcium encrypted computation integration - Payment statistics tracking via confidential computations @@ -64,12 +63,6 @@ arcium deploy \ npx ts-node init-comp-def-final.ts ``` -### 4. Whitelist tokens - -```bash -npx ts-node scripts/whitelist-tokens.ts -``` - ## Testing ```bash @@ -105,7 +98,7 @@ yarn test ## Program IDs -- Program ID: `7fvHNYVuZP6EYt68GLUa4kU8f8dCBSaGafL9aDhhtMZN` +- Program ID: `7xeQNUggKc2e5q6AQxsFBLBkXGg2p54kSx11zVainMks` (matches `Anchor.toml` / `declare_id!` in `programs/ble-revshare`) - Arcium Program ID: `Arcj82pX7HxYKLR92qvgZUAd7vGS1k4hQvAFcPATFdEQ` ## License diff --git a/programs/ble-revshare/src/constants.rs b/programs/ble-revshare/src/constants.rs index e9f881b..06393c2 100644 --- a/programs/ble-revshare/src/constants.rs +++ b/programs/ble-revshare/src/constants.rs @@ -3,4 +3,7 @@ use arcium_anchor::prelude::comp_def_offset; pub const COMP_DEF_OFFSET_PAYMENT_STATS: u32 = comp_def_offset("payment_v3"); +pub const TREASURY_CUT_BPS: u64 = 2; +pub const BROADCASTER_SHARE_OF_TREASURY_BPS: u64 = 30; + pub const TREASURY_WALLET: Pubkey = pubkey!("DqyfDvr7yG4d3mtW6AiXgbuVM7GZWqn4RVARFbJxwtFc"); diff --git a/programs/ble-revshare/src/errors.rs b/programs/ble-revshare/src/errors.rs index 6e68128..969572c 100644 --- a/programs/ble-revshare/src/errors.rs +++ b/programs/ble-revshare/src/errors.rs @@ -18,4 +18,6 @@ pub enum ErrorCode { InvalidTreasury, #[msg("Payment payload has expired")] PaymentExpired, + #[msg("Payment amount must be greater than zero")] + InvalidAmount, } diff --git a/programs/ble-revshare/src/instructions/execute_payment.rs b/programs/ble-revshare/src/instructions/execute_payment.rs index c68e7a4..50e3079 100644 --- a/programs/ble-revshare/src/instructions/execute_payment.rs +++ b/programs/ble-revshare/src/instructions/execute_payment.rs @@ -4,7 +4,9 @@ use arcium_anchor::prelude::*; use super::payment_callback::PaymentV3Callback; use crate::{ArciumSignerAccount, ID, ID_CONST}; -use crate::constants::{COMP_DEF_OFFSET_PAYMENT_STATS, TREASURY_WALLET}; +use crate::constants::{ + BROADCASTER_SHARE_OF_TREASURY_BPS, COMP_DEF_OFFSET_PAYMENT_STATS, TREASURY_CUT_BPS, TREASURY_WALLET, +}; use crate::errors::ErrorCode; use crate::events::PaymentEvent; use crate::state::PaymentReceipt; @@ -115,6 +117,7 @@ pub(crate) fn handler( Clock::get()?.unix_timestamp <= expires_at, ErrorCode::PaymentExpired ); + require!(amount > 0, ErrorCode::InvalidAmount); msg!("Payer: {}", ctx.accounts.payer.key()); msg!("Sign PDA: {}", ctx.accounts.sign_pda_account.key()); @@ -146,7 +149,7 @@ pub(crate) fn handler( ); let treasury_total_amount = amount - .checked_mul(2) + .checked_mul(TREASURY_CUT_BPS) .ok_or(ErrorCode::MathOverflow)? / 100; @@ -173,7 +176,7 @@ pub(crate) fn handler( ); broadcaster_share_amount = treasury_total_amount - .checked_mul(30) + .checked_mul(BROADCASTER_SHARE_OF_TREASURY_BPS) .ok_or(ErrorCode::MathOverflow)? / 100; } else if ctx.accounts.broadcaster_token_account.is_some() { diff --git a/tests/ble-revshare.ts b/tests/ble-revshare.ts index 77721f0..e713ed4 100644 --- a/tests/ble-revshare.ts +++ b/tests/ble-revshare.ts @@ -306,6 +306,45 @@ describe("ble-revshare", () => { } }); + test("rejects zero payment amount", async () => { + const computationOffset = new anchor.BN(randomBytes(8), "hex"); + const nonce = BigInt(deserializeLE(randomBytes(16)).toString()); + const paymentId = Buffer.from(randomBytes(32)); + const expiresAt = new anchor.BN(Math.floor(Date.now() / 1000) + PAYLOAD_TTL_SECS); + + try { + await program.methods + .executePayment( + computationOffset, + Array.from(paymentId), + new anchor.BN(0), + Array.from(randomBytes(32)), + new anchor.BN(nonce.toString()), + Array.from(payer.publicKey.toBytes()), + expiresAt + ) + .accountsPartial({ + payer: payer.publicKey, + broadcaster: broadcaster.publicKey, + recipient: recipient.publicKey, + mint, + paymentReceipt: paymentReceipt(paymentId), + payerTokenAccount: senderTokenAccount, + recipientTokenAccount, + treasuryTokenAccount, + broadcasterTokenAccount, + ...arciumAccounts(computationOffset), + }) + .signers([payer, broadcaster]) + .rpc(); + + assert.fail("Expected InvalidAmount error"); + } catch (err) { + const error = ensureError(err); + assert.match(error.message, /InvalidAmount/); + } + }); + test("rejects expired payment payload", async () => { const computationOffset = new anchor.BN(randomBytes(8), "hex"); const nonce = BigInt(deserializeLE(randomBytes(16)).toString());