diff --git a/crates/js_api/src/subgraph/add_order.rs b/crates/js_api/src/subgraph/add_order.rs
new file mode 100644
index 000000000..57efbba77
--- /dev/null
+++ b/crates/js_api/src/subgraph/add_order.rs
@@ -0,0 +1,16 @@
+use cynic::Id;
+use rain_orderbook_bindings::wasm_traits::prelude::*;
+use rain_orderbook_subgraph_client::{OrderbookSubgraphClient, OrderbookSubgraphClientError};
+use reqwest::Url;
+
+/// Internal function to fetch Add Orders for a given transaction
+/// Returns an array of AddOrder structs
+#[wasm_bindgen(js_name = "getTransactionAddOrders")]
+pub async fn get_transaction_add_orders(
+ url: &str,
+ tx_hash: &str,
+) -> Result {
+ let client = OrderbookSubgraphClient::new(Url::parse(url)?);
+ let add_orders = client.transaction_add_orders(Id::new(tx_hash)).await?;
+ Ok(to_value(&add_orders)?)
+}
diff --git a/crates/js_api/src/subgraph/mod.rs b/crates/js_api/src/subgraph/mod.rs
index 7df2bad7f..7b843a1ba 100644
--- a/crates/js_api/src/subgraph/mod.rs
+++ b/crates/js_api/src/subgraph/mod.rs
@@ -7,6 +7,7 @@ use rain_orderbook_subgraph_client::OrderbookSubgraphClientError;
use thiserror::Error;
use wasm_bindgen::{JsError, JsValue};
+pub mod add_order;
pub mod order;
pub mod transaction;
pub mod vault;
diff --git a/crates/subgraph/src/orderbook_client.rs b/crates/subgraph/src/orderbook_client.rs
index aa902c629..c7096bc9f 100644
--- a/crates/subgraph/src/orderbook_client.rs
+++ b/crates/subgraph/src/orderbook_client.rs
@@ -2,6 +2,7 @@ use crate::cynic_client::{CynicClient, CynicClientError};
use crate::pagination::{PaginationArgs, PaginationClient, PaginationClientError};
use crate::performance::vol::{get_vaults_vol, VaultVolume};
use crate::performance::OrderPerformance;
+use crate::types::add_order::{TransactionAddOrdersQuery, TransactionAddOrdersVariables};
use crate::types::common::*;
use crate::types::order::{
BatchOrderDetailQuery, BatchOrderDetailQueryVariables, OrderDetailQuery, OrderIdList,
@@ -395,4 +396,24 @@ impl OrderbookSubgraphClient {
.ok_or(OrderbookSubgraphClientError::Empty)?;
Ok(transaction)
}
+
+ /// Fetch all add orders for a given transaction
+ pub async fn transaction_add_orders(
+ &self,
+ id: Id,
+ ) -> Result, OrderbookSubgraphClientError> {
+ let data = self
+ .query::(
+ TransactionAddOrdersVariables {
+ id: Bytes(id.inner().to_string()),
+ },
+ )
+ .await?;
+
+ if data.add_orders.is_empty() {
+ return Err(OrderbookSubgraphClientError::Empty);
+ }
+
+ Ok(data.add_orders)
+ }
}
diff --git a/crates/subgraph/src/types/add_order.rs b/crates/subgraph/src/types/add_order.rs
new file mode 100644
index 000000000..04db0bbe4
--- /dev/null
+++ b/crates/subgraph/src/types/add_order.rs
@@ -0,0 +1,16 @@
+use super::common::{AddOrderWithOrder, Bytes};
+use crate::schema;
+use typeshare::typeshare;
+
+#[derive(cynic::QueryVariables, Debug)]
+pub struct TransactionAddOrdersVariables {
+ pub id: Bytes,
+}
+
+#[derive(cynic::QueryFragment, Debug)]
+#[cynic(graphql_type = "Query", variables = "TransactionAddOrdersVariables")]
+#[typeshare]
+pub struct TransactionAddOrdersQuery {
+ #[arguments(where: { transaction_: { id: $id } })]
+ pub add_orders: Vec,
+}
diff --git a/crates/subgraph/src/types/common.rs b/crates/subgraph/src/types/common.rs
index cc97ff93c..18404311d 100644
--- a/crates/subgraph/src/types/common.rs
+++ b/crates/subgraph/src/types/common.rs
@@ -382,6 +382,15 @@ pub struct AddOrder {
pub transaction: Transaction,
}
+#[derive(cynic::QueryFragment, Debug, Serialize, Clone)]
+#[cfg_attr(target_family = "wasm", derive(Tsify))]
+#[cynic(graphql_type = "AddOrder")]
+pub struct AddOrderWithOrder {
+ pub transaction: Transaction,
+ #[cfg_attr(target_family = "wasm", tsify(type = "OrderSubgraph"))]
+ pub order: Order,
+}
+
#[derive(cynic::Scalar, Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(target_family = "wasm", derive(Tsify), serde(rename = "SgBigInt"))]
#[typeshare]
diff --git a/crates/subgraph/src/types/mod.rs b/crates/subgraph/src/types/mod.rs
index aa590dc15..59d6e66af 100644
--- a/crates/subgraph/src/types/mod.rs
+++ b/crates/subgraph/src/types/mod.rs
@@ -1,3 +1,4 @@
+pub mod add_order;
pub mod common;
mod impls;
pub mod order;
diff --git a/packages/orderbook/test/js_api/addOrder.test.ts b/packages/orderbook/test/js_api/addOrder.test.ts
new file mode 100644
index 000000000..5bcc1cc3c
--- /dev/null
+++ b/packages/orderbook/test/js_api/addOrder.test.ts
@@ -0,0 +1,381 @@
+import assert from 'assert';
+import { getLocal } from 'mockttp';
+import { describe, it, beforeEach, afterEach } from 'vitest';
+import { Transaction, AddOrderWithOrder } from '../../dist/types/js_api.js';
+import { getTransactionAddOrders } from '../../dist/cjs/js_api.js';
+
+const transaction1: Transaction = {
+ id: '0xb5d715bc74b7a7f2aac8cca544c1c95e209ed4113b82269ac3285142324bc6af',
+ from: '0xf08bcbce72f62c95dcb7c07dcb5ed26acfcfbc11',
+ blockNumber: '37432554',
+ timestamp: '1739448802'
+};
+
+const mockAddOrder: AddOrderWithOrder = {
+ transaction: {
+ id: '0xb5d715bc74b7a7f2aac8cca544c1c95e209ed4113b82269ac3285142324bc6af',
+ from: '0xf08bcbce72f62c95dcb7c07dcb5ed26acfcfbc11',
+ blockNumber: '37432554',
+ timestamp: '1739448802'
+ },
+ order: {
+ id: '0x1a69eeb7970d3c8d5776493327fb262e31fc880c9cc4a951607418a7963d9fa1',
+ orderBytes:
+ '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000f08bcbce72f62c95dcb7c07dcb5ed26acfcfbc1100000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000005c00000000000000000000000000000000000000000000000000000000000000640392c489ef67afdc348209452c338ea5ba2b6152b936e152f610d05e1a20621a40000000000000000000000005fb33d710f8b58de4c9fdec703b5c2487a5219d600000000000000000000000084c6e7f5a1e5dd89594cc25bef4722a1b8871ae60000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000049d000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000c7d713b49da0000914d696e20747261646520616d6f756e742e00000000000000000000000000008b616d6f756e742d75736564000000000000000000000000000000000000000000000000000000000000000000000000000000000000000340aad21b3b70000000000000000000000000000000000000000000000000006194049f30f7200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000000000000000000000000000e043da6172500008f6c6173742d74726164652d74696d65000000000000000000000000000000008d6c6173742d74726164652d696f0000000000000000000000000000000000008c696e697469616c2d74696d650000000000000000000000000000000000000000000000000000000000000000000000000000000000000006f05b59d3b200000000000000000000000000000000000000000000000000008ac7230489e80000000000000000000000020000915e36ef882941816356bc3718df868054f868ad000000000000000000000000000000000000000000000000000000000000027d0a00000024007400e0015801b401e001f40218025c080500040b20000200100001001000000b120003001000010b110004001000030b0100051305000201100001011000003d120000011000020010000003100404211200001d02000001100003031000010c1200004911000003100404001000012b12000001100003031000010c1200004a0200001a0b00090b1000060b20000700100000001000011b1200001a10000047120000001000001a1000004712000001100000011000002e12000001100005011000042e120000001000053d12000001100004001000042e1200000010000601100005001000032e120000481200011d0b020a0010000001100000011000062713000001100003031000010c12000049110000001000030010000247120000001000010b110008001000050110000700100001201200001f12000001100000011000004712000000100006001000073d120000011000002b12000000100008001000043b120000160901080b1000070b10000901100008001000013d1200001b12000001100006001000013d1200000b100009001000033a120000001000040010000248120001001000000b110008001000053d12000000100006001000042b1200000a0401011a10000001100009031000010c1200004a020000001000000110000a031000010c1200004a020000040200010110000b031000010c120000491100000803000201100009031000010c120000491100000110000a031000010c12000049110000100c01030110000d001000002e1200000110000c3e120000001000010010000100100001001000010010000100100001001000010010000100100001001000013d1a0000020100010210000e3611000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000001d80c49bbbcd1c0911346656b529df9e5c2f783d0000000000000000000000000000000000000000000000000000000000000012a6e3c06415539f92823a18ba63e1c0303040c4892970a0d1e3a27663d7583b33000000000000000000000000000000000000000000000000000000000000000100000000000000000000000012e605bc104e93b45e1ad99f9e555f659051c2bb0000000000000000000000000000000000000000000000000000000000000012a6e3c06415539f92823a18ba63e1c0303040c4892970a0d1e3a27663d7583b33',
+ orderHash: '0x557147dd0daa80d5beff0023fe6a3505469b2b8c4406ce1ab873e1a652572dd4',
+ owner: '0xf08bcbce72f62c95dcb7c07dcb5ed26acfcfbc11',
+ outputs: [
+ {
+ id: '0x49f6b665c395c7b975caa2fc167cb5119981bbb86798bcaf3c4570153d09dfcf',
+ owner: '0xf08bcbce72f62c95dcb7c07dcb5ed26acfcfbc11',
+ vaultId: '75486334982066122983501547829219246999490818941767825330875804445439814023987',
+ balance: '987000000000000000',
+ token: {
+ id: '0x12e605bc104e93b45e1ad99f9e555f659051c2bb',
+ address: '0x12e605bc104e93b45e1ad99f9e555f659051c2bb',
+ name: 'Staked FLR',
+ symbol: 'sFLR',
+ decimals: '18'
+ },
+ orderbook: {
+ id: '0xcee8cd002f151a536394e564b84076c41bbbcd4d'
+ },
+ ordersAsOutput: [
+ {
+ id: '0x1a69eeb7970d3c8d5776493327fb262e31fc880c9cc4a951607418a7963d9fa1',
+ orderHash: '0x557147dd0daa80d5beff0023fe6a3505469b2b8c4406ce1ab873e1a652572dd4',
+ active: true
+ }
+ ],
+ ordersAsInput: [],
+ balanceChanges: [
+ {
+ __typename: 'deposit',
+ data: {
+ id: '0x1bf9c93f8ac04810e733b61a7d5dabba66fc1a47235e6ab027e76c9758a2a9e8',
+ __typename: 'Deposit',
+ amount: '1000000000000000000',
+ newVaultBalance: '1000000000000000000',
+ oldVaultBalance: '0',
+ vault: {
+ id: '0x49f6b665c395c7b975caa2fc167cb5119981bbb86798bcaf3c4570153d09dfcf',
+ vault_id:
+ '75486334982066122983501547829219246999490818941767825330875804445439814023987',
+ token: {
+ id: '0x12e605bc104e93b45e1ad99f9e555f659051c2bb',
+ address: '0x12e605bc104e93b45e1ad99f9e555f659051c2bb',
+ name: 'Staked FLR',
+ symbol: 'sFLR',
+ decimals: '18'
+ }
+ },
+ timestamp: '1739448802',
+ transaction: {
+ id: '0xb5d715bc74b7a7f2aac8cca544c1c95e209ed4113b82269ac3285142324bc6af',
+ from: '0xf08bcbce72f62c95dcb7c07dcb5ed26acfcfbc11',
+ blockNumber: '37432554',
+ timestamp: '1739448802'
+ },
+ orderbook: {
+ id: '0xcee8cd002f151a536394e564b84076c41bbbcd4d'
+ }
+ }
+ },
+ {
+ __typename: 'withdrawal',
+ data: {
+ id: '0x252f6727a7a9bf1047cd9764351e9a2514140c5664589b0e5ecc7f9a4c69329c',
+ __typename: 'Withdrawal',
+ amount: '-11000000000000000',
+ newVaultBalance: '987000000000000000',
+ oldVaultBalance: '998000000000000000',
+ vault: {
+ id: '0x49f6b665c395c7b975caa2fc167cb5119981bbb86798bcaf3c4570153d09dfcf',
+ vault_id:
+ '75486334982066122983501547829219246999490818941767825330875804445439814023987',
+ token: {
+ id: '0x12e605bc104e93b45e1ad99f9e555f659051c2bb',
+ address: '0x12e605bc104e93b45e1ad99f9e555f659051c2bb',
+ name: 'Staked FLR',
+ symbol: 'sFLR',
+ decimals: '18'
+ }
+ },
+ timestamp: '1739460802',
+ transaction: {
+ id: '0xf4052dcf0a9ef208be249822c002bf656d273b4583e92928066fd8fb0a67c3f0',
+ from: '0xf08bcbce72f62c95dcb7c07dcb5ed26acfcfbc11',
+ blockNumber: '37439233',
+ timestamp: '1739460802'
+ },
+ orderbook: {
+ id: '0xcee8cd002f151a536394e564b84076c41bbbcd4d'
+ }
+ }
+ },
+ {
+ __typename: 'withdrawal',
+ data: {
+ id: '0x3b272ce8735a1778d584ed2d49532d571a815909b8f89b2d7d2c6744fcf7cb7c',
+ __typename: 'Withdrawal',
+ amount: '-1000000000000000',
+ newVaultBalance: '998000000000000000',
+ oldVaultBalance: '999000000000000000',
+ vault: {
+ id: '0x49f6b665c395c7b975caa2fc167cb5119981bbb86798bcaf3c4570153d09dfcf',
+ vault_id:
+ '75486334982066122983501547829219246999490818941767825330875804445439814023987',
+ token: {
+ id: '0x12e605bc104e93b45e1ad99f9e555f659051c2bb',
+ address: '0x12e605bc104e93b45e1ad99f9e555f659051c2bb',
+ name: 'Staked FLR',
+ symbol: 'sFLR',
+ decimals: '18'
+ }
+ },
+ timestamp: '1739460777',
+ transaction: {
+ id: '0xe3e1be9b3e11420de1f1d34f460c14d8688183b78b2dbcfd9b45560b553e451a',
+ from: '0xf08bcbce72f62c95dcb7c07dcb5ed26acfcfbc11',
+ blockNumber: '37439219',
+ timestamp: '1739460777'
+ },
+ orderbook: {
+ id: '0xcee8cd002f151a536394e564b84076c41bbbcd4d'
+ }
+ }
+ },
+ {
+ __typename: 'withdrawal',
+ data: {
+ id: '0x9d19a7aa2486c2640669eb04c8c4ed3e11073a04767d6dcfc3468ae12f695849',
+ __typename: 'Withdrawal',
+ amount: '-1000000000000000',
+ newVaultBalance: '999000000000000000',
+ oldVaultBalance: '1000000000000000000',
+ vault: {
+ id: '0x49f6b665c395c7b975caa2fc167cb5119981bbb86798bcaf3c4570153d09dfcf',
+ vault_id:
+ '75486334982066122983501547829219246999490818941767825330875804445439814023987',
+ token: {
+ id: '0x12e605bc104e93b45e1ad99f9e555f659051c2bb',
+ address: '0x12e605bc104e93b45e1ad99f9e555f659051c2bb',
+ name: 'Staked FLR',
+ symbol: 'sFLR',
+ decimals: '18'
+ }
+ },
+ timestamp: '1739460481',
+ transaction: {
+ id: '0x3bf239fb20fed202f04da468cc62d762390ab5f80b67b477565f740277f94df3',
+ from: '0xf08bcbce72f62c95dcb7c07dcb5ed26acfcfbc11',
+ blockNumber: '37439068',
+ timestamp: '1739460481'
+ },
+ orderbook: {
+ id: '0xcee8cd002f151a536394e564b84076c41bbbcd4d'
+ }
+ }
+ }
+ ]
+ }
+ ],
+ inputs: [
+ {
+ id: '0x538830b4f8cc03840cea5af799dc532be4363a3ee8f4c6123dbff7a0acc86dac',
+ owner: '0xf08bcbce72f62c95dcb7c07dcb5ed26acfcfbc11',
+ vaultId: '75486334982066122983501547829219246999490818941767825330875804445439814023987',
+ balance: '797990000000000000',
+ token: {
+ id: '0x1d80c49bbbcd1c0911346656b529df9e5c2f783d',
+ address: '0x1d80c49bbbcd1c0911346656b529df9e5c2f783d',
+ name: 'Wrapped Flare',
+ symbol: 'WFLR',
+ decimals: '18'
+ },
+ orderbook: {
+ id: '0xcee8cd002f151a536394e564b84076c41bbbcd4d'
+ },
+ ordersAsOutput: [],
+ ordersAsInput: [
+ {
+ id: '0x1a69eeb7970d3c8d5776493327fb262e31fc880c9cc4a951607418a7963d9fa1',
+ orderHash: '0x557147dd0daa80d5beff0023fe6a3505469b2b8c4406ce1ab873e1a652572dd4',
+ active: true
+ }
+ ],
+ balanceChanges: [
+ {
+ __typename: 'withdrawal',
+ data: {
+ id: '0x3c8de8385099c2f7775cb4695af43d7e38863ae9442402d73f70ebf865da1c4c',
+ __typename: 'Withdrawal',
+ amount: '-2000000000000000',
+ newVaultBalance: '797990000000000000',
+ oldVaultBalance: '799990000000000000',
+ vault: {
+ id: '0x538830b4f8cc03840cea5af799dc532be4363a3ee8f4c6123dbff7a0acc86dac',
+ vault_id:
+ '75486334982066122983501547829219246999490818941767825330875804445439814023987',
+ token: {
+ id: '0x1d80c49bbbcd1c0911346656b529df9e5c2f783d',
+ address: '0x1d80c49bbbcd1c0911346656b529df9e5c2f783d',
+ name: 'Wrapped Flare',
+ symbol: 'WFLR',
+ decimals: '18'
+ }
+ },
+ timestamp: '1739460781',
+ transaction: {
+ id: '0x6198a5fdf46f37f336bbd8615c18757f3a83ead6ec63ad02d865d46feb284310',
+ from: '0xf08bcbce72f62c95dcb7c07dcb5ed26acfcfbc11',
+ blockNumber: '37439221',
+ timestamp: '1739460781'
+ },
+ orderbook: {
+ id: '0xcee8cd002f151a536394e564b84076c41bbbcd4d'
+ }
+ }
+ },
+ {
+ __typename: 'withdrawal',
+ data: {
+ id: '0x7616be6722758517786fdcd94549ce0172d7d34fd411b5778ee0667cd1b1bdba',
+ __typename: 'Withdrawal',
+ amount: '-10000000000000',
+ newVaultBalance: '999990000000000000',
+ oldVaultBalance: '1000000000000000000',
+ vault: {
+ id: '0x538830b4f8cc03840cea5af799dc532be4363a3ee8f4c6123dbff7a0acc86dac',
+ vault_id:
+ '75486334982066122983501547829219246999490818941767825330875804445439814023987',
+ token: {
+ id: '0x1d80c49bbbcd1c0911346656b529df9e5c2f783d',
+ address: '0x1d80c49bbbcd1c0911346656b529df9e5c2f783d',
+ name: 'Wrapped Flare',
+ symbol: 'WFLR',
+ decimals: '18'
+ }
+ },
+ timestamp: '1739460415',
+ transaction: {
+ id: '0x8562f41d7d4a8af98ed9db1fbb9575f759846edfab0c4310fc2962b93c5eac7d',
+ from: '0xf08bcbce72f62c95dcb7c07dcb5ed26acfcfbc11',
+ blockNumber: '37439034',
+ timestamp: '1739460415'
+ },
+ orderbook: {
+ id: '0xcee8cd002f151a536394e564b84076c41bbbcd4d'
+ }
+ }
+ },
+ {
+ __typename: 'withdrawal',
+ data: {
+ id: '0x8e0c007bc831906b8b327be965e6aded6f5b8bc4905823b3047dcd2a69f01c83',
+ __typename: 'Withdrawal',
+ amount: '-200000000000000000',
+ newVaultBalance: '799990000000000000',
+ oldVaultBalance: '999990000000000000',
+ vault: {
+ id: '0x538830b4f8cc03840cea5af799dc532be4363a3ee8f4c6123dbff7a0acc86dac',
+ vault_id:
+ '75486334982066122983501547829219246999490818941767825330875804445439814023987',
+ token: {
+ id: '0x1d80c49bbbcd1c0911346656b529df9e5c2f783d',
+ address: '0x1d80c49bbbcd1c0911346656b529df9e5c2f783d',
+ name: 'Wrapped Flare',
+ symbol: 'WFLR',
+ decimals: '18'
+ }
+ },
+ timestamp: '1739460627',
+ transaction: {
+ id: '0xb330355574bd73c72d61b102ba7d23a0e07d677cb97e71db4495d0472587649b',
+ from: '0xf08bcbce72f62c95dcb7c07dcb5ed26acfcfbc11',
+ blockNumber: '37439143',
+ timestamp: '1739460627'
+ },
+ orderbook: {
+ id: '0xcee8cd002f151a536394e564b84076c41bbbcd4d'
+ }
+ }
+ },
+ {
+ __typename: 'deposit',
+ data: {
+ id: '0xcc853bdf3784e8c2e2ac9a43bdc9a2e56cc0d880a10ae8d25c3d675f6d114e74',
+ __typename: 'Deposit',
+ amount: '1000000000000000000',
+ newVaultBalance: '1000000000000000000',
+ oldVaultBalance: '0',
+ vault: {
+ id: '0x538830b4f8cc03840cea5af799dc532be4363a3ee8f4c6123dbff7a0acc86dac',
+ vault_id:
+ '75486334982066122983501547829219246999490818941767825330875804445439814023987',
+ token: {
+ id: '0x1d80c49bbbcd1c0911346656b529df9e5c2f783d',
+ address: '0x1d80c49bbbcd1c0911346656b529df9e5c2f783d',
+ name: 'Wrapped Flare',
+ symbol: 'WFLR',
+ decimals: '18'
+ }
+ },
+ timestamp: '1739460078',
+ transaction: {
+ id: '0x1f628ccbe37c1395b81c25cc1d9bfef6266d9782c093e1c42bab225335fe8ba0',
+ from: '0xf08bcbce72f62c95dcb7c07dcb5ed26acfcfbc11',
+ blockNumber: '37438849',
+ timestamp: '1739460078'
+ },
+ orderbook: {
+ id: '0xcee8cd002f151a536394e564b84076c41bbbcd4d'
+ }
+ }
+ }
+ ]
+ }
+ ],
+ orderbook: {
+ id: '0xcee8cd002f151a536394e564b84076c41bbbcd4d'
+ },
+ active: true,
+ timestampAdded: '1739448802',
+ meta: '0xff0a89c674ee7874a300590a932f2a20302e2063616c63756c6174652d696f202a2f200a7573696e672d776f7264732d66726f6d20307846653234313143446131393344394534653833413563323334433746643332303130313838336143203078393135453336656638383239343138313633353662433337313844663836383035344638363861440a616d6f756e742d65706f6368730a74726164652d65706f6368733a63616c6c3c323e28292c0a6d61782d6f75747075743a2063616c6c3c333e28616d6f756e742d65706f6368732074726164652d65706f636873292c0a696f3a2063616c6c3c343e2874726164652d65706f636873292c0a3a63616c6c3c353e28696f293b0a0a2f2a20312e2068616e646c652d696f202a2f200a6d696e2d616d6f756e743a206d756c283120302e39292c0a3a656e7375726528677265617465722d7468616e2d6f722d657175616c2d746f286f75747075742d7661756c742d64656372656173652829206d696e2d616d6f756e742920224d696e20747261646520616d6f756e742e22292c0a757365643a206765742868617368286f726465722d6861736828292022616d6f756e742d757365642229292c0a3a7365742868617368286f726465722d6861736828292022616d6f756e742d757365642229206164642875736564206f75747075742d7661756c742d6465637265617365282929293b0a0a2f2a20322e206765742d65706f6368202a2f200a696e697469616c2d74696d653a2063616c6c3c363e28292c0a6c6173742d74696d65205f3a2063616c6c3c373e28292c0a6475726174696f6e3a20737562286e6f77282920616e79286c6173742d74696d6520696e697469616c2d74696d6529292c0a746f74616c2d6475726174696f6e3a20737562286e6f77282920696e697469616c2d74696d65292c0a726174696f2d667265657a652d616d6f756e742d65706f6368733a2064697628312031292c0a726174696f2d667265657a652d74726164652d65706f6368733a206d756c28726174696f2d667265657a652d616d6f756e742d65706f63687320646976283630203138303029292c0a616d6f756e742d65706f6368733a2064697628746f74616c2d6475726174696f6e203630292c0a74726164652d65706f6368733a2073617475726174696e672d73756228646976286475726174696f6e20313830302920726174696f2d667265657a652d74726164652d65706f636873293b0a0a2f2a20332e20616d6f756e742d666f722d65706f6368202a2f200a616d6f756e742d65706f6368730a74726164652d65706f6368733a2c0a746f74616c2d617661696c61626c653a206c696e6561722d67726f7774682830203120616d6f756e742d65706f636873292c0a757365643a206765742868617368286f726465722d6861736828292022616d6f756e742d757365642229292c0a756e757365643a2073756228746f74616c2d617661696c61626c652075736564292c0a64656361793a2063616c6c3c383e2874726164652d65706f636873292c0a7368792d64656361793a20657665727928677265617465722d7468616e2874726164652d65706f63687320302e303529206465636179292c0a7661726961626c652d636f6d706f6e656e743a2073756228312031292c0a7461726765742d616d6f756e743a206164642831206d756c287661726961626c652d636f6d706f6e656e74207368792d646563617929292c0a6361707065642d756e757365643a206d696e28756e75736564207461726765742d616d6f756e74293b0a0a2f2a20342e20696f2d666f722d65706f6368202a2f200a65706f63683a2c0a6c6173742d696f3a2063616c6c3c373e28292c0a6d61782d6e6578742d74726164653a20616e79286d756c286c6173742d696f20312e3031292063616c6c3c393e2829292c0a626173656c696e652d6e6578742d74726164653a206d756c286c6173742d696f2030292c0a7265616c2d626173656c696e653a206d617828626173656c696e652d6e6578742d74726164652063616c6c3c393e2829292c0a7661726961626c652d636f6d706f6e656e743a2073617475726174696e672d737562286d61782d6e6578742d7472616465207265616c2d626173656c696e65292c0a61626f76652d626173656c696e653a206d756c287661726961626c652d636f6d706f6e656e742063616c6c3c383e2865706f636829292c0a5f3a20616464287265616c2d626173656c696e652061626f76652d626173656c696e65293b0a0a2f2a20352e207365742d6c6173742d7472616465202a2f200a6c6173742d696f3a2c0a3a7365742868617368286f726465722d68617368282920226c6173742d74726164652d74696d652229206e6f772829292c0a3a7365742868617368286f726465722d68617368282920226c6173742d74726164652d696f2229206c6173742d696f293b0a0a2f2a20362e206765742d696e697469616c2d74696d65202a2f200a5f3a6765742868617368286f726465722d6861736828292022696e697469616c2d74696d652229293b0a0a2f2a20372e206765742d6c6173742d7472616465202a2f200a6c6173742d74696d653a6765742868617368286f726465722d68617368282920226c6173742d74726164652d74696d652229292c0a6c6173742d696f3a6765742868617368286f726465722d68617368282920226c6173742d74726164652d696f2229293b0a0a2f2a20382e2068616c666c696665202a2f200a65706f63683a2c0a2f2a2a0a202a20536872696e6b696e6720746865206d756c7469706c696572206c696b6520746869730a202a207468656e206170706c79696e672069742031302074696d657320616c6c6f777320666f720a202a2062657474657220707265636973696f6e207768656e206d61782d696f2d726174696f0a202a2069732076657279206c617267652c20652e672e207e31653130206f72207e316532302b0a202a0a202a205468697320776f726b7320626563617573652060706f77657260206c6f7365730a202a20707265636973696f6e206f6e20626173652060302e3560207768656e207468650a202a206578706f6e656e74206973206c6172676520616e642063616e206576656e20676f0a202a20746f20603060207768696c652074686520696f2d726174696f206973207374696c6c0a202a206c617267652e2042657474657220746f206b65657020746865206d756c7469706c6965720a202a2068696768657220707265636973696f6e20616e642064726f702074686520696f2d726174696f0a202a20736d6f6f74686c7920666f72206173206c6f6e672061732077652063616e2e0a202a2f0a6d756c7469706c6965723a0a2020706f77657228302e35206469762865706f636820313029292c0a76616c3a0a20206d756c280a202020206d756c7469706c6965720a202020206d756c7469706c6965720a202020206d756c7469706c6965720a202020206d756c7469706c6965720a202020206d756c7469706c6965720a202020206d756c7469706c6965720a202020206d756c7469706c6965720a202020206d756c7469706c6965720a202020206d756c7469706c6965720a202020206d756c7469706c6965720a2020293b0a0a2f2a20392e2073666c722d626173656c696e652d696e76202a2f200a5f3a20696e762873666c722d65786368616e67652d726174652829293b011bff13109e41336ff20278186170706c69636174696f6e2f6f637465742d73747265616d',
+ addEvents: [
+ {
+ transaction: {
+ id: '0xb5d715bc74b7a7f2aac8cca544c1c95e209ed4113b82269ac3285142324bc6af',
+ from: '0xf08bcbce72f62c95dcb7c07dcb5ed26acfcfbc11',
+ blockNumber: '37432554',
+ timestamp: '1739448802'
+ }
+ }
+ ],
+ trades: []
+ }
+};
+
+const addOrders: AddOrderWithOrder[] = [mockAddOrder];
+
+describe('Rain Orderbook JS API Package Bindgen Tests - Add Order', async function () {
+ const mockServer = getLocal();
+ beforeEach(() => mockServer.start(8091));
+ afterEach(() => mockServer.stop());
+
+ it('should fetch add orders for a transaction', async () => {
+ await mockServer
+ .forPost('/sg1')
+ .thenReply(200, JSON.stringify({ data: { addOrders: addOrders } }));
+
+ try {
+ const result: AddOrderWithOrder[] = await getTransactionAddOrders(
+ mockServer.url + '/sg1',
+ transaction1.id
+ );
+ assert.equal(result[0].order.id, mockAddOrder.order.id);
+ } catch (e) {
+ assert.fail('expected to resolve, but failed' + (e instanceof Error ? e.message : String(e)));
+ }
+ });
+});
diff --git a/packages/orderbook/test/js_api/transaction.test.ts b/packages/orderbook/test/js_api/transaction.test.ts
index 809db66bb..6600c7d11 100644
--- a/packages/orderbook/test/js_api/transaction.test.ts
+++ b/packages/orderbook/test/js_api/transaction.test.ts
@@ -11,9 +11,9 @@ const transaction1 = {
timestamp: '1'
} as unknown as Transaction;
-describe('Rain Orderbook JS API Package Bindgen Tests - Order', async function () {
+describe('Rain Orderbook JS API Package Bindgen Tests - Transaction', async function () {
const mockServer = getLocal();
- beforeEach(() => mockServer.start(8090));
+ beforeEach(() => mockServer.start(8093));
afterEach(() => mockServer.stop());
it('should fetch a single transaction', async () => {
diff --git a/packages/ui-components/src/__tests__/transactionStore.test.ts b/packages/ui-components/src/__tests__/transactionStore.test.ts
index 10630ccb6..2d3396849 100644
--- a/packages/ui-components/src/__tests__/transactionStore.test.ts
+++ b/packages/ui-components/src/__tests__/transactionStore.test.ts
@@ -5,7 +5,7 @@ import transactionStore, {
TransactionErrorMessage
} from '../lib/stores/transactionStore';
import { waitForTransactionReceipt, sendTransaction, switchChain, type Config } from '@wagmi/core';
-import { getTransaction } from '@rainlanguage/orderbook/js_api';
+import { getTransaction, getTransactionAddOrders } from '@rainlanguage/orderbook/js_api';
import { waitFor } from '@testing-library/svelte';
vi.mock('@wagmi/core', () => ({
@@ -15,7 +15,8 @@ vi.mock('@wagmi/core', () => ({
}));
vi.mock('@rainlanguage/orderbook/js_api', () => ({
- getTransaction: vi.fn()
+ getTransaction: vi.fn(),
+ getTransactionAddOrders: vi.fn()
}));
describe('transactionStore', () => {
@@ -30,7 +31,8 @@ describe('transactionStore', () => {
awaitApprovalTx,
transactionSuccess,
transactionError,
- awaitTransactionIndexing
+ awaitTransactionIndexing,
+ awaitNewOrderIndexing
} = transactionStore;
beforeEach(() => {
@@ -49,7 +51,9 @@ describe('transactionStore', () => {
hash: '',
data: null,
functionName: '',
- message: ''
+ message: '',
+ newOrderId: '',
+ network: ''
});
});
@@ -106,7 +110,8 @@ describe('transactionStore', () => {
deploymentCalldata: mockDeploymentCalldata,
orderbookAddress: mockOrderbookAddress as `0x${string}`,
chainId: 1,
- subgraphUrl: 'test.com'
+ subgraphUrl: 'test.com',
+ network: 'flare'
});
expect(get(transactionStore).status).toBe(TransactionStatus.PENDING_SUBGRAPH);
@@ -122,7 +127,8 @@ describe('transactionStore', () => {
deploymentCalldata: '0x',
orderbookAddress: mockOrderbookAddress as `0x${string}`,
chainId: 1,
- subgraphUrl: 'test.com'
+ subgraphUrl: 'test.com',
+ network: 'flare'
});
expect(get(transactionStore).status).toBe(TransactionStatus.ERROR);
@@ -141,7 +147,8 @@ describe('transactionStore', () => {
deploymentCalldata: '0x',
orderbookAddress: mockOrderbookAddress as `0x${string}`,
chainId: 1,
- subgraphUrl: 'test.com'
+ subgraphUrl: 'test.com',
+ network: 'flare'
});
expect(get(transactionStore).status).toBe(TransactionStatus.ERROR);
@@ -161,7 +168,8 @@ describe('transactionStore', () => {
deploymentCalldata: '0x',
orderbookAddress: mockOrderbookAddress as `0x${string}`,
chainId: 1,
- subgraphUrl: 'test.com'
+ subgraphUrl: 'test.com',
+ network: 'flare'
});
expect(get(transactionStore).status).toBe(TransactionStatus.ERROR);
@@ -178,7 +186,8 @@ describe('transactionStore', () => {
deploymentCalldata: '0x',
orderbookAddress: mockOrderbookAddress as `0x${string}`,
chainId: 1,
- subgraphUrl: 'test.com'
+ subgraphUrl: 'test.com',
+ network: 'flare'
});
expect(get(transactionStore).status).toBe(TransactionStatus.ERROR);
@@ -196,7 +205,8 @@ describe('transactionStore', () => {
deploymentCalldata: '0x',
orderbookAddress: mockOrderbookAddress as `0x${string}`,
chainId: 1,
- subgraphUrl: 'test.com'
+ subgraphUrl: 'test.com',
+ network: 'flare'
});
expect(get(transactionStore).status).toBe(TransactionStatus.ERROR);
@@ -222,14 +232,15 @@ describe('transactionStore', () => {
deploymentCalldata: '0x',
orderbookAddress: mockOrderbookAddress as `0x${string}`,
chainId: 1,
- subgraphUrl: 'test.com'
+ subgraphUrl: 'test.com',
+ network: 'flare'
});
expect(sendTransaction).toHaveBeenCalledTimes(3); // 2 approvals + 1 deployment
expect(get(transactionStore).status).toBe(TransactionStatus.PENDING_SUBGRAPH);
});
- it('should handle waiting for subgraph indexing', async () => {
+ it('should handle successfuly waiting for subgraph indexing', async () => {
const mockSubgraphUrl = 'test.com';
const mockTxHash = 'mockHash';
const mockSuccessMessage = 'Success! Transaction confirmed';
@@ -275,4 +286,57 @@ describe('transactionStore', () => {
vi.useRealTimers();
});
+
+ it('should handle successful new order indexing', async () => {
+ const mockSubgraphUrl = 'test.com';
+ const mockTxHash = 'mockHash';
+ const mockNetwork = 'flare';
+ const mockOrderId = 'order123';
+
+ (getTransactionAddOrders as Mock).mockResolvedValue([
+ {
+ order: {
+ id: mockOrderId
+ }
+ }
+ ]);
+
+ vi.useFakeTimers({ shouldAdvanceTime: true });
+
+ await awaitNewOrderIndexing(mockSubgraphUrl, mockTxHash, mockNetwork);
+
+ vi.runOnlyPendingTimers();
+
+ await waitFor(() => {
+ expect(get(transactionStore).status).toBe(TransactionStatus.SUCCESS);
+ expect(get(transactionStore).hash).toBe(mockTxHash);
+ expect(get(transactionStore).newOrderId).toBe(mockOrderId);
+ expect(get(transactionStore).network).toBe(mockNetwork);
+ });
+ });
+
+ it('should handle new order indexing timeout', async () => {
+ vi.useFakeTimers();
+ const mockSubgraphUrl = 'test.com';
+ const mockTxHash = 'mockHash';
+ const mockNetwork = 'flare';
+
+ (getTransactionAddOrders as Mock).mockResolvedValue([]);
+
+ const indexingPromise = awaitNewOrderIndexing(mockSubgraphUrl, mockTxHash, mockNetwork);
+
+ expect(get(transactionStore).status).toBe(TransactionStatus.PENDING_SUBGRAPH);
+ expect(get(transactionStore).message).toBe('Waiting for new Order to be indexed...');
+
+ await vi.advanceTimersByTime(10000);
+ await indexingPromise;
+
+ expect(get(transactionStore).status).toBe(TransactionStatus.ERROR);
+ expect(get(transactionStore).message).toBe(
+ 'The subgraph took too long to respond. Please check again later.'
+ );
+ expect(get(transactionStore).error).toBe(TransactionErrorMessage.TIMEOUT);
+
+ vi.useRealTimers();
+ });
});
diff --git a/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte b/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte
index c22f8ae34..124d917a7 100644
--- a/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte
+++ b/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte
@@ -50,6 +50,7 @@
orderbookAddress: Hex;
chainId: number;
subgraphUrl: string;
+ network: string;
}) => void;
export let handleUpdateGuiState: (gui: DotrainOrderGui) => void;
@@ -164,7 +165,8 @@
async function handleAddOrder() {
try {
- if (!gui || !$wagmiConfig) return;
+ if (!gui || !$wagmiConfig || !networkKey)
+ throw new Error(DeploymentStepErrors.ADD_ORDER_FAILED);
const { address } = getAccount($wagmiConfig);
if (!address) return;
let approvals = await gui.generateApprovalCalldatas(address);
@@ -189,7 +191,8 @@
deploymentCalldata,
orderbookAddress,
chainId,
- subgraphUrl
+ subgraphUrl,
+ network: networkKey
});
} catch (e) {
error = DeploymentStepErrors.ADD_ORDER_FAILED;
diff --git a/packages/ui-components/src/lib/stores/transactionStore.ts b/packages/ui-components/src/lib/stores/transactionStore.ts
index 9200d0808..d65014f3b 100644
--- a/packages/ui-components/src/lib/stores/transactionStore.ts
+++ b/packages/ui-components/src/lib/stores/transactionStore.ts
@@ -11,7 +11,7 @@ import type {
Vault,
WithdrawCalldataResult
} from '@rainlanguage/orderbook/js_api';
-import { getTransaction } from '@rainlanguage/orderbook/js_api';
+import { getTransaction, getTransactionAddOrders } from '@rainlanguage/orderbook/js_api';
export const ADDRESS_ZERO = '0x0000000000000000000000000000000000000000';
export const ONE = BigInt('1000000000000000000');
@@ -50,6 +50,7 @@ export type DeploymentTransactionArgs = {
orderbookAddress: Hex;
chainId: number;
subgraphUrl: string;
+ network: string;
};
export type DepositOrWithdrawTransactionArgs = {
@@ -76,6 +77,8 @@ export type TransactionState = {
data: null;
functionName: string;
message: string;
+ newOrderId: string;
+ network: string;
};
export type TransactionStore = {
@@ -97,7 +100,9 @@ const initialState: TransactionState = {
hash: '',
data: null,
functionName: '',
- message: ''
+ message: '',
+ newOrderId: '',
+ network: ''
};
const transactionStore = () => {
@@ -136,6 +141,31 @@ const transactionStore = () => {
}, 1000);
};
+ const awaitNewOrderIndexing = async (subgraphUrl: string, txHash: string, network: string) => {
+ update((state) => ({
+ ...state,
+ status: TransactionStatus.PENDING_SUBGRAPH,
+ message: 'Waiting for new Order to be indexed...'
+ }));
+
+ let attempts = 0;
+ const interval: NodeJS.Timeout = setInterval(async () => {
+ attempts++;
+ const addOrders = await getTransactionAddOrders(subgraphUrl, txHash);
+ if (attempts >= 10) {
+ update((state) => ({
+ ...state,
+ message: 'The subgraph took too long to respond. Please check again later.'
+ }));
+ clearInterval(interval);
+ return transactionError(TransactionErrorMessage.TIMEOUT);
+ } else if (addOrders?.length > 0) {
+ clearInterval(interval);
+ return transactionSuccess(txHash, '', addOrders[0].order.id, network);
+ }
+ }, 1000);
+ };
+
const checkingWalletAllowance = (message?: string) =>
update((state) => ({
...state,
@@ -162,12 +192,19 @@ const transactionStore = () => {
status: TransactionStatus.PENDING_DEPLOYMENT,
message: 'Confirming transaction...'
}));
- const transactionSuccess = (hash: string, message?: string) => {
+ const transactionSuccess = (
+ hash: string,
+ message?: string,
+ newOrderId?: string,
+ network?: string
+ ) => {
update((state) => ({
...state,
status: TransactionStatus.SUCCESS,
hash: hash,
- message: message || ''
+ message: message || '',
+ newOrderId: newOrderId || '',
+ network: network || ''
}));
};
const transactionError = (message: TransactionErrorMessage, hash?: string) =>
@@ -184,7 +221,8 @@ const transactionStore = () => {
deploymentCalldata,
orderbookAddress,
chainId,
- subgraphUrl
+ subgraphUrl,
+ network
}: DeploymentTransactionArgs) => {
try {
await switchChain(config, { chainId });
@@ -225,11 +263,7 @@ const transactionStore = () => {
try {
awaitDeployTx(hash);
await waitForTransactionReceipt(config, { hash });
- if (subgraphUrl === '') {
- return transactionSuccess(hash, `Strategy deployed successfully.`);
- } else {
- return awaitTransactionIndexing(subgraphUrl, hash, `Strategy deployed successfully.`);
- }
+ return awaitNewOrderIndexing(subgraphUrl, hash, network);
} catch {
return transactionError(TransactionErrorMessage.DEPLOYMENT_FAILED);
}
@@ -339,7 +373,8 @@ const transactionStore = () => {
awaitApprovalTx,
transactionSuccess,
transactionError,
- awaitTransactionIndexing
+ awaitTransactionIndexing,
+ awaitNewOrderIndexing
};
};
diff --git a/packages/webapp/src/lib/components/DeployModal.svelte b/packages/webapp/src/lib/components/DeployModal.svelte
index 2111651d6..6c0e5d9fb 100644
--- a/packages/webapp/src/lib/components/DeployModal.svelte
+++ b/packages/webapp/src/lib/components/DeployModal.svelte
@@ -14,6 +14,7 @@
export let orderbookAddress: Hex;
export let chainId: number;
export let subgraphUrl: string;
+ export let network: string;
const messages = {
success: 'Your strategy was successfully deployed.',
@@ -27,7 +28,8 @@
deploymentCalldata,
orderbookAddress,
chainId,
- subgraphUrl
+ subgraphUrl,
+ network
});
diff --git a/packages/webapp/src/lib/components/TransactionModal.svelte b/packages/webapp/src/lib/components/TransactionModal.svelte
index 3f7460d79..182fe024a 100644
--- a/packages/webapp/src/lib/components/TransactionModal.svelte
+++ b/packages/webapp/src/lib/components/TransactionModal.svelte
@@ -58,15 +58,25 @@
>
{messages.success}
- {#if $transactionStore.message}
-
- {$transactionStore.message}
-
- {/if}
+
+ {#if $transactionStore.message}
+
+ {$transactionStore.message}
+
+ {/if}
+
+
+ {#if $transactionStore.newOrderId && $transactionStore.network}
+
+
+
+ {/if}
+
+
+
-
{:else}