diff --git a/crates/js_api/src/subgraph/order.rs b/crates/js_api/src/subgraph/order.rs index ecd50b9ff..2dedda3cf 100644 --- a/crates/js_api/src/subgraph/order.rs +++ b/crates/js_api/src/subgraph/order.rs @@ -27,3 +27,59 @@ pub async fn get_order(url: &str, id: &str) -> Result, + end_timestamp: Option, +) -> Result { + let client = OrderbookSubgraphClient::new(Url::parse(url)?); + let trades = client + .order_trades_list( + Id::new(order_id), + pagination_args, + start_timestamp, + end_timestamp, + ) + .await?; + Ok(to_value(&trades)?) +} + +/// Get details for a specific trade +/// Returns a Trade struct +#[wasm_bindgen(js_name = "getOrderTradeDetail")] +pub async fn get_order_trade_detail( + url: &str, + trade_id: &str, +) -> Result { + let client = OrderbookSubgraphClient::new(Url::parse(url)?); + let trade = client.order_trade_detail(Id::new(trade_id)).await?; + Ok(to_value(&trade)?) +} + +/// Fetch the count of trades for a specific order +/// Returns the count as a JavaScript-compatible number +#[wasm_bindgen(js_name = "getOrderTradesCount")] +pub async fn get_order_trades_count( + url: &str, + order_id: &str, + start_timestamp: Option, + end_timestamp: Option, +) -> Result { + // Create the subgraph client using the provided URL + let client = OrderbookSubgraphClient::new(Url::parse(url)?); + + // Fetch all trades for the specific order and calculate the count + let trades_count = client + .order_trades_list_all(Id::new(order_id), start_timestamp, end_timestamp) + .await? + .len(); + + // Convert the count to a JavaScript-compatible value and return + Ok(to_value(&trades_count)?) +} diff --git a/crates/subgraph/src/types/common.rs b/crates/subgraph/src/types/common.rs index cd09b1aa5..aebbc7222 100644 --- a/crates/subgraph/src/types/common.rs +++ b/crates/subgraph/src/types/common.rs @@ -315,14 +315,18 @@ pub struct TradeEvent { } #[derive(cynic::QueryFragment, Debug, Clone, Serialize)] +#[cfg_attr(target_family = "wasm", derive(Tsify))] #[typeshare] #[serde(rename_all = "camelCase")] pub struct Trade { pub id: Bytes, pub trade_event: TradeEvent, + #[cfg_attr(target_family = "wasm", tsify(type = "SgBigInt"))] pub output_vault_balance_change: TradeVaultBalanceChange, pub order: TradeStructPartialOrder, + #[cfg_attr(target_family = "wasm", tsify(type = "SgBigInt"))] pub input_vault_balance_change: TradeVaultBalanceChange, + #[cfg_attr(target_family = "wasm", tsify(type = "SgBigInt"))] pub timestamp: BigInt, pub orderbook: Orderbook, } @@ -584,4 +588,5 @@ mod impls { impl_all_wasm_traits!(Bytes); impl_all_wasm_traits!(OrdersListFilterArgs); impl_all_wasm_traits!(VaultsListFilterArgs); + impl_all_wasm_traits!(Trade); } diff --git a/packages/orderbook/test/js_api/order.test.ts b/packages/orderbook/test/js_api/order.test.ts index 094a6d93c..9dbdfb1b3 100644 --- a/packages/orderbook/test/js_api/order.test.ts +++ b/packages/orderbook/test/js_api/order.test.ts @@ -1,13 +1,23 @@ import assert from "assert"; import { getLocal } from "mockttp"; import { describe, it, beforeEach, afterEach } from "vitest"; -import { Order, OrderWithSubgraphName } from "../../dist/types/js_api.js"; -import { getOrders, getOrder } from "../../dist/cjs/js_api.js"; +import { + Order, + OrderWithSubgraphName, + Trade, +} from "../../dist/types/js_api.js"; +import { + getOrders, + getOrder, + getOrderTradesList, + getOrderTradeDetail, + getOrderTradesCount, +} from "../../dist/cjs/js_api.js"; const order1 = { id: "order1", orderBytes: - "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", orderHash: "0x1", owner: "0x0000000000000000000000000000000000000000", outputs: [ @@ -70,7 +80,7 @@ const order1 = { }, trades: [], }; -const order2 = { +const order2: Order = { id: "order2", orderBytes: "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", @@ -135,6 +145,163 @@ const order2 = { id: "0x0000000000000000000000000000000000000000", }, trades: [], +} as unknown as Order; + +const mockOrderTradesList: Trade[] = [ + { + id: "0x07db8b3f3e7498f9d4d0e40b98f57c020d3d277516e86023a8200a20464d4894", + timestamp: "1632000000", + tradeEvent: { + sender: "0x0000000000000000000000000000000000000000", + transaction: { + id: "0x0000000000000000000000000000000000000000", + from: "0x0000000000000000000000000000000000000000", + timestamp: "1632000000", + blockNumber: "0", + }, + }, + outputVaultBalanceChange: { + amount: "-100", + vault: { + id: "vault-1", + vaultId: "1", + token: { + id: "token-1", + address: "0x1111111111111111111111111111111111111111", + name: "Token One", + symbol: "TK1", + decimals: "18", + }, + }, + id: "output-change-1", + // @ts-expect-error __typename is expected in rpc response + __typename: "TradeVaultBalanceChange", + newVaultBalance: "900", + oldVaultBalance: "1000", + timestamp: "1632000000", + transaction: { + id: "0x0000000000000000000000000000000000000000", + from: "0x0000000000000000000000000000000000000000", + timestamp: "1632000000", + blockNumber: "0", + }, + orderbook: { id: "orderbook-1" }, + }, + order: { + id: order1.id, + orderHash: + "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", + }, + inputVaultBalanceChange: { + amount: "50", + vault: { + id: "vault-2", + vaultId: "2", + token: { + id: "token-2", + address: "0x2222222222222222222222222222222222222222", + name: "Token Two", + symbol: "TK2", + decimals: "18", + }, + }, + id: "input-change-1", + // @ts-expect-error __typename is expected in rpc response + __typename: "TradeVaultBalanceChange", + newVaultBalance: "150", + oldVaultBalance: "100", + timestamp: "1632000000", + transaction: { + id: "0x0000000000000000000000000000000000000000", + from: "0x0000000000000000000000000000000000000000", + timestamp: "1632000000", + blockNumber: "0", + }, + orderbook: { id: "orderbook-1" }, + }, + orderbook: { + id: "orderbook-1", + }, + }, +]; + +const mockTrade: Trade = { + id: "trade1", + order: { + id: "order1", + orderHash: "0x1", + }, + tradeEvent: { + sender: "0x0000000000000000000000000000000000000000", + transaction: { + id: "0x0000000000000000000000000000000000000000", + from: "0x0000000000000000000000000000000000000000", + blockNumber: "0", + timestamp: "0", + }, + }, + timestamp: "0", + orderbook: { + id: "0x0000000000000000000000000000000000000000", + }, + outputVaultBalanceChange: { + id: "0x0000000000000000000000000000000000000000", + // @ts-expect-error __typename is expected in rpc response + __typename: "TradeVaultBalanceChange", + amount: "-7", + newVaultBalance: "93", + oldVaultBalance: "100", + vault: { + id: "0x0000000000000000000000000000000000000000", + vaultId: "1", + token: { + id: "0x0000000000000000000000000000000000000000", + address: "0x0000000000000000000000000000000000000000", + name: "T1", + symbol: "T1", + decimals: "18", + }, + }, + timestamp: "0", + transaction: { + id: "0x0000000000000000000000000000000000000000", + from: "0x0000000000000000000000000000000000000000", + blockNumber: "0", + timestamp: "0", + }, + orderbook: { + id: "0x0000000000000000000000000000000000000000", + }, + }, + inputVaultBalanceChange: { + id: "0x0000000000000000000000000000000000000000", + // @ts-expect-error __typename is expected in rpc response + __typename: "TradeVaultBalanceChange", + amount: "5", + newVaultBalance: "105", + oldVaultBalance: "100", + vault: { + id: "0x0000000000000000000000000000000000000000", + vaultId: "2", + token: { + id: "0x0000000000000000000000000000000000000000", + address: "0x0000000000000000000000000000000000000000", + name: "T2", + symbol: "T2", + decimals: "6", + }, + }, + timestamp: "0", + transaction: { + id: "0x0000000000000000000000000000000000000000", + from: "0x0000000000000000000000000000000000000000", + blockNumber: "0", + timestamp: "0", + }, + orderbook: { + id: "0x0000000000000000000000000000000000000000", + }, + }, }; describe("Rain Orderbook JS API Package Bindgen Tests - Order", async function () { @@ -152,7 +319,10 @@ describe("Rain Orderbook JS API Package Bindgen Tests - Order", async function ( assert.equal(result.id, order1.id); } catch (e) { console.log(e); - assert.fail("expected to resolve, but failed"); + assert.fail( + "expected to resolve, but failed" + + (e instanceof Error ? e.message : String(e)) + ); } }); @@ -187,7 +357,118 @@ describe("Rain Orderbook JS API Package Bindgen Tests - Order", async function ( assert.equal(result[1].subgraphName, "network-two"); } catch (e) { console.log(e); - assert.fail("expected to resolve, but failed"); + assert.fail( + "expected to resolve, but failed" + + (e instanceof Error ? e.message : String(e)) + ); + } + }); + + it("should fetch trades for a single order", async () => { + await mockServer.forPost("/sg1").thenReply( + 200, + JSON.stringify({ + data: { + trades: mockOrderTradesList, + }, + }) + ); + + try { + const result = await getOrderTradesList( + mockServer.url + "/sg1", + order1.id, + { + page: 1, + pageSize: 10, + }, + undefined, + undefined + ); + + assert.ok(result, "Result should exist"); + assert.equal(result.length, 1, "Should have one trade"); + assert.equal( + result[0].id, + "0x07db8b3f3e7498f9d4d0e40b98f57c020d3d277516e86023a8200a20464d4894", + "Trade ID should match" + ); + } catch (e: unknown) { + console.error("Test error:", e); + assert.fail( + "Expected to resolve, but failed: " + + (e instanceof Error ? e.message : String(e)) + ); + } + }); + + it("should fetch order trade detail", async () => { + await mockServer + .forPost("/sg1") + .thenReply(200, JSON.stringify({ data: { trade: mockTrade } })); + + try { + const result: Trade = await getOrderTradeDetail( + mockServer.url + "/sg1", + mockTrade.id + ); + assert.equal(result.id, mockTrade.id); + assert.equal(result.order.id, mockTrade.order.id); + assert.equal( + result.outputVaultBalanceChange.amount, + mockTrade.outputVaultBalanceChange.amount + ); + assert.equal( + result.inputVaultBalanceChange.amount, + mockTrade.inputVaultBalanceChange.amount + ); + } catch (e) { + console.log(e); + assert.fail( + "expected to resolve, but failed" + + +(e instanceof Error ? e.message : String(e)) + ); + } + }); + it("should fetch trade count for a single order", async () => { + await mockServer.forPost("/sg1").thenReply( + 200, + JSON.stringify({ + data: { + trades: mockOrderTradesList, + }, + }) + ); + + await mockServer.forPost("/sg1").thenReply( + 200, + JSON.stringify({ + data: { + trades: [], + }, + }) + ); + + try { + const count = await getOrderTradesCount( + mockServer.url + "/sg1", + "0x07db8b3f3e7498f9d4d0e40b98f57c020d3d277516e86023a8200a20464d4894", + undefined, + undefined + ); + console.log(count); + + assert.strictEqual(typeof count, "number", "Count should be a number"); + assert.strictEqual(count, 1, "Should count one trade"); + } catch (e) { + console.error("Test error:", e); + if (e instanceof Error) { + console.error("Error details:", e.stack); + } + assert.fail( + "Expected to resolve, but failed: " + + (e instanceof Error ? e.message : String(e)) + ); } }); }); diff --git a/packages/ui-components/src/lib/index.ts b/packages/ui-components/src/lib/index.ts index e5f80e458..f96bedf55 100644 --- a/packages/ui-components/src/lib/index.ts +++ b/packages/ui-components/src/lib/index.ts @@ -39,6 +39,7 @@ export { } from './utils/time'; export { bigintStringToHex, HEX_INPUT_REGEX } from './utils/hex'; export { vaultBalanceDisplay } from './utils/vault'; +export { prepareHistoricalOrderChartData } from './services/historicalOrderCharts'; // Constants diff --git a/packages/ui-components/src/lib/services/historicalOrderCharts.ts b/packages/ui-components/src/lib/services/historicalOrderCharts.ts new file mode 100644 index 000000000..e48f85628 --- /dev/null +++ b/packages/ui-components/src/lib/services/historicalOrderCharts.ts @@ -0,0 +1,526 @@ +import type { Trade } from '../typeshare/subgraphTypes'; +import type { UTCTimestamp } from 'lightweight-charts'; +import { timestampSecondsToUTCTimestamp } from '../utils/time'; +import { sortBy } from 'lodash'; +import { formatUnits } from 'viem'; + +export type HistoricalOrderChartData = { value: number; time: UTCTimestamp; color?: string }[]; + +export function prepareHistoricalOrderChartData(takeOrderEntities: Trade[], colorTheme: string) { + const transformedData = takeOrderEntities.map((d) => ({ + value: Math.abs( + Number( + formatUnits( + BigInt(d.inputVaultBalanceChange.amount), + Number(d.inputVaultBalanceChange.vault.token.decimals ?? 0) + ) + ) / + Number( + formatUnits( + BigInt(d.outputVaultBalanceChange.amount), + Number(d.outputVaultBalanceChange.vault.token.decimals ?? 0) + ) + ) + ), + time: timestampSecondsToUTCTimestamp(BigInt(d.timestamp)), + color: colorTheme == 'dark' ? '#5178FF' : '#4E4AF6', + outputAmount: +d.outputVaultBalanceChange.amount + })); + + // if we have multiple object in the array with the same timestamp, we need to merge them + // we do this by taking the weighted average of the ioratio values for objects that share the same timestamp. + const uniqueTimestamps = Array.from(new Set(transformedData.map((d) => d.time))); + const finalData: HistoricalOrderChartData = []; + uniqueTimestamps.forEach((timestamp) => { + const objectsWithSameTimestamp = transformedData.filter((d) => d.time === timestamp); + if (objectsWithSameTimestamp.length > 1) { + // calculate a weighted average of the ioratio values using the amount of the output token as the weight + const ioratioSum = objectsWithSameTimestamp.reduce( + (acc, d) => acc + d.value * d.outputAmount, + 0 + ); + const outputAmountSum = objectsWithSameTimestamp.reduce((acc, d) => acc + d.outputAmount, 0); + const ioratioAverage = ioratioSum / outputAmountSum; + finalData.push({ + value: ioratioAverage, + time: timestamp, + color: objectsWithSameTimestamp[0].color + }); + } else { + finalData.push(objectsWithSameTimestamp[0]); + } + }); + + return sortBy(finalData, (d) => d.time); +} + +if (import.meta.vitest) { + const { it, expect } = import.meta.vitest; + + it('transforms and sorts data as expected', () => { + const takeOrderEntities: Trade[] = [ + { + id: '1', + timestamp: '1632000000', + tradeEvent: { + sender: 'sender_address', + transaction: { + id: 'transaction_id', + from: 'sender_address', + timestamp: '1632000000', + blockNumber: '0' + } + }, + outputVaultBalanceChange: { + amount: '100', + vault: { + id: '1', + vault_id: 'vault-id1', + token: { + id: 'output_token', + address: 'output_token', + name: 'output_token', + symbol: 'output_token', + decimals: '1' + } + }, + id: '1', + typename: 'Withdraw', + newVaultBalance: '0', + oldVaultBalance: '0', + timestamp: '0', + transaction: { + id: 'transaction_id', + from: 'sender_address', + timestamp: '1632000000', + blockNumber: '0' + }, + orderbook: { id: '1' } + }, + order: { + id: 'order_id', + orderHash: 'orderHash' + }, + inputVaultBalanceChange: { + vault: { + id: '1', + vault_id: 'vault-id1', + token: { + id: 'output_token', + address: 'output_token', + name: 'output_token', + symbol: 'output_token', + decimals: '1' + } + }, + amount: '50', + id: '1', + typename: 'Withdraw', + newVaultBalance: '0', + oldVaultBalance: '0', + timestamp: '0', + transaction: { + id: 'transaction_id', + from: 'sender_address', + timestamp: '1632000000', + blockNumber: '0' + }, + orderbook: { id: '1' } + }, + orderbook: { + id: '0x00' + } + }, + { + id: '2', + timestamp: '1631000000', + tradeEvent: { + sender: 'sender_address', + transaction: { + id: 'transaction_id', + from: 'sender_address', + timestamp: '1631000000', + blockNumber: '0' + } + }, + outputVaultBalanceChange: { + amount: '100', + vault: { + id: '1', + vault_id: 'vault-id1', + token: { + id: 'output_token', + address: 'output_token', + name: 'output_token', + symbol: 'output_token', + decimals: '1' + } + }, + id: '1', + typename: 'Withdraw', + newVaultBalance: '0', + oldVaultBalance: '0', + timestamp: '0', + transaction: { + id: 'transaction_id', + from: 'sender_address', + timestamp: '1632000000', + blockNumber: '0' + }, + orderbook: { id: '1' } + }, + order: { + id: 'order_id', + orderHash: 'orderHash' + }, + inputVaultBalanceChange: { + vault: { + id: '1', + vault_id: 'vault-id1', + token: { + id: 'output_token', + address: 'output_token', + name: 'output_token', + symbol: 'output_token', + decimals: '1' + } + }, + amount: '50', + id: '1', + typename: 'Withdraw', + newVaultBalance: '0', + oldVaultBalance: '0', + timestamp: '0', + transaction: { + id: 'transaction_id', + from: 'sender_address', + timestamp: '1632000000', + blockNumber: '0' + }, + orderbook: { id: '1' } + }, + orderbook: { + id: '0x00' + } + }, + { + id: '3', + timestamp: '1630000000', + tradeEvent: { + sender: 'sender_address', + transaction: { + id: 'transaction_id', + from: 'sender_address', + timestamp: '1630000000', + blockNumber: '0' + } + }, + outputVaultBalanceChange: { + amount: '100', + vault: { + id: '1', + vault_id: 'vault-id1', + token: { + id: 'output_token', + address: 'output_token', + name: 'output_token', + symbol: 'output_token', + decimals: '1' + } + }, + id: '1', + typename: 'Withdraw', + newVaultBalance: '0', + oldVaultBalance: '0', + timestamp: '0', + transaction: { + id: 'transaction_id', + from: 'sender_address', + timestamp: '1632000000', + blockNumber: '0' + }, + orderbook: { id: '1' } + }, + order: { + id: 'order_id', + orderHash: 'orderHash' + }, + inputVaultBalanceChange: { + vault: { + id: '1', + vault_id: 'vault-id1', + token: { + id: 'output_token', + address: 'output_token', + name: 'output_token', + symbol: 'output_token', + decimals: '1' + } + }, + amount: '50', + id: '1', + typename: 'Withdraw', + newVaultBalance: '0', + oldVaultBalance: '0', + timestamp: '0', + transaction: { + id: 'transaction_id', + from: 'sender_address', + timestamp: '1632000000', + blockNumber: '0' + }, + orderbook: { id: '1' } + }, + orderbook: { + id: '0x00' + } + } + ]; + + const result = prepareHistoricalOrderChartData(takeOrderEntities, 'dark'); + + expect(result.length).toEqual(3); + expect(result[0].value).toEqual(0.5); + expect(result[0].time).toEqual(1630000000); + expect(result[1].value).toEqual(0.5); + expect(result[1].time).toEqual(1631000000); + expect(result[2].value).toEqual(0.5); + expect(result[2].time).toEqual(1632000000); + + // check the color + expect(result[0].color).toEqual('#5178FF'); + expect(result[1].color).toEqual('#5178FF'); + expect(result[2].color).toEqual('#5178FF'); + }); + + it('handles the case where multiple trades have the same timestamp', () => { + const takeOrderEntities: Trade[] = [ + { + id: '1', + timestamp: '1632000000', + tradeEvent: { + sender: 'sender_address', + transaction: { + id: 'transaction_id', + from: 'sender_address', + timestamp: '1632000000', + blockNumber: '0' + } + }, + outputVaultBalanceChange: { + amount: '100', + vault: { + id: '1', + vault_id: 'vault-id1', + token: { + id: 'output_token', + address: 'output_token', + name: 'output_token', + symbol: 'output_token', + decimals: '1' + } + }, + id: '1', + typename: 'Withdraw', + newVaultBalance: '0', + oldVaultBalance: '0', + timestamp: '0', + transaction: { + id: 'transaction_id', + from: 'sender_address', + timestamp: '1632000000', + blockNumber: '0' + }, + orderbook: { id: '1' } + }, + order: { + id: 'order_id', + orderHash: 'orderHash' + }, + inputVaultBalanceChange: { + vault: { + id: '1', + vault_id: 'vault-id1', + token: { + id: 'output_token', + address: 'output_token', + name: 'output_token', + symbol: 'output_token', + decimals: '1' + } + }, + amount: '50', + id: '1', + typename: 'Withdraw', + newVaultBalance: '0', + oldVaultBalance: '0', + timestamp: '0', + transaction: { + id: 'transaction_id', + from: 'sender_address', + timestamp: '1632000000', + blockNumber: '0' + }, + orderbook: { id: '1' } + }, + orderbook: { + id: '0x00' + } + }, + { + id: '2', + timestamp: '1632000000', + tradeEvent: { + sender: 'sender_address', + transaction: { + id: 'transaction_id', + from: 'sender_address', + timestamp: '1632000000', + blockNumber: '0' + } + }, + outputVaultBalanceChange: { + amount: '200', + vault: { + id: '1', + vault_id: 'vault-id1', + token: { + id: 'output_token', + address: 'output_token', + name: 'output_token', + symbol: 'output_token', + decimals: '1' + } + }, + id: '1', + typename: 'Withdraw', + newVaultBalance: '0', + oldVaultBalance: '0', + timestamp: '0', + transaction: { + id: 'transaction_id', + from: 'sender_address', + timestamp: '1632000000', + blockNumber: '0' + }, + orderbook: { id: '1' } + }, + order: { + id: 'order_id', + orderHash: 'orderHash' + }, + inputVaultBalanceChange: { + vault: { + id: '1', + vault_id: 'vault-id1', + token: { + id: 'output_token', + address: 'output_token', + name: 'output_token', + symbol: 'output_token', + decimals: '1' + } + }, + amount: '50', + id: '1', + typename: 'Withdraw', + newVaultBalance: '0', + oldVaultBalance: '0', + timestamp: '0', + transaction: { + id: 'transaction_id', + from: 'sender_address', + timestamp: '1632000000', + blockNumber: '0' + }, + orderbook: { id: '1' } + }, + orderbook: { + id: '0x00' + } + }, + { + id: '3', + timestamp: '1632000000', + tradeEvent: { + sender: 'sender_address', + transaction: { + id: 'transaction_id', + from: 'sender_address', + timestamp: '1632000000', + blockNumber: '0' + } + }, + outputVaultBalanceChange: { + amount: '400', + vault: { + id: '1', + vault_id: 'vault-id1', + token: { + id: 'output_token', + address: 'output_token', + name: 'output_token', + symbol: 'output_token', + decimals: '1' + } + }, + id: '1', + typename: 'Withdraw', + newVaultBalance: '0', + oldVaultBalance: '0', + timestamp: '0', + transaction: { + id: 'transaction_id', + from: 'sender_address', + timestamp: '1632000000', + blockNumber: '0' + }, + orderbook: { id: '1' } + }, + order: { + id: 'order_id', + orderHash: 'orderHash' + }, + inputVaultBalanceChange: { + vault: { + id: '1', + vault_id: 'vault-id1', + token: { + id: 'output_token', + address: 'output_token', + name: 'output_token', + symbol: 'output_token', + decimals: '1' + } + }, + amount: '50', + id: '1', + typename: 'Withdraw', + newVaultBalance: '0', + oldVaultBalance: '0', + timestamp: '0', + transaction: { + id: 'transaction_id', + from: 'sender_address', + timestamp: '1632000000', + blockNumber: '0' + }, + orderbook: { id: '1' } + }, + orderbook: { + id: '0x00' + } + } + ]; + + const result = prepareHistoricalOrderChartData(takeOrderEntities, 'dark'); + + // calculate the weighted average of the ioratio values + const ioratioSum = 0.5 * 100 + 0.25 * 200 + 0.125 * 400; + const outputAmountSum = 100 + 200 + 400; + const ioratioAverage = ioratioSum / outputAmountSum; + + expect(result.length).toEqual(1); + expect(result[0].value).toEqual(ioratioAverage); + }); +} diff --git a/packages/webapp/src/routes/orders/[id]/+page.svelte b/packages/webapp/src/routes/orders/[id]/+page.svelte new file mode 100644 index 000000000..0e7cba3e1 --- /dev/null +++ b/packages/webapp/src/routes/orders/[id]/+page.svelte @@ -0,0 +1,36 @@ + + + + +{#if $query.data} + {#each $query.data as trade} + {trade.id} + + {/each} +{/if} diff --git a/packages/webapp/src/routes/orders/[id]/TradeCount.svelte b/packages/webapp/src/routes/orders/[id]/TradeCount.svelte new file mode 100644 index 000000000..3828f387f --- /dev/null +++ b/packages/webapp/src/routes/orders/[id]/TradeCount.svelte @@ -0,0 +1,22 @@ + + +
+

Trade Count

+ {#if $query.data} + {$query.data} + {/if} +
diff --git a/packages/webapp/src/routes/orders/[id]/TradeDetail.svelte b/packages/webapp/src/routes/orders/[id]/TradeDetail.svelte new file mode 100644 index 000000000..417a774a1 --- /dev/null +++ b/packages/webapp/src/routes/orders/[id]/TradeDetail.svelte @@ -0,0 +1,22 @@ + + +
+

Trade Detail

+ {#if $query.data} + {$query.data.timestamp} + {/if} +
diff --git a/tauri-app/src-tauri/src/main.rs b/tauri-app/src-tauri/src/main.rs index 71750fafd..ee78d1106 100644 --- a/tauri-app/src-tauri/src/main.rs +++ b/tauri-app/src-tauri/src/main.rs @@ -19,7 +19,7 @@ use commands::order::{ }; use commands::order_quote::{batch_order_quotes, debug_order_quote}; use commands::order_take::{ - order_trades_count, order_trades_list, order_trades_list_write_csv, order_vaults_volume, + order_trades_count, order_trades_list_write_csv, order_vaults_volume, order_trades_list }; use commands::trade_debug::debug_trade; use commands::vault::{ diff --git a/tauri-app/src/lib/components/charts/OrderTradesChart.svelte b/tauri-app/src/lib/components/charts/OrderTradesChart.svelte index 03247ffcf..9d94573c8 100644 --- a/tauri-app/src/lib/components/charts/OrderTradesChart.svelte +++ b/tauri-app/src/lib/components/charts/OrderTradesChart.svelte @@ -1,16 +1,32 @@