Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change order links to orderHash not order IDs #1387

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 21 additions & 14 deletions crates/js_api/src/subgraph/order.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
use std::collections::{HashMap, HashSet};

use cynic::Id;
use rain_orderbook_common::types::OrderDetailExtended;
use rain_orderbook_subgraph_client::{
types::common::{SgOrder, SgOrdersListFilterArgs, SgVault},
types::common::{SgBytes, SgOrder, SgOrdersListFilterArgs, SgVault},
MultiOrderbookSubgraphClient, MultiSubgraphArgs, OrderbookSubgraphClient,
OrderbookSubgraphClientError, SgPaginationArgs,
};
use reqwest::Url;
use std::collections::{HashMap, HashSet};
use wasm_bindgen_utils::{impl_wasm_traits, prelude::*};

use serde::{Deserialize, Serialize};
Expand All @@ -19,14 +18,6 @@ pub struct OrderWithSortedVaults {
}
impl_wasm_traits!(OrderWithSortedVaults);

/// Internal function to fetch a single order
/// Returns the SgOrder struct
pub async fn get_sg_order(url: &str, id: &str) -> Result<SgOrder, OrderbookSubgraphClientError> {
let client = OrderbookSubgraphClient::new(Url::parse(url)?);
let order = client.order_detail(Id::new(id)).await?;
Ok(order)
}

/// Fetch all orders from multiple subgraphs
/// Returns a list of OrderWithSubgraphName structs
#[wasm_bindgen(js_name = "getOrders")]
Expand Down Expand Up @@ -73,11 +64,27 @@ fn sort_vaults(order: &SgOrder) -> HashMap<String, Vec<SgVault>> {
sorted_vaults
}

/// Internal function to fetch a single order
/// Returns the SgOrder struct
pub async fn get_sg_order_by_hash(
url: &str,
hash: &str,
) -> Result<SgOrder, OrderbookSubgraphClientError> {
let client = OrderbookSubgraphClient::new(Url::parse(url)?);
let order = client
.order_detail_by_hash(SgBytes(hash.to_string()))
.await?;
Ok(order)
}

/// Fetch a single order
/// Returns the Order struct with sorted vaults
#[wasm_bindgen(js_name = "getOrder")]
pub async fn get_order(url: &str, id: &str) -> Result<JsValue, OrderbookSubgraphClientError> {
let order = get_sg_order(url, id).await?;
#[wasm_bindgen(js_name = "getOrderByHash")]
pub async fn get_order_by_hash(
url: &str,
hash: &str,
) -> Result<JsValue, OrderbookSubgraphClientError> {
let order = get_sg_order_by_hash(url, hash).await?;
Ok(to_js_value(&OrderWithSortedVaults {
order: order.clone(),
vaults: sort_vaults(&order),
Expand Down
23 changes: 20 additions & 3 deletions crates/subgraph/src/orderbook_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use crate::performance::OrderPerformance;
use crate::types::add_order::{SgTransactionAddOrdersQuery, TransactionAddOrdersVariables};
use crate::types::common::*;
use crate::types::order::{
SgBatchOrderDetailQuery, SgBatchOrderDetailQueryVariables, SgOrderDetailQuery, SgOrderIdList,
SgOrdersListQuery,
SgBatchOrderDetailQuery, SgBatchOrderDetailQueryVariables, SgOrderDetailByHashQuery,
SgOrderDetailByHashQueryVariables, SgOrderDetailByIdQuery, SgOrderIdList, SgOrdersListQuery,
};
use crate::types::order_trade::{SgOrderTradeDetailQuery, SgOrderTradesListQuery};
use crate::types::remove_order::{
Expand Down Expand Up @@ -75,7 +75,7 @@ impl OrderbookSubgraphClient {
/// Fetch single order
pub async fn order_detail(&self, id: Id) -> Result<SgOrder, OrderbookSubgraphClientError> {
let data = self
.query::<SgOrderDetailQuery, SgIdQueryVariables>(SgIdQueryVariables { id: &id })
.query::<SgOrderDetailByIdQuery, SgIdQueryVariables>(SgIdQueryVariables { id: &id })
.await?;
let order = data.order.ok_or(OrderbookSubgraphClientError::Empty)?;

Expand Down Expand Up @@ -443,4 +443,21 @@ impl OrderbookSubgraphClient {

Ok(data.remove_orders)
}

/// Fetch single order given its hash
pub async fn order_detail_by_hash(
&self,
hash: SgBytes,
) -> Result<SgOrder, OrderbookSubgraphClientError> {
let data = self
.query::<SgOrderDetailByHashQuery, SgOrderDetailByHashQueryVariables>(
SgOrderDetailByHashQueryVariables { hash },
)
.await?;
let order = data
.orders
.first()
.ok_or(OrderbookSubgraphClientError::Empty)?;
Ok(order.clone())
}
}
19 changes: 18 additions & 1 deletion crates/subgraph/src/types/order.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,27 @@ pub struct SgOrdersListQuery {
pub orders: Vec<SgOrder>,
}

#[derive(cynic::QueryVariables, Debug)]
pub struct SgOrderDetailByHashQueryVariables {
pub hash: SgBytes,
}

#[derive(cynic::QueryFragment, Debug, Serialize)]
#[cynic(
graphql_type = "Query",
variables = "SgOrderDetailByHashQueryVariables"
)]
#[cfg_attr(target_family = "wasm", derive(Tsify))]
#[serde(rename_all = "camelCase")]
pub struct SgOrderDetailByHashQuery {
#[arguments(where: { orderHash: $hash })]
pub orders: Vec<SgOrder>,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(graphql_type = "Query", variables = "SgIdQueryVariables")]
#[cfg_attr(target_family = "wasm", derive(Tsify))]
pub struct SgOrderDetailQuery {
pub struct SgOrderDetailByIdQuery {
#[arguments(id: $id)]
#[cfg_attr(target_family = "wasm", tsify(optional))]
pub order: Option<SgOrder>,
Expand Down
4 changes: 2 additions & 2 deletions crates/subgraph/tests/order_test.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
use cynic::Id;
use insta::assert_snapshot;
use rain_orderbook_subgraph_client::types::common::*;
use rain_orderbook_subgraph_client::types::order::SgOrderDetailQuery;
use rain_orderbook_subgraph_client::types::order::SgOrderDetailByIdQuery;

#[test]
fn orders_query_gql_output() {
use cynic::QueryBuilder;

let id = Id::new("1234");
let request_body = SgOrderDetailQuery::build(SgIdQueryVariables { id: &id });
let request_body = SgOrderDetailByIdQuery::build(SgIdQueryVariables { id: &id });

assert_snapshot!(request_body.query);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ source: crates/subgraph/tests/order_test.rs
assertion_line: 13
expression: request_body.query
---
query SgOrderDetailQuery($id: ID!) {
query SgOrderDetailByIdQuery($id: ID!) {
order(id: $id) {
id
orderBytes
Expand Down
35 changes: 30 additions & 5 deletions packages/orderbook/test/js_api/order.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import {
OrderWithSortedVaults
} from '../../dist/types/js_api.js';
import {
getOrder,
getOrders,
getOrderByHash,
getOrderTradesList,
getOrderTradeDetail,
getOrderTradesCount,
Expand Down Expand Up @@ -379,10 +379,13 @@ describe('Rain Orderbook JS API Package Bindgen Tests - SgOrder', async function
afterEach(() => mockServer.stop());

it('should fetch a single order', async () => {
await mockServer.forPost('/sg1').thenReply(200, JSON.stringify({ data: { order: order1 } }));
await mockServer.forPost('/sg1').thenReply(200, JSON.stringify({ data: { orders: [order1] } }));

try {
const result: OrderWithSortedVaults = await getOrder(mockServer.url + '/sg1', order1.id);
const result: OrderWithSortedVaults = await getOrderByHash(
mockServer.url + '/sg1',
order1.orderHash
);
assert.equal(result.order.id, order1.id);
} catch (e) {
console.log(e);
Expand Down Expand Up @@ -712,10 +715,10 @@ describe('Rain Orderbook JS API Package Bindgen Tests - SgOrder', async function
await mockServer
.forPost('/sg1')
.once()
.thenReply(200, JSON.stringify({ data: { order: { ...order1, inputs, outputs } } }));
.thenReply(200, JSON.stringify({ data: { orders: [{ ...order1, inputs, outputs }] } }));

try {
const result: OrderWithSortedVaults = await getOrder(mockServer.url + '/sg1', order1.id);
const result: OrderWithSortedVaults = await getOrderByHash(mockServer.url + '/sg1', order1.orderHash);

const inputs = result.vaults.get('inputs');
const outputs = result.vaults.get('outputs');
Expand All @@ -737,4 +740,26 @@ describe('Rain Orderbook JS API Package Bindgen Tests - SgOrder', async function
assert.fail('expected to resolve, but failed' + (e instanceof Error ? e.message : String(e)));
}
});

it('should fetch an order by orderHash', async () => {
const mockOrder = {
...order1,
orderHash: '0xbf8075f73b0a6418d719e52189d59bf35a0949e5983b3edbbc0338c02ab17353'
};
await mockServer
.forPost('/sg1')
.thenReply(200, JSON.stringify({ data: { orders: [mockOrder] } }));

try {
const result: OrderWithSortedVaults = await getOrderByHash(
mockServer.url + '/sg1',
mockOrder.orderHash
);

assert.equal(result.order.orderHash, mockOrder.orderHash);
} catch (e) {
console.log(e);
assert.fail('expected to resolve, but failed' + (e instanceof Error ? e.message : String(e)));
}
});
});
16 changes: 9 additions & 7 deletions packages/ui-components/src/__tests__/OrderDetail.test.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import ButtonVaultLink from '../lib/components/ButtonVaultLink.svelte';
import { createQuery } from '@tanstack/svelte-query';
import type { OrderWithSortedVaults } from '@rainlanguage/orderbook/js_api';
import { getOrder } from '@rainlanguage/orderbook/js_api';
import { getOrderByHash } from '@rainlanguage/orderbook/js_api';
import { QKEY_ORDER } from '../lib/queries/keys';
import type { Readable } from 'svelte/store';
import { Button } from 'flowbite-svelte';
Expand All @@ -21,15 +21,17 @@
undefined;
export let handleOrderRemoveModal: ((props: OrderRemoveModalProps) => void) | undefined =
undefined;
export let id: string;
export let orderHash: string;
export let subgraphUrl: string;
export let chainId: number;
export let orderbookAddress: Hex;

$: orderDetailQuery = createQuery<OrderWithSortedVaults>({
queryKey: [id, QKEY_ORDER + id],
queryFn: () => getOrder(subgraphUrl, id),
enabled: !!subgraphUrl && !!id
queryKey: [orderHash, QKEY_ORDER + orderHash],
queryFn: () => {
return getOrderByHash(subgraphUrl, orderHash);
},
enabled: !!subgraphUrl
});
</script>

Expand Down Expand Up @@ -58,7 +60,7 @@
{/if}

<Refresh
on:click={async () => await invalidateIdQuery(queryClient, id)}
on:click={async () => await invalidateIdQuery(queryClient, orderHash)}
spin={$orderDetailQuery.isLoading || $orderDetailQuery.isFetching}
/>
</svelte:fragment>
Expand Down Expand Up @@ -98,6 +100,6 @@
</svelte:fragment>

<svelte:fragment slot="below" let:data>
<div>Below content: {data.order.id}</div>
<div>Below content: {data.order.orderHash}</div>
</svelte:fragment>
</TanstackPageContentDetail>
23 changes: 9 additions & 14 deletions packages/ui-components/src/__tests__/OrderDetail.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { expect } from '../lib/test/matchers';
import OrderDetail from './OrderDetail.test.svelte';
import type { SgOrder, SgVault } from '@rainlanguage/orderbook/js_api';
import userEvent from '@testing-library/user-event';
import type { Config } from 'wagmi';

const { mockWalletAddressMatchesOrBlankStore } = await vi.hoisted(
() => import('../lib/__mocks__/stores')
Expand All @@ -25,13 +24,6 @@ const mockOrder: SgOrder = {

vi.mock('@tanstack/svelte-query');

const wagmiConfig = {
chains: [],
signer: {
address: '0x123'
}
} as unknown as Config;

const chainId = 1;
const orderbookAddress = '0x123';

Expand All @@ -52,7 +44,7 @@ describe('OrderDetail Component', () => {

render(OrderDetail, {
props: {
id: 'mockId',
orderHash: 'mockHash',
subgraphUrl: 'https://example.com',
walletAddressMatchesOrBlank: mockWalletAddressMatchesOrBlankStore,
chainId,
Expand Down Expand Up @@ -83,7 +75,7 @@ describe('OrderDetail Component', () => {

render(OrderDetail, {
props: {
id: mockOrder.id,
orderHash: 'mockHash',
subgraphUrl: 'https://example.com',
walletAddressMatchesOrBlank: mockWalletAddressMatchesOrBlankStore,
handleOrderRemoveModal,
Expand All @@ -103,7 +95,7 @@ describe('OrderDetail Component', () => {

render(OrderDetail, {
props: {
id: mockOrder.id,
orderHash: 'mockHash',
subgraphUrl: 'https://example.com',
walletAddressMatchesOrBlank: mockWalletAddressMatchesOrBlankStore,
handleOrderRemoveModal: vi.fn(),
Expand All @@ -120,6 +112,7 @@ describe('OrderDetail Component', () => {
it('correctly categorizes and displays vaults in input, output, and shared categories', async () => {
const vault1 = {
id: '1',
orderHash: 'mockHash',
vaultId: '0xabc',
owner: '0x123',
token: {
Expand All @@ -139,6 +132,7 @@ describe('OrderDetail Component', () => {
} as unknown as SgVault;
const vault2 = {
id: '2',
orderHash: 'mockHash',
vaultId: '0xbcd',
owner: '0x123',
token: {
Expand All @@ -160,6 +154,7 @@ describe('OrderDetail Component', () => {
id: '3',
vaultId: '0xdef',
owner: '0x123',
orderHash: 'mockHash',
token: {
id: '0x456',
address: '0x456',
Expand Down Expand Up @@ -204,7 +199,7 @@ describe('OrderDetail Component', () => {
mockWalletAddressMatchesOrBlankStore.mockSetSubscribeValue(() => true);
render(OrderDetail, {
props: {
id: mockOrderWithVaults.id,
orderHash: mockOrderWithVaults.orderHash,
subgraphUrl: 'https://example.com',
walletAddressMatchesOrBlank: mockWalletAddressMatchesOrBlankStore,
chainId,
Expand Down Expand Up @@ -245,7 +240,7 @@ describe('OrderDetail Component', () => {

render(OrderDetail, {
props: {
id: 'mockId',
orderHash: 'mockHash',
subgraphUrl: 'https://example.com',
walletAddressMatchesOrBlank: mockWalletAddressMatchesOrBlankStore,
chainId,
Expand All @@ -258,7 +253,7 @@ describe('OrderDetail Component', () => {

await waitFor(() => {
expect(mockInvalidateQueries).toHaveBeenCalledWith({
queryKey: ['mockId'],
queryKey: ['mockHash'],
refetchType: 'all',
exact: false
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ describe('OrderOrVaultHash', () => {
const button = getByTestId('vault-order-input');
expect(button).toBeTruthy();
expect(button.classList.toString()).toContain('text-white bg-green');
expect(button.getAttribute('data-id')).toBe('123');
expect(button.getAttribute('data-id')).toBe('0x123abc');
});

it('renders with inactive order', () => {
Expand Down
Loading