2021-06-25 16:52:29 +02:00
|
|
|
import log from 'loglevel';
|
|
|
|
|
2023-02-01 18:53:21 +01:00
|
|
|
import { isNullOrUndefined } from '@metamask/utils';
|
2021-11-17 18:04:50 +01:00
|
|
|
import { SWAPS_API_V2_BASE_URL } from '../../../shared/constants/swaps';
|
2021-03-12 23:23:26 +01:00
|
|
|
import {
|
2022-01-28 14:46:26 +01:00
|
|
|
BUYABLE_CHAINS_MAP,
|
2022-09-14 16:55:31 +02:00
|
|
|
CHAIN_IDS,
|
2023-01-31 13:01:10 +01:00
|
|
|
WyreChainSettings,
|
|
|
|
CurrencySymbol,
|
|
|
|
ChainId,
|
2021-03-12 23:23:26 +01:00
|
|
|
} from '../../../shared/constants/network';
|
2021-06-25 16:52:29 +02:00
|
|
|
import getFetchWithTimeout from '../../../shared/modules/fetch-with-timeout';
|
2022-05-13 01:27:49 +02:00
|
|
|
import {
|
|
|
|
TRANSAK_API_KEY,
|
|
|
|
MOONPAY_API_KEY,
|
|
|
|
COINBASEPAY_API_KEY,
|
|
|
|
} from '../constants/on-ramp';
|
2022-09-23 18:38:40 +02:00
|
|
|
import { formatMoonpaySymbol } from '../../../ui/helpers/utils/moonpay';
|
2021-06-25 15:10:24 +02:00
|
|
|
|
2022-07-19 18:13:45 +02:00
|
|
|
const fetchWithTimeout = getFetchWithTimeout();
|
2021-06-25 16:52:29 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a Wyre purchase URL.
|
2022-01-07 16:57:33 +01:00
|
|
|
*
|
2023-01-31 13:01:10 +01:00
|
|
|
* @param walletAddress - Ethereum destination address
|
|
|
|
* @param chainId - Current chain ID
|
|
|
|
* @param symbol - Token symbol to buy
|
2021-06-25 16:52:29 +02:00
|
|
|
* @returns String
|
|
|
|
*/
|
2023-01-31 13:01:10 +01:00
|
|
|
const createWyrePurchaseUrl = async (
|
|
|
|
walletAddress: string,
|
|
|
|
chainId: keyof typeof BUYABLE_CHAINS_MAP,
|
2023-02-01 18:53:21 +01:00
|
|
|
symbol?: CurrencySymbol,
|
2023-01-31 13:01:10 +01:00
|
|
|
): Promise<any> => {
|
|
|
|
const { wyre = {} as WyreChainSettings } = BUYABLE_CHAINS_MAP[chainId];
|
2022-05-27 18:04:26 +02:00
|
|
|
const { srn, currencyCode } = wyre;
|
|
|
|
|
|
|
|
const networkId = parseInt(chainId, 16);
|
2022-09-28 16:41:56 +02:00
|
|
|
const fiatOnRampUrlApi = `${SWAPS_API_V2_BASE_URL}/networks/${networkId}/fiatOnRampUrl?serviceName=wyre&destinationAddress=${walletAddress}¤cy=${
|
|
|
|
symbol || currencyCode
|
|
|
|
}`;
|
|
|
|
const wyrePurchaseUrlFallback = `https://pay.sendwyre.com/purchase?dest=${srn}:${walletAddress}&destCurrency=${
|
|
|
|
symbol || currencyCode
|
|
|
|
}&accountId=AC-7AG3W4XH4N2&paymentMethod=debit-card`;
|
2021-06-25 16:52:29 +02:00
|
|
|
try {
|
|
|
|
const response = await fetchWithTimeout(fiatOnRampUrlApi, {
|
|
|
|
method: 'GET',
|
|
|
|
headers: {
|
2021-12-09 20:06:24 +01:00
|
|
|
Accept: 'application/json',
|
2021-06-25 16:52:29 +02:00
|
|
|
'Content-Type': 'application/json',
|
|
|
|
},
|
|
|
|
});
|
|
|
|
const parsedResponse = await response.json();
|
|
|
|
if (response.ok && parsedResponse.url) {
|
|
|
|
return parsedResponse.url;
|
|
|
|
}
|
|
|
|
log.warn('Failed to create a Wyre purchase URL', parsedResponse);
|
|
|
|
} catch (err) {
|
|
|
|
log.warn('Failed to create a Wyre purchase URL', err);
|
|
|
|
}
|
|
|
|
return wyrePurchaseUrlFallback; // In case the API call would fail, we return a fallback URL for Wyre's Checkout.
|
|
|
|
};
|
|
|
|
|
2021-06-25 15:10:24 +02:00
|
|
|
/**
|
|
|
|
* Create a Transak Checkout URL.
|
|
|
|
* API docs here: https://www.notion.so/Query-Parameters-9ec523df3b874ec58cef4fa3a906f238
|
2022-01-07 16:57:33 +01:00
|
|
|
*
|
2023-01-31 13:01:10 +01:00
|
|
|
* @param walletAddress - Ethereum destination address
|
|
|
|
* @param chainId - Current chain ID
|
|
|
|
* @param symbol - Token symbol to buy
|
2021-06-25 15:10:24 +02:00
|
|
|
* @returns String
|
|
|
|
*/
|
2023-01-31 13:01:10 +01:00
|
|
|
const createTransakUrl = (
|
|
|
|
walletAddress: string,
|
|
|
|
chainId: keyof typeof BUYABLE_CHAINS_MAP,
|
2023-02-01 18:53:21 +01:00
|
|
|
symbol?: CurrencySymbol,
|
2023-01-31 13:01:10 +01:00
|
|
|
): string => {
|
2022-09-19 17:00:57 +02:00
|
|
|
const { nativeCurrency, network } = BUYABLE_CHAINS_MAP[chainId];
|
2022-01-28 14:46:26 +01:00
|
|
|
|
2021-06-25 15:10:24 +02:00
|
|
|
const queryParams = new URLSearchParams({
|
|
|
|
apiKey: TRANSAK_API_KEY,
|
|
|
|
hostURL: 'https://metamask.io',
|
2022-09-19 17:00:57 +02:00
|
|
|
defaultCryptoCurrency: symbol || nativeCurrency,
|
2022-01-28 14:46:26 +01:00
|
|
|
networks: network,
|
|
|
|
walletAddress,
|
2021-06-25 15:10:24 +02:00
|
|
|
});
|
2022-01-28 14:46:26 +01:00
|
|
|
|
2021-06-25 15:10:24 +02:00
|
|
|
return `https://global.transak.com/?${queryParams}`;
|
|
|
|
};
|
2021-03-12 23:23:26 +01:00
|
|
|
|
2022-03-21 10:26:52 +01:00
|
|
|
/**
|
|
|
|
* Create a MoonPay Checkout URL.
|
|
|
|
*
|
2023-01-31 13:01:10 +01:00
|
|
|
* @param walletAddress - Destination address
|
|
|
|
* @param chainId - Current chain ID
|
|
|
|
* @param symbol - Token symbol to buy
|
2022-03-21 10:26:52 +01:00
|
|
|
* @returns String
|
|
|
|
*/
|
2023-01-31 13:01:10 +01:00
|
|
|
const createMoonPayUrl = async (
|
|
|
|
walletAddress: string,
|
|
|
|
chainId: keyof typeof BUYABLE_CHAINS_MAP,
|
2023-02-01 18:53:21 +01:00
|
|
|
symbol?: CurrencySymbol,
|
2023-01-31 13:01:10 +01:00
|
|
|
): Promise<string> => {
|
|
|
|
const { moonPay: { defaultCurrencyCode, showOnlyCurrencies } = {} as any } =
|
2022-07-31 20:26:40 +02:00
|
|
|
BUYABLE_CHAINS_MAP[chainId];
|
2022-03-21 10:26:52 +01:00
|
|
|
const moonPayQueryParams = new URLSearchParams({
|
|
|
|
apiKey: MOONPAY_API_KEY,
|
|
|
|
walletAddress,
|
2023-02-01 18:53:21 +01:00
|
|
|
defaultCurrencyCode: symbol
|
|
|
|
? formatMoonpaySymbol(symbol, chainId)
|
|
|
|
: defaultCurrencyCode,
|
2022-03-21 10:26:52 +01:00
|
|
|
showOnlyCurrencies,
|
|
|
|
});
|
|
|
|
const queryParams = new URLSearchParams({
|
|
|
|
url: `https://buy.moonpay.com?${moonPayQueryParams}`,
|
|
|
|
context: 'extension',
|
|
|
|
});
|
|
|
|
const moonPaySignUrl = `${SWAPS_API_V2_BASE_URL}/moonpaySign/?${queryParams}`;
|
|
|
|
try {
|
|
|
|
const response = await fetchWithTimeout(moonPaySignUrl, {
|
|
|
|
method: 'GET',
|
|
|
|
headers: {
|
|
|
|
Accept: 'application/json',
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
},
|
|
|
|
});
|
|
|
|
const parsedResponse = await response.json();
|
|
|
|
if (response.ok && parsedResponse.url) {
|
|
|
|
return parsedResponse.url;
|
|
|
|
}
|
|
|
|
log.warn('Failed to create a MoonPay purchase URL', parsedResponse);
|
|
|
|
} catch (err) {
|
|
|
|
log.warn('Failed to create a MoonPay purchase URL', err);
|
|
|
|
}
|
|
|
|
return '';
|
|
|
|
};
|
|
|
|
|
2022-05-13 01:27:49 +02:00
|
|
|
/**
|
|
|
|
* Create a Coinbase Pay Checkout URL.
|
|
|
|
*
|
2023-01-31 13:01:10 +01:00
|
|
|
* @param walletAddress - Ethereum destination address
|
|
|
|
* @param chainId - Current chain ID
|
|
|
|
* @param symbol - Token symbol to buy
|
2022-05-13 01:27:49 +02:00
|
|
|
* @returns String
|
|
|
|
*/
|
2023-01-31 13:01:10 +01:00
|
|
|
const createCoinbasePayUrl = (
|
|
|
|
walletAddress: string,
|
|
|
|
chainId: keyof typeof BUYABLE_CHAINS_MAP,
|
2023-02-01 18:53:21 +01:00
|
|
|
symbol?: CurrencySymbol,
|
2023-01-31 13:01:10 +01:00
|
|
|
): string => {
|
2022-09-19 17:00:57 +02:00
|
|
|
// since coinbasePayCurrencies is going to be extended to include all tokens supported
|
|
|
|
// we now default to nativeCurrency instead of the 2 previous tokens + eth that we had before
|
|
|
|
const { nativeCurrency } = BUYABLE_CHAINS_MAP[chainId];
|
2022-05-13 01:27:49 +02:00
|
|
|
const queryParams = new URLSearchParams({
|
|
|
|
appId: COINBASEPAY_API_KEY,
|
|
|
|
attribution: 'extension',
|
|
|
|
destinationWallets: JSON.stringify([
|
|
|
|
{
|
|
|
|
address: walletAddress,
|
2022-09-19 17:00:57 +02:00
|
|
|
assets: symbol ? [symbol] : [nativeCurrency],
|
2022-05-13 01:27:49 +02:00
|
|
|
},
|
|
|
|
]),
|
|
|
|
});
|
|
|
|
return `https://pay.coinbase.com/buy?${queryParams}`;
|
|
|
|
};
|
|
|
|
|
2018-04-16 19:08:04 +02:00
|
|
|
/**
|
|
|
|
* Gives the caller a url at which the user can acquire eth, depending on the network they are in
|
|
|
|
*
|
2023-01-31 13:01:10 +01:00
|
|
|
* @param opts - Options required to determine the correct url
|
|
|
|
* @param opts.chainId - The chainId for which to return a url
|
|
|
|
* @param opts.address - The address the bought ETH should be sent to. Only relevant if chainId === '0x1'.
|
2022-01-07 16:57:33 +01:00
|
|
|
* @param opts.service
|
2023-01-31 13:01:10 +01:00
|
|
|
* @param opts.symbol - The symbol of the token to buy. Only relevant if buying a token.
|
|
|
|
* @returns The url at which the user can access ETH, while in the given chain. If the passed
|
2021-03-12 23:23:26 +01:00
|
|
|
* chainId does not match any of the specified cases, or if no chainId is given, returns undefined.
|
2018-04-16 19:08:04 +02:00
|
|
|
*/
|
2023-01-31 13:01:10 +01:00
|
|
|
export default async function getBuyUrl({
|
|
|
|
chainId,
|
|
|
|
address,
|
|
|
|
service,
|
|
|
|
symbol,
|
|
|
|
}: {
|
|
|
|
chainId: keyof typeof BUYABLE_CHAINS_MAP;
|
2023-02-01 18:53:21 +01:00
|
|
|
address?: string;
|
|
|
|
service?: string;
|
|
|
|
symbol?: CurrencySymbol;
|
2023-01-31 13:01:10 +01:00
|
|
|
}): Promise<string> {
|
2023-02-01 18:53:21 +01:00
|
|
|
let serviceToUse = service;
|
2019-03-29 03:03:35 +01:00
|
|
|
// default service by network if not specified
|
2023-02-01 18:53:21 +01:00
|
|
|
if (isNullOrUndefined(service)) {
|
2020-08-15 13:58:11 +02:00
|
|
|
// eslint-disable-next-line no-param-reassign
|
2023-02-01 18:53:21 +01:00
|
|
|
serviceToUse = getDefaultServiceForChain(chainId);
|
2019-11-20 01:03:20 +01:00
|
|
|
}
|
2019-03-29 03:03:35 +01:00
|
|
|
|
2023-02-01 18:53:21 +01:00
|
|
|
switch (serviceToUse) {
|
2019-03-29 03:20:19 +01:00
|
|
|
case 'wyre':
|
2023-02-01 18:53:21 +01:00
|
|
|
if (address) {
|
|
|
|
return await createWyrePurchaseUrl(address as string, chainId, symbol);
|
|
|
|
}
|
|
|
|
throw new Error('Address is required when requesting url for Wyre');
|
2021-06-25 15:10:24 +02:00
|
|
|
case 'transak':
|
2023-02-01 18:53:21 +01:00
|
|
|
if (address) {
|
|
|
|
return createTransakUrl(address as string, chainId, symbol);
|
|
|
|
}
|
|
|
|
throw new Error('Address is required when requesting url for Transak');
|
2022-03-21 10:26:52 +01:00
|
|
|
case 'moonpay':
|
2023-02-01 18:53:21 +01:00
|
|
|
if (address) {
|
|
|
|
return createMoonPayUrl(address as string, chainId, symbol);
|
|
|
|
}
|
|
|
|
throw new Error('Address is required when requesting url for Moonpay');
|
2022-05-13 01:27:49 +02:00
|
|
|
case 'coinbase':
|
2023-02-01 18:53:21 +01:00
|
|
|
if (address) {
|
|
|
|
return createCoinbasePayUrl(address as string, chainId, symbol);
|
|
|
|
}
|
|
|
|
throw new Error(
|
|
|
|
'Address is required when requesting url for Coinbase Pay',
|
|
|
|
);
|
2019-03-29 03:03:35 +01:00
|
|
|
case 'metamask-faucet':
|
2021-02-04 19:15:23 +01:00
|
|
|
return 'https://faucet.metamask.io/';
|
2019-04-17 19:34:49 +02:00
|
|
|
case 'goerli-faucet':
|
2021-02-04 19:15:23 +01:00
|
|
|
return 'https://goerli-faucet.slock.it/';
|
2022-09-14 20:26:45 +02:00
|
|
|
case 'sepolia-faucet':
|
|
|
|
return 'https://faucet.sepolia.dev/';
|
2019-11-27 17:08:35 +01:00
|
|
|
default:
|
2021-02-04 19:15:23 +01:00
|
|
|
throw new Error(
|
|
|
|
`Unknown cryptocurrency exchange or faucet: "${service}"`,
|
|
|
|
);
|
2019-03-29 03:03:35 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-31 13:01:10 +01:00
|
|
|
function getDefaultServiceForChain(chainId: ChainId): string {
|
2021-03-12 23:23:26 +01:00
|
|
|
switch (chainId) {
|
2022-09-14 16:55:31 +02:00
|
|
|
case CHAIN_IDS.MAINNET:
|
2021-02-04 19:15:23 +01:00
|
|
|
return 'wyre';
|
2022-09-14 16:55:31 +02:00
|
|
|
case CHAIN_IDS.GOERLI:
|
2021-02-04 19:15:23 +01:00
|
|
|
return 'goerli-faucet';
|
2022-09-14 20:26:45 +02:00
|
|
|
case CHAIN_IDS.SEPOLIA:
|
|
|
|
return 'sepolia-faucet';
|
2019-11-27 17:08:35 +01:00
|
|
|
default:
|
2020-11-03 00:41:28 +01:00
|
|
|
throw new Error(
|
2021-03-12 23:23:26 +01:00
|
|
|
`No default cryptocurrency exchange or faucet for chainId: "${chainId}"`,
|
2021-02-04 19:15:23 +01:00
|
|
|
);
|
2017-04-05 03:23:46 +02:00
|
|
|
}
|
2017-04-25 23:39:01 +02:00
|
|
|
}
|