Skip to content

Commit

Permalink
Merge pull request #135 from Slesarew/fix-events-check
Browse files Browse the repository at this point in the history
fix: remove routine events check
  • Loading branch information
Slesarew authored Nov 18, 2024
2 parents 29e8eb2 + 0f2bb69 commit cf19a81
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 63 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@

All notable changes to this project will be documented in this file.

## [0.2.7] - 2024-11-18

### 🚀 Features

- Asset Hub transactions with fee currency
- Autofill tip with asset
- Pass asset id into transaction constructor to properly select fee currency

### 🧪 Testing

- Test cases to cover partial withdrawal and Asset Gub transfers

## [0.2.6] - 2024-11-01

### 🚀 Features
Expand Down
25 changes: 12 additions & 13 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "kalatori"
authors = ["Alzymologist Oy <contact@zymologia.fi>"]
version = "0.2.6"
version = "0.2.7"
edition = "2021"
description = "A gateway daemon for Kalatori."
license = "GPL-3.0-or-later"
Expand All @@ -27,10 +27,10 @@ serde = { version = "1", features = ["derive", "rc"] }
tracing = "0.1"
scale-info = "2"
axum-macros = "0.4"
primitive-types = { version = "0.12", features = ["codec"] }
primitive-types = { version = "0.13", features = ["codec"] }
jsonrpsee = { version = "0.24", features = ["ws-client"] }
thiserror = "1"
frame-metadata = "16"
frame-metadata = "17"
const-hex = "1"
codec = { package = "parity-scale-codec", version = "3", features = [
"chain-error",
Expand Down
1 change: 1 addition & 0 deletions src/chain/payout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ pub async fn payout(
block,
block_number,
0,
currency.asset_id,
)?;

let sign_this = batch_transaction
Expand Down
71 changes: 29 additions & 42 deletions src/chain/tracker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,52 +116,39 @@ pub fn start_chain_watch(
break;
}

match transfer_events(
&client,
&block,
&watcher.metadata,
)
.await {
Ok(events) => {
let mut id_remove_list = Vec::new();
let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_millis() as u64;
let mut id_remove_list = Vec::new();
let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_millis() as u64;

for (id, invoice) in &watched_accounts {
if events.iter().any(|event| was_balance_received_at_account(&invoice.address, &event.0.fields)) {
match invoice.check(&client, &watcher, &block).await {
Ok(true) => {
state.order_paid(id.clone()).await;
id_remove_list.push(id.to_owned());
}
Ok(false) => (),
Err(e) => {
tracing::warn!("account fetch error: {0:?}", e);
}
}
} else if invoice.death.0 >= now {
match invoice.check(&client, &watcher, &block).await {
Ok(paid) => {
if paid {
state.order_paid(id.clone()).await;
}

id_remove_list.push(id.to_owned());
}
Err(e) => {
tracing::warn!("account fetch error: {0:?}", e);
}
}
// Important! There used to be a significant oprimisation that
// watched events and checked only accounts that have tranfers into
// them in given block; this was found to be unreliable: there are
// ways to transfer funds without emitting a transfer event (one
// notable example is through asset exchange procedure directed
// straight into invoice account), and probably even without any
// reliably expected event (through XCM). Thus we just scan all
// accounts, every time. Please submit a PR or an issue if you
// figure out a reliable optimization for this.
for (id, invoice) in &watched_accounts {
match invoice.check(&client, &watcher, &block).await {
Ok(true) => {
state.order_paid(id.clone()).await;
id_remove_list.push(id.to_owned());
},
Ok(false) => {
if invoice.death.0 <= now {
id_remove_list.push(id.to_owned());
}
},
Err(e) => {
tracing::warn!("account fetch error: {0:?}", e);
}
for id in id_remove_list {
watched_accounts.remove(&id);
}
},
Err(e) => {
tracing::warn!("Events fetch error {e} at {}", chain.name);
break;
},
}
}

for id in id_remove_list {
watched_accounts.remove(&id);
};

tracing::debug!("Block {} from {} processed successfully", block.to_string(), chain.name);
}
ChainTrackerRequest::WatchAccount(request) => {
Expand Down
4 changes: 4 additions & 0 deletions src/chain/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ pub fn construct_batch_transaction(
block: BlockHash,
block_number: u32,
nonce: u32,
asset: Option<u32>,
) -> Result<TransactionToFill, ChainError> {
let mut transaction_to_fill = TransactionToFill::init(&mut (), metadata, genesis_hash.0)?;

Expand Down Expand Up @@ -296,6 +297,9 @@ pub fn construct_batch_transaction(

transaction_to_fill.populate_block_info(Some(block.0), Some(block_number.into()));
transaction_to_fill.populate_nonce(nonce);
if let Some(asset) = asset {
transaction_to_fill.try_default_tip_assets_in_given_asset(&mut (), metadata, asset);
}

for ext in transaction_to_fill.extensions.iter_mut() {
if ext.finalize().is_none() {
Expand Down
74 changes: 69 additions & 5 deletions tests/kalatori-api-test-suite/tests/order.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ describe('Order Endpoint Blackbox Tests', () => {
expect(repaidOrderDetails.withdrawal_status).toBe('completed');
}, 100000);

it.skip('should create, repay, and automatically withdraw an order in USDC', async () => {
it('should create, repay, and automatically withdraw an order in USDC', async () => {
const orderId = generateRandomOrderId();
await createOrder(orderId, usdcOrderData);
const orderDetails = await getOrderDetails(orderId);
Expand All @@ -255,7 +255,46 @@ describe('Order Endpoint Blackbox Tests', () => {
expect(repaidOrderDetails.withdrawal_status).toBe('completed');
}, 50000);

it.skip('should not automatically withdraw an order until fully repaid', async () => {
it('should not automatically withdraw DOT order until fully repaid', async () => {
const orderId = generateRandomOrderId();
await createOrder(orderId, dotOrderData);
const orderDetails = await getOrderDetails(orderId);
const paymentAccount = orderDetails.payment_account;
expect(paymentAccount).toBeDefined();

const halfAmount = orderDetails.amount/2;

// Partial repayment
await transferFunds(
orderDetails.currency.rpc_url,
paymentAccount,
halfAmount,
orderDetails.currency.asset_id
);
// lets wait for the changes to get propagated on chain and app to catch them
await new Promise(resolve => setTimeout(resolve, 15000));

let repaidOrderDetails = await getOrderDetails(orderId);
expect(repaidOrderDetails.payment_status).toBe('pending');
expect(repaidOrderDetails.withdrawal_status).toBe('waiting');

// Full repayment
await transferFunds(
orderDetails.currency.rpc_url,
paymentAccount,
halfAmount+5,
orderDetails.currency.asset_id
);

// lets wait for the changes to get propagated on chain and app to catch them
await new Promise(resolve => setTimeout(resolve, 15000));

repaidOrderDetails = await getOrderDetails(orderId);
expect(repaidOrderDetails.payment_status).toBe('paid');
expect(repaidOrderDetails.withdrawal_status).toBe('completed');
}, 100000);

it('should not automatically withdraw USDC order until fully repaid', async () => {
const orderId = generateRandomOrderId();
await createOrder(orderId, usdcOrderData);
const orderDetails = await getOrderDetails(orderId);
Expand Down Expand Up @@ -292,9 +331,9 @@ describe('Order Endpoint Blackbox Tests', () => {
repaidOrderDetails = await getOrderDetails(orderId);
expect(repaidOrderDetails.payment_status).toBe('paid');
expect(repaidOrderDetails.withdrawal_status).toBe('completed');
}, 50000);
}, 100000);

it.skip('should not update order if received payment in wrong currency', async () => {
it('should not update order if received payment in wrong currency', async () => {
const orderId = generateRandomOrderId();
await createOrder(orderId, usdcOrderData);
const orderDetails = await getOrderDetails(orderId);
Expand All @@ -317,7 +356,7 @@ describe('Order Endpoint Blackbox Tests', () => {
expect(repaidOrderDetails.withdrawal_status).toBe('waiting');
}, 50000);

it('should be able to force withdraw partially repayed order', async () => {
it('should be able to force withdraw partially repayed DOT order', async () => {
const orderId = generateRandomOrderId();
await createOrder(orderId, dotOrderData);
const orderDetails = await getOrderDetails(orderId);
Expand All @@ -342,6 +381,31 @@ describe('Order Endpoint Blackbox Tests', () => {
expect(forcedOrderDetails.withdrawal_status).toBe('forced');
}, 100000);

it('should be able to force withdraw partially repayed USDC order', async () => {
const orderId = generateRandomOrderId();
await createOrder(orderId, usdcOrderData);
const orderDetails = await getOrderDetails(orderId);
const paymentAccount = orderDetails.payment_account;
expect(paymentAccount).toBeDefined();

await transferFunds(orderDetails.currency.rpc_url, paymentAccount, usdcOrderData.amount/2);

// lets wait for the changes to get propagated on chain and app to catch them
await new Promise(resolve => setTimeout(resolve, 15000));

const partiallyRepaidOrderDetails = await getOrderDetails(orderId);
expect(partiallyRepaidOrderDetails.payment_status).toBe('pending');
expect(partiallyRepaidOrderDetails.withdrawal_status).toBe('waiting');

const response = await request(baseUrl)
.post(`/v2/order/${orderId}/forceWithdrawal`);
expect(response.status).toBe(201);

let forcedOrderDetails = await getOrderDetails(orderId);
expect(forcedOrderDetails.payment_status).toBe('pending');
expect(forcedOrderDetails.withdrawal_status).toBe('forced');
}, 100000);

it('should return 404 for non-existing order on force withdrawal', async () => {
const nonExistingOrderId = 'nonExistingOrder123';
const response = await request(baseUrl)
Expand Down

0 comments on commit cf19a81

Please sign in to comment.