Skip to content

Commit

Permalink
feat: provider proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
Keyrxng committed Jun 1, 2024
1 parent 72a8777 commit e299b2f
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import { verifyCurrentNetwork } from "../web3/verify-current-network";
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 { useHandler } from "../web3/use-rpc-handler";
import { createProviderProxy } from "../web3/onchain-call-handler";

declare const SUPABASE_URL: string;
declare const SUPABASE_ANON_KEY: string;
Expand All @@ -32,9 +33,22 @@ export async function readClaimDataFromUrl(app: AppState) {
app.claimTxs = await getClaimedTxs(app);

try {
app.provider = await useRpcHandler(app);
// create a handler instance
const handler = await useHandler(app.networkId as number);
// get the fastest provider
const provider = await handler.getFastestRpcProvider();
// needs to be assigned to create our proxy
app.provider = provider;
// create the proxy
app.provider = createProviderProxy(app, handler);
} catch (e) {
toaster.create("error", `e`);
if (e instanceof Error) {
toaster.create("error", e.message);
} else {
if (typeof e === "string") {
toaster.create("error", e);
}
}
}

try {
Expand Down
63 changes: 63 additions & 0 deletions static/scripts/rewards/web3/onchain-call-handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { ethers } from "ethers";
import { AppState } from "../app-state";
import { JsonRpcProvider } from "@ethersproject/providers";
import { toaster } from "../toaster";

/**
* Creates a proxy for the provider so that we can retry any failed provider call
* across the app.
*
* Should a call fail it will retry the call starting with the fastest provider
* until it has tried all providers.
*
* It will do this three times before throwing an error. It is more likely
* it'll succeed on the first loop but we'll try three times to be sure.
*/

export function createProviderProxy(app: AppState, handler: RPCHandler): JsonRpcProvider {
return new Proxy(app.provider, {
get: function (target: JsonRpcProvider, prop: keyof JsonRpcProvider) {
if (typeof target[prop] === "function") {
return async function (...args: unknown[]) {
// first attempt at the call, if it fails we don't care about the error
try {
return await (target[prop] as (...args: unknown[]) => Promise<unknown>)(...args);
} catch {
//
}

const latencies: Record<string, number> = await handler.getLatencies();
const sortedLatencies = Object.entries(latencies).sort((a, b) => a[1] - b[1]);

let loops = 3;

let lastError: Error | unknown | null = null;

while (loops > 0) {
for (const [rpc] of sortedLatencies) {
console.log(`[PROXY] Connected to: ${rpc}`);
try {
// we do not want to change the app.provider as it is the proxy itself
const newProvider = new ethers.providers.JsonRpcProvider(rpc.split("__")[1]);
return await (newProvider[prop] as (...args: unknown[]) => Promise<unknown>)(...args);
} catch (e) {
console.error("[PROXY] Provider Error -> retrying with new provider");
lastError = e;
}
}
loops--;
}

toaster.create("error", "Operation failed to complete, see more in the console");

if (lastError instanceof Error) {
console.error(lastError);
} else {
console.error("Unknown error", lastError);
}
};
}
return target[prop];
},
});
}

0 comments on commit e299b2f

Please sign in to comment.