From c6e029d2fd33e7827eeaa9999c614fdb9437c5a3 Mon Sep 17 00:00:00 2001 From: YaronZaki Date: Tue, 19 May 2026 13:27:37 +0000 Subject: [PATCH 1/3] feat(contracts): add dispute resolution mechanism MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add arbitrator address set at initialization - Add dispute() callable by owner or contributor when UnderReview - Add resolve(winner) callable only by arbitrator - resolve pays out to winner and transitions to Completed - Events emitted for dispute and resolve via env.events().publish - Unit tests cover full dispute → resolve path Closes #4 --- apps/contracts/src/lib.rs | 212 ++++++++++++++++++++++++++++++++------ 1 file changed, 180 insertions(+), 32 deletions(-) diff --git a/apps/contracts/src/lib.rs b/apps/contracts/src/lib.rs index 651dc97..07363f8 100644 --- a/apps/contracts/src/lib.rs +++ b/apps/contracts/src/lib.rs @@ -9,6 +9,7 @@ pub enum BountyStatus { Funded, InProgress, UnderReview, + Disputed, Completed, Cancelled, } @@ -18,12 +19,19 @@ pub struct EscrowContract; #[contractimpl] impl EscrowContract { - /// Initialize a bounty. Sets owner, amount, token address, and status to Created. - pub fn initialize(env: Env, owner: Address, amount: i128, token_address: Address) { + /// Initialize a bounty. Sets owner, amount, token address, arbitrator, and status to Created. + pub fn initialize( + env: Env, + owner: Address, + amount: i128, + token_address: Address, + arbitrator: Address, + ) { owner.require_auth(); env.storage().instance().set(&symbol_short!("OWNER"), &owner); env.storage().instance().set(&symbol_short!("AMOUNT"), &amount); env.storage().instance().set(&symbol_short!("TOKEN"), &token_address); + env.storage().instance().set(&symbol_short!("ARBITRATR"), &arbitrator); env.storage() .instance() .set(&symbol_short!("STATUS"), &BountyStatus::Created); @@ -110,6 +118,52 @@ impl EscrowContract { .set(&symbol_short!("STATUS"), &BountyStatus::Cancelled); } + /// Raise a dispute. Callable by owner or contributor when status is UnderReview. + /// Transitions UnderReview → Disputed. + pub fn dispute(env: Env, caller: Address) { + caller.require_auth(); + Self::assert_status(&env, BountyStatus::UnderReview, "dispute requires UnderReview status"); + + let owner: Address = env.storage().instance().get(&symbol_short!("OWNER")).unwrap(); + let contributor: Address = env.storage().instance().get(&symbol_short!("CONTRIB")).unwrap(); + assert!( + caller == owner || caller == contributor, + "only owner or contributor can dispute" + ); + + env.storage() + .instance() + .set(&symbol_short!("STATUS"), &BountyStatus::Disputed); + + env.events().publish((symbol_short!("dispute"), caller), ()); + } + + /// Arbitrator resolves the dispute by choosing a winner. + /// Pays out to `winner` and transitions Disputed → Completed. + pub fn resolve(env: Env, arbitrator: Address, winner: Address) { + arbitrator.require_auth(); + Self::assert_arbitrator(&env, &arbitrator); + Self::assert_status(&env, BountyStatus::Disputed, "resolve requires Disputed status"); + + let owner: Address = env.storage().instance().get(&symbol_short!("OWNER")).unwrap(); + let contributor: Address = env.storage().instance().get(&symbol_short!("CONTRIB")).unwrap(); + assert!( + winner == owner || winner == contributor, + "winner must be owner or contributor" + ); + + let amount: i128 = env.storage().instance().get(&symbol_short!("AMOUNT")).unwrap(); + let token_address: Address = env.storage().instance().get(&symbol_short!("TOKEN")).unwrap(); + let token = token::Client::new(&env, &token_address); + token.transfer(&env.current_contract_address(), &winner, &amount); + + env.storage() + .instance() + .set(&symbol_short!("STATUS"), &BountyStatus::Completed); + + env.events().publish((symbol_short!("resolve"), winner), ()); + } + pub fn get_owner(env: Env) -> Address { env.storage().instance().get(&symbol_short!("OWNER")).unwrap() } @@ -130,6 +184,10 @@ impl EscrowContract { env.storage().instance().get(&symbol_short!("TOKEN")).unwrap() } + pub fn get_arbitrator(env: Env) -> Address { + env.storage().instance().get(&symbol_short!("ARBITRATR")).unwrap() + } + // --- helpers --- fn assert_owner(env: &Env, caller: &Address) { @@ -142,6 +200,11 @@ impl EscrowContract { assert!(caller == &contributor, "only contributor can call this"); } + fn assert_arbitrator(env: &Env, caller: &Address) { + let arbitrator: Address = env.storage().instance().get(&symbol_short!("ARBITRATR")).unwrap(); + assert!(caller == &arbitrator, "only arbitrator can call this"); + } + fn assert_status(env: &Env, expected: BountyStatus, msg: &'static str) { let status: BountyStatus = env.storage().instance().get(&symbol_short!("STATUS")).unwrap(); assert!(status == expected, "{}", msg); @@ -157,7 +220,7 @@ mod tests { Address, Env, }; - fn setup() -> (Env, EscrowContractClient<'static>, Address, Address, Address, i128) { + fn setup() -> (Env, EscrowContractClient<'static>, Address, Address, Address, Address, i128) { let env = Env::default(); env.mock_all_auths(); @@ -170,6 +233,7 @@ mod tests { let client = EscrowContractClient::new(&env, &contract_id); let owner = Address::generate(&env); + let arbitrator = Address::generate(&env); let amount: i128 = 1000; token_admin_client.mint(&owner, &amount); @@ -177,23 +241,35 @@ mod tests { let token_client = TokenClient::new(&env, &token_address); token_client.approve(&owner, &contract_id, &amount, &200); - (env, client, owner, token_address, contract_id, amount) + (env, client, owner, token_address, contract_id, arbitrator, amount) + } + + fn setup_under_review( + ) -> (Env, EscrowContractClient<'static>, Address, Address, Address, Address, Address, i128) { + let (env, client, owner, token_address, contract_id, arbitrator, amount) = setup(); + client.initialize(&owner, &amount, &token_address, &arbitrator); + client.fund(&owner); + let contributor = Address::generate(&env); + client.start_work(&contributor); + client.submit(&contributor); + (env, client, owner, token_address, contract_id, arbitrator, contributor, amount) } #[test] fn test_initialize_stores_fields() { - let (_, client, owner, token_address, _, amount) = setup(); - client.initialize(&owner, &amount, &token_address); + let (_, client, owner, token_address, _, arbitrator, amount) = setup(); + client.initialize(&owner, &amount, &token_address, &arbitrator); assert_eq!(client.get_owner(), owner); assert_eq!(client.get_amount(), amount); assert_eq!(client.get_token(), token_address); + assert_eq!(client.get_arbitrator(), arbitrator); assert_eq!(client.get_status(), BountyStatus::Created); } #[test] fn test_fund_transfers_tokens_and_transitions() { - let (env, client, owner, token_address, contract_id, amount) = setup(); - client.initialize(&owner, &amount, &token_address); + let (env, client, owner, token_address, contract_id, arbitrator, amount) = setup(); + client.initialize(&owner, &amount, &token_address, &arbitrator); let token = TokenClient::new(&env, &token_address); assert_eq!(token.balance(&owner), amount); @@ -207,13 +283,8 @@ mod tests { #[test] fn test_approve_pays_contributor() { - let (env, client, owner, token_address, contract_id, amount) = setup(); - client.initialize(&owner, &amount, &token_address); - client.fund(&owner); - - let contributor = Address::generate(&env); - client.start_work(&contributor); - client.submit(&contributor); + let (env, client, owner, token_address, contract_id, arbitrator, contributor, amount) = + setup_under_review(); let token = TokenClient::new(&env, &token_address); assert_eq!(token.balance(&contract_id), amount); @@ -227,8 +298,8 @@ mod tests { #[test] fn test_cancel_from_funded_refunds_owner() { - let (env, client, owner, token_address, contract_id, amount) = setup(); - client.initialize(&owner, &amount, &token_address); + let (env, client, owner, token_address, contract_id, arbitrator, amount) = setup(); + client.initialize(&owner, &amount, &token_address, &arbitrator); client.fund(&owner); let token = TokenClient::new(&env, &token_address); @@ -244,8 +315,8 @@ mod tests { #[test] fn test_cancel_from_created_no_transfer() { - let (env, client, owner, token_address, _, amount) = setup(); - client.initialize(&owner, &amount, &token_address); + let (env, client, owner, token_address, _, arbitrator, amount) = setup(); + client.initialize(&owner, &amount, &token_address, &arbitrator); let token = TokenClient::new(&env, &token_address); let owner_balance_before = token.balance(&owner); @@ -258,8 +329,8 @@ mod tests { #[test] fn test_start_work_transitions_to_in_progress() { - let (env, client, owner, token_address, _, amount) = setup(); - client.initialize(&owner, &amount, &token_address); + let (env, client, owner, token_address, _, arbitrator, amount) = setup(); + client.initialize(&owner, &amount, &token_address, &arbitrator); client.fund(&owner); let contributor = Address::generate(&env); client.start_work(&contributor); @@ -269,8 +340,8 @@ mod tests { #[test] fn test_submit_transitions_to_under_review() { - let (env, client, owner, token_address, _, amount) = setup(); - client.initialize(&owner, &amount, &token_address); + let (env, client, owner, token_address, _, arbitrator, amount) = setup(); + client.initialize(&owner, &amount, &token_address, &arbitrator); client.fund(&owner); let contributor = Address::generate(&env); client.start_work(&contributor); @@ -279,14 +350,91 @@ mod tests { } #[test] - #[should_panic(expected = "only owner can call this")] - fn test_approve_unauthorized_panics() { - let (env, client, owner, token_address, _, amount) = setup(); - client.initialize(&owner, &amount, &token_address); + fn test_dispute_by_owner_transitions_to_disputed() { + let (_, client, owner, _, _, _, _, _) = setup_under_review(); + client.dispute(&owner); + assert_eq!(client.get_status(), BountyStatus::Disputed); + } + + #[test] + fn test_dispute_by_contributor_transitions_to_disputed() { + let (_, client, _, _, _, _, contributor, _) = setup_under_review(); + client.dispute(&contributor); + assert_eq!(client.get_status(), BountyStatus::Disputed); + } + + #[test] + fn test_resolve_pays_contributor_and_completes() { + let (env, client, _, token_address, contract_id, arbitrator, contributor, amount) = + setup_under_review(); + client.dispute(&contributor); + + let token = TokenClient::new(&env, &token_address); + assert_eq!(token.balance(&contract_id), amount); + + client.resolve(&arbitrator, &contributor); + + assert_eq!(client.get_status(), BountyStatus::Completed); + assert_eq!(token.balance(&contributor), amount); + assert_eq!(token.balance(&contract_id), 0); + } + + #[test] + fn test_resolve_pays_owner_and_completes() { + let (env, client, owner, token_address, contract_id, arbitrator, contributor, amount) = + setup_under_review(); + client.dispute(&contributor); + + let token = TokenClient::new(&env, &token_address); + client.resolve(&arbitrator, &owner); + + assert_eq!(client.get_status(), BountyStatus::Completed); + assert_eq!(token.balance(&owner), amount); + assert_eq!(token.balance(&contract_id), 0); + } + + #[test] + #[should_panic(expected = "only owner or contributor can dispute")] + fn test_dispute_by_stranger_panics() { + let (env, client, _, _, _, _, _, _) = setup_under_review(); + let stranger = Address::generate(&env); + client.dispute(&stranger); + } + + #[test] + #[should_panic(expected = "dispute requires UnderReview status")] + fn test_dispute_wrong_status_panics() { + let (env, client, owner, token_address, _, arbitrator, amount) = setup(); + client.initialize(&owner, &amount, &token_address, &arbitrator); client.fund(&owner); let contributor = Address::generate(&env); client.start_work(&contributor); - client.submit(&contributor); + // Still InProgress, not UnderReview + client.dispute(&owner); + } + + #[test] + #[should_panic(expected = "only arbitrator can call this")] + fn test_resolve_by_non_arbitrator_panics() { + let (env, client, _, _, _, _, contributor, _) = setup_under_review(); + client.dispute(&contributor); + let stranger = Address::generate(&env); + client.resolve(&stranger, &contributor); + } + + #[test] + #[should_panic(expected = "winner must be owner or contributor")] + fn test_resolve_with_invalid_winner_panics() { + let (env, client, _, _, _, arbitrator, contributor, _) = setup_under_review(); + client.dispute(&contributor); + let stranger = Address::generate(&env); + client.resolve(&arbitrator, &stranger); + } + + #[test] + #[should_panic(expected = "only owner can call this")] + fn test_approve_unauthorized_panics() { + let (env, client, _, _, _, _, _, _) = setup_under_review(); let not_owner = Address::generate(&env); client.approve(¬_owner); } @@ -294,8 +442,8 @@ mod tests { #[test] #[should_panic(expected = "cancel only allowed from Created or Funded")] fn test_cancel_from_in_progress_panics() { - let (env, client, owner, token_address, _, amount) = setup(); - client.initialize(&owner, &amount, &token_address); + let (env, client, owner, token_address, _, arbitrator, amount) = setup(); + client.initialize(&owner, &amount, &token_address, &arbitrator); client.fund(&owner); let contributor = Address::generate(&env); client.start_work(&contributor); @@ -305,8 +453,8 @@ mod tests { #[test] #[should_panic(expected = "fund requires Created status")] fn test_double_fund_panics() { - let (_, client, owner, token_address, _, amount) = setup(); - client.initialize(&owner, &amount, &token_address); + let (_, client, owner, token_address, _, arbitrator, amount) = setup(); + client.initialize(&owner, &amount, &token_address, &arbitrator); client.fund(&owner); client.fund(&owner); } From d089755727fea96b1002855f7bd6859a2555a424 Mon Sep 17 00:00:00 2001 From: YaronZaki Date: Tue, 19 May 2026 13:48:38 +0000 Subject: [PATCH 2/3] style: apply rustfmt formatting and update lockfile --- apps/contracts/src/lib.rs | 38 +++++++++++++++++++++++++++----------- package-lock.json | 19 +++++++++++++++++++ 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/apps/contracts/src/lib.rs b/apps/contracts/src/lib.rs index 07363f8..271188a 100644 --- a/apps/contracts/src/lib.rs +++ b/apps/contracts/src/lib.rs @@ -87,7 +87,8 @@ impl EscrowContract { let amount: i128 = env.storage().instance().get(&symbol_short!("AMOUNT")).unwrap(); let token_address: Address = env.storage().instance().get(&symbol_short!("TOKEN")).unwrap(); - let contributor: Address = env.storage().instance().get(&symbol_short!("CONTRIB")).unwrap(); + let contributor: Address = + env.storage().instance().get(&symbol_short!("CONTRIB")).unwrap(); let token = token::Client::new(&env, &token_address); token.transfer(&env.current_contract_address(), &contributor, &amount); @@ -100,7 +101,8 @@ impl EscrowContract { pub fn cancel(env: Env, owner: Address) { owner.require_auth(); Self::assert_owner(&env, &owner); - let status: BountyStatus = env.storage().instance().get(&symbol_short!("STATUS")).unwrap(); + let status: BountyStatus = + env.storage().instance().get(&symbol_short!("STATUS")).unwrap(); assert!( status == BountyStatus::Created || status == BountyStatus::Funded, "cancel only allowed from Created or Funded" @@ -108,7 +110,8 @@ impl EscrowContract { if status == BountyStatus::Funded { let amount: i128 = env.storage().instance().get(&symbol_short!("AMOUNT")).unwrap(); - let token_address: Address = env.storage().instance().get(&symbol_short!("TOKEN")).unwrap(); + let token_address: Address = + env.storage().instance().get(&symbol_short!("TOKEN")).unwrap(); let token = token::Client::new(&env, &token_address); token.transfer(&env.current_contract_address(), &owner, &amount); } @@ -125,7 +128,8 @@ impl EscrowContract { Self::assert_status(&env, BountyStatus::UnderReview, "dispute requires UnderReview status"); let owner: Address = env.storage().instance().get(&symbol_short!("OWNER")).unwrap(); - let contributor: Address = env.storage().instance().get(&symbol_short!("CONTRIB")).unwrap(); + let contributor: Address = + env.storage().instance().get(&symbol_short!("CONTRIB")).unwrap(); assert!( caller == owner || caller == contributor, "only owner or contributor can dispute" @@ -146,7 +150,8 @@ impl EscrowContract { Self::assert_status(&env, BountyStatus::Disputed, "resolve requires Disputed status"); let owner: Address = env.storage().instance().get(&symbol_short!("OWNER")).unwrap(); - let contributor: Address = env.storage().instance().get(&symbol_short!("CONTRIB")).unwrap(); + let contributor: Address = + env.storage().instance().get(&symbol_short!("CONTRIB")).unwrap(); assert!( winner == owner || winner == contributor, "winner must be owner or contributor" @@ -196,17 +201,20 @@ impl EscrowContract { } fn assert_contributor(env: &Env, caller: &Address) { - let contributor: Address = env.storage().instance().get(&symbol_short!("CONTRIB")).unwrap(); + let contributor: Address = + env.storage().instance().get(&symbol_short!("CONTRIB")).unwrap(); assert!(caller == &contributor, "only contributor can call this"); } fn assert_arbitrator(env: &Env, caller: &Address) { - let arbitrator: Address = env.storage().instance().get(&symbol_short!("ARBITRATR")).unwrap(); + let arbitrator: Address = + env.storage().instance().get(&symbol_short!("ARBITRATR")).unwrap(); assert!(caller == &arbitrator, "only arbitrator can call this"); } fn assert_status(env: &Env, expected: BountyStatus, msg: &'static str) { - let status: BountyStatus = env.storage().instance().get(&symbol_short!("STATUS")).unwrap(); + let status: BountyStatus = + env.storage().instance().get(&symbol_short!("STATUS")).unwrap(); assert!(status == expected, "{}", msg); } } @@ -244,8 +252,16 @@ mod tests { (env, client, owner, token_address, contract_id, arbitrator, amount) } - fn setup_under_review( - ) -> (Env, EscrowContractClient<'static>, Address, Address, Address, Address, Address, i128) { + fn setup_under_review() -> ( + Env, + EscrowContractClient<'static>, + Address, + Address, + Address, + Address, + Address, + i128, + ) { let (env, client, owner, token_address, contract_id, arbitrator, amount) = setup(); client.initialize(&owner, &amount, &token_address, &arbitrator); client.fund(&owner); @@ -283,7 +299,7 @@ mod tests { #[test] fn test_approve_pays_contributor() { - let (env, client, owner, token_address, contract_id, arbitrator, contributor, amount) = + let (env, client, owner, token_address, contract_id, _arbitrator, contributor, amount) = setup_under_review(); let token = TokenClient::new(&env, &token_address); diff --git a/package-lock.json b/package-lock.json index 6a69ad5..d72c19d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -51,10 +51,13 @@ "@types/node": "^20.14.2", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", + "@typescript-eslint/eslint-plugin": "^7.0.0", + "@typescript-eslint/parser": "^7.0.0", "autoprefixer": "^10.4.19", "eslint": "^8.57.0", "eslint-config-next": "14.2.35", "postcss": "^8.4.38", + "prettier": "^3.3.2", "tailwindcss": "^3.4.4", "typescript": "^5.5.4" } @@ -8357,6 +8360,22 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", + "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", From 94278f60a4d1703657bd77361cb237fbc2422add Mon Sep 17 00:00:00 2001 From: YaronZaki Date: Tue, 19 May 2026 13:56:48 +0000 Subject: [PATCH 3/3] style: apply rustfmt formatting --- apps/contracts/src/lib.rs | 62 +++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/apps/contracts/src/lib.rs b/apps/contracts/src/lib.rs index 271188a..36a5163 100644 --- a/apps/contracts/src/lib.rs +++ b/apps/contracts/src/lib.rs @@ -20,13 +20,7 @@ pub struct EscrowContract; #[contractimpl] impl EscrowContract { /// Initialize a bounty. Sets owner, amount, token address, arbitrator, and status to Created. - pub fn initialize( - env: Env, - owner: Address, - amount: i128, - token_address: Address, - arbitrator: Address, - ) { + pub fn initialize(env: Env, owner: Address, amount: i128, token_address: Address, arbitrator: Address) { owner.require_auth(); env.storage().instance().set(&symbol_short!("OWNER"), &owner); env.storage().instance().set(&symbol_short!("AMOUNT"), &amount); @@ -87,8 +81,7 @@ impl EscrowContract { let amount: i128 = env.storage().instance().get(&symbol_short!("AMOUNT")).unwrap(); let token_address: Address = env.storage().instance().get(&symbol_short!("TOKEN")).unwrap(); - let contributor: Address = - env.storage().instance().get(&symbol_short!("CONTRIB")).unwrap(); + let contributor: Address = env.storage().instance().get(&symbol_short!("CONTRIB")).unwrap(); let token = token::Client::new(&env, &token_address); token.transfer(&env.current_contract_address(), &contributor, &amount); @@ -101,8 +94,7 @@ impl EscrowContract { pub fn cancel(env: Env, owner: Address) { owner.require_auth(); Self::assert_owner(&env, &owner); - let status: BountyStatus = - env.storage().instance().get(&symbol_short!("STATUS")).unwrap(); + let status: BountyStatus = env.storage().instance().get(&symbol_short!("STATUS")).unwrap(); assert!( status == BountyStatus::Created || status == BountyStatus::Funded, "cancel only allowed from Created or Funded" @@ -110,8 +102,7 @@ impl EscrowContract { if status == BountyStatus::Funded { let amount: i128 = env.storage().instance().get(&symbol_short!("AMOUNT")).unwrap(); - let token_address: Address = - env.storage().instance().get(&symbol_short!("TOKEN")).unwrap(); + let token_address: Address = env.storage().instance().get(&symbol_short!("TOKEN")).unwrap(); let token = token::Client::new(&env, &token_address); token.transfer(&env.current_contract_address(), &owner, &amount); } @@ -128,8 +119,7 @@ impl EscrowContract { Self::assert_status(&env, BountyStatus::UnderReview, "dispute requires UnderReview status"); let owner: Address = env.storage().instance().get(&symbol_short!("OWNER")).unwrap(); - let contributor: Address = - env.storage().instance().get(&symbol_short!("CONTRIB")).unwrap(); + let contributor: Address = env.storage().instance().get(&symbol_short!("CONTRIB")).unwrap(); assert!( caller == owner || caller == contributor, "only owner or contributor can dispute" @@ -150,8 +140,7 @@ impl EscrowContract { Self::assert_status(&env, BountyStatus::Disputed, "resolve requires Disputed status"); let owner: Address = env.storage().instance().get(&symbol_short!("OWNER")).unwrap(); - let contributor: Address = - env.storage().instance().get(&symbol_short!("CONTRIB")).unwrap(); + let contributor: Address = env.storage().instance().get(&symbol_short!("CONTRIB")).unwrap(); assert!( winner == owner || winner == contributor, "winner must be owner or contributor" @@ -201,20 +190,17 @@ impl EscrowContract { } fn assert_contributor(env: &Env, caller: &Address) { - let contributor: Address = - env.storage().instance().get(&symbol_short!("CONTRIB")).unwrap(); + let contributor: Address = env.storage().instance().get(&symbol_short!("CONTRIB")).unwrap(); assert!(caller == &contributor, "only contributor can call this"); } fn assert_arbitrator(env: &Env, caller: &Address) { - let arbitrator: Address = - env.storage().instance().get(&symbol_short!("ARBITRATR")).unwrap(); + let arbitrator: Address = env.storage().instance().get(&symbol_short!("ARBITRATR")).unwrap(); assert!(caller == &arbitrator, "only arbitrator can call this"); } fn assert_status(env: &Env, expected: BountyStatus, msg: &'static str) { - let status: BountyStatus = - env.storage().instance().get(&symbol_short!("STATUS")).unwrap(); + let status: BountyStatus = env.storage().instance().get(&symbol_short!("STATUS")).unwrap(); assert!(status == expected, "{}", msg); } } @@ -228,7 +214,15 @@ mod tests { Address, Env, }; - fn setup() -> (Env, EscrowContractClient<'static>, Address, Address, Address, Address, i128) { + fn setup() -> ( + Env, + EscrowContractClient<'static>, + Address, + Address, + Address, + Address, + i128, + ) { let env = Env::default(); env.mock_all_auths(); @@ -268,7 +262,16 @@ mod tests { let contributor = Address::generate(&env); client.start_work(&contributor); client.submit(&contributor); - (env, client, owner, token_address, contract_id, arbitrator, contributor, amount) + ( + env, + client, + owner, + token_address, + contract_id, + arbitrator, + contributor, + amount, + ) } #[test] @@ -299,8 +302,7 @@ mod tests { #[test] fn test_approve_pays_contributor() { - let (env, client, owner, token_address, contract_id, _arbitrator, contributor, amount) = - setup_under_review(); + let (env, client, owner, token_address, contract_id, _arbitrator, contributor, amount) = setup_under_review(); let token = TokenClient::new(&env, &token_address); assert_eq!(token.balance(&contract_id), amount); @@ -381,8 +383,7 @@ mod tests { #[test] fn test_resolve_pays_contributor_and_completes() { - let (env, client, _, token_address, contract_id, arbitrator, contributor, amount) = - setup_under_review(); + let (env, client, _, token_address, contract_id, arbitrator, contributor, amount) = setup_under_review(); client.dispute(&contributor); let token = TokenClient::new(&env, &token_address); @@ -397,8 +398,7 @@ mod tests { #[test] fn test_resolve_pays_owner_and_completes() { - let (env, client, owner, token_address, contract_id, arbitrator, contributor, amount) = - setup_under_review(); + let (env, client, owner, token_address, contract_id, arbitrator, contributor, amount) = setup_under_review(); client.dispute(&contributor); let token = TokenClient::new(&env, &token_address);