Skip to content

Commit

Permalink
Merge pull request #194 from 0xsequence/databeat
Browse files Browse the repository at this point in the history
Databeat
  • Loading branch information
AlexanderKolberg authored Feb 25, 2025
2 parents 5c6fc9b + 402139f commit f9e3621
Show file tree
Hide file tree
Showing 9 changed files with 269 additions and 82 deletions.
1 change: 1 addition & 0 deletions packages/sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
}
},
"dependencies": {
"@databeat/tracker": "^0.9.3",
"@legendapp/state": "catalog:",
"@radix-ui/react-dialog": "catalog:",
"@radix-ui/react-popover": "catalog:",
Expand Down
63 changes: 63 additions & 0 deletions packages/sdk/src/react/_internal/databeat/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import type { Event as DatabeatEvent } from '@databeat/tracker';
import { Databeat } from '@databeat/tracker';

import { useConfig } from '../../hooks';
import type {
EventType,
TrackCreateListing,
TrackCreateOffer,
TrackSellItems,
TrackTransactionFailed,
} from './types';

export type EventTypes = keyof typeof EventType;
export type Event = DatabeatEvent<EventTypes>;

export class DatabeatAnalytics extends Databeat<Extract<EventTypes, string>> {
// Currently handled by kit-checkout
// trackBuyItems(args: TrackBuyItems) {
// this.track({
// event: 'BUY_ITEMS',
// props: args.props,
// nums: args.nums
// })
// }

trackSellItems(args: TrackSellItems) {
this.track({
event: 'SELL_ITEMS',
props: args.props,
nums: args.nums,
});
}

trackCreateListing(args: TrackCreateListing) {
this.track({
event: 'CREATE_LISTING',
props: args.props,
nums: args.nums,
});
}

trackCreateOffer(args: TrackCreateOffer) {
this.track({
event: 'CREATE_OFFER',
props: args.props,
nums: args.nums,
});
}

trackTransactionFailed(args: TrackTransactionFailed) {
this.track({
event: 'TRANSACTION_FAILED',
props: args,
});
}
}

export const useAnalytics = () => {
const config = useConfig();
return new DatabeatAnalytics('https://databeat.sequence.app', {
jwt: config.projectAccessKey,
});
};
70 changes: 70 additions & 0 deletions packages/sdk/src/react/_internal/databeat/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import type { MarketplaceKind, OrderbookKind } from '../api';

export enum EventType {
BUY_ITEMS = 0,
SELL_ITEMS = 1,
CREATE_LISTING = 2,
CREATE_OFFER = 3,
CANCEL_LISTING = 4,
CANCEL_OFFER = 5,
TRANSACTION_FAILED = 6,
}

interface PropsEvent {
[key: string]: string;
}

interface NumsEvent {
[key: string]: number;
}

interface Transaction extends PropsEvent {
chainId: string;
txnHash: string;
}

interface TradeItemsInfo extends PropsEvent {
marketplaceKind: MarketplaceKind;
collectionAddress: string;
currencyAddress: string;
currencySymbol: string;
}

interface TradeItemsValues extends NumsEvent {
currencyValueDecimal: number;
currencyValueRaw: number;
}

export interface TrackBuyItems {
props: TradeItemsInfo & Transaction;
nums: TradeItemsValues;
}

export interface TrackSellItems {
props: TradeItemsInfo & Transaction;
nums: TradeItemsValues;
}

interface ListOfferItemsInfo extends PropsEvent {
orderbookKind: OrderbookKind;
collectionAddress: string;
currencyAddress: string;
currencySymbol: string;
}

interface ListOfferItemsValues extends NumsEvent {
currencyValueDecimal: number;
currencyValueRaw: number;
}

export interface TrackCreateListing {
props: ListOfferItemsInfo & Transaction;
nums: ListOfferItemsValues;
}

export interface TrackCreateOffer {
props: ListOfferItemsInfo & Transaction;
nums: ListOfferItemsValues;
}

export interface TrackTransactionFailed extends Transaction, PropsEvent {}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Observable } from '@legendapp/state';
import type { Address, Hex } from 'viem';
import { type Address, type Hex, formatUnits } from 'viem';
import type { OrderbookKind } from '../../../../../types';
import {
ExecuteType,
Expand All @@ -10,17 +10,21 @@ import {
collectableKeys,
getMarketplaceClient,
} from '../../../../_internal';
import { useAnalytics } from '../../../../_internal/databeat';
import { TransactionType } from '../../../../_internal/types';
import type { ListingInput } from '../../../../_internal/types';
import { useWallet } from '../../../../_internal/wallet/useWallet';
import type {
SignatureStep,
TransactionStep as WalletTransactionStep,
} from '../../../../_internal/utils';
import { useConfig, useGenerateListingTransaction } from '../../../../hooks';
import { useWallet } from '../../../../_internal/wallet/useWallet';
import {
useConfig,
useCurrencies,
useGenerateListingTransaction,
} from '../../../../hooks';
import { useTransactionStatusModal } from '../../_internal/components/transactionStatusModal';
import type { ModalCallbacks } from '../../_internal/types';

interface UseTransactionStepsArgs {
listingInput: ListingInput;
chainId: string;
Expand All @@ -44,7 +48,11 @@ export const useTransactionSteps = ({
const expiry = new Date(Number(listingInput.listing.expiry) * 1000);
const { show: showTransactionStatusModal } = useTransactionStatusModal();
const sdkConfig = useConfig();
const { data: currencies } = useCurrencies({
chainId: Number(chainId),
});
const marketplaceClient = getMarketplaceClient(chainId, sdkConfig);
const analytics = useAnalytics();
const { generateListingTransactionAsync, isPending: generatingSteps } =
useGenerateListingTransaction({
chainId,
Expand Down Expand Up @@ -164,6 +172,34 @@ export const useTransactionSteps = ({
steps$.transaction.isExecuting.set(false);
steps$.transaction.exist.set(false);
}

if (hash || orderId) {
const currencyDecimal =
currencies?.find(
(currency) =>
currency.contractAddress === listingInput.listing.currencyAddress,
)?.decimals || 0;

const currencyValueRaw = Number(listingInput.listing.pricePerToken);
const currencyValueDecimal = Number(
formatUnits(BigInt(currencyValueRaw), currencyDecimal),
);

analytics.trackCreateListing({
props: {
orderbookKind,
collectionAddress,
currencyAddress: listingInput.listing.currencyAddress,
currencySymbol: '',
chainId,
txnHash: hash || '',
},
nums: {
currencyValueDecimal,
currencyValueRaw,
},
});
}
} catch (error) {
steps$.transaction.isExecuting.set(false);
steps$.transaction.exist.set(false);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Observable } from '@legendapp/state';
import type { Address, Hex } from 'viem';
import { type Address, type Hex, formatUnits } from 'viem';
import { OrderbookKind, type Price } from '../../../../../types';
import {
ExecuteType,
Expand All @@ -10,6 +10,7 @@ import {
collectableKeys,
getMarketplaceClient,
} from '../../../../_internal';
import { useAnalytics } from '../../../../_internal/databeat';
import { TransactionType } from '../../../../_internal/types';
import type { OfferInput } from '../../../../_internal/types';
import type {
Expand All @@ -21,7 +22,6 @@ import { useConfig, useCurrency } from '../../../../hooks';
import { useGenerateOfferTransaction } from '../../../../hooks/useGenerateOfferTransaction';
import { useTransactionStatusModal } from '../../_internal/components/transactionStatusModal';
import type { ModalCallbacks } from '../../_internal/types';

export type ExecutionState = 'approval' | 'offer' | null;

interface UseTransactionStepsArgs {
Expand All @@ -47,6 +47,7 @@ export const useTransactionSteps = ({
const expiry = new Date(Number(offerInput.offer.expiry) * 1000);
const { show: showTransactionStatusModal } = useTransactionStatusModal();
const sdkConfig = useConfig();
const analytics = useAnalytics();
const marketplaceClient = getMarketplaceClient(chainId, sdkConfig);
const { generateOfferTransactionAsync, isPending: generatingSteps } =
useGenerateOfferTransaction({
Expand Down Expand Up @@ -177,6 +178,29 @@ export const useTransactionSteps = ({
steps$.transaction.isExecuting.set(false);
steps$.transaction.exist.set(false);
}

if (hash || orderId) {
const currencyDecimal = currency?.decimals || 0;
const currencyValueRaw = Number(offerInput.offer.pricePerToken);
const currencyValueDecimal = Number(
formatUnits(BigInt(currencyValueRaw), currencyDecimal),
);

analytics.trackCreateOffer({
props: {
orderbookKind,
collectionAddress,
currencyAddress: offerInput.offer.currencyAddress,
currencySymbol: currency?.symbol || '',
chainId,
txnHash: hash || '',
},
nums: {
currencyValueDecimal,
currencyValueRaw,
},
});
}
} catch (error) {
steps$.transaction.isExecuting.set(false);
steps$.transaction.exist.set(false);
Expand Down
4 changes: 3 additions & 1 deletion packages/sdk/src/react/ui/modals/SellModal/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import { LoadingModal } from '../_internal/components/actionModal/LoadingModal';
import TokenPreview from '../_internal/components/tokenPreview';
import TransactionDetails from '../_internal/components/transactionDetails';
import TransactionHeader from '../_internal/components/transactionHeader';
import { sellModal$ } from './store';
import { useSell } from './hooks/useSell';
import { sellModal$ } from './store';

export const SellModal = () => {
return <Show if={sellModal$.isOpen}>{() => <Modal />}</Show>;
Expand Down Expand Up @@ -58,6 +58,8 @@ const Modal = observer(() => {
collectible?.decimals || 0,
).toString()
: '1',
pricePerToken: order?.priceAmount ?? '',
currencyAddress: order?.priceCurrencyAddress ?? '',
},
],
callbacks,
Expand Down
17 changes: 10 additions & 7 deletions packages/sdk/src/react/ui/modals/SellModal/hooks/useSell.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
import type { Observable } from '@legendapp/state';
import { useEffect } from 'react';
import type { MarketplaceKind, TransactionSteps } from '../../../../_internal';
import type { ModalCallbacks } from '../../_internal/types';
import { useGetTokenApprovalData } from './useGetTokenApproval';
import { useTransactionSteps } from './useTransactionSteps';
import { useEffect } from 'react';
import type {
MarketplaceKind,
OrderData,
TransactionSteps,
} from '../../../../_internal';

export type SellOrder = {
orderId: string;
quantity: string;
pricePerToken: string;
currencyAddress: string;
};

interface UseSellArgs {
collectibleId: string;
chainId: string;
collectionAddress: string;
marketplace: MarketplaceKind;
ordersData: Array<OrderData>;
ordersData: Array<SellOrder>;
callbacks?: ModalCallbacks;
closeMainModal: () => void;
steps$: Observable<TransactionSteps>;
Expand Down
Loading

0 comments on commit f9e3621

Please sign in to comment.