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

add react hooks and swap sdk provider #75

Open
wants to merge 2 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/react/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export { useCancelOrder } from './useCancelOrder';
export { useCreateBasedOrder } from './useCreateBasedOrder';
export { useCreateOrder } from './useCreateOrder';
export { useFulfillOrder } from './useFulfillOrder';
export { useOrders } from './useOrders';
export { useQuickSwap } from './useQuickSwap';
export { useWallet } from './useWallet';
35 changes: 35 additions & 0 deletions src/react/hooks/useCancelOrder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { BigNumberish, ContractReceipt } from 'ethers';
import { useContext } from 'react';

import { SwapSdkContext } from '../providers/swapSdkProvider';

/**
* Get a function to cancel an order by nonce and type
*/
export function useCancelOrder() {
const { nftSwap } = useContext(SwapSdkContext);

/**
* Cancel an order by nonce and type
* @param nonce nonce of the order to be cancel
* @param orderType type of token from the order (ERC721 or ERC1155)
* @returns a transaction receipt if successful
*/
const cancelOrder = async (
nonce: BigNumberish,
orderType: 'ERC721' | 'ERC1155'
): Promise<ContractReceipt | undefined> => {
if (!nftSwap) return;

try {
const cancelTx = await nftSwap.cancelOrder(nonce, orderType);
const cancelTxReceipt = await cancelTx.wait();
return cancelTxReceipt;
} catch (error) {
console.error(error);
return undefined;
}
};

return cancelOrder;
}
56 changes: 56 additions & 0 deletions src/react/hooks/useCreateBasedOrder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { useContext } from 'react';

import {
SignedNftOrderV4,
UserFacingERC20AssetDataSerializedV4,
} from '../../sdk';
import { SwapSdkContext } from '../providers/swapSdkProvider';

export interface NftCollection {
tokenAddress: string;
type: 'ERC721' | 'ERC1155';
}

/**
* Get the function to create order from a specific collection
*/
export function useCreateBasedOrder() {
const { nftSwap } = useContext(SwapSdkContext);

/**
* Create an order with any NFT from specific collection maker has and post it in the orderbook if successful
* @param erc20Asset an object that contains the type "ERC20", the amount to sell and the address of the token
* @param nftCollectionAsset an object that contains the type of NFT to sell (ERC721 or ERC1155) and NFT collection address
* @param makerAddress wallet address of order creator
* @param chainId id of the chain in which the transaction will be performed
* @param metadata an optional record object that will be stored with the order in the orderbook
* @returns signed order
*/
const createBasedOrder = async (
erc20Asset: UserFacingERC20AssetDataSerializedV4,
nftCollectionAsset: NftCollection,
makerAddress: string | undefined,
chainId: number | string,
metadata?: Record<string, string>
): Promise<SignedNftOrderV4 | undefined> => {
if (!nftSwap) return;
if (!makerAddress) return;

try {
const collectionBasedOrder = nftSwap.buildCollectionBasedOrder(
erc20Asset,
nftCollectionAsset,
makerAddress
);

const signedOrder = await nftSwap.signOrder(collectionBasedOrder);
await nftSwap.postOrder(signedOrder, chainId, metadata);
return signedOrder;
} catch (error) {
console.error(error);
return undefined;
}
};

return createBasedOrder;
}
99 changes: 99 additions & 0 deletions src/react/hooks/useCreateOrder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { useContext } from 'react';

import { Fee, SignedNftOrderV4, SwappableAssetV4 } from '../../sdk';
import { SwapSdkContext } from '../providers/swapSdkProvider';

/**
* Get the order creation function
*/
export function useCreateOrder() {
const { nftSwap } = useContext(SwapSdkContext);

/**
* Create an order and post it in the orderbook if successful
* @param makerAsset an asset (ERC20, ERC721, or ERC1155) the user has
* @param takerAsset an asset (ERC20, ERC721, or ERC1155) the user wants
* @param makerAddress wallet address of user who creates the order
* @param chainId id of the chain in which the transaction will be performed
* @param metadata an optional record object that will be stored with the order in the orderbook
* @param fees optional array that contents config for fee and royalties
* @returns signed order
*/
const createOrder = async (
makerAsset: SwappableAssetV4,
takerAsset: SwappableAssetV4,
makerAddress: string | undefined,
chainId: number | string,
metadata?: Record<string, string>,
fees?: Fee[]
): Promise<SignedNftOrderV4 | undefined> => {
if (!nftSwap) return;
if (!makerAddress) return;

const approvalStatus = await nftSwap.loadApprovalStatus(
makerAsset,
makerAddress
);
if (!approvalStatus.contractApproved) {
const approvalTx = await nftSwap.approveTokenOrNftByAsset(
makerAsset,
makerAddress
);
await approvalTx.wait();
}

let signedOrder: SignedNftOrderV4 | null = null;

if (makerAsset.type === 'ERC20' && takerAsset.type === 'ERC721') {
const ercToNftOrder = nftSwap.buildOrder(
makerAsset,
takerAsset,
makerAddress,
{
fees,
}
);
signedOrder = await nftSwap.signOrder(ercToNftOrder);
}
if (makerAsset.type === 'ERC721' && takerAsset.type === 'ERC20') {
const nftToErcOrder = nftSwap.buildOrder(
makerAsset,
takerAsset,
makerAddress,
{
fees,
}
);
signedOrder = await nftSwap.signOrder(nftToErcOrder);
}
if (makerAsset.type === 'ERC20' && takerAsset.type === 'ERC1155') {
const ercToMtOrder = nftSwap.buildOrder(
makerAsset,
takerAsset,
makerAddress,
{
fees,
}
);
signedOrder = await nftSwap.signOrder(ercToMtOrder);
}
if (makerAsset.type === 'ERC1155' && takerAsset.type === 'ERC20') {
const mtToErcOrder = nftSwap.buildOrder(
makerAsset,
takerAsset,
makerAddress,
{
fees,
}
);
signedOrder = await nftSwap.signOrder(mtToErcOrder);
}

if (!signedOrder) return;

await nftSwap.postOrder(signedOrder, chainId, metadata);
return signedOrder;
};

return createOrder;
}
99 changes: 99 additions & 0 deletions src/react/hooks/useFulfillOrder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { ContractReceipt } from 'ethers';

import { useContext } from 'react';

import {
ApprovalOverrides,
FillOrderOverrides,
SwappableAssetV4,
} from '../../sdk';
import { PayableOverrides, TransactionOverrides } from '../../sdk/common/types';
import { PostOrderResponsePayload } from '../../sdk/v4/orderbook';
import { SwapSdkContext } from '../providers/swapSdkProvider';

/**
* Get the order fulfillment function
*/
export function useFulfillOrder() {
const { nftSwap } = useContext(SwapSdkContext);

/**
* Fulfills signed order
* @param order order to fulfill
* @param takerAddress buyer wallet address
* @param approvalOverrides optional config for approval status load
* @param approvalTransactionOverrides optional config for transaction approve
* @param fillOrderOverrides optional config for order fulfillment
* @param transactionOverrides optional config for swap transaction
* @returns a transaction receipt if successful
*/
const fulfillOrder = async (
order: PostOrderResponsePayload | undefined,
takerAddress: string | undefined,
approvalOverrides?: Partial<ApprovalOverrides>,
approvalTransactionOverrides?: Partial<TransactionOverrides>,
fillOrderOverrides?: Partial<FillOrderOverrides>,
transactionOverrides?: Partial<PayableOverrides>
): Promise<ContractReceipt | undefined> => {
if (!nftSwap) return;
if (!order) return;
if (!takerAddress) return;

let takerAsset: SwappableAssetV4 | null = null;

switch (order.nftType) {
case 'ERC20':
takerAsset = {
tokenAddress: order.erc20Token,
amount: order.erc20TokenAmount,
type: 'ERC20',
};
break;
case 'ERC721':
takerAsset = {
tokenAddress: order.nftToken,
tokenId: order.nftTokenId,
type: 'ERC721',
};
break;
case 'ERC1155':
takerAsset = {
tokenAddress: order.nftToken,
tokenId: order.nftTokenId,
amount: order.erc20TokenAmount,
type: 'ERC1155',
};
break;
default:
takerAsset = null;
break;
}

if (!takerAsset) return;

const approvalStatus = await nftSwap.loadApprovalStatus(
takerAsset,
takerAddress,
approvalOverrides
);
if (!approvalStatus.contractApproved) {
const approvalTx = await nftSwap.approveTokenOrNftByAsset(
takerAsset,
takerAddress,
approvalTransactionOverrides
);
await approvalTx.wait();
}

const fillTx = await nftSwap.fillSignedOrder(
order.order,
fillOrderOverrides,
transactionOverrides
);
const fillTxReceipt = await fillTx.wait();

return fillTxReceipt;
};

return fulfillOrder;
}
41 changes: 41 additions & 0 deletions src/react/hooks/useOrders.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { useContext, useEffect, useState } from 'react';

import {
PostOrderResponsePayload,
SearchOrdersParams,
} from '../../sdk/v4/orderbook';
import { SwapSdkContext } from '../providers/swapSdkProvider';

/**
* Get orders from the Trader.xyz Open NFT Orderbook
* @param searchParams optional conditions to search for specific orders
* @returns an array of orders and a function to refresh it
*/
export function useOrders(searchParams?: Partial<SearchOrdersParams>) {
const { signer, nftSwap } = useContext(SwapSdkContext);

const [orders, setOrders] = useState<PostOrderResponsePayload[]>();

const fetchOrders = async (): Promise<void> => {
if (!signer) return;
if (!nftSwap) return;

try {
const fetchedOrdersData = await nftSwap.getOrders(searchParams);
const fetchedOrders = fetchedOrdersData.orders;
setOrders(fetchedOrders);
} catch (error: any) {
console.error(`Unable to load orders:\n${error.message}`);
setOrders(undefined);
}
};

useEffect(() => {
fetchOrders();
}, [signer, nftSwap]);

return [orders, fetchOrders] as [
PostOrderResponsePayload[] | undefined,
() => Promise<void>
];
}