Skip to content
Closed
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
28 changes: 28 additions & 0 deletions .github/workflows/manki.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Manki Review

on:
pull_request:
types: [opened, synchronize]
issue_comment:
types: [created, edited]
pull_request_review:
types: [submitted]

permissions:
contents: read
pull-requests: write
issues: write
id-token: write

concurrency:
group: manki-${{ github.event_name }}-${{ github.event.pull_request.number || github.event.issue.number || github.run_id }}
cancel-in-progress: false

jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: xdustinface/manki@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
18 changes: 18 additions & 0 deletions .manki.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Manki — AI Code Review Configuration
# https://github.com/xdustinface/manki

auto_review: true
auto_approve: true

exclude_paths:
- "*.lock"
- "fuzz/**"

instructions: |
This is a Rust implementation of the Dash cryptocurrency protocol.
Pay special attention to:
- Consensus-critical code paths — changes here can cause chain splits
- FFI safety for C/Swift bindings in dash-spv-* crates
- Proper error handling — prefer Result over unwrap/expect in library code
- DIP (Dash Improvement Proposal) compliance for protocol changes
- Memory safety in hash/crypto implementations
4 changes: 2 additions & 2 deletions key-wallet-ffi/FFI_API.md
Original file line number Diff line number Diff line change
Expand Up @@ -852,7 +852,7 @@ Get the parent wallet ID of a managed account Note: ManagedAccount doesn't stor
#### `managed_wallet_check_transaction`

```c
managed_wallet_check_transaction(managed_wallet: *mut FFIManagedWalletInfo, wallet: *mut FFIWallet, tx_bytes: *const u8, tx_len: usize, context_type: FFITransactionContext, block_height: c_uint, block_hash: *const u8, // 32 bytes if not null timestamp: u64, update_state: bool, result_out: *mut FFITransactionCheckResult, error: *mut FFIError,) -> bool
managed_wallet_check_transaction(managed_wallet: *mut FFIManagedWalletInfo, wallet: *mut FFIWallet, tx_bytes: *const u8, tx_len: usize, context_type: FFITransactionContext, block_info: FFIBlockInfo, update_state: bool, result_out: *mut FFITransactionCheckResult, error: *mut FFIError,) -> bool
```

**Description:**
Expand Down Expand Up @@ -1300,7 +1300,7 @@ Build and sign a transaction using the wallet's managed info This is the recomm
#### `wallet_check_transaction`

```c
wallet_check_transaction(wallet: *mut FFIWallet, tx_bytes: *const u8, tx_len: usize, context_type: FFITransactionContext, block_height: u32, block_hash: *const u8, // 32 bytes if not null timestamp: u64, update_state: bool, result_out: *mut FFITransactionCheckResult, error: *mut FFIError,) -> bool
wallet_check_transaction(wallet: *mut FFIWallet, tx_bytes: *const u8, tx_len: usize, context_type: FFITransactionContext, block_info: FFIBlockInfo, update_state: bool, result_out: *mut FFITransactionCheckResult, error: *mut FFIError,) -> bool
```

**Description:**
Expand Down
24 changes: 5 additions & 19 deletions key-wallet-ffi/src/managed_account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use dashcore::hashes::Hash;

use crate::address_pool::{FFIAddressPool, FFIAddressPoolType};
use crate::error::{FFIError, FFIErrorCode};
use crate::types::FFIAccountType;
use crate::types::{FFIAccountType, FFITransactionContextDetails};
use crate::wallet_manager::FFIWalletManager;
use crate::FFINetwork;
use key_wallet::account::account_collection::{DashpayAccountKey, PlatformPaymentAccountKey};
Expand Down Expand Up @@ -666,12 +666,8 @@ pub struct FFITransactionRecord {
pub txid: [u8; 32],
/// Net amount for this account (positive = received, negative = sent)
pub net_amount: i64,
/// Block height if confirmed, 0 if unconfirmed
pub height: u32,
/// Block hash if confirmed (32 bytes), all zeros if unconfirmed
pub block_hash: [u8; 32],
/// Unix timestamp
pub timestamp: u64,
/// Transaction context (mempool, instant-send, in-block, chain-locked + block info)
pub context: FFITransactionContextDetails,
/// Fee if known, 0 if unknown
pub fee: u64,
/// Whether this is our transaction
Expand Down Expand Up @@ -729,18 +725,8 @@ pub unsafe extern "C" fn managed_core_account_get_transactions(
// Copy net amount
ffi_record.net_amount = record.net_amount;

// Copy height (0 if unconfirmed)
ffi_record.height = record.height.unwrap_or(0);

// Copy block hash (zeros if unconfirmed)
if let Some(block_hash) = record.block_hash {
ffi_record.block_hash = block_hash.to_byte_array();
} else {
ffi_record.block_hash = [0u8; 32];
}

// Copy timestamp
ffi_record.timestamp = record.timestamp;
// Copy transaction context
ffi_record.context = FFITransactionContextDetails::from(record.context);

// Copy fee (0 if unknown)
ffi_record.fee = record.fee.unwrap_or(0);
Expand Down
28 changes: 13 additions & 15 deletions key-wallet-ffi/src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ use key_wallet::wallet::managed_wallet_info::wallet_info_interface::WalletInfoIn
use secp256k1::{Message, Secp256k1, SecretKey};

use crate::error::{FFIError, FFIErrorCode};
use crate::types::{block_info_from_ffi, FFINetwork, FFITransactionContext, FFIWallet};
use crate::types::{
transaction_context_from_ffi, FFIBlockInfo, FFINetwork, FFITransactionContext, FFIWallet,
};
use crate::FFIWalletManager;

// MARK: - Transaction Types
Expand Down Expand Up @@ -392,9 +394,7 @@ pub unsafe extern "C" fn wallet_check_transaction(
tx_bytes: *const u8,
tx_len: usize,
context_type: FFITransactionContext,
block_height: u32,
block_hash: *const u8, // 32 bytes if not null
timestamp: u64,
block_info: FFIBlockInfo,
update_state: bool,
result_out: *mut FFITransactionCheckResult,
error: *mut FFIError,
Expand Down Expand Up @@ -423,18 +423,16 @@ pub unsafe extern "C" fn wallet_check_transaction(
};

// Build the transaction context
use key_wallet::transaction_checking::TransactionContext;
let context = match context_type {
FFITransactionContext::Mempool => TransactionContext::Mempool,
FFITransactionContext::InBlock => {
let info = block_info_from_ffi(block_height, block_hash, timestamp);
TransactionContext::InBlock(info)
}
FFITransactionContext::InChainLockedBlock => {
let info = block_info_from_ffi(block_height, block_hash, timestamp);
TransactionContext::InChainLockedBlock(info)
let context = match transaction_context_from_ffi(context_type, &block_info) {
Some(ctx) => ctx,
None => {
FFIError::set_error(
error,
FFIErrorCode::InvalidInput,
"Block info must not be zeroed for confirmed contexts".to_string(),
);
return false;
}
FFITransactionContext::InstantSend => TransactionContext::InstantSend,
};

// Create a ManagedWalletInfo from the wallet
Expand Down
27 changes: 12 additions & 15 deletions key-wallet-ffi/src/transaction_checking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ use std::slice;

use crate::error::{FFIError, FFIErrorCode};
use crate::managed_wallet::{managed_wallet_info_free, FFIManagedWalletInfo};
use crate::types::{block_info_from_ffi, FFITransactionContext, FFIWallet};
use crate::types::{transaction_context_from_ffi, FFIBlockInfo, FFITransactionContext, FFIWallet};
use dashcore::consensus::Decodable;
use dashcore::Transaction;
use key_wallet::transaction_checking::{
account_checker::CoreAccountTypeMatch, TransactionContext, WalletTransactionChecker,
account_checker::CoreAccountTypeMatch, WalletTransactionChecker,
};
use key_wallet::wallet::managed_wallet_info::ManagedWalletInfo;

Expand Down Expand Up @@ -112,9 +112,7 @@ pub unsafe extern "C" fn managed_wallet_check_transaction(
tx_bytes: *const u8,
tx_len: usize,
context_type: FFITransactionContext,
block_height: c_uint,
block_hash: *const u8, // 32 bytes if not null
timestamp: u64,
block_info: FFIBlockInfo,
update_state: bool,
result_out: *mut FFITransactionCheckResult,
error: *mut FFIError,
Expand All @@ -141,17 +139,16 @@ pub unsafe extern "C" fn managed_wallet_check_transaction(
};

// Build the transaction context
let context = match context_type {
FFITransactionContext::Mempool => TransactionContext::Mempool,
FFITransactionContext::InBlock => {
let info = block_info_from_ffi(block_height, block_hash, timestamp);
TransactionContext::InBlock(info)
}
FFITransactionContext::InChainLockedBlock => {
let info = block_info_from_ffi(block_height, block_hash, timestamp);
TransactionContext::InChainLockedBlock(info)
let context = match transaction_context_from_ffi(context_type, &block_info) {
Some(ctx) => ctx,
None => {
FFIError::set_error(
error,
FFIErrorCode::InvalidInput,
"Block info must not be zeroed for confirmed contexts".to_string(),
);
return false;
}
FFITransactionContext::InstantSend => TransactionContext::InstantSend,
};

// Check the transaction - wallet is now required
Expand Down
Loading
Loading