Skip to content

Commit

Permalink
fix(exchange): access token management
Browse files Browse the repository at this point in the history
  • Loading branch information
banklesss committed Mar 18, 2024
1 parent 53c5a03 commit 455dbd7
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export const CreateExchangeOrderScreen = () => {
},
onSuccess: (referralLink) => {
if (referralLink.toString() !== '') {
console.log('referralLink', referralLink)
Linking.openURL(referralLink.toString())
track.exchangeSubmitted({ramp_type: orderType === 'sell' ? 'Sell' : 'Buy', ada_amount: orderAmount})
navigateTo.exchangeOpenOrder()
Expand Down
117 changes: 93 additions & 24 deletions packages/exchange/src/adapters/api.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {Exchange} from '@yoroi/types'
import {exchangeApiMaker, providers} from './api'

describe('exchangeApiMaker', () => {
Expand All @@ -21,6 +22,9 @@ describe('exchangeApiMaker', () => {
getBaseUrl: jest
.fn()
.mockReturnValue(jest.fn().mockResolvedValue('encryptus-url')),
extractParamsFromBaseUrl: jest.fn(() => ({
access_token: 'FAKE_TOKEN',
})),
},
}

Expand Down Expand Up @@ -49,39 +53,101 @@ describe('exchangeApiMaker', () => {
getBaseUrl: jest
.fn()
.mockReturnValue(jest.fn().mockResolvedValue('encryptus-url')),
extractParamsFromBaseUrl: jest.fn(() => ({
access_token: 'FAKE_TOKEN',
})),
},
}

const api = exchangeApiMaker({isProduction, partner}, deps)
const result = await api.getBaseUrl(providerId)
expect(result).toBe('encryptus-url')
})

it('does not resolve', async () => {
const isProduction = true
const partner = 'yoroi'
const providerId = 'none'
const deps = {
banxaApi: {
getBaseUrl: jest
.fn()
.mockReturnValue(jest.fn().mockResolvedValue('banxa-url')),
},
encryptusApi: {
getBaseUrl: jest
.fn()
.mockReturnValue(jest.fn().mockResolvedValue('encryptus-url')),
extractParamsFromBaseUrl: jest.fn(() => ({
access_token: 'FAKE_TOKEN',
})),
},
}

const api = exchangeApiMaker({isProduction, partner}, deps)

try {
await api.getBaseUrl(providerId)
} catch (e: any) {
expect(e).toBeInstanceOf(Exchange.Errors.ProviderNotFound)
}
})
})
})

it('does not resolve', async () => {
const isProduction = true
const partner = 'yoroi'
const providerId = 'none'
const deps = {
banxaApi: {
getBaseUrl: jest
.fn()
.mockReturnValue(jest.fn().mockResolvedValue('banxa-url')),
},
encryptusApi: {
getBaseUrl: jest
.fn()
.mockReturnValue(jest.fn().mockResolvedValue('encryptus-url')),
},
}

const api = exchangeApiMaker({isProduction, partner}, deps)

try {
await api.getBaseUrl(providerId)
} catch (e: any) {
expect(e.message).toBe('Unknown provider: none')
}
describe('extractParamsFromBaseUrl', () => {
describe('Encryptus', () => {
it('extracts the params', () => {
const isProduction = true
const partner = 'yoroi'
const providerId = 'encryptus'
const baseUrl = 'https://fake-base-url/?access_token=FAKE_TOKEN'

const deps = {
banxaApi: {
getBaseUrl: jest
.fn()
.mockReturnValue(jest.fn().mockResolvedValue('banxa-url')),
},
encryptusApi: {
getBaseUrl: jest
.fn()
.mockReturnValue(jest.fn().mockResolvedValue('encryptus-url')),
extractParamsFromBaseUrl: jest.fn(() => ({
access_token: 'FAKE_TOKEN',
})),
},
}

const api = exchangeApiMaker({isProduction, partner}, deps)
expect(api.extractParamsFromBaseUrl?.(providerId, baseUrl)).toEqual({
access_token: 'FAKE_TOKEN',
})
})

it('does extract params', () => {
const isProduction = true
const partner = 'yoroi'
const providerId = 'none'
const baseUrl = 'https://fake-base-url/'

const deps = {
banxaApi: {
getBaseUrl: jest
.fn()
.mockReturnValue(jest.fn().mockResolvedValue('banxa-url')),
},
encryptusApi: {
getBaseUrl: jest
.fn()
.mockReturnValue(jest.fn().mockResolvedValue('encryptus-url')),
extractParamsFromBaseUrl: jest.fn(() => ({})),
},
}

const api = exchangeApiMaker({isProduction, partner}, deps)
expect(api.extractParamsFromBaseUrl?.(providerId, baseUrl)).toEqual({})
})
})
})

Expand All @@ -98,6 +164,9 @@ describe('exchangeApiMaker', () => {
getBaseUrl: jest
.fn()
.mockReturnValue(jest.fn().mockResolvedValue('encryptus-url')),
extractParamsFromBaseUrl: jest
.fn()
.mockReturnValue({access_token: 'FAKE_TOKEN'}),
},
}

Expand Down
22 changes: 19 additions & 3 deletions packages/exchange/src/adapters/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import {Exchange} from '@yoroi/types'
import {AxiosRequestConfig} from 'axios'
import {freeze} from 'immer'

import {encryptusApiGetBaseUrl} from './encryptus/api'
import {
encryptusApiGetBaseUrl,
encryptusExtractParamsFromBaseUrl,
} from './encryptus/api'
import {banxaApiGetBaseUrl} from './banxa/api'

const initialDeps = freeze(
Expand All @@ -12,6 +15,7 @@ const initialDeps = freeze(
},
encryptusApi: {
getBaseUrl: encryptusApiGetBaseUrl,
extractParamsFromBaseUrl: encryptusExtractParamsFromBaseUrl,
},
},
true,
Expand All @@ -24,7 +28,10 @@ export const exchangeApiMaker = (
encryptusApi,
}: {
banxaApi: {getBaseUrl: typeof banxaApiGetBaseUrl}
encryptusApi: {getBaseUrl: typeof encryptusApiGetBaseUrl}
encryptusApi: {
getBaseUrl: typeof encryptusApiGetBaseUrl
extractParamsFromBaseUrl: typeof encryptusExtractParamsFromBaseUrl
}
} = initialDeps,
): Exchange.Api => {
const getProviders = async () => Promise.resolve(providers)
Expand All @@ -47,7 +54,16 @@ export const exchangeApiMaker = (
}
}

return freeze({getBaseUrl, getProviders}, true)
const extractParamsFromBaseUrl = (providerId: string, baseUrl: string) => {
switch (providerId) {
case 'encryptus':
return encryptusApi.extractParamsFromBaseUrl(baseUrl)
default:
return {}
}
}

return freeze({getBaseUrl, getProviders, extractParamsFromBaseUrl}, true)
}

export const providers: Readonly<Record<string, Exchange.Provider>> = freeze(
Expand Down
20 changes: 20 additions & 0 deletions packages/exchange/src/adapters/encryptus/api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
EncryptusApiResponse,
encryptusApiConfig,
encryptusApiGetBaseUrl,
encryptusExtractParamsFromBaseUrl,
} from './api'
import {getEncryptusBaseUrlResponse} from './api.mocks'

Expand Down Expand Up @@ -130,3 +131,22 @@ describe('getEncryptusBaseUrl', () => {
expect(getCryptoAddress).toBeDefined()
})
})

describe('encryptusExtractParamsFromBaseUrl', () => {
it('extracts the params from the base url', () => {
const baseUrl = `https://sandbox.encryptus.co/pw?access_token=FAKE_TOKEN`
const params = encryptusExtractParamsFromBaseUrl(baseUrl.toString())
expect(params).toEqual({access_token: 'FAKE_TOKEN'})
})

it('throws validation error because the params are missing', () => {
const baseUrl = `https://sandbox.encryptus.co/pw`
try {
encryptusExtractParamsFromBaseUrl(baseUrl.toString())

fail('should be filed before')
} catch (e: any) {
expect(e).toBeInstanceOf(Exchange.Errors.Validation)
}
})
})
22 changes: 22 additions & 0 deletions packages/exchange/src/adapters/encryptus/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {z} from 'zod'
import {AxiosRequestConfig} from 'axios'

import {getValidationError} from '../../helpers/get-validation-error'
import {Exchange} from '@yoroi/types'

const initialDeps = freeze({request: fetchData}, true)

Expand Down Expand Up @@ -35,6 +36,23 @@ export const encryptusApiGetBaseUrl = (
}
}

export const encryptusExtractParamsFromBaseUrl = (
baseUrl: string,
): Pick<Exchange.ReferralUrlQueryStringParams, 'access_token'> => {
const url = new URL(baseUrl)
const params = new URLSearchParams(url.search)

try {
const parsedParams = EncryptusBaseUrlParams.parse({
access_token: params.get('access_token'),
})

return {access_token: parsedParams.access_token}
} catch (error: unknown) {
throw getValidationError(error)
}
}

export type EncryptusApiResponse = {
status: number
data: {
Expand All @@ -48,6 +66,10 @@ const EncryptusApiResponseSchema = z.object({
}),
})

const EncryptusBaseUrlParams = z.object({
access_token: z.string(),
})

export const encryptusApiConfig = freeze(
{
production: {
Expand Down
2 changes: 2 additions & 0 deletions packages/exchange/src/adapters/zod-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export const urlReferralQueryStringParamsSchema = z
blockchain: z.string().refine(isBlockchainCode).optional(),
walletAddress: z.string(),
returnUrl: z.string().optional(),
access_token: z.string().optional(),
balance: z.string().optional(),
})
.refine((data) => {
return (
Expand Down
9 changes: 7 additions & 2 deletions packages/exchange/src/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,13 @@ export const exchangeManagerMaker = ({
) => {
try {
const baseUrl = await api.getBaseUrl(providerId, fetcherOptions)
const validatedQueries =
urlReferralQueryStringParamsSchema.parse(queries)

const baseUrlParams =
api.extractParamsFromBaseUrl?.(providerId, baseUrl) ?? {}
const validatedQueries = urlReferralQueryStringParamsSchema.parse({
...queries,
...baseUrlParams,
})
const url = new URL(baseUrl)
const params = new URLSearchParams()
for (const [key, value] of Object.entries(validatedQueries)) {
Expand Down
6 changes: 6 additions & 0 deletions packages/types/src/exchange/api.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import {AxiosRequestConfig} from 'axios'

import {ExchangeProvider} from './provider'
import {ExchangeReferralUrlQueryStringParams} from './query-string'

export interface ExchangeApi {
getBaseUrl(
providerId: string,
fetcherOptions?: AxiosRequestConfig,
): Promise<string>
getProviders(): Promise<Record<string, ExchangeProvider>>

extractParamsFromBaseUrl?(
providerId: string,
baseUrl: string,
): Partial<ExchangeReferralUrlQueryStringParams>
}
6 changes: 6 additions & 0 deletions packages/types/src/exchange/query-string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,10 @@ export type ExchangeReferralUrlQueryStringParams = {

/** This is the url that users will be redirected to when they have completed or cancel the order process. e.g. https://{returnUrl}.com) */
returnUrl?: string

/* platform access token */
access_token?: string

/* wallet ADA balance */
balance?: string
}

0 comments on commit 455dbd7

Please sign in to comment.