Call Wyre’s API via our backend to generate Wyre’s Checkout URL (#11387)

* Call Wyre’s API via our backend to generate Wyre’s Checkout URL

* Add back paymentMethod=debit-card, use a fallback URL if no url is returned from BE

* Fix a lint issue

* Refactor how to return Wyre’s Checkout URL

* Add 2 constants into a test file, refactoring
feature/default_network_editable
Daniel 3 years ago committed by GitHub
parent cb652c0fae
commit a1d7271ed7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 38
      app/scripts/lib/buy-eth-url.js
  2. 61
      app/scripts/lib/buy-eth-url.test.js
  3. 4
      ui/store/actions.js

@ -1,3 +1,6 @@
import log from 'loglevel';
import { METASWAP_CHAINID_API_HOST_MAP } from '../../../shared/constants/swaps';
import { import {
GOERLI_CHAIN_ID, GOERLI_CHAIN_ID,
KOVAN_CHAIN_ID, KOVAN_CHAIN_ID,
@ -5,8 +8,39 @@ import {
RINKEBY_CHAIN_ID, RINKEBY_CHAIN_ID,
ROPSTEN_CHAIN_ID, ROPSTEN_CHAIN_ID,
} from '../../../shared/constants/network'; } from '../../../shared/constants/network';
import { SECOND } from '../../../shared/constants/time';
import getFetchWithTimeout from '../../../shared/modules/fetch-with-timeout';
import { TRANSAK_API_KEY } from '../constants/on-ramp'; import { TRANSAK_API_KEY } from '../constants/on-ramp';
const fetchWithTimeout = getFetchWithTimeout(SECOND * 30);
/**
* Create a Wyre purchase URL.
* @param {String} address Ethereum destination address
* @returns String
*/
const createWyrePurchaseUrl = async (address) => {
const fiatOnRampUrlApi = `${METASWAP_CHAINID_API_HOST_MAP[MAINNET_CHAIN_ID]}/fiatOnRampUrl?serviceName=wyre&destinationAddress=${address}`;
const wyrePurchaseUrlFallback = `https://pay.sendwyre.com/purchase?dest=ethereum:${address}&destCurrency=ETH&accountId=AC-7AG3W4XH4N2&paymentMethod=debit-card`;
try {
const response = await fetchWithTimeout(fiatOnRampUrlApi, {
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 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.
};
/** /**
* Create a Transak Checkout URL. * Create a Transak Checkout URL.
* API docs here: https://www.notion.so/Query-Parameters-9ec523df3b874ec58cef4fa3a906f238 * API docs here: https://www.notion.so/Query-Parameters-9ec523df3b874ec58cef4fa3a906f238
@ -33,7 +67,7 @@ const createTransakUrl = (address) => {
* chainId does not match any of the specified cases, or if no chainId is given, returns undefined. * chainId does not match any of the specified cases, or if no chainId is given, returns undefined.
* *
*/ */
export default function getBuyEthUrl({ chainId, address, service }) { export default async function getBuyEthUrl({ chainId, address, service }) {
// default service by network if not specified // default service by network if not specified
if (!service) { if (!service) {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
@ -42,7 +76,7 @@ export default function getBuyEthUrl({ chainId, address, service }) {
switch (service) { switch (service) {
case 'wyre': case 'wyre':
return `https://pay.sendwyre.com/purchase?dest=ethereum:${address}&destCurrency=ETH&accountId=AC-7AG3W4XH4N2&paymentMethod=debit-card`; return await createWyrePurchaseUrl(address);
case 'transak': case 'transak':
return createTransakUrl(address); return createTransakUrl(address);
case 'metamask-faucet': case 'metamask-faucet':

@ -1,4 +1,5 @@
import { strict as assert } from 'assert'; import { strict as assert } from 'assert';
import nock from 'nock';
import { import {
KOVAN_CHAIN_ID, KOVAN_CHAIN_ID,
MAINNET_CHAIN_ID, MAINNET_CHAIN_ID,
@ -8,52 +9,68 @@ import {
import { TRANSAK_API_KEY } from '../constants/on-ramp'; import { TRANSAK_API_KEY } from '../constants/on-ramp';
import getBuyEthUrl from './buy-eth-url'; import getBuyEthUrl from './buy-eth-url';
describe('buy-eth-url', function () { const WYRE_ACCOUNT_ID = 'AC-7AG3W4XH4N2';
const mainnet = { const ETH_ADDRESS = '0x0dcd5d886577d5581b0c524242ef2ee70be3e7bc';
const MAINNET = {
chainId: MAINNET_CHAIN_ID, chainId: MAINNET_CHAIN_ID,
amount: 5, amount: 5,
address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', address: ETH_ADDRESS,
}; };
const ropsten = { const ROPSTEN = {
chainId: ROPSTEN_CHAIN_ID, chainId: ROPSTEN_CHAIN_ID,
}; };
const rinkeby = { const RINKEBY = {
chainId: RINKEBY_CHAIN_ID, chainId: RINKEBY_CHAIN_ID,
}; };
const kovan = { const KOVAN = {
chainId: KOVAN_CHAIN_ID, chainId: KOVAN_CHAIN_ID,
}; };
describe('buy-eth-url', function () {
it('returns Wyre url with an ETH address for Ethereum mainnet', async function () {
nock('https://api.metaswap.codefi.network')
.get(`/fiatOnRampUrl?serviceName=wyre&destinationAddress=${ETH_ADDRESS}`)
.reply(200, {
url: `https://pay.sendwyre.com/purchase?accountId=${WYRE_ACCOUNT_ID}&utm_campaign=${WYRE_ACCOUNT_ID}&destCurrency=ETH&utm_medium=widget&paymentMethod=debit-card&reservation=MLZVUF8FMXZUMARJC23B&dest=ethereum%3A${ETH_ADDRESS}&utm_source=checkout`,
});
const wyreUrl = await getBuyEthUrl(MAINNET);
assert.equal(
wyreUrl,
`https://pay.sendwyre.com/purchase?accountId=${WYRE_ACCOUNT_ID}&utm_campaign=${WYRE_ACCOUNT_ID}&destCurrency=ETH&utm_medium=widget&paymentMethod=debit-card&reservation=MLZVUF8FMXZUMARJC23B&dest=ethereum%3A${ETH_ADDRESS}&utm_source=checkout`,
);
nock.cleanAll();
});
it('returns Wyre url with an ETH address for Ethereum mainnet', function () { it('returns a fallback Wyre url if /orders/reserve API call fails', async function () {
const wyreUrl = getBuyEthUrl(mainnet); const wyreUrl = await getBuyEthUrl(MAINNET);
assert.equal( assert.equal(
wyreUrl, wyreUrl,
'https://pay.sendwyre.com/purchase?dest=ethereum:0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc&destCurrency=ETH&accountId=AC-7AG3W4XH4N2&paymentMethod=debit-card', `https://pay.sendwyre.com/purchase?dest=ethereum:${ETH_ADDRESS}&destCurrency=ETH&accountId=${WYRE_ACCOUNT_ID}&paymentMethod=debit-card`,
); );
}); });
it('returns Transak url with an ETH address for Ethereum mainnet', function () { it('returns Transak url with an ETH address for Ethereum mainnet', async function () {
const transakUrl = getBuyEthUrl({ ...mainnet, service: 'transak' }); const transakUrl = await getBuyEthUrl({ ...MAINNET, service: 'transak' });
assert.equal( assert.equal(
transakUrl, transakUrl,
`https://global.transak.com/?apiKey=${TRANSAK_API_KEY}&hostURL=https%3A%2F%2Fmetamask.io&defaultCryptoCurrency=ETH&walletAddress=0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc`, `https://global.transak.com/?apiKey=${TRANSAK_API_KEY}&hostURL=https%3A%2F%2Fmetamask.io&defaultCryptoCurrency=ETH&walletAddress=${ETH_ADDRESS}`,
); );
}); });
it('returns metamask ropsten faucet for network 3', function () { it('returns metamask ropsten faucet for network 3', async function () {
const ropstenUrl = getBuyEthUrl(ropsten); const ropstenUrl = await getBuyEthUrl(ROPSTEN);
assert.equal(ropstenUrl, 'https://faucet.metamask.io/'); assert.equal(ropstenUrl, 'https://faucet.metamask.io/');
}); });
it('returns rinkeby dapp for network 4', function () { it('returns rinkeby dapp for network 4', async function () {
const rinkebyUrl = getBuyEthUrl(rinkeby); const rinkebyUrl = await getBuyEthUrl(RINKEBY);
assert.equal(rinkebyUrl, 'https://www.rinkeby.io/'); assert.equal(rinkebyUrl, 'https://www.rinkeby.io/');
}); });
it('returns kovan github test faucet for network 42', function () { it('returns kovan github test faucet for network 42', async function () {
const kovanUrl = getBuyEthUrl(kovan); const kovanUrl = await getBuyEthUrl(KOVAN);
assert.equal(kovanUrl, 'https://github.com/kovan-testnet/faucet'); assert.equal(kovanUrl, 'https://github.com/kovan-testnet/faucet');
}); });
}); });

@ -1826,8 +1826,8 @@ export function showSendTokenPage() {
} }
export function buyEth(opts) { export function buyEth(opts) {
return (dispatch) => { return async (dispatch) => {
const url = getBuyEthUrl(opts); const url = await getBuyEthUrl(opts);
global.platform.openTab({ url }); global.platform.openTab({ url });
dispatch({ dispatch({
type: actionConstants.BUY_ETH, type: actionConstants.BUY_ETH,

Loading…
Cancel
Save