Skip to content
Merged
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
5 changes: 4 additions & 1 deletion packages/controllers/exports/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,10 @@ export { OptionsStateController } from '../src/controllers/OptionsStateControlle
export type { OptionsStateControllerState } from '../src/controllers/OptionsStateController.js'

export { ExchangeController } from '../src/controllers/ExchangeController.js'
export type { ExchangeControllerState } from '../src/controllers/ExchangeController.js'
export type {
ExchangeControllerState,
CurrentPayment
} from '../src/controllers/ExchangeController.js'

// -- Utils -------------------------------------------------------------------
export { AssetUtil } from '../src/utils/AssetUtil.js'
Expand Down
134 changes: 113 additions & 21 deletions packages/controllers/src/controllers/ExchangeController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ import { type CaipNetworkId } from '@reown/appkit-common'

import { getActiveNetworkTokenAddress } from '../utils/ChainControllerUtil.js'
import { CoreHelperUtil } from '../utils/CoreHelperUtil.js'
import { formatCaip19Asset, getExchanges, getPayUrl } from '../utils/ExchangeUtil.js'
import {
type GetBuyStatusResult,
formatCaip19Asset,
getBuyStatus,
getExchanges,
getPayUrl
} from '../utils/ExchangeUtil.js'
import type { Exchange, PayUrlParams } from '../utils/ExchangeUtil.js'
import { AccountController } from './AccountController.js'
import { BlockchainApiController } from './BlockchainApiController.js'
Expand All @@ -31,7 +37,9 @@ const DEFAULT_STATE: ExchangeControllerState = {
error: null,
exchanges: [],
isLoading: false,
currentPayment: undefined
currentPayment: undefined,
isPaymentInProgress: false,
paymentId: ''
}

// -- Types --------------------------------------------- //
Expand Down Expand Up @@ -66,31 +74,15 @@ export interface ExchangeControllerState {
exchanges: Exchange[]
currentPayment?: CurrentPayment
paymentAsset: PaymentAsset
isPaymentInProgress: boolean
paymentId: string
}

type StateKey = keyof ExchangeControllerState
type PaymentType = 'wallet' | 'exchange'

// -- State --------------------------------------------- //
const state = proxy<ExchangeControllerState>({
paymentAsset: {
network: 'eip155:1',
asset: 'native',
metadata: {
name: 'Ethereum',
symbol: 'ETH',
decimals: 18
}
},
amount: 0,
tokenAmount: 0,
tokenPrice: null,
priceLoading: false,
error: null,
exchanges: [],
isLoading: false,
currentPayment: undefined
})
const state = proxy<ExchangeControllerState>(DEFAULT_STATE)

// -- Controller ---------------------------------------- //
export const ExchangeController = {
Expand Down Expand Up @@ -188,6 +180,7 @@ export const ExchangeController = {
type: 'exchange',
exchangeId
},
source: 'fund-from-exchange',
headless: false
}
})
Expand All @@ -207,6 +200,9 @@ export const ExchangeController = {
throw new Error('No account connected')
}

state.isPaymentInProgress = true
state.paymentId = crypto.randomUUID()

state.currentPayment = {
type: 'exchange',
exchangeId
Expand All @@ -233,5 +229,101 @@ export const ExchangeController = {
state.error = 'Unable to initiate payment'
SnackController.showError(state.error)
}
},

async waitUntilComplete({
exchangeId,
sessionId,
paymentId,
retries = 20
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is 20 retries too much?

}: {
exchangeId: string
sessionId: string
paymentId: string
retries?: number
}): Promise<GetBuyStatusResult> {
const status = await this.getBuyStatus(exchangeId, sessionId, paymentId)
if (status.status === 'SUCCESS' || status.status === 'FAILED') {
return status
}

if (retries === 0) {
throw new Error('Unable to get deposit status')
}

// Wait 1 second before checking again
await new Promise(resolve => {
setTimeout(resolve, 5000)
})
Comment on lines +254 to +257
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like it's 5 seconds?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lmk if it should be 5 or 1 seconds


return this.waitUntilComplete({
exchangeId,
sessionId,
paymentId,
retries: retries - 1
})
},

async getBuyStatus(exchangeId: string, sessionId: string, paymentId: string) {
try {
if (!state.currentPayment) {
throw new Error('No current payment')
}

const status = await getBuyStatus({ sessionId, exchangeId })
state.currentPayment.status = status.status
if (status.status === 'SUCCESS' || status.status === 'FAILED') {
state.currentPayment.result = status.txHash
state.isPaymentInProgress = false
EventsController.sendEvent({
type: 'track',
event: status.status === 'SUCCESS' ? 'PAY_SUCCESS' : 'PAY_ERROR',
properties: {
source: 'fund-from-exchange',
paymentId,
configuration: {
network: state.paymentAsset.network,
asset: state.paymentAsset.asset,
recipient: AccountController.state.address || '',
amount: state.amount
},
currentPayment: {
type: 'exchange',
exchangeId: state.currentPayment?.exchangeId,
sessionId: state.currentPayment?.sessionId,
result: status.txHash
}
}
})
}

return status
} catch (error) {
return {
status: 'UNKNOWN',
txHash: ''
} as GetBuyStatusResult
}
},
reset() {
state.currentPayment = undefined
state.isPaymentInProgress = false
state.paymentId = ''
state.paymentAsset = {
network: 'eip155:1',
asset: 'native',
metadata: {
name: 'Ethereum',
symbol: 'ETH',
decimals: 0
}
}
state.amount = 0
state.tokenAmount = 0
state.tokenPrice = null
state.priceLoading = false
state.error = null
state.exchanges = []
state.isLoading = false
}
}
18 changes: 12 additions & 6 deletions packages/controllers/src/utils/ExchangeUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export function getApiUrl() {
return `https://rpc.walletconnect.org/v1/json-rpc?projectId=${projectId}&source=fund-wallet`
}

type JsonRpcResponse<T> = {
export type JsonRpcResponse<T> = {
jsonrpc: string
id: number
result: T
Expand All @@ -62,35 +62,41 @@ export type GetExchangesResult = {
total: number
}

type GetPayUrlParams = {
export type GetPayUrlParams = {
exchangeId: string
asset: string
amount: string
recipient: string
}

type GetPayUrlResult = {
export type GetPayUrlResult = {
url: string
sessionId: string
}

type GetBuyStatusParams = {
export type GetBuyStatusParams = {
sessionId: string
exchangeId: string
}

type GetBuyStatusResult = {
export type GetBuyStatusResult = {
status: ExchangeBuyStatus
txHash?: string
}

async function sendRequest<T>(method: string, params: unknown): Promise<JsonRpcResponse<T>> {
const url = getApiUrl()
const { sdkType: st, sdkVersion: sv, projectId } = OptionsController.getSnapshot()
const requestBody = {
jsonrpc: '2.0',
id: 1,
method,
params
params: {
...(params || {}),
st,
sv,
projectId
}
}
const response = await fetch(url, {
method: 'POST',
Expand Down
4 changes: 4 additions & 0 deletions packages/controllers/src/utils/TypeUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,7 @@ type PayEvent =
address?: string
event: 'PAY_SUCCESS'
properties: {
source: 'pay' | 'fund-from-exchange'
paymentId: string
configuration: PayConfiguration
currentPayment: PayCurrentPayment
Expand All @@ -910,6 +911,7 @@ type PayEvent =
address?: string
event: 'PAY_ERROR'
properties: {
source: 'pay' | 'fund-from-exchange'
paymentId: string
configuration: PayConfiguration
currentPayment: PayCurrentPayment
Expand All @@ -921,6 +923,7 @@ type PayEvent =
address?: string
event: 'PAY_INITIATED'
properties: {
source: 'pay' | 'fund-from-exchange'
paymentId: string
configuration: PayConfiguration
currentPayment: PayCurrentPayment
Expand All @@ -947,6 +950,7 @@ type PayEvent =
currentPayment: PayCurrentPayment
headless: boolean
caipNetworkId?: CaipNetworkId
source: 'pay' | 'fund-from-exchange'
}
}

Expand Down
Loading