Skip to content

Commit

Permalink
Merge pull request #367 from EresDevOrg/development
Browse files Browse the repository at this point in the history
  • Loading branch information
0x4007 authored Jan 17, 2025
2 parents 2420644 + e7205e6 commit ad513f9
Show file tree
Hide file tree
Showing 24 changed files with 190 additions and 191 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# common variables
CHAIN_ID="" # mainnet: 1, goerli: 5
FRONTEND_URL=""
BACKEND_URL="" # "" or if you want to work on frontend only, use "https://pay.ubq.fi"
UBIQUIBOT_PRIVATE_KEY=""
RPC_PROVIDER_URL=""
PAYMENT_TOKEN_ADDRESS="" # // DAI address, mainnet: 0x6b175474e89094c44da98b954eedeac495271d0f, goerli: 0x11fE4B6AE13d2a6055C8D9cF65c55bac32B5d844
Expand Down
59 changes: 59 additions & 0 deletions .github/sync-env-vars.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/bin/bash

# Check if required environment variables are set
if [ -z "$CLOUDFLARE_ACCOUNT_ID" ] || [ -z "$CLOUDFLARE_API_TOKEN" ] || [ -z "$GITHUB_REPOSITORY" ] || \
[ -z "$RELOADLY_API_CLIENT_ID" ] || [ -z "$RELOADLY_API_CLIENT_SECRET" ] || \
[ -z "$RELOADLY_SANDBOX_API_CLIENT_ID" ] || [ -z "$RELOADLY_SANDBOX_API_CLIENT_SECRET" ]; then
echo "Error: Required environment variables are not set"
exit 1
fi

# Extract just the repository name from org/repo format
REPOSITORY_NAME=$(echo "$GITHUB_REPOSITORY" | cut -d'/' -f2)
# Replace dots with hyphens
REPOSITORY_NAME=${REPOSITORY_NAME//./-}

# Echo the repository name
echo "Repository name: $REPOSITORY_NAME"

# Make the API call to Cloudflare
curl -X PATCH \
"https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/pages/projects/${REPOSITORY_NAME}/deployment_configs" \
-H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \
-H "Content-Type: application/json" \
--data '{
"deployment_configs": {
"production": {
"env_vars": {
"USE_RELOADLY_SANDBOX": {
"value": "false",
"type": "plain_text"
},
"RELOADLY_API_CLIENT_ID": {
"value": "'"${RELOADLY_API_CLIENT_ID}"'",
"type": "secret_text"
},
"RELOADLY_API_CLIENT_SECRET": {
"value": "'"${RELOADLY_API_CLIENT_SECRET}"'",
"type": "secret_text"
}
}
},
"preview": {
"env_vars": {
"USE_RELOADLY_SANDBOX": {
"value": "true",
"type": "plain_text"
},
"RELOADLY_API_CLIENT_ID": {
"value": "'"${RELOADLY_SANDBOX_API_CLIENT_ID}"'",
"type": "secret_text"
},
"RELOADLY_API_CLIENT_SECRET": {
"value": "'"${RELOADLY_SANDBOX_API_CLIENT_SECRET}"'",
"type": "secret_text"
}
}
}
}
}'
1 change: 1 addition & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ jobs:
env: # Set environment variables for the build
SUPABASE_URL: "https://wfzpewmlyiozupulbuur.supabase.co"
SUPABASE_ANON_KEY: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6IndmenBld21seWlvenVwdWxidXVyIiwicm9sZSI6ImFub24iLCJpYXQiOjE2OTU2NzQzMzksImV4cCI6MjAxMTI1MDMzOX0.SKIL3Q0NOBaMehH0ekFspwgcu3afp3Dl9EDzPqs1nKs"
BACKEND_URL: ""

- name: Upload build artifact
uses: actions/upload-artifact@v4
Expand Down
19 changes: 17 additions & 2 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,20 @@ jobs:
- name: Check out repository
uses: actions/checkout@v4

- name: Make env sync script executable
run: chmod +x .github/sync-env-vars.sh

- name: Run env sync script script
env:
GITHUB_REPOSITORY: ${{ github.repository }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
RELOADLY_API_CLIENT_ID: ${{ secrets.RELOADLY_API_CLIENT_ID }}
RELOADLY_API_CLIENT_SECRET: ${{ secrets.RELOADLY_API_CLIENT_SECRET }}
RELOADLY_SANDBOX_API_CLIENT_ID: ${{ secrets.RELOADLY_SANDBOX_API_CLIENT_ID }}
RELOADLY_SANDBOX_API_CLIENT_SECRET: ${{ secrets.RELOADLY_SANDBOX_API_CLIENT_SECRET }}
run: bash .github/sync-env-vars.sh

- name: Set up Node.js
uses: actions/setup-node@v4
with:
Expand All @@ -55,10 +69,11 @@ jobs:
echo "CLAIMABLE_URL=$url" >> $GITHUB_ENV
env:
BENEFICIARY_ADDRESS: "0xefC0e701A824943b469a694aC564Aa1efF7Ab7dd"
PAYMENT_TOKEN_ADDRESS: "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d"
AMOUNT_IN_ETH: 0
PAYMENT_TOKEN_ADDRESS: "0xC6ed4f520f6A4e4DC27273509239b7F8A68d2068"
AMOUNT_IN_ETH: 30
CHAIN_ID: 100
FRONTEND_URL: "${{ env.DEPLOYMENT_URL }}"
BACKEND_URL: ""
RPC_PROVIDER_URL: "https://rpc.ankr.com/gnosis"
UBIQUIBOT_PRIVATE_KEY: ${{ secrets.UBIQUIBOT_APP_PRIVATE_KEY_TEST }}

Expand Down
8 changes: 6 additions & 2 deletions .github/workflows/generate-permit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ on:
beneficiary:
required: true
description: The address of the beneficiary's wallet
amount:
required: true
description: The amount of permit
evmPrivateEncrypted:
required: true
description: Ubiquibot's Private Key
Expand All @@ -29,9 +32,10 @@ jobs:
yarn start:sign
env:
BENEFICIARY_ADDRESS: ${{ github.event.inputs.beneficiary }}
PAYMENT_TOKEN_ADDRESS: "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d"
AMOUNT_IN_ETH: 0
PAYMENT_TOKEN_ADDRESS: "0xC6ed4f520f6A4e4DC27273509239b7F8A68d2068"
AMOUNT_IN_ETH: ${{ github.event.inputs.amount }}
CHAIN_ID: 100
FRONTEND_URL: "http://localhost:8080"
BACKEND_URL: ""
RPC_PROVIDER_URL: "https://rpc.ankr.com/gnosis"
UBIQUIBOT_PRIVATE_KEY: ${{ github.event.inputs.evmPrivateEncrypted }}
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ A vanilla Typescript dApp for claiming Ubiquity Rewards. It also includes tools
# Common variables
CHAIN_ID="31337"
FRONTEND_URL="http://localhost:8080"
BACKEND_URL="" # "" or if you want to work on frontend only, use "https://pay.ubq.fi"
UBIQUIBOT_PRIVATE_KEY="0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"
RPC_PROVIDER_URL="http://127.0.0.1:8545"
PAYMENT_TOKEN_ADDRESS="0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d"
Expand Down Expand Up @@ -152,3 +153,18 @@ Notice that this examples uses gnosis chain for nonce invalidation. If you need

1. Set `RPC_PROVIDER_URL` on step 1 to the desired RPC chain provider
2. On step 3 open UI for the desired chain

### Working with frontend only

Following environment variables will help you quickly get started with frontend only. Rest of the environment variables should be specified as described [above](https://github.com/ubiquity/pay.ubq.fi#setup-local-testing-environment).

```
CHAIN_ID="100"
BACKEND_URL="https://pay.ubq.fi"
RPC_PROVIDER_URL="https://rpc.gnosischain.com"
```

In this case, the production deploy of the backend is served to your frontend and you can change things in the frontend.

There are some `/shared` files for frontend & backend. To make sure you didn't break anything in backend, you should occasionally run
`yarn test:unit`
2 changes: 1 addition & 1 deletion build/esbuild-build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const esBuildContext: esbuild.BuildOptions = {
},
outdir: "static/out",
entryNames: "[dir]", // Ensure the CSS is named bundles.css
define: createEnvDefines(["SUPABASE_URL", "SUPABASE_ANON_KEY"], {
define: createEnvDefines(["SUPABASE_URL", "SUPABASE_ANON_KEY", "BACKEND_URL"], {
commitHash: execSync(`git rev-parse --short HEAD`).toString().trim(),
}),
plugins: [
Expand Down
2 changes: 1 addition & 1 deletion cypress/scripts/anvil.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { spawnSync } from "child_process";
import { useHandler } from "../../static/scripts/rewards/web3/use-rpc-handler";
import { useHandler } from "../../shared/use-rpc-handler";
import { RPCHandler } from "@ubiquity-dao/rpc-handler";

class Anvil {
Expand Down
5 changes: 5 additions & 0 deletions functions/get-cards-env.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { Context } from "./utils/types";

export async function onRequest(ctx: Context): Promise<Response> {
return Response.json({ USE_RELOADLY_SANDBOX: ctx.env.USE_RELOADLY_SANDBOX }, { status: 200 });
}
35 changes: 18 additions & 17 deletions functions/post-order.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
import { JsonRpcProvider, TransactionReceipt, TransactionResponse } from "@ethersproject/providers";
import { Interface, TransactionDescription } from "@ethersproject/abi";
import { TransactionReceipt, TransactionResponse } from "@ethersproject/providers";
import { verifyMessage } from "@ethersproject/wallet";
import { BigNumber } from "ethers";
import { Interface, TransactionDescription } from "@ethersproject/abi";
import { Tokens, chainIdToRewardTokenMap, giftCardTreasuryAddress, permit2Address } from "../shared/constants";
import { getFastestRpcUrl, getGiftCardOrderId, getMintMessageToSign } from "../shared/helpers";
import { PostOrderParams, postOrderParamsSchema } from "../shared/api-types";
import {
Tokens,
chainIdToRewardTokenMap,
giftCardTreasuryAddress,
permit2Address,
permitAllowedChainIds,
ubiquityDollarAllowedChainIds,
ubiquityDollarChainAddresses,
} from "../shared/constants";
import { getGiftCardOrderId, getMintMessageToSign } from "../shared/helpers";
import { getGiftCardValue, isClaimableForAmount } from "../shared/pricing";
import { ExchangeRate, GiftCard } from "../shared/types";
import { permit2Abi } from "../static/scripts/rewards/abis/permit2-abi";
import { erc20Abi } from "../static/scripts/rewards/abis/erc20-abi";
import { permit2Abi } from "../static/scripts/rewards/abis/permit2-abi";
import { useRpcHandler } from "../shared/use-rpc-handler";
import { getTransactionFromOrderId } from "./get-order";
import { findBestCard } from "./utils/best-card-finder";
import { commonHeaders, getAccessToken, getReloadlyApiBaseUrl } from "./utils/shared";
import { AccessToken, Context, ReloadlyFailureResponse, ReloadlyOrderResponse } from "./utils/types";
import { validateEnvVars, validateRequestMethod } from "./utils/validators";
import { PostOrderParams, postOrderParamsSchema } from "../shared/api-types";
import { permitAllowedChainIds, ubiquityDollarAllowedChainIds, ubiquityDollarChainAddresses } from "../shared/constants";
import { findBestCard } from "./utils/best-card-finder";

export async function onRequest(ctx: Context): Promise<Response> {
try {
Expand All @@ -29,15 +37,7 @@ export async function onRequest(ctx: Context): Promise<Response> {
}
const { type, productId, txHash, chainId, country } = result.data;

const fastestRpcUrl = await getFastestRpcUrl(chainId);

const provider = new JsonRpcProvider(
{
url: fastestRpcUrl,
skipFetchSetup: true,
},
chainId
);
const provider = await useRpcHandler(chainId);

const [txReceipt, tx, giftCard]: [TransactionReceipt, TransactionResponse, GiftCard] = await Promise.all([
provider.getTransactionReceipt(txHash),
Expand Down Expand Up @@ -157,6 +157,7 @@ async function orderGiftCard(
productAdditionalRequirements: {
userId: userId,
},
senderName: "Ubiquity",
});

console.log(`Placing order at url: ${url}`);
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"author": "Ubiquity DAO",
"license": "MIT",
"engines": {
"node": "20.10.0"
"node": "20.10.0",
"yarn": "^1.22.21"
},
"scripts": {
"start": "run-s start:sign serve:watch",
Expand Down
13 changes: 1 addition & 12 deletions shared/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
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";
import { GiftCard } from "./types";

export function getGiftCardOrderId(rewardToAddress: string, signature: string) {
const checksumAddress = ethers.utils.getAddress(rewardToAddress);
Expand All @@ -29,15 +27,6 @@ export function getMintMessageToSign(type: "permit" | "ubiquity-dollar", chainId
});
}

export async function getFastestRpcUrl(networkId: number) {
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 {
return giftCard.denominationType == "RANGE" && isRangePriceGiftCardClaimable(giftCard, reward);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { RPCHandler, HandlerConstructorConfig, NetworkId } from "@ubiquity-dao/rpc-handler";
import { networkRpcs } from "./constants";
import { JsonRpcProvider } from "@ethersproject/providers";

export function convertToNetworkId(networkId: number | string): NetworkId {
if (typeof networkId === "string") {
Expand Down Expand Up @@ -34,12 +36,16 @@ export async function useRpcHandler(networkId: number) {
if (!networkId) {
throw new Error("Network ID not set");
}

const handler = useHandler(networkId);
const provider = await handler.getFastestRpcProvider();
const url = provider.connection.url;
if (!url) {
throw new Error("Provider URL not set");
try {
const handler = useHandler(networkId);
const provider = await handler.getFastestRpcProvider();
const url = provider.connection.url;
if (!url) {
throw new Error("Provider URL not set");
}
return provider;
} catch (e) {
console.log(`RpcHandler is having issues. Error: ${e} \nUsing backup rpc.`);
return new JsonRpcProvider({ url: networkRpcs[networkId], skipFetchSetup: true });
}
return provider;
}
4 changes: 2 additions & 2 deletions static/scripts/rewards/app-state.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { JsonRpcProvider, JsonRpcSigner } from "@ethersproject/providers";
import { Permit } from "@ubiquibot/permit-generation/types";
import { Permit } from "@ubiquibot/permit-generation";
import { getNetworkExplorer } from "@ubiquity-dao/rpc-handler";
import { convertToNetworkId } from "./web3/use-rpc-handler";
import { convertToNetworkId } from "../../../shared/use-rpc-handler";

export class AppState {
public claims: Permit[] = [];
Expand Down
2 changes: 1 addition & 1 deletion static/scripts/rewards/cirip/query-reverse-ens.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ethers } from "ethers";
import { useHandler } from "../web3/use-rpc-handler";
import { useHandler } from "../../../../shared/use-rpc-handler";

export async function queryReverseEns(address: string) {
// Try to get the ENS name from localStorage
Expand Down
27 changes: 25 additions & 2 deletions static/scripts/rewards/gift-cards/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import ct from "countries-and-timezones";

declare const BACKEND_URL: string;

export function getApiBaseUrl() {
// specify when backend functions and frontend are deployed to a different URL
return "";
return BACKEND_URL;
}

async function getCountryCodeByIp() {
Expand Down Expand Up @@ -35,3 +36,25 @@ export async function getUserCountryCode() {
}
return null;
}

export async function isReloadlySandbox() {
const response = await fetch(`${getApiBaseUrl()}/get-cards-env`);
if (response.status == 200) {
const responseJson = await response.json();
return responseJson.USE_RELOADLY_SANDBOX === "true";
}
return false;
}

export async function detectCardsEnv() {
const isCardsSandbox = await isReloadlySandbox();
if (isCardsSandbox) {
const cardEnvElement = document.createElement("div");
cardEnvElement.setAttribute("class", "cards-env");
cardEnvElement.textContent = "You are using Reloadly Sandbox.";
const footer = document.getElementsByTagName("footer");
if (footer.length) {
footer[0].parentNode?.insertBefore(cardEnvElement, footer[0].nextSibling);
}
}
}
5 changes: 4 additions & 1 deletion static/scripts/rewards/gift-cards/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { getGiftCardOrderId, isGiftCardAvailable } from "../../../../shared/help
import { GiftCard, OrderTransaction } from "../../../../shared/types";
import { AppState } from "../app-state";
import { getGiftCardHtml } from "./gift-card";
import { getApiBaseUrl, getUserCountryCode } from "./helpers";
import { detectCardsEnv, getApiBaseUrl, getUserCountryCode } from "./helpers";
import { attachMintAction } from "./mint/mint-action";
import { getRedeemCodeHtml } from "./reveal/redeem-code-html";
import { attachRevealAction } from "./reveal/reveal-action";
Expand All @@ -16,7 +16,10 @@ export async function initClaimGiftCard(app: AppState) {
}
giftCardsSection.innerHTML = "Loading...";

void detectCardsEnv();

const countryCode = await getUserCountryCode();

if (!countryCode) {
giftCardsSection.innerHTML = `<p class="card-error">Failed to load suitable virtual cards for you. Refresh or try disabling adblocker.</p>`;
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { checkRenderInvalidatePermitAdminControl, checkRenderMakeClaimControl }
import { claimRewardsPagination } from "./claim-rewards-pagination";
import { renderTransaction } from "./render-transaction";
import { setClaimMessage } from "./set-claim-message";
import { useRpcHandler } from "../web3/use-rpc-handler";
import { useRpcHandler } from "../../../../shared/use-rpc-handler";
import { switchNetwork } from "../web3/switch-network";
import { ethers } from "ethers";
import { getNetworkName, NetworkId } from "@ubiquity-dao/rpc-handler";
Expand Down
Loading

0 comments on commit ad513f9

Please sign in to comment.