Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PR: offer new fallback intl mastercard SKU 18732 #362

Merged
merged 15 commits into from
Dec 13, 2024
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
17 changes: 9 additions & 8 deletions cypress/scripts/funding.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable sonarjs/no-duplicate-string */
import { SpawnSyncOptionsWithStringEncoding, spawnSync } from "child_process";
import { chainIdToRewardTokenMap } from "../../shared/constants";

/**
* Handles the async funding of the testing environment
Expand All @@ -16,11 +17,11 @@ class TestFunder {
fundingWallet = "0x70997970C51812dc3A010C7d01b50e0d17dc79C8";
beneficiary = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266";
permit2 = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
WXDAI = "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d";
whale = "0xba12222222228d8ba445958a75a0704d566bf2c8";
rewardToken = chainIdToRewardTokenMap[100];
whale = "0xefC0e701A824943b469a694aC564Aa1efF7Ab7dd";
expected = {
allowance: "999999999999999111119999999999999999",
balance: "337888400000000000000000",
balance: "10000000000000000000000",
};

async execute() {
Expand Down Expand Up @@ -117,7 +118,7 @@ class TestFunder {
private async _fundingAllowanceCheck() {
const allowance = await this._exec({
command: "cast",
args: ["call", this.WXDAI, "allowance(address,address)(uint256)", this.fundingWallet, this.permit2, "--rpc-url", this.anvilRPC],
args: ["call", this.rewardToken, "allowance(address,address)(uint256)", this.fundingWallet, this.permit2, "--rpc-url", this.anvilRPC],
options: { encoding: "utf8" },
});

Expand All @@ -127,7 +128,7 @@ class TestFunder {
private async _fundingBalanceCheck() {
const balance = await this._exec({
command: "cast",
args: ["call", this.WXDAI, "balanceOf(address)(uint256)", this.fundingWallet, "--rpc-url", this.anvilRPC],
args: ["call", this.rewardToken, "balanceOf(address)(uint256)", this.fundingWallet, "--rpc-url", this.anvilRPC],
options: { encoding: "utf8" },
});

Expand All @@ -141,7 +142,7 @@ class TestFunder {
"send",
"--rpc-url",
this.anvilRPC,
this.WXDAI,
this.rewardToken,
"--unlocked",
"--from",
address,
Expand Down Expand Up @@ -173,7 +174,7 @@ class TestFunder {
"send",
"--rpc-url",
this.anvilRPC,
this.WXDAI,
this.rewardToken,
"--unlocked",
"--from",
this.whale,
Expand All @@ -200,7 +201,7 @@ class TestFunder {
"send",
"--rpc-url",
this.anvilRPC,
this.WXDAI,
this.rewardToken,
"--unlocked",
"--from",
this.fundingWallet,
Expand Down
13 changes: 11 additions & 2 deletions functions/post-order.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export async function onRequest(ctx: Context): Promise<Response> {
return Response.json({ message: "The permit has already claimed a gift card." }, { status: 400 });
}

const order = await orderGiftCard(productId, giftCardValue, orderId, accessToken);
const order = await orderGiftCard(txReceipt.from.toLowerCase(), productId, giftCardValue, orderId, accessToken);

if (order.status != "REFUNDED" && order.status != "FAILED") {
return Response.json(order, { status: 200 });
Expand Down Expand Up @@ -138,7 +138,13 @@ export async function getGiftCardById(productId: number, accessToken: AccessToke
return responseJson as GiftCard;
}

async function orderGiftCard(productId: number, cardValue: number, identifier: string, accessToken: AccessToken): Promise<ReloadlyOrderResponse> {
async function orderGiftCard(
userId: string,
productId: number,
cardValue: number,
identifier: string,
accessToken: AccessToken
): Promise<ReloadlyOrderResponse> {
const url = `${getReloadlyApiBaseUrl(accessToken.isSandbox)}/orders`;
console.log(`Placing order at url: ${url}`);

Expand All @@ -148,6 +154,9 @@ async function orderGiftCard(productId: number, cardValue: number, identifier: s
unitPrice: cardValue.toFixed(2),
customIdentifier: identifier,
preOrder: false,
productAdditionalRequirements: {
userId: userId,
},
});

console.log(`Placing order at url: ${url}`);
Expand Down
28 changes: 21 additions & 7 deletions functions/utils/best-card-finder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { isGiftCardAvailable } from "../../shared/helpers";
import { GiftCard } from "../../shared/types";
import { commonHeaders, getGiftCards, getReloadlyApiBaseUrl } from "./shared";
import { getGiftCardById } from "../post-order";
import { fallbackIntlMastercard, fallbackIntlVisa, masterCardIntlSkus, visaIntlSkus } from "./reloadly-lists";
import { fallbackIntlMastercardFirst, fallbackIntlMastercardSecond, fallbackIntlVisa, masterCardIntlSkus, visaIntlSkus } from "./reloadly-lists";
import { AccessToken, ReloadlyFailureResponse } from "./types";

export async function findBestCard(countryCode: string, amount: BigNumberish, accessToken: AccessToken): Promise<GiftCard | null> {
Expand Down Expand Up @@ -55,9 +55,14 @@ async function findBestMastercard(masterCards: GiftCard[], countryCode: string,
}
}

const fallbackMastercard = await getFallbackIntlMastercard(accessToken);
if (fallbackMastercard && isGiftCardAvailable(fallbackMastercard, amount)) {
return fallbackMastercard;
const fallbackMastercardFirst = await getFirstFallbackIntlMastercard(accessToken);
if (fallbackMastercardFirst && isGiftCardAvailable(fallbackMastercardFirst, amount)) {
return fallbackMastercardFirst;
}

const fallbackMastercardSecond = await getSecondFallbackIntlMastercard(accessToken);
if (fallbackMastercardSecond && isGiftCardAvailable(fallbackMastercardSecond, amount)) {
return fallbackMastercardSecond;
}

return null;
Expand All @@ -78,11 +83,20 @@ async function findBestVisaCard(visaCards: GiftCard[], countryCode: string, amou
}
return null;
}
async function getFallbackIntlMastercard(accessToken: AccessToken): Promise<GiftCard | null> {
async function getFirstFallbackIntlMastercard(accessToken: AccessToken): Promise<GiftCard | null> {
try {
return await getGiftCardById(fallbackIntlMastercardFirst.sku, accessToken);
} catch (e) {
console.error(`Failed to load first fallback mastercard: ${JSON.stringify(fallbackIntlMastercardFirst)}`, e);
return null;
}
}

async function getSecondFallbackIntlMastercard(accessToken: AccessToken): Promise<GiftCard | null> {
try {
return await getGiftCardById(fallbackIntlMastercard.sku, accessToken);
return await getGiftCardById(fallbackIntlMastercardSecond.sku, accessToken);
} catch (e) {
console.error(`Failed to load international US mastercard: ${JSON.stringify(fallbackIntlMastercard)}`, e);
console.error(`Failed to load second fallback mastercard: ${JSON.stringify(fallbackIntlMastercardSecond)}`, e);
return null;
}
}
Expand Down
15 changes: 14 additions & 1 deletion functions/utils/reloadly-lists.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
/* eslint-disable sonarjs/no-duplicate-string */
// Keep duplicate country names in different lists

export const fallbackIntlMastercard = {
export const fallbackIntlMastercardFirst = {
country: "United States",
countryCode: "US",
name: "Mastercard Prepaid USD Debit (Virtual only) US",
sku: 18732,
};

export const fallbackIntlMastercardSecond = {
country: "United States",
countryCode: "US",
name: "Virtual MasterCard International USD US",
Expand All @@ -16,6 +23,12 @@ export const fallbackIntlVisa = {
};

export const masterCardIntlSkus = [
{
country: "United States",
countryCode: "US",
name: "Mastercard Prepaid USD Debit (Virtual only) US",
sku: 18732,
},
{
country: "United States",
countryCode: "US",
Expand Down
12 changes: 10 additions & 2 deletions shared/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export enum Tokens {
DAI = "0x6b175474e89094c44da98b954eedeac495271d0f",
WXDAI = "0xe91d153e0b41518a2ce8dd3d7944fa863463a97d",
UUSD = "0xC6ed4f520f6A4e4DC27273509239b7F8A68d2068",
}

export const permitAllowedChainIds = [1, 5, 10, 100, 31337];
Expand All @@ -18,8 +19,15 @@ export const ubiquityDollarChainAddresses: Record<number, string> = {

export const chainIdToRewardTokenMap: Record<number, string> = {
1: Tokens.DAI,
100: Tokens.WXDAI,
31337: Tokens.WXDAI,
100: Tokens.UUSD,
31337: Tokens.UUSD,
};

export const networkRpcs: Record<number, string> = {
1: "https://gateway.tenderly.co/public/mainnet",
5: "https://eth-goerli.public.blastapi.io",
100: "https://rpc.gnosischain.com",
31337: "http://127.0.0.1:8545",
};

export const chainIdToNameMap: Record<number, string> = {
Expand Down
8 changes: 7 additions & 1 deletion shared/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { BigNumberish, ethers } from "ethers";
import { GiftCard } from "./types";
import { isRangePriceGiftCardClaimable } from "./pricing";
import { useRpcHandler } from "../static/scripts/rewards/web3/use-rpc-handler";
import { networkRpcs } from "./constants";

export function getGiftCardOrderId(rewardToAddress: string, signature: string) {
const checksumAddress = ethers.utils.getAddress(rewardToAddress);
Expand Down Expand Up @@ -29,7 +30,12 @@ export function getMintMessageToSign(type: "permit" | "ubiquity-dollar", chainId
}

export async function getFastestRpcUrl(networkId: number) {
return (await useRpcHandler(networkId)).connection.url;
try {
return (await useRpcHandler(networkId)).connection.url;
} catch (e) {
console.log(`RpcHandler is having issues. Error: ${e} \nUsing backup rpc.`);
return networkRpcs[networkId];
}
}

export function isGiftCardAvailable(giftCard: GiftCard, reward: BigNumberish): boolean {
Expand Down
10 changes: 8 additions & 2 deletions static/scripts/rewards/gift-cards/activate/activate-html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,14 @@ export function getGiftCardActivateInfoHtml(giftCard: GiftCard) {
<fieldset>
<legend>How to use redeem code?</legend>
<div class="instructions">
<p>${giftCard.redeemInstruction.concise}</p>
${giftCard.redeemInstruction.concise != giftCard.redeemInstruction.verbose ? `<p>${giftCard.redeemInstruction.verbose}</p>` : ``}
<p
>${giftCard.redeemInstruction.concise.replace("\n", "<br>")}
${giftCard.redeemInstruction.concise != giftCard.redeemInstruction.verbose
? `<a href="javascript:;" onclick="document.getElementById('verbose').classList.remove('hidden');this.remove();">...Read more</a>`
: ``}</p
>

<p id="verbose" class="hidden">${giftCard.redeemInstruction.verbose.replace("\n", "<br>")}</p>
</div>
</fieldset>
</div>
Expand Down
2 changes: 2 additions & 0 deletions static/scripts/rewards/gift-cards/gift-card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ export function getGiftCardHtml(giftCard: GiftCard, rewardAmount: BigNumberish)
</div>
<div class="details">
<h3>${giftCard.productName}</h3>

<div class="pricing ${giftCard.denominationType}">
${giftCard.denominationType == "FIXED" ? getFixedPricesHtml(giftCard, rewardAmount) : getRangePricesHtml(giftCard, rewardAmount)}
</div>
<div>SKU: ${giftCard.productId}</div>
<button id="mint" class="btn" data-loading="false">
<div class="action">Mint</div>
<div class="icon"
Expand Down
2 changes: 1 addition & 1 deletion static/scripts/ubiquity-dollar/transaction-history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ function transactionRowHtml(transaction: Transaction) {
<tr>
<td><a href="https://etherscan.io/tx/${transaction.txHash}">${transaction.txHash?.slice(0, 16)}...</a></td>
<td>${transaction.date.toISOString().split("T")[0]}</td>
<td>${transaction.amount ? formatUnits(transaction.amount, 18) : 0} uAD</td>
<td>${transaction.amount ? formatUnits(transaction.amount, 18) : 0} UUSD</td>
<td>
<button id="${transaction.txHash}" class="btn" data-loading="false">
<div class="action">Open</div>
Expand Down
13 changes: 13 additions & 0 deletions static/styles/rewards/gift-cards.css
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,15 @@
font-size: 24px;
color: #fff;
}
.redeem-info {
width: 100%;
}
.redeem-info fieldset {
min-width: 0;
}
.redeem-info fieldset a {
overflow-wrap: break-word;
}
.redeem-info p {
text-transform: none;
}
Expand All @@ -106,6 +115,10 @@
padding: 12px;
}

.redeem-info fieldset .instructions p#verbose.hidden {
display: none;
}

.btn[data-loading="true"] > .icon {
display: none;
}
Expand Down
2 changes: 1 addition & 1 deletion static/ubiquity-dollar.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
<div class="card-section">
<div>
<input id="ubiquity-dollar-amount" class="amount-input" type="number" min="1" placeholder="Enter amount" />
<span>uAD</span>
<span>UUSD</span>
</div>
<button id="check-gift-card" class="btn" data-loading="false">
<div class="action">Check gift card</div>
Expand Down
Loading
Loading