Skip to content

Commit 8015ff7

Browse files
chore(checkout-widgets): Fetch Transak URL from API (#2738)
Co-authored-by: Jeet <[email protected]>
1 parent 033bf4b commit 8015ff7

File tree

4 files changed

+186
-103
lines changed

4 files changed

+186
-103
lines changed

packages/checkout/sdk/src/fiatRamp/fiatRamp.test.ts

Lines changed: 63 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,13 @@
11
import { Environment } from '@imtbl/config';
2+
import { AxiosResponse } from 'axios';
23
import { CheckoutConfiguration } from '../config';
34
import { RemoteConfigFetcher } from '../config/remoteConfigFetcher';
45
import { FiatRampService, FiatRampWidgetParams } from './fiatRamp';
56
import { ExchangeType, OnRampProvider } from '../types';
67
import { HttpClient } from '../api/http';
78

89
const defaultURL = 'https://global-stg.transak.com';
9-
const defaultParams = {
10-
apiKey: 'mock-api-key',
11-
network: 'immutablezkevm',
12-
defaultPaymentMethod: 'credit_debit_card',
13-
disablePaymentMethods: '',
14-
productsAvailed: 'buy',
15-
exchangeScreenTitle: 'Buy',
16-
themeColor: '0D0D0D',
17-
};
18-
19-
const defaultWidgetUrl = `${defaultURL}?${new URLSearchParams(
20-
defaultParams,
21-
).toString()}`;
10+
const SANDBOX_WIDGET_URL = 'https://api.sandbox.immutable.com/checkout/v1/widget-url';
2211

2312
jest.mock('../config/remoteConfigFetcher');
2413

@@ -29,6 +18,9 @@ describe('FiatRampService', () => {
2918

3019
beforeEach(() => {
3120
mockedHttpClient = new HttpClient() as jest.Mocked<HttpClient>;
21+
mockedHttpClient.post = jest.fn().mockResolvedValue({
22+
data: { url: defaultURL },
23+
} as AxiosResponse);
3224
});
3325

3426
describe('feeEstimate', () => {
@@ -111,21 +103,22 @@ describe('FiatRampService', () => {
111103
);
112104
fiatRampService = new FiatRampService(config);
113105
});
106+
114107
it(`should return widget url with non-configurable query params when onRampProvider is Transak' +
115108
'and default to IMX`, async () => {
116109
const params: FiatRampWidgetParams = {
117110
exchangeType: ExchangeType.ONRAMP,
118111
isPassport: false,
119112
};
120-
const result = await fiatRampService.createWidgetUrl(params);
121-
expect(result).toContain(defaultWidgetUrl);
122-
expect(result).toContain('&defaultCryptoCurrency=IMX');
123-
expect(result).not.toContain('&email=');
124-
expect(result).not.toContain(
125-
'&isAutoFillUserData=true&disableWalletAddressForm=true',
113+
const result = await fiatRampService.createWidgetUrl(params, mockedHttpClient);
114+
expect(result).toContain('https://global-stg.transak.com');
115+
expect(mockedHttpClient.post).toHaveBeenCalledWith(
116+
SANDBOX_WIDGET_URL,
117+
expect.objectContaining({
118+
default_crypto_currency: 'IMX',
119+
}),
120+
{ method: 'POST' },
126121
);
127-
expect(result).not.toContain('&defaultCryptoAmount=');
128-
expect(result).not.toContain('&walletAddress=');
129122
});
130123

131124
it(`should return widget url with encoded email, isAutoFillUserData and disableWalletAddressForm query params
@@ -135,11 +128,17 @@ describe('FiatRampService', () => {
135128
isPassport: true,
136129
137130
};
138-
const result = await fiatRampService.createWidgetUrl(params);
139-
expect(result).toContain(defaultWidgetUrl);
140-
expect(result).toContain('&email=passport.user%2540immutable.com');
141-
expect(result).toContain('&isAutoFillUserData=true');
142-
expect(result).toContain('&disableWalletAddressForm=true');
131+
const result = await fiatRampService.createWidgetUrl(params, mockedHttpClient);
132+
expect(result).toContain('https://global-stg.transak.com');
133+
expect(mockedHttpClient.post).toHaveBeenCalledWith(
134+
SANDBOX_WIDGET_URL,
135+
expect.objectContaining({
136+
137+
is_auto_fill_user_data: true,
138+
disable_wallet_address_form: true,
139+
}),
140+
{ method: 'POST' },
141+
);
143142
});
144143

145144
it(`should return widget url with defaultFiatAmount and defaultCryptoCurrency query params when tokenAmount and
@@ -148,12 +147,16 @@ describe('FiatRampService', () => {
148147
exchangeType: ExchangeType.ONRAMP,
149148
isPassport: false,
150149
};
151-
const result = await fiatRampService.createWidgetUrl(params);
152-
expect(result).toContain(defaultWidgetUrl);
153-
expect(result).toContain('&defaultFiatAmount=50');
154-
expect(result).toContain('&defaultCryptoCurrency=IMX');
155-
expect(result).not.toContain('&defaultCryptoAmount=100');
156-
expect(result).not.toContain('&cryptoCurrencyCode=ETH');
150+
const result = await fiatRampService.createWidgetUrl(params, mockedHttpClient);
151+
expect(result).toContain('https://global-stg.transak.com');
152+
expect(mockedHttpClient.post).toHaveBeenCalledWith(
153+
SANDBOX_WIDGET_URL,
154+
expect.objectContaining({
155+
default_fiat_amount: 50,
156+
default_crypto_currency: 'IMX',
157+
}),
158+
{ method: 'POST' },
159+
);
157160
});
158161

159162
it(`should return widget url with defaultCryptoAmount and cryptoCurrencyCode query params when tokenAmount and
@@ -164,11 +167,16 @@ describe('FiatRampService', () => {
164167
tokenAmount: '100',
165168
tokenSymbol: 'ETH',
166169
};
167-
const result = await fiatRampService.createWidgetUrl(params);
168-
expect(result).toContain(defaultWidgetUrl);
169-
expect(result).toContain('&defaultCryptoAmount=100');
170-
expect(result).toContain('&cryptoCurrencyCode=ETH');
171-
expect(result).not.toContain('&defaultCryptoCurrency=IMX');
170+
const result = await fiatRampService.createWidgetUrl(params, mockedHttpClient);
171+
expect(result).toContain('https://global-stg.transak.com');
172+
expect(mockedHttpClient.post).toHaveBeenCalledWith(
173+
SANDBOX_WIDGET_URL,
174+
expect.objectContaining({
175+
default_crypto_amount: '100',
176+
crypto_currency_code: 'ETH',
177+
}),
178+
{ method: 'POST' },
179+
);
172180
});
173181

174182
it('should return widget url with walletAddress query params when walletAddress is present', async () => {
@@ -177,9 +185,15 @@ describe('FiatRampService', () => {
177185
isPassport: false,
178186
walletAddress: '0x1234567890',
179187
};
180-
const result = await fiatRampService.createWidgetUrl(params);
181-
expect(result).toContain(defaultWidgetUrl);
182-
expect(result).toContain('&walletAddress=0x1234567890');
188+
const result = await fiatRampService.createWidgetUrl(params, mockedHttpClient);
189+
expect(result).toContain('https://global-stg.transak.com');
190+
expect(mockedHttpClient.post).toHaveBeenCalledWith(
191+
SANDBOX_WIDGET_URL,
192+
expect.objectContaining({
193+
wallet_address: '0x1234567890',
194+
}),
195+
{ method: 'POST' },
196+
);
183197
});
184198

185199
it('should return widget url with allowed crypto tokens in query params when allowed list is present', async () => {
@@ -188,9 +202,15 @@ describe('FiatRampService', () => {
188202
isPassport: false,
189203
allowedTokens: ['ETH', 'IMX'],
190204
};
191-
const result = await fiatRampService.createWidgetUrl(params);
192-
expect(result).toContain(defaultWidgetUrl);
193-
expect(result).toContain('&cryptoCurrencyList=eth%2Cimx');
205+
const result = await fiatRampService.createWidgetUrl(params, mockedHttpClient);
206+
expect(result).toContain('https://global-stg.transak.com');
207+
expect(mockedHttpClient.post).toHaveBeenCalledWith(
208+
SANDBOX_WIDGET_URL,
209+
expect.objectContaining({
210+
crypto_currency_list: 'eth,imx',
211+
}),
212+
{ method: 'POST' },
213+
);
194214
});
195215
});
196216
});

packages/checkout/sdk/src/fiatRamp/fiatRamp.ts

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { ExchangeType } from '../types/fiatRamp';
22
import { OnRampConfig, OnRampProvider, OnRampProviderFees } from '../types';
33
import { CheckoutConfiguration } from '../config';
4-
import { TRANSAK_API_BASE_URL } from '../env';
4+
import { IMMUTABLE_API_BASE_URL } from '../env';
5+
import { HttpClient } from '../api/http';
56

67
export interface FiatRampWidgetParams {
78
exchangeType: ExchangeType;
@@ -33,36 +34,40 @@ export class FiatRampService {
3334
return config[OnRampProvider.TRANSAK]?.fees;
3435
}
3536

36-
public async createWidgetUrl(params: FiatRampWidgetParams): Promise<string> {
37-
return await this.getTransakWidgetUrl(params);
37+
public async createWidgetUrl(
38+
params: FiatRampWidgetParams,
39+
httpClient = new HttpClient(),
40+
): Promise<string> {
41+
return await this.getTransakWidgetUrl(params, httpClient);
3842
}
3943

4044
private async getTransakWidgetUrl(
4145
params: FiatRampWidgetParams,
46+
httpClient: HttpClient,
4247
): Promise<string> {
4348
const onRampConfig = (await this.config.remote.getConfig(
4449
'onramp',
4550
)) as OnRampConfig;
4651

47-
const widgetUrl = TRANSAK_API_BASE_URL[this.config.environment];
52+
const createWidgetUrl = `${IMMUTABLE_API_BASE_URL[this.config.environment]}/checkout/v1/widget-url`;
4853
let widgetParams: Record<string, any> = {
49-
apiKey: onRampConfig[OnRampProvider.TRANSAK].publishableApiKey,
54+
api_key: onRampConfig[OnRampProvider.TRANSAK].publishableApiKey,
5055
network: 'immutablezkevm',
51-
defaultPaymentMethod: 'credit_debit_card',
52-
disablePaymentMethods: '',
53-
productsAvailed: 'buy',
54-
exchangeScreenTitle: params.customSubTitle === '' ? ' ' : (params.customSubTitle ?? 'Buy'),
55-
themeColor: '0D0D0D',
56-
defaultCryptoCurrency: params.tokenSymbol || 'IMX',
57-
hideMenu: !(params.showMenu ?? true),
56+
default_payment_method: 'credit_debit_card',
57+
disable_payment_methods: '',
58+
products_availed: 'buy',
59+
exchange_screen_title: params.customSubTitle === '' ? ' ' : (params.customSubTitle ?? 'Buy'),
60+
theme_color: '0D0D0D',
61+
default_crypto_currency: params.tokenSymbol || 'IMX',
62+
hide_menu: !(params.showMenu ?? true),
5863
};
5964

6065
if (params.isPassport && params.email) {
6166
widgetParams = {
6267
...widgetParams,
63-
email: encodeURIComponent(params.email),
64-
isAutoFillUserData: true,
65-
disableWalletAddressForm: true,
68+
email: params.email,
69+
is_auto_fill_user_data: true,
70+
disable_wallet_address_form: true,
6671
};
6772
}
6873

@@ -72,31 +77,32 @@ export class FiatRampService {
7277
if (params.tokenAmount && params.tokenSymbol) {
7378
widgetParams = {
7479
...widgetParams,
75-
defaultCryptoAmount: params.tokenAmount,
76-
cryptoCurrencyCode: params.tokenSymbol,
80+
default_crypto_amount: params.tokenAmount,
81+
crypto_currency_code: params.tokenSymbol,
7782
};
7883
} else {
7984
widgetParams = {
8085
...widgetParams,
81-
defaultFiatAmount: 50,
82-
defaultFiatCurrency: 'usd',
86+
default_fiat_amount: 50,
87+
default_fiat_currency: 'usd',
8388
};
8489
}
8590

8691
if (params.walletAddress) {
8792
widgetParams = {
8893
...widgetParams,
89-
walletAddress: params.walletAddress,
94+
wallet_address: params.walletAddress,
9095
};
9196
}
9297

9398
if (params.allowedTokens) {
9499
widgetParams = {
95100
...widgetParams,
96-
cryptoCurrencyList: params.allowedTokens?.join(',').toLowerCase(),
101+
crypto_currency_list: params.allowedTokens?.join(',').toLowerCase(),
97102
};
98103
}
99104

100-
return `${widgetUrl}?${new URLSearchParams(widgetParams).toString()}`;
105+
const response = await httpClient.post(createWidgetUrl, widgetParams, { method: 'POST' });
106+
return response.data.url;
101107
}
102108
}

packages/checkout/widgets-lib/src/components/Transak/useTransakIframe.ts

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable @typescript-eslint/naming-convention */
12
import { useCallback, useEffect, useState } from 'react';
23
import { Environment } from '@imtbl/config';
34

@@ -50,6 +51,12 @@ export const TRANSAK_API_KEY = {
5051
[Environment.PRODUCTION]: 'ad1bca70-d917-4628-bb0f-5609537498bc',
5152
};
5253

54+
export const IMMUTABLE_API_BASE_URL = {
55+
development: 'https://api.dev.immutable.com',
56+
[Environment.SANDBOX]: 'https://api.sandbox.immutable.com',
57+
[Environment.PRODUCTION]: 'https://api.immutable.com',
58+
};
59+
5360
export const useTransakIframe = (props: UseTransakIframeProps) => {
5461
const {
5562
contractId, environment, transakParams, onError,
@@ -64,7 +71,10 @@ export const useTransakIframe = (props: UseTransakIframeProps) => {
6471
estimatedGasLimit,
6572
cryptoCurrencyCode,
6673
excludeFiatCurrencies,
67-
...restWidgetParams
74+
exchangeScreenTitle,
75+
email,
76+
walletAddress,
77+
partnerOrderId,
6878
} = transakParams;
6979

7080
// FIXME: defaulting to first nft in the list
@@ -104,21 +114,38 @@ export const useTransakIframe = (props: UseTransakIframeProps) => {
104114

105115
const { id: nftTransactionId } = await response.json();
106116

107-
const baseWidgetUrl = `${TRANSAK_WIDGET_BASE_URL[environment]}?`;
108-
const queryParams = new URLSearchParams({
109-
apiKey: TRANSAK_API_KEY[environment],
110-
environment: TRANSAK_ENVIRONMENT[environment],
111-
isNFT: 'true',
112-
nftTransactionId,
113-
themeColor: '0D0D0D',
114-
...restWidgetParams,
115-
});
117+
const requestBody: Record<string, unknown> = {
118+
api_key: TRANSAK_API_KEY[environment],
119+
nft_transaction_id: nftTransactionId,
120+
theme_color: '0D0D0D',
121+
exchange_screen_title: exchangeScreenTitle,
122+
wallet_address: walletAddress,
123+
partner_order_id: partnerOrderId,
124+
};
125+
126+
if (email) {
127+
requestBody.email = email;
128+
}
116129

117130
if (excludeFiatCurrencies) {
118-
queryParams.append('excludeFiatCurrencies', excludeFiatCurrencies.join(','));
131+
requestBody.exclude_fiat_currencies = excludeFiatCurrencies.join(',');
132+
}
133+
134+
const widgetUrlResponse = await fetch(`${IMMUTABLE_API_BASE_URL[environment]}/checkout/v1/widget-url`, {
135+
method: 'POST',
136+
headers: {
137+
// eslint-disable-next-line @typescript-eslint/naming-convention
138+
'Content-Type': 'application/json',
139+
},
140+
body: JSON.stringify(requestBody),
141+
});
142+
143+
if (!widgetUrlResponse.ok) {
144+
throw new Error('Failed to get widget URL');
119145
}
120146

121-
return `${baseWidgetUrl}${queryParams.toString()}`;
147+
const { url } = await widgetUrlResponse.json();
148+
return url;
122149
} catch {
123150
onError?.();
124151
}

0 commit comments

Comments
 (0)