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

Soft quote #9

Merged
merged 8 commits into from
Dec 12, 2023
Merged
Show file tree
Hide file tree
Changes from 5 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
6 changes: 5 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@ on:
- 'v**'
- 'releases/v**'

permissions:
packages: read
contents: read

jobs:
build-and-test:
runs-on: ubuntu-latest
env:
CR_PAT: ${{ secrets.GITHUB_TOKEN }}
GHP_PAT: ${{ secrets.GITHUB_TOKEN }}

steps:
- name: Checkout repo
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"codegen": "rm -rf ./src/lib/codegen && wagmi generate && npx buf generate",
"format": "prettier --write \"**/*.{ts,tsx,md,json}\"",
"gen-docs": "typedoc",
"generate:grpc": "npx buf generate",
albertocevallos marked this conversation as resolved.
Show resolved Hide resolved
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"prepare": "git submodule update --init --recursive && pnpm codegen",
Expand Down Expand Up @@ -61,7 +62,7 @@
"@connectrpc/connect-query": "0.5.3",
"@connectrpc/connect-web": "^1.1.2",
"@tanstack/react-query": "^4.36.1",
"@valorem-labs-inc/sdk": "^0.0.4",
"@valorem-labs-inc/sdk": "^0.0.8",
"@wagmi/core": "1.4.7",
"abitype": "0.8.7",
"connectkit": "^1.5.3",
Expand Down
87 changes: 55 additions & 32 deletions pnpm-lock.yaml

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

130 changes: 130 additions & 0 deletions src/hooks/useSoftQuote.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import type {
OptionType,
ParsedSoftQuoteResponse,
} from '@valorem-labs-inc/sdk';
import {
CLEAR_ADDRESS,
ItemType,
QuoteRequest,
SoftQuote,
SEAPORT_ADDRESS,
parseSoftQuoteResponse,
toH160,
toH256,
} from '@valorem-labs-inc/sdk';
import { useQueryClient } from '@tanstack/react-query';
import { useMemo } from 'react';
import { useAccount, useChainId } from 'wagmi';
import { hexToBigInt } from 'viem';
import { useStream } from './useStream';
import { usePromiseClient } from './usePromiseClient';

/**
* Configuration for the useSoftQuote hook.
* quoteRequest - An object or instance containing the details for requesting a quote.
* enabled - Flag to enable the hook.
* timeoutMs - Timeout for the quote request in milliseconds.
* onError - Callback function for handling errors.
*/
export interface UseRFQConfig {
quoteRequest:
| QuoteRequest
| {
tokenId: OptionType['tokenId'];
action: QuoteRequest['action'];
amount: bigint;
}
| undefined;
enabled?: boolean;
timeoutMs?: number;
onError?: (err: Error) => void;
}

/**
* Return type of the useSoftQuote hook.
* quotes - Array of parsed quote responses.
* responses - Array of raw quote responses.
* openStream - Function to open the stream for receiving quotes.
* resetAndRestartStream - Function to reset and restart the quote stream.
* abortStream - Function to abort the quote stream.
* error - Error object if an error occurred during the RFQ process.
*/
export interface UseRFQReturn {
quotes?: ParsedSoftQuoteResponse[];
responses?: ParsedSoftQuoteResponse[];
openStream: () => Promise<() => void>;
resetAndRestartStream: () => void;
abortStream: () => void;
error?: Error;
}

/**
* Hook to manage the useSoftQuote process in the Valorem trading environment.
* It handles sending quote requests to market makers and receiving their responses.
* @param config - Configuration for the RFQ process.
* @returns An object containing the quotes, response management functions, and any errors.
*/
export const useSoftQuote = ({
quoteRequest,
enabled,
timeoutMs = 15000,
onError,
}: UseRFQConfig): UseRFQReturn => {
const grpcClient = usePromiseClient(SoftQuote);
const queryClient = useQueryClient();
const { address } = useAccount();
const chainId = useChainId();

const request = useMemo(() => {
if (quoteRequest === undefined) return undefined;

// pre-constructed quote request
if (quoteRequest instanceof QuoteRequest) return quoteRequest;

// construct quote request from quote request config
if (address === undefined) return undefined;
const { tokenId, action, amount } = quoteRequest;
if (tokenId === undefined) return undefined;

return new QuoteRequest({
ulid: undefined,
takerAddress: toH160(address),
itemType: ItemType.ERC1155,
tokenAddress: toH160(CLEAR_ADDRESS),
identifierOrCriteria: toH256(tokenId),
amount: toH256(amount),
action,
chainId: toH256(BigInt(chainId)),
seaportAddress: toH160(hexToBigInt(SEAPORT_ADDRESS)),
});
}, [address, chainId, quoteRequest]);

const {
data,
responses,
openStream,
resetAndRestartStream,
abortStream,
error,
} = useStream<typeof SoftQuote, ParsedSoftQuoteResponse>({
queryClient,
queryKey: ['useSoftQuote'],
grpcClient,
method: 'webTaker',
request,
enabled: enabled && request !== undefined,
keepAlive: true,
timeoutMs,
parseResponse: parseSoftQuoteResponse,
onError,
});

return {
quotes: data,
responses,
openStream,
resetAndRestartStream,
abortStream,
error,
};
};