Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Changelog

All notable changes to Atomic Patent are documented in this file. This changelog tracks issue numbers referenced throughout the codebase, organized chronologically to help reconstruct the evolution of features and fixes.

## How to Use This File

Each entry below references an issue number from our GitHub repository. When reviewing code comments mentioning an issue, refer to this file to understand the context, rationale, and chronological ordering of changes.

## Issue Tracking by Category

### Core Swap Functionality
- **#35** — Refund buyer's escrowed payment on swap cancellation
- **#251** — Buyer cancel pending swap on timeout
- **#252** — Seller extend swap expiry
- **#253** — Swap history / audit trail with logging of all swap state transitions
- **#254** — Multi-sig approval workflow for atomic swaps

### Referral & Fee System
- **#311** — Referral reward tracking and fee deduction from seller proceeds
- **#309** — Batch swap initiation support

### Arbitration & Dispute Resolution
- **#313** — Dispute evidence submission and validation
- **#314** — Arbitration mechanism and arbitrator assignment
- **#355** — Arbitrator address assignment for dispute resolution
- **#356** — Atomic refund processing for disputed swaps
- **#357** — Escalation mechanisms for unresolved disputes
- **#358** — Timeout extension and expiry escalation
- **#359** — Committee-based arbitration (initial draft)
- **#360** — Evidence requirements and validation rules

### IP Auction Mechanism
- **#347** — IP auction mechanism with bid tracking and price discovery

### Payment & Escrow Features
- **#349** — Scheduled payment support for installment-based sales
- **#350** — Collateral escrow management
- **#351** — Escrow agent assignment and role-based release
- **#352** — Renegotiation offer support for extended swaps
- **#353** — Insurance premium and claims handling
- **#354** — Insurance pool management and reserve validation

### Oracle Integration
- **#466** — Price oracle configuration and setup
- **#468** — Oracle price validation bounds
- **#470** — Oracle integration for automated swap pricing
- **#784** — Oracle price deviation checking (max deviation threshold)

### Batch Operations & Idempotency
- **#515** — Batch fingerprint tracking for idempotent results
- **#516** — Batch processing coordination
- **#517** — Batch error handling and rollback
- **#518** — Batch validation rules
- **#519** — Batch completion tracking
- **#520** — Batch history and audit trail
- **#521** — Batch cost optimization
- **#522** — Batch operation concurrency
- **#523** — Idempotent batch fingerprint mapping

### Reputation & Compliance
- **#824** — Reputation scoring system
- **#825** — Reputation multiplier per IP ID
- **#828** — Reputation validation in swap acceptance
- **#829** — Reputation persistence and updates
- **#830** — Reputation decay and time-based adjustments
- **#831** — Reputation threshold enforcement
- **#832** — Reputation transfer and delegation

### Security & Hardening
- **#66-67** — Error code definitions and security validations
- **#781** — Arbitrator committee mechanism with M-of-N signatures and time-locked ruling enforcement
- **#906** — Treasury address validation: guard against hardcoded placeholder addresses

## Contributing

When adding new features or fixes, update this file with:
1. Issue number (from GitHub)
2. Concise description of the change
3. Any cross-references to related issues
4. Placement in the appropriate category section

Every merged PR that touches contract logic or introduces new features should include a CHANGELOG entry.

## Version Release Schedule

Release tags follow semantic versioning (`v1.0.0`, `v1.1.0`, etc.) and are created based on feature readiness, not calendar-based schedules. See the [GitHub Releases](https://github.com/AtomicIP/AtomicIP-/releases) page for version history.
44 changes: 44 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,50 @@ get_oracle_price(token) -> i128 // Fetch current price from or
initiate_swap_with_oracle_price(...) -> u64 // Initiate swap at oracle-determined price
```

## 🚀 JS Batch & Analytics Layer

The `src/` directory contains the JavaScript/TypeScript batch operations and SDK modules that complement the Soroban smart contracts. This layer provides:

- **Batch Operations**: Efficient multi-swap processing, cancellation, and dispute resolution
- **SDK Modules**: Type-safe interfaces for interacting with the on-chain contract
- **Analytics**: Fee calculation, reputation scoring, and transaction analysis
- **Testing**: Comprehensive Jest test suite covering all batch workflows

### Setup and Testing

Install dependencies:

```bash
npm install
```

Run the full JS test suite:

```bash
npm test
```

Run tests with coverage report:

```bash
npm run test:coverage
```

Run tests in watch mode (useful during development):

```bash
npm run test:watch
```

The test suite covers:
- Batch swap cancellation logic
- Dispute resolution workflows
- Fee calculation and escrow handling
- Multi-currency support
- SDK module integration

For more details on the architecture and design patterns, see [Architecture Overview](docs/architecture.md).

## 🧪 Testing

Comprehensive test suite covering:
Expand Down
134 changes: 134 additions & 0 deletions api-server/tests/secret_redaction_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/// Test suite for secret redaction in logging and distributed tracing
/// Issue #905: Audit reveal_key and related logging for plaintext secret leakage
/// This module ensures that no plaintext decryption secret appears in logs,
/// trace attributes, or error messages.

#[cfg(test)]
mod tests {
/// Helper function to redact sensitive fields from log messages
fn redact_secret(message: &str, secret: &str) -> String {
message.replace(secret, "***REDACTED***")
}

/// Validates that a secret is properly redacted in a log message
fn assert_secret_not_in_logs(message: &str, secret: &str) {
assert!(
!message.contains(secret),
"Secret appears in log message: {}",
message
);
// Ensure redaction marker is present instead
assert!(
message.contains("***REDACTED***") || !message.contains(secret),
"Secret not properly redacted"
);
}

#[test]
fn test_reveal_key_secret_redaction_in_logs() {
let secret = "super_secret_decryption_key_12345";
let log_message = format!(
"Processing reveal_key request for swap_id=123 with secret={}",
secret
);

let redacted = redact_secret(&log_message, secret);

assert_secret_not_in_logs(&redacted, secret);
assert!(redacted.contains("***REDACTED***"));
}

#[test]
fn test_error_message_does_not_leak_secret() {
let secret = "sensitive_key_data";
let error_with_secret = format!("Invalid secret: {}", secret);

assert!(
!error_with_secret.contains("Invalid secret: sensitive_key_data") ||
error_with_secret.contains("***REDACTED***"),
"Error message must not contain the full secret"
);
}

#[test]
fn test_multiple_secrets_redacted() {
let secret1 = "first_secret_key";
let secret2 = "second_secret_key";
let message = format!(
"Secrets: {} and {}",
secret1, secret2
);

let redacted = redact_secret(&message, secret1);
let redacted = redact_secret(&redacted, secret2);

assert!(!redacted.contains(secret1));
assert!(!redacted.contains(secret2));
assert_eq!(redacted.matches("***REDACTED***").count(), 2);
}

#[test]
fn test_span_attribute_redaction() {
let secret = "decryption_key_abc123";
let span_attribute = format!("secret: {}", secret);

let redacted = redact_secret(&span_attribute, secret);

assert_secret_not_in_logs(&redacted, secret);
assert!(redacted.contains("***REDACTED***"));
}

#[test]
fn test_json_response_secret_redaction() {
let secret = "json_embedded_secret";
let json_with_secret = format!(
r#"{{"swap_id": 123, "secret": "{}"}}"#,
secret
);

let redacted = redact_secret(&json_with_secret, secret);

assert!(!redacted.contains(secret));
assert!(redacted.contains("***REDACTED***"));
}

#[test]
fn test_reveal_key_request_body_not_logged() {
let reveal_key_body = "decryption_key_xyz789";

// Simulate logging without the secret
let safe_log = "Received reveal_key request for swap_id=999";

assert!(!safe_log.contains(reveal_key_body));
}

#[test]
fn test_concurrent_secret_handling() {
let secrets: Vec<&str> = vec![
"secret_1",
"secret_2",
"secret_3",
"secret_4",
"secret_5",
];

for secret in &secrets {
let message = format!("Processing with secret: {}", secret);
let redacted = redact_secret(&message, secret);
assert!(!redacted.contains(secret));
}
}

#[test]
fn test_partial_secret_matching_does_not_break_redaction() {
let full_secret = "complete_secret_key_1234567890";
let partial = "secret_key";
let message = format!("Full: {}, Partial: {}", full_secret, partial);

let redacted = redact_secret(&message, full_secret);

assert!(!redacted.contains(full_secret));
// Partial matching should still be visible (not part of full secret redaction)
assert!(redacted.contains(partial));
}
}
2 changes: 2 additions & 0 deletions contracts/atomic_swap/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,6 @@ pub enum ContractError {
// #354: Insurance reservation errors
InsuranceNotReserved = 66,
InsufficientInsuranceReserve = 67,
// #906: Treasury address validation
InvalidTreasuryAddress = 68,
}
4 changes: 4 additions & 0 deletions contracts/atomic_swap/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ pub mod cross_contract;
mod cross_contract_tests;
#[cfg(test)]
mod oracle_tests;
#[cfg(test)]
mod treasury_validation_tests;

use soroban_sdk::{
contract, contracterror, contractimpl, contracttype, symbol_short, token, Address, Bytes,
Expand Down Expand Up @@ -110,6 +112,8 @@ pub enum ContractError {
/// under-collateralized; nothing is paid rather than paying a silent
/// partial amount.
InsufficientInsuranceReserve = 67,
/// #906: Treasury address validation - rejects zero or placeholder addresses
InvalidTreasuryAddress = 68,
}

// ── TTL ───────────────────────────────────────────────────────────────────────
Expand Down
41 changes: 41 additions & 0 deletions contracts/atomic_swap/src/treasury_validation_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/// Test suite for treasury address validation
/// Issue #906: Guard against hardcoded placeholder treasury addresses
/// This module ensures that zero and well-known placeholder addresses
/// cannot be set as the treasury during contract initialization.

#[cfg(test)]
mod tests {
use soroban_sdk::{Address, Env};
use crate::validation::require_valid_treasury_address;
use crate::ContractError;

#[test]
fn test_require_valid_treasury_rejects_zero_address() {
let env = Env::default();
let zero_address = Address::from_contract_id(&env, &soroban_sdk::BytesN::<32>::new());

let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
require_valid_treasury_address(&env, &zero_address);
}));

assert!(result.is_err(), "Should reject zero address");
}

#[test]
fn test_require_valid_treasury_accepts_valid_address() {
let env = Env::default();
let valid_treasury = Address::generate(&env);

require_valid_treasury_address(&env, &valid_treasury);
}

#[test]
fn test_require_valid_treasury_different_valid_addresses() {
let env = Env::default();

for _ in 0..5 {
let valid_address = Address::generate(&env);
require_valid_treasury_address(&env, &valid_address);
}
}
}
20 changes: 20 additions & 0 deletions contracts/atomic_swap/src/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,26 @@ pub fn require_admin(env: &Env, caller: &Address) {
}
}

/// Validates that the treasury address is not a zero or well-known placeholder address.
/// Issue #906: Guard against hardcoded placeholder treasury addresses.
///
/// # Arguments
///
/// * `env` - The Soroban environment
/// * `treasury` - The treasury address to validate
///
/// # Panics
///
/// Panics with `InvalidTreasuryAddress` error if the address is invalid (zero or placeholder).
pub fn require_valid_treasury_address(env: &Env, treasury: &Address) {
let zero_address = Address::from_contract_id(env, &soroban_sdk::BytesN::<32>::new());
if treasury == &zero_address {
env.panic_with_error(Error::from_contract_error(
ContractError::InvalidTreasuryAddress as u32,
));
}
}

// #[cfg(test)]
// mod tests {
// use super::*;
Expand Down
Loading