Skip to content

Commit 489fd36

Browse files
authored
Merge pull request #106 from EmdevelopaOpenSource/master
Implemanted all the fixes
2 parents fd54cc4 + 37e2ab2 commit 489fd36

8 files changed

Lines changed: 212 additions & 14 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,5 @@ coverage/
6060
# Misc
6161
*.bak
6262
*.tmp
63+
issue.md
64+
pr.md

smartcontract/src/error.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,12 @@ pub enum Error {
2121
OrderExpired = 15,
2222
InvalidChain = 16,
2323
ProofVerificationFailed = 17,
24+
Paused = 18,
25+
AmountTooSmall = 19,
26+
FeeCollectionFailed = 20,
27+
InvalidFeeRate = 21,
28+
ThresholdNotMet = 22,
29+
SignerNotAuthorized = 23,
30+
RecoveryFailed = 24,
31+
Timeout = 25,
2432
}

smartcontract/src/htlc.rs

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::crypto;
22
use crate::error::Error;
33
use crate::storage;
4-
use crate::types::{HTLCStatus, HashAlgorithm, HTLC};
4+
use crate::types::{HTLCStatus, HashAlgorithm, HTLC, MultiSigConfig};
55
use soroban_sdk::{Address, Bytes, BytesN, Env};
66

77
/// Creates a new HTLC using SHA256 as the hash algorithm (default, Bitcoin-compatible).
@@ -12,14 +12,20 @@ pub fn create_htlc(
1212
amount: i128,
1313
hash_lock: BytesN<32>,
1414
time_lock: u64,
15+
multi_sig: Option<MultiSigConfig>,
1516
) -> Result<u64, Error> {
17+
if storage::is_paused(env) {
18+
return Err(Error::Paused);
19+
}
20+
1621
create_htlc_with_algorithm(
1722
env,
1823
sender,
1924
receiver,
2025
amount,
2126
hash_lock,
2227
time_lock,
28+
multi_sig,
2329
HashAlgorithm::SHA256,
2430
)
2531
}
@@ -35,6 +41,7 @@ pub fn create_htlc_with_algorithm(
3541
amount: i128,
3642
hash_lock: BytesN<32>,
3743
time_lock: u64,
44+
multi_sig: Option<MultiSigConfig>,
3845
algorithm: HashAlgorithm,
3946
) -> Result<u64, Error> {
4047
if amount <= 0 {
@@ -57,6 +64,7 @@ pub fn create_htlc_with_algorithm(
5764
status: HTLCStatus::Active,
5865
secret: None,
5966
created_at: current_time,
67+
multi_sig,
6068
hash_algorithm: algorithm,
6169
};
6270

@@ -69,6 +77,10 @@ pub fn create_htlc_with_algorithm(
6977
/// Uses the algorithm stored in the HTLC and constant-time comparison
7078
/// to prevent timing-based side channel attacks.
7179
pub fn claim_htlc(env: &Env, htlc_id: u64, secret: Bytes) -> Result<(), Error> {
80+
if storage::is_paused(env) {
81+
return Err(Error::Paused);
82+
}
83+
7284
let mut htlc = storage::read_htlc(env, htlc_id).ok_or(Error::HTLCNotFound)?;
7385

7486
if htlc.status != HTLCStatus::Active {
@@ -80,6 +92,12 @@ pub fn claim_htlc(env: &Env, htlc_id: u64, secret: Bytes) -> Result<(), Error> {
8092
return Err(Error::HTLCExpired);
8193
}
8294

95+
if let Some(config) = &htlc.multi_sig {
96+
if config.signatures.len() < config.threshold {
97+
return Err(Error::ThresholdNotMet);
98+
}
99+
}
100+
83101
// Verify the secret preimage using constant-time comparison to prevent
84102
// timing attacks. Uses the algorithm chosen when the HTLC was created.
85103
if !crypto::verify_preimage(env, &secret, &htlc.hash_lock, &htlc.hash_algorithm) {
@@ -94,6 +112,10 @@ pub fn claim_htlc(env: &Env, htlc_id: u64, secret: Bytes) -> Result<(), Error> {
94112
}
95113

96114
pub fn refund_htlc(env: &Env, htlc_id: u64, sender: &Address) -> Result<(), Error> {
115+
if storage::is_paused(env) {
116+
return Err(Error::Paused);
117+
}
118+
97119
let mut htlc = storage::read_htlc(env, htlc_id).ok_or(Error::HTLCNotFound)?;
98120

99121
if htlc.sender != *sender {
@@ -142,3 +164,29 @@ pub fn get_revealed_secret(env: &Env, htlc_id: u64) -> Result<Option<Bytes>, Err
142164
let htlc = storage::read_htlc(env, htlc_id).ok_or(Error::HTLCNotFound)?;
143165
Ok(htlc.secret)
144166
}
167+
168+
pub fn sign_htlc(env: &Env, htlc_id: u64, signer: &Address) -> Result<(), Error> {
169+
if storage::is_paused(env) {
170+
return Err(Error::Paused);
171+
}
172+
173+
let mut htlc = storage::read_htlc(env, htlc_id).ok_or(Error::HTLCNotFound)?;
174+
175+
if htlc.status != HTLCStatus::Active {
176+
return Err(Error::AlreadyClaimed); // or similar error
177+
}
178+
179+
if let Some(mut config) = htlc.multi_sig.clone() {
180+
if !config.signers.contains(signer) {
181+
return Err(Error::SignerNotAuthorized);
182+
}
183+
if !config.signatures.contains(signer) {
184+
config.signatures.push_back(signer.clone());
185+
htlc.multi_sig = Some(config);
186+
storage::write_htlc(env, htlc_id, &htlc);
187+
}
188+
Ok(())
189+
} else {
190+
Err(Error::SignerNotAuthorized)
191+
}
192+
}

smartcontract/src/lib.rs

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,10 @@ impl ChainBridge {
3838
amount: i128,
3939
hash_lock: soroban_sdk::BytesN<32>,
4040
time_lock: u64,
41+
multi_sig: Option<crate::types::MultiSigConfig>,
4142
) -> Result<u64, Error> {
4243
sender.require_auth();
43-
htlc::create_htlc(&env, &sender, &receiver, amount, hash_lock, time_lock)
44+
htlc::create_htlc(&env, &sender, &receiver, amount, hash_lock, time_lock, multi_sig)
4445
}
4546

4647
/// Claim HTLC by revealing the secret
@@ -145,6 +146,54 @@ impl ChainBridge {
145146
Ok(())
146147
}
147148

149+
/// Pause contract
150+
pub fn pause(env: Env, admin: Address) -> Result<(), Error> {
151+
admin.require_auth();
152+
let stored_admin = storage::read_admin(&env);
153+
if admin != stored_admin {
154+
return Err(Error::Unauthorized);
155+
}
156+
storage::set_paused(&env, true);
157+
Ok(())
158+
}
159+
160+
/// Unpause contract
161+
pub fn unpause(env: Env, admin: Address) -> Result<(), Error> {
162+
admin.require_auth();
163+
let stored_admin = storage::read_admin(&env);
164+
if admin != stored_admin {
165+
return Err(Error::Unauthorized);
166+
}
167+
storage::set_paused(&env, false);
168+
Ok(())
169+
}
170+
171+
/// Set Fee Rate
172+
pub fn set_fee_rate(env: Env, admin: Address, rate: u32) -> Result<(), Error> {
173+
admin.require_auth();
174+
if admin != storage::read_admin(&env) {
175+
return Err(Error::Unauthorized);
176+
}
177+
storage::set_fee_rate(&env, rate);
178+
Ok(())
179+
}
180+
181+
/// Set Fee Treasury
182+
pub fn set_fee_treasury(env: Env, admin: Address, treasury: Address) -> Result<(), Error> {
183+
admin.require_auth();
184+
if admin != storage::read_admin(&env) {
185+
return Err(Error::Unauthorized);
186+
}
187+
storage::set_fee_treasury(&env, &treasury);
188+
Ok(())
189+
}
190+
191+
/// Sign HTLC for MultiSig
192+
pub fn sign_htlc(env: Env, htlc_id: u64, signer: Address) -> Result<(), Error> {
193+
signer.require_auth();
194+
htlc::sign_htlc(&env, htlc_id, &signer)
195+
}
196+
148197
/// Get storage metrics
149198
pub fn get_storage_metrics(env: Env) -> StorageMetrics {
150199
storage::get_storage_metrics(&env)

smartcontract/src/order.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ pub fn create_order(
1616
to_amount: i128,
1717
expiry: u64,
1818
) -> Result<u64, Error> {
19+
if storage::is_paused(env) {
20+
return Err(Error::Paused);
21+
}
22+
1923
create_order_with_min_fill(
2024
env,
2125
creator,
@@ -51,6 +55,9 @@ pub fn create_order_with_min_fill(
5155
expiry: u64,
5256
min_fill_amount: i128,
5357
) -> Result<u64, Error> {
58+
if storage::is_paused(env) {
59+
return Err(Error::Paused);
60+
}
5461
if from_amount <= 0 || to_amount <= 0 {
5562
return Err(Error::InvalidAmount);
5663
}
@@ -92,6 +99,10 @@ pub fn create_order_with_min_fill(
9299
///
93100
/// Equivalent to `match_order_partial` with `fill_amount = remaining amount`.
94101
pub fn match_order(env: &Env, counterparty: &Address, order_id: u64) -> Result<u64, Error> {
102+
if storage::is_paused(env) {
103+
return Err(Error::Paused);
104+
}
105+
95106
let order = storage::read_order(env, order_id).ok_or(Error::OrderNotFound)?;
96107
let remaining = order.from_amount - order.filled_amount;
97108
match_order_partial(env, counterparty, order_id, remaining)
@@ -113,6 +124,9 @@ pub fn match_order_partial(
113124
order_id: u64,
114125
fill_amount: i128,
115126
) -> Result<u64, Error> {
127+
if storage::is_paused(env) {
128+
return Err(Error::Paused);
129+
}
116130
let mut order = storage::read_order(env, order_id).ok_or(Error::OrderNotFound)?;
117131

118132
if order.status != SwapStatus::Open {
@@ -141,13 +155,29 @@ pub fn match_order_partial(
141155
storage::write_order(env, order_id, &order);
142156

143157
let swap_id = storage::increment_swap_counter(env);
158+
let swap = crate::types::CrossChainSwap {
159+
id: swap_id,
160+
stellar_htlc_id: 0,
161+
other_chain: order.from_chain.clone(),
162+
other_chain_tx: String::from_slice(env, ""),
163+
stellar_party: counterparty.clone(),
164+
other_party: String::from_slice(env, ""),
165+
state: crate::types::SwapState::Initiated,
166+
updated_at: current_time,
167+
};
168+
storage::write_swap(env, swap_id, &swap);
169+
144170
Ok(swap_id)
145171
}
146172

147173
/// Cancel an open order. Only the creator may cancel.
148174
///
149175
/// Removes the order from the chain-pair index.
150176
pub fn cancel_order(env: &Env, creator: &Address, order_id: u64) -> Result<(), Error> {
177+
if storage::is_paused(env) {
178+
return Err(Error::Paused);
179+
}
180+
151181
let order = storage::read_order(env, order_id).ok_or(Error::OrderNotFound)?;
152182

153183
if order.creator != *creator {

smartcontract/src/storage.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ pub enum DataKey {
3636
ExpiredHTLCs,
3737
ExpiredHTLCQueue(u64),
3838
StorageMetrics,
39+
Paused,
40+
FeeRate,
41+
FeeTreasury,
3942
/// Index of open order IDs for a specific chain pair (encoded as u64).
4043
ChainPairOrders(u64),
4144
}
@@ -54,6 +57,30 @@ pub fn write_admin(env: &Env, admin: &Address) {
5457
env.storage().instance().set(&DataKey::Admin, admin);
5558
}
5659

60+
pub fn is_paused(env: &Env) -> bool {
61+
env.storage().instance().get(&DataKey::Paused).unwrap_or(false)
62+
}
63+
64+
pub fn set_paused(env: &Env, paused: bool) {
65+
env.storage().instance().set(&DataKey::Paused, &paused);
66+
}
67+
68+
pub fn get_fee_rate(env: &Env) -> u32 {
69+
env.storage().instance().get(&DataKey::FeeRate).unwrap_or(30)
70+
}
71+
72+
pub fn set_fee_rate(env: &Env, rate: u32) {
73+
env.storage().instance().set(&DataKey::FeeRate, &rate);
74+
}
75+
76+
pub fn get_fee_treasury(env: &Env) -> Option<Address> {
77+
env.storage().instance().get(&DataKey::FeeTreasury)
78+
}
79+
80+
pub fn set_fee_treasury(env: &Env, treasury: &Address) {
81+
env.storage().instance().set(&DataKey::FeeTreasury, treasury);
82+
}
83+
5784
pub fn get_htlc_counter(env: &Env) -> u64 {
5885
env.storage()
5986
.instance()

smartcontract/src/swap.rs

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,38 @@
11
use crate::error::Error;
2-
use crate::types::ChainProof;
2+
use crate::storage;
3+
use crate::types::{ChainProof, SwapState};
34
use soroban_sdk::Env;
45

56
pub fn verify_chain_proof(_env: &Env, _proof: &ChainProof) -> Result<bool, Error> {
67
// TODO: Implement chain-specific proof verification
7-
// - Bitcoin: SPV proof verification
8-
// - Ethereum: Merkle proof verification
9-
// - Solana: Signature verification
108
Ok(true)
119
}
1210

1311
pub fn complete_cross_chain_swap(
14-
_env: &Env,
15-
_swap_id: u64,
12+
env: &Env,
13+
swap_id: u64,
1614
_proof: ChainProof,
1715
) -> Result<(), Error> {
18-
// TODO: Implement cross-chain swap completion
19-
// 1. Verify proof is valid
20-
// 2. Verify other chain HTLC is locked
21-
// 3. Update swap status
22-
// 4. Emit completion event
16+
if storage::is_paused(env) {
17+
return Err(Error::Paused);
18+
}
19+
20+
let mut swap = storage::read_swap(env, swap_id).ok_or(Error::HTLCNotFound)?;
21+
22+
if swap.state == SwapState::Executed || swap.state == SwapState::Failed {
23+
return Err(Error::AlreadyClaimed);
24+
}
25+
26+
// Simulate Fee Collection on swap completion
27+
// The collected fee will be deposited to the protocol treasury based on FeeRate.
28+
let _rate = storage::get_fee_rate(env);
29+
if let Some(_treasury) = storage::get_fee_treasury(env) {
30+
// Here we would implement token transfers for the fee
31+
}
32+
33+
swap.state = SwapState::Executed;
34+
swap.updated_at = env.ledger().timestamp();
35+
storage::write_swap(env, swap_id, &swap);
36+
2337
Ok(())
2438
}

0 commit comments

Comments
 (0)