Commit ff9cc5cb authored by Jack Short's avatar Jack Short Committed by GitHub

feat: pwat amp events (#5991)

* feat: implementing graphql endpoint

* changing from hook to function call

* initial gql routing works

* feat: initial pwatRouting setup

* sending correct amount

* removing console

* it is working

* sufficient balance

* 0 if no inputCurrency

* removing value to send if erc20

* removing console

* permit2 optional flag

* removing not necessary stuff

* mobile fixes

* overlay needs to be here

* changing swap amount to pool reserves

* refactoring routing logic

* no route found button state

* better price loading for insufficient liquidity

* refactoring graphql routing code

* overflow

* initial comments

* resetting bag status on input currency change

* locking

* done

* remove helper text for eth

* fix: pay with any token routing bug

* reordering button

* zindex

* price updated

* keeping debounce

* feat: adding amplitude events for pwat

* bumping analytics version

* types and hooks

* moving erc20 flag to useSendTransaction

* why did i put it in a hook

* no return
parent 719fd524
...@@ -41,7 +41,6 @@ export enum ActivityType { ...@@ -41,7 +41,6 @@ export enum ActivityType {
Send = 'SEND', Send = 'SEND',
Stake = 'STAKE', Stake = 'STAKE',
Swap = 'SWAP', Swap = 'SWAP',
Swapx = 'SWAPX',
Staking = 'Staking', Staking = 'Staking',
Unknown = 'UNKNOWN', Unknown = 'UNKNOWN',
Unstake = 'UNSTAKE', Unstake = 'UNSTAKE',
...@@ -83,7 +82,8 @@ export enum Chain { ...@@ -83,7 +82,8 @@ export enum Chain {
Ethereum = 'ETHEREUM', Ethereum = 'ETHEREUM',
EthereumGoerli = 'ETHEREUM_GOERLI', EthereumGoerli = 'ETHEREUM_GOERLI',
Optimism = 'OPTIMISM', Optimism = 'OPTIMISM',
Polygon = 'POLYGON' Polygon = 'POLYGON',
UnknownChain = 'UNKNOWN_CHAIN'
} }
export type ContractInput = { export type ContractInput = {
...@@ -196,6 +196,7 @@ export type NftAssetListingsArgs = { ...@@ -196,6 +196,7 @@ export type NftAssetListingsArgs = {
after?: InputMaybe<Scalars['String']>; after?: InputMaybe<Scalars['String']>;
asc?: InputMaybe<Scalars['Boolean']>; asc?: InputMaybe<Scalars['Boolean']>;
before?: InputMaybe<Scalars['String']>; before?: InputMaybe<Scalars['String']>;
datasource?: InputMaybe<DatasourceProvider>;
first?: InputMaybe<Scalars['Int']>; first?: InputMaybe<Scalars['Int']>;
last?: InputMaybe<Scalars['Int']>; last?: InputMaybe<Scalars['Int']>;
}; };
...@@ -310,6 +311,7 @@ export type NftCollection = { ...@@ -310,6 +311,7 @@ export type NftCollection = {
export type NftCollectionMarketsArgs = { export type NftCollectionMarketsArgs = {
currencies: Array<Currency>; currencies: Array<Currency>;
datasource?: InputMaybe<DatasourceProvider>;
}; };
export type NftCollectionConnection = { export type NftCollectionConnection = {
...@@ -621,6 +623,7 @@ export type QueryNftAssetsArgs = { ...@@ -621,6 +623,7 @@ export type QueryNftAssetsArgs = {
asc?: InputMaybe<Scalars['Boolean']>; asc?: InputMaybe<Scalars['Boolean']>;
before?: InputMaybe<Scalars['String']>; before?: InputMaybe<Scalars['String']>;
chain?: InputMaybe<Chain>; chain?: InputMaybe<Chain>;
datasource?: InputMaybe<DatasourceProvider>;
filter?: InputMaybe<NftAssetsFilterInput>; filter?: InputMaybe<NftAssetsFilterInput>;
first?: InputMaybe<Scalars['Int']>; first?: InputMaybe<Scalars['Int']>;
last?: InputMaybe<Scalars['Int']>; last?: InputMaybe<Scalars['Int']>;
...@@ -632,9 +635,12 @@ export type QueryNftBalancesArgs = { ...@@ -632,9 +635,12 @@ export type QueryNftBalancesArgs = {
after?: InputMaybe<Scalars['String']>; after?: InputMaybe<Scalars['String']>;
before?: InputMaybe<Scalars['String']>; before?: InputMaybe<Scalars['String']>;
chain?: InputMaybe<Chain>; chain?: InputMaybe<Chain>;
cursor?: InputMaybe<Scalars['String']>;
datasource?: InputMaybe<DatasourceProvider>;
filter?: InputMaybe<NftBalancesFilterInput>; filter?: InputMaybe<NftBalancesFilterInput>;
first?: InputMaybe<Scalars['Int']>; first?: InputMaybe<Scalars['Int']>;
last?: InputMaybe<Scalars['Int']>; last?: InputMaybe<Scalars['Int']>;
limit?: InputMaybe<Scalars['Int']>;
ownerAddress: Scalars['String']; ownerAddress: Scalars['String'];
}; };
...@@ -642,6 +648,7 @@ export type QueryNftBalancesArgs = { ...@@ -642,6 +648,7 @@ export type QueryNftBalancesArgs = {
export type QueryNftCollectionsArgs = { export type QueryNftCollectionsArgs = {
after?: InputMaybe<Scalars['String']>; after?: InputMaybe<Scalars['String']>;
before?: InputMaybe<Scalars['String']>; before?: InputMaybe<Scalars['String']>;
datasource?: InputMaybe<DatasourceProvider>;
filter?: InputMaybe<NftCollectionsFilterInput>; filter?: InputMaybe<NftCollectionsFilterInput>;
first?: InputMaybe<Scalars['Int']>; first?: InputMaybe<Scalars['Int']>;
last?: InputMaybe<Scalars['Int']>; last?: InputMaybe<Scalars['Int']>;
...@@ -832,6 +839,7 @@ export type TokenProjectMarketsArgs = { ...@@ -832,6 +839,7 @@ export type TokenProjectMarketsArgs = {
export type TokenProjectMarket = { export type TokenProjectMarket = {
__typename?: 'TokenProjectMarket'; __typename?: 'TokenProjectMarket';
currency: Currency; currency: Currency;
/** @deprecated Use marketCap */
fullyDilutedMarketCap?: Maybe<Amount>; fullyDilutedMarketCap?: Maybe<Amount>;
id: Scalars['ID']; id: Scalars['ID'];
marketCap?: Maybe<Amount>; marketCap?: Maybe<Amount>;
...@@ -839,9 +847,12 @@ export type TokenProjectMarket = { ...@@ -839,9 +847,12 @@ export type TokenProjectMarket = {
priceHighLow?: Maybe<Amount>; priceHighLow?: Maybe<Amount>;
priceHistory?: Maybe<Array<Maybe<TimestampedAmount>>>; priceHistory?: Maybe<Array<Maybe<TimestampedAmount>>>;
pricePercentChange?: Maybe<Amount>; pricePercentChange?: Maybe<Amount>;
/** @deprecated Use pricePercentChange */
pricePercentChange24h?: Maybe<Amount>; pricePercentChange24h?: Maybe<Amount>;
tokenProject: TokenProject; tokenProject: TokenProject;
/** @deprecated Use TokenMarket.volume for Uniswap volume */
volume?: Maybe<Amount>; volume?: Maybe<Amount>;
/** @deprecated Use TokenMarket.volume with duration DAY for Uniswap volume */
volume24h?: Maybe<Amount>; volume24h?: Maybe<Amount>;
}; };
......
...@@ -179,12 +179,13 @@ const Bag = () => { ...@@ -179,12 +179,13 @@ const Bag = () => {
return { totalEthPrice } return { totalEthPrice }
}, [itemsInBag]) }, [itemsInBag])
const purchaseAssets = async (routingData: RouteResponse) => { const purchaseAssets = async (routingData: RouteResponse, purchasingWithErc20: boolean) => {
if (!provider || !routingData) return if (!provider || !routingData) return
const purchaseResponse = await sendTransaction( const purchaseResponse = await sendTransaction(
provider?.getSigner(), provider?.getSigner(),
itemsInBag.filter((item) => item.status !== BagItemStatus.UNAVAILABLE).map((item) => item.asset), itemsInBag.filter((item) => item.status !== BagItemStatus.UNAVAILABLE).map((item) => item.asset),
routingData routingData,
purchasingWithErc20
) )
if ( if (
purchaseResponse && purchaseResponse &&
...@@ -230,10 +231,11 @@ const Bag = () => { ...@@ -230,10 +231,11 @@ const Bag = () => {
return return
} }
const { route, routeResponse } = buildRouteResponse(data.nftRoute, !!tokenTradeInput) const purchasingWithErc20 = !!tokenTradeInput
const { route, routeResponse } = buildRouteResponse(data.nftRoute, purchasingWithErc20)
const { hasPriceAdjustment, updatedAssets } = combineBuyItemsWithTxRoute(itemsToBuy, route) const { hasPriceAdjustment, updatedAssets } = combineBuyItemsWithTxRoute(itemsToBuy, route)
const shouldRefetchCalldata = hasPriceAdjustment && !!tokenTradeInput const shouldRefetchCalldata = hasPriceAdjustment && purchasingWithErc20
const fetchedPriceChangedAssets = updatedAssets const fetchedPriceChangedAssets = updatedAssets
.filter((asset) => asset.updatedPriceInfo) .filter((asset) => asset.updatedPriceInfo)
...@@ -270,7 +272,7 @@ const Bag = () => { ...@@ -270,7 +272,7 @@ const Bag = () => {
if (shouldRefetchCalldata) { if (shouldRefetchCalldata) {
setBagStatus(BagStatus.CONFIRM_QUOTE) setBagStatus(BagStatus.CONFIRM_QUOTE)
} else { } else {
purchaseAssets(routeResponse) purchaseAssets(routeResponse, purchasingWithErc20)
setBagStatus(BagStatus.CONFIRMING_IN_WALLET) setBagStatus(BagStatus.CONFIRMING_IN_WALLET)
shouldLock = true shouldLock = true
} }
...@@ -325,7 +327,7 @@ const Bag = () => { ...@@ -325,7 +327,7 @@ const Bag = () => {
if (hasAssets) { if (hasAssets) {
if (!shouldReview) { if (!shouldReview) {
purchaseAssets(routeData) purchaseAssets(routeData, false)
setBagStatus(BagStatus.CONFIRMING_IN_WALLET) setBagStatus(BagStatus.CONFIRMING_IN_WALLET)
} else if (!hasAssetsInReview) setBagStatus(BagStatus.CONFIRM_REVIEW) } else if (!hasAssetsInReview) setBagStatus(BagStatus.CONFIRM_REVIEW)
else { else {
......
...@@ -2,7 +2,7 @@ import { BigNumber } from '@ethersproject/bignumber' ...@@ -2,7 +2,7 @@ import { BigNumber } from '@ethersproject/bignumber'
import { formatEther } from '@ethersproject/units' import { formatEther } from '@ethersproject/units'
import { parseEther } from '@ethersproject/units' import { parseEther } from '@ethersproject/units'
import { t, Trans } from '@lingui/macro' import { t, Trans } from '@lingui/macro'
import { TraceEvent } from '@uniswap/analytics' import { sendAnalyticsEvent, TraceEvent } from '@uniswap/analytics'
import { BrowserEvent, InterfaceElementName, NFTEventName } from '@uniswap/analytics-events' import { BrowserEvent, InterfaceElementName, NFTEventName } from '@uniswap/analytics-events'
import { formatPriceImpact } from '@uniswap/conedison/format' import { formatPriceImpact } from '@uniswap/conedison/format'
import { Currency, CurrencyAmount, Percent, Token, TradeType } from '@uniswap/sdk-core' import { Currency, CurrencyAmount, Percent, Token, TradeType } from '@uniswap/sdk-core'
...@@ -518,6 +518,7 @@ export const BagFooter = ({ totalEthPrice, fetchAssets, eventProperties }: BagFo ...@@ -518,6 +518,7 @@ export const BagFooter = ({ totalEthPrice, fetchAssets, eventProperties }: BagFo
const traceEventProperties = { const traceEventProperties = {
usd_value: usdcValue?.toExact(), usd_value: usdcValue?.toExact(),
using_erc20: !!inputCurrency,
...eventProperties, ...eventProperties,
} }
...@@ -531,7 +532,14 @@ export const BagFooter = ({ totalEthPrice, fetchAssets, eventProperties }: BagFo ...@@ -531,7 +532,14 @@ export const BagFooter = ({ totalEthPrice, fetchAssets, eventProperties }: BagFo
<ThemedText.SubHeaderSmall> <ThemedText.SubHeaderSmall>
<Trans>Pay with</Trans> <Trans>Pay with</Trans>
</ThemedText.SubHeaderSmall> </ThemedText.SubHeaderSmall>
<CurrencyInput onClick={() => (bagIsLocked ? undefined : setTokenSelectorOpen(true))}> <CurrencyInput
onClick={() => {
if (!bagIsLocked) {
setTokenSelectorOpen(true)
sendAnalyticsEvent(NFTEventName.NFT_BUY_TOKEN_SELECTOR_CLICKED)
}
}}
>
<CurrencyLogo currency={activeCurrency} size="24px" /> <CurrencyLogo currency={activeCurrency} size="24px" />
<ThemedText.HeadlineSmall fontWeight={500} lineHeight="24px"> <ThemedText.HeadlineSmall fontWeight={500} lineHeight="24px">
{activeCurrency?.symbol} {activeCurrency?.symbol}
...@@ -606,7 +614,15 @@ export const BagFooter = ({ totalEthPrice, fetchAssets, eventProperties }: BagFo ...@@ -606,7 +614,15 @@ export const BagFooter = ({ totalEthPrice, fetchAssets, eventProperties }: BagFo
<CurrencySearchModal <CurrencySearchModal
isOpen={tokenSelectorOpen} isOpen={tokenSelectorOpen}
onDismiss={() => setTokenSelectorOpen(false)} onDismiss={() => setTokenSelectorOpen(false)}
onCurrencySelect={(currency: Currency) => setInputCurrency(currency.isNative ? undefined : currency)} onCurrencySelect={(currency: Currency) => {
setInputCurrency(currency.isNative ? undefined : currency)
if (currency.isToken) {
sendAnalyticsEvent(NFTEventName.NFT_BUY_TOKEN_SELECTED, {
token_address: currency.address,
token_symbol: currency.symbol,
})
}
}}
selectedCurrency={activeCurrency ?? undefined} selectedCurrency={activeCurrency ?? undefined}
onlyShowCurrenciesWithBalance={true} onlyShowCurrenciesWithBalance={true}
/> />
......
...@@ -50,6 +50,7 @@ const TxCompleteModal = () => { ...@@ -50,6 +50,7 @@ const TxCompleteModal = () => {
const [ethPrice, setEthPrice] = useState(3000) const [ethPrice, setEthPrice] = useState(3000)
const [showUnavailable, setShowUnavailable] = useState(false) const [showUnavailable, setShowUnavailable] = useState(false)
const txHash = useSendTransaction((state) => state.txHash) const txHash = useSendTransaction((state) => state.txHash)
const purchasedWithErc20 = useSendTransaction((state) => state.purchasedWithErc20)
const setTxState = useSendTransaction((state) => state.setState) const setTxState = useSendTransaction((state) => state.setState)
const txState = useSendTransaction((state) => state.state) const txState = useSendTransaction((state) => state.state)
const transactionStateRef = useRef(txState) const transactionStateRef = useRef(txState)
...@@ -115,6 +116,7 @@ const TxCompleteModal = () => { ...@@ -115,6 +116,7 @@ const TxCompleteModal = () => {
buy_quantity: nftsPurchased.length, buy_quantity: nftsPurchased.length,
usd_value: parseFloat(formatEther(totalPurchaseValue)) * ethPrice, usd_value: parseFloat(formatEther(totalPurchaseValue)) * ethPrice,
transaction_hash: txHash, transaction_hash: txHash,
using_erc20: purchasedWithErc20,
...formatAssetEventProperties(nftsPurchased), ...formatAssetEventProperties(nftsPurchased),
...trace, ...trace,
}} }}
......
...@@ -19,10 +19,12 @@ interface TxState { ...@@ -19,10 +19,12 @@ interface TxState {
setState: (state: TxStateType) => void setState: (state: TxStateType) => void
txHash: string txHash: string
clearTxHash: () => void clearTxHash: () => void
purchasedWithErc20: boolean
sendTransaction: ( sendTransaction: (
signer: JsonRpcSigner, signer: JsonRpcSigner,
selectedAssets: UpdatedGenieAsset[], selectedAssets: UpdatedGenieAsset[],
transactionData: RouteResponse transactionData: RouteResponse,
purchasedWithErc20: boolean
) => Promise<TxResponse | undefined> ) => Promise<TxResponse | undefined>
} }
...@@ -31,9 +33,10 @@ export const useSendTransaction = create<TxState>()( ...@@ -31,9 +33,10 @@ export const useSendTransaction = create<TxState>()(
(set) => ({ (set) => ({
state: TxStateType.New, state: TxStateType.New,
txHash: '', txHash: '',
purchasedWithErc20: false,
clearTxHash: () => set({ txHash: '' }), clearTxHash: () => set({ txHash: '' }),
setState: (newState) => set(() => ({ state: newState })), setState: (newState) => set(() => ({ state: newState })),
sendTransaction: async (signer, selectedAssets, transactionData) => { sendTransaction: async (signer, selectedAssets, transactionData, purchasedWithErc20) => {
const address = await signer.getAddress() const address = await signer.getAddress()
try { try {
const txNoGasLimit = { const txNoGasLimit = {
...@@ -50,6 +53,7 @@ export const useSendTransaction = create<TxState>()( ...@@ -50,6 +53,7 @@ export const useSendTransaction = create<TxState>()(
const res = await signer.sendTransaction(tx) const res = await signer.sendTransaction(tx)
set({ state: TxStateType.Confirming }) set({ state: TxStateType.Confirming })
set({ txHash: res.hash }) set({ txHash: res.hash })
set({ purchasedWithErc20 })
sendAnalyticsEvent(NFTEventName.NFT_BUY_BAG_SIGNED, { transaction_hash: res.hash }) sendAnalyticsEvent(NFTEventName.NFT_BUY_BAG_SIGNED, { transaction_hash: res.hash })
const txReceipt = await res.wait() const txReceipt = await res.wait()
......
...@@ -4931,10 +4931,10 @@ ...@@ -4931,10 +4931,10 @@
"@typescript-eslint/types" "5.47.0" "@typescript-eslint/types" "5.47.0"
eslint-visitor-keys "^3.3.0" eslint-visitor-keys "^3.3.0"
"@uniswap/analytics-events@^2.1.0": "@uniswap/analytics-events@^2.3.0":
version "2.1.0" version "2.3.0"
resolved "https://registry.yarnpkg.com/@uniswap/analytics-events/-/analytics-events-2.1.0.tgz#0a112f642d0121fdf69b5dc9a17639f06aa63085" resolved "https://registry.yarnpkg.com/@uniswap/analytics-events/-/analytics-events-2.3.0.tgz#e4d6b29633c09872be3b9b760b1a192b96368887"
integrity sha512-HkWyri7PxnIS6B5sysym1LCMPnenkeAFyI41fYGDUNq3a5aEDuD77jyyFSwdW4yZfUOxq3zBUTmeQOIf/GT+tQ== integrity sha512-oShunkYEfa45RQAtl2aQfF91gfX4QirLa/fR+FyL5jfl+Ei4AZ1ihtyVjJ1VLOJlObX1p08JjlpA0yxqDwPYHw==
"@uniswap/analytics@1.2.0": "@uniswap/analytics@1.2.0":
version "1.2.0" version "1.2.0"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment