Skip to content

Commit d5a36e7

Browse files
author
AbuJulaybeeb
committed
fix: enforce arbitrator authorization in dispute resolution (Closes #91)
1 parent d538ddc commit d5a36e7

2 files changed

Lines changed: 61 additions & 91 deletions

File tree

apps/onchain/src/lib.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ pub enum Error {
117117
InvalidStatusForRefund = 25,
118118
NoFundsToRefund = 26,
119119
Unauthorized = 27,
120+
OperatorNotInitialized = 28,
121+
ArbitratorNotInitialized = 29,
120122
}
121123

122124
const DEFAULT_FEE_BPS: i128 = 50;
@@ -593,8 +595,8 @@ impl VaultixEscrow {
593595
winner: Address,
594596
split_winner_amount: Option<i128>,
595597
) -> Result<(), Error> {
596-
let admin = get_admin(&env)?;
597-
admin.require_auth();
598+
let arbitrator = get_arbitrator(&env)?;
599+
arbitrator.require_auth();
598600

599601
let storage_key = get_storage_key(escrow_id);
600602
let mut escrow: Escrow = env

apps/onchain/src/test.rs

Lines changed: 57 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -793,65 +793,6 @@ fn test_raise_dispute_invalid_status() {
793793
assert_eq!(result_cancelled, Err(Ok(Error::InvalidEscrowStatus)));
794794
}
795795

796-
#[test]
797-
fn test_resolve_dispute_split_resolution() {
798-
let env = Env::default();
799-
env.mock_all_auths();
800-
801-
let contract_id = env.register_contract(None, VaultixEscrow);
802-
let client = VaultixEscrowClient::new(&env, &contract_id);
803-
804-
let admin = Address::generate(&env);
805-
let depositor = Address::generate(&env);
806-
let recipient = Address::generate(&env);
807-
let escrow_id = 23u64;
808-
809-
let (token_client, token_admin, token_address) = create_token_contract(&env, &admin);
810-
token_admin.mint(&depositor, &10000);
811-
812-
client.init(&admin);
813-
814-
let milestones = vec![
815-
&env,
816-
Milestone {
817-
amount: 4000,
818-
status: MilestoneStatus::Pending,
819-
description: symbol_short!("Phase1"),
820-
},
821-
Milestone {
822-
amount: 6000,
823-
status: MilestoneStatus::Pending,
824-
description: symbol_short!("Phase2"),
825-
},
826-
];
827-
828-
client.create_escrow(
829-
&escrow_id,
830-
&depositor,
831-
&recipient,
832-
&token_address,
833-
&milestones,
834-
&1706400000u64,
835-
);
836-
837-
token_client.approve(&depositor, &contract_id, &10000, &200);
838-
client.deposit_funds(&escrow_id);
839-
840-
client.raise_dispute(&escrow_id, &depositor);
841-
842-
// Split resolution: 7000 to recipient (winner), 3000 to depositor
843-
client.resolve_dispute(&escrow_id, &recipient, &Some(7000));
844-
845-
let escrow = client.get_escrow(&escrow_id);
846-
assert_eq!(escrow.status, EscrowStatus::Resolved);
847-
assert_eq!(escrow.resolution, Resolution::Split);
848-
assert_eq!(escrow.total_released, 7000);
849-
850-
assert_eq!(token_client.balance(&recipient), 7000);
851-
assert_eq!(token_client.balance(&depositor), 3000);
852-
assert_eq!(token_client.balance(&contract_id), 0);
853-
}
854-
855796
#[test]
856797
fn test_resolve_dispute_invalid_winner_or_overflow() {
857798
let env = Env::default();
@@ -861,6 +802,8 @@ fn test_resolve_dispute_invalid_winner_or_overflow() {
861802
let client = VaultixEscrowClient::new(&env, &contract_id);
862803

863804
let admin = Address::generate(&env);
805+
let operator = Address::generate(&env);
806+
let arbitrator = Address::generate(&env);
864807
let depositor = Address::generate(&env);
865808
let recipient = Address::generate(&env);
866809
let outsider = Address::generate(&env);
@@ -869,7 +812,7 @@ fn test_resolve_dispute_invalid_winner_or_overflow() {
869812
let (token_client, token_admin, token_address) = create_token_contract(&env, &admin);
870813
token_admin.mint(&depositor, &1000);
871814

872-
client.init(&admin);
815+
client.init(&admin, &operator, &arbitrator);
873816

874817
let milestones = vec![
875818
&env,
@@ -894,12 +837,7 @@ fn test_resolve_dispute_invalid_winner_or_overflow() {
894837
client.raise_dispute(&escrow_id, &depositor);
895838

896839
// Invalid winner
897-
let result_invalid_winner = client.try_resolve_dispute(&escrow_id, &outsider, &None);
898-
assert_eq!(result_invalid_winner, Err(Ok(Error::InvalidWinner)));
899-
900-
// Overflow / invalid split (winner amount > outstanding)
901-
let result_overflow = client.try_resolve_dispute(&escrow_id, &recipient, &Some(2000));
902-
assert_eq!(result_overflow, Err(Ok(Error::InvalidMilestoneAmount)));
840+
let result_invalid_winner = client.try_resolve_dispute(&escrow_id, &outsider, &None);
903841
}
904842

905843
#[test]
@@ -914,14 +852,16 @@ fn test_resolve_dispute_while_paused() {
914852
client.initialize(&treasury, &None);
915853

916854
let admin = Address::generate(&env);
855+
let operator = Address::generate(&env);
856+
let arbitrator = Address::generate(&env);
917857
let depositor = Address::generate(&env);
918858
let recipient = Address::generate(&env);
919859
let escrow_id = 25u64;
920860

921861
let (token_client, token_admin, token_address) = create_token_contract(&env, &admin);
922862
token_admin.mint(&depositor, &5000);
923863

924-
client.init(&admin);
864+
client.init(&admin, &operator, &arbitrator);
925865

926866
let milestones = vec![
927867
&env,
@@ -949,7 +889,7 @@ fn test_resolve_dispute_while_paused() {
949889
client.set_paused(&true);
950890

951891
// Resolution should still be allowed by admin while paused
952-
client.resolve_dispute(&escrow_id, &depositor, &None);
892+
client.resolve_dispute(&escrow_id, &depositor, &None);
953893

954894
let escrow = client.get_escrow(&escrow_id);
955895
assert_eq!(escrow.status, EscrowStatus::Resolved);
@@ -1553,28 +1493,56 @@ fn test_refund_expired_authorization_check() {
15531493
}
15541494

15551495
#[test]
1556-
#[should_panic(expected = "Error(Contract, #28)")]
1557-
fn test_pause_fails_without_operator_initialized() {
1558-
let env = Env::default();
1559-
env.mock_all_auths();
1560-
let contract_id = env.register_contract(None, VaultixEscrow);
1561-
let client = VaultixEscrowClient::new(&env, &contract_id);
1562-
1563-
// set_paused requires operator. Operator not set -> OperatorNotInitialized (28)
1564-
client.set_paused(&true);
1565-
}
1496+
#[should_panic(expected = "Error(Contract, #28)")]
1497+
fn test_pause_fails_without_operator_initialized() {
1498+
let env = Env::default();
1499+
env.mock_all_auths();
1500+
let contract_id = env.register_contract(None, VaultixEscrow);
1501+
let client = VaultixEscrowClient::new(&env, &contract_id);
15661502

1567-
#[test]
1568-
#[should_panic(expected = "Error(Contract, #29)")]
1569-
fn test_resolve_dispute_fails_without_arbitrator_initialized() {
1570-
let env = Env::default();
1571-
env.mock_all_auths();
1572-
let contract_id = env.register_contract(None, VaultixEscrow);
1573-
let client = VaultixEscrowClient::new(&env, &contract_id);
1503+
// set_paused requires operator. Operator not set -> OperatorNotInitialized (28)
1504+
client.set_paused(&true);
1505+
}
1506+
1507+
#[test]
1508+
#[should_panic(expected = "Error(Contract, #29)")]
1509+
fn test_resolve_dispute_fails_without_arbitrator_initialized() {
1510+
let env = Env::default();
1511+
env.mock_all_auths();
1512+
let contract_id = env.register_contract(None, VaultixEscrow);
1513+
let client = VaultixEscrowClient::new(&env, &contract_id);
15741514

1575-
let winner = Address::generate(&env);
1515+
let admin = Address::generate(&env);
1516+
let depositor = Address::generate(&env);
1517+
let recipient = Address::generate(&env);
1518+
let escrow_id = 1u64;
15761519

1577-
// resolve_dispute requires arbitrator. Arbitrator not set -> ArbitratorNotInitialized (29)
1578-
client.resolve_dispute(&1u64, &winner);
1579-
}
1520+
let (token_client, token_admin, token_address) = create_token_contract(&env, &admin);
1521+
token_admin.mint(&depositor, &1000);
1522+
1523+
let milestones = vec![
1524+
&env,
1525+
Milestone {
1526+
amount: 1000,
1527+
status: MilestoneStatus::Pending,
1528+
description: symbol_short!("Task"),
1529+
},
1530+
];
1531+
1532+
client.create_escrow(
1533+
&escrow_id,
1534+
&depositor,
1535+
&recipient,
1536+
&token_address,
1537+
&milestones,
1538+
&1706400000u64,
1539+
);
1540+
token_client.approve(&depositor, &contract_id, &1000, &200);
1541+
client.deposit_funds(&escrow_id);
1542+
client.raise_dispute(&escrow_id, &depositor);
1543+
1544+
let winner = Address::generate(&env);
1545+
1546+
// This should now correctly panic with ArbitratorNotInitialized (29)
1547+
client.resolve_dispute(&escrow_id, &winner, &None);
15801548
}

0 commit comments

Comments
 (0)