Skip to content

Commit

Permalink
[Release v1.0.4] - RPC interception and wallet provider upgrades (#29)
Browse files Browse the repository at this point in the history
* Fix for estimateGas, update package version

* Update provider to work more effectively accross all sites
  • Loading branch information
0xLienid committed Jun 9, 2023
1 parent 91aeda0 commit 6e20484
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 58 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/node_modules/
/dist/
/dist/
*.tgz
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@guardianui/test",
"version": "1.0.3",
"version": "1.0.4",
"description": "<p align=\"center\"> <picture> <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://github.com/GuardianUI/landing-page/blob/main/assets/images/logo.png\"> <img alt=\"guardianui logo\" src=\"https://github.com/GuardianUI/landing-page/blob/main/assets/images/logo.png\" width=\"auto\" height=\"75\"> </picture> </p>",
"main": "./dist/index.js",
"exports": {
Expand Down
90 changes: 41 additions & 49 deletions src/fixtures/DappTest.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { expect, Page, test as base } from "@playwright/test";
import { GUI } from "../models/GUI";
import { isArbiRPC, isMainnetRPC, isOptiRPC, isPolyRPC } from "../utils";
import { handleArrayRequest, handleSingleRequest, isArbiRPC, isMainnetRPC, isOptiRPC, isPolyRPC } from "../utils";
import { ethers } from "ethers";
import { promises as fs} from "fs";
import * as path from "path";
Expand Down Expand Up @@ -33,18 +33,16 @@ export const test = base.extend<{ gui: GUI }>({
// Parse the request data to pull out RPC method and params
const data = JSON.parse(request.postData() as string);

// Set up provider object to interact with
const providerUrl: string = await page.evaluate("window.ethereum.provider.connection.url");
const provider = new ethers.providers.JsonRpcProvider(providerUrl, parseInt(chainId));

// Send the RPC request to Anvil and record the response
const resultData = await provider.send(data.method, data.params);

const updatedData = {
"jsonrpc": "2.0",
"id": data.id,
"result": resultData
};
// Handle different request types
let updatedData;
if (data.length && data[0].method !== undefined) {
updatedData = await handleArrayRequest(page, data);
} else if (!data.length && data.method !== undefined) {
updatedData = await handleSingleRequest(page, data);
} else {
console.log("Problematic request data structure: " + JSON.stringify(data));
throw new Error("Invalid RPC request data");
}

// Fulfill the request with the updated data
route.fulfill({
Expand All @@ -70,18 +68,16 @@ export const test = base.extend<{ gui: GUI }>({
// Parse the request data to pull out RPC method and params
const data = JSON.parse(request.postData() as string);

// Set up provider object to interact with
const providerUrl: string = await page.evaluate("window.ethereum.provider.connection.url");
const provider = new ethers.providers.JsonRpcProvider(providerUrl, parseInt(chainId));

// Send the RPC request to Anvil and record the response
const resultData = await provider.send(data.method, data.params);

const updatedData = {
"jsonrpc": "2.0",
"id": data.id,
"result": resultData
};
// Hanlde different request types
let updatedData;
if (data.length && data[0].method !== undefined) {
updatedData = await handleArrayRequest(page, data);
} else if (!data.length && data.method !== undefined) {
updatedData = await handleSingleRequest(page, data);
} else {
console.log("Problematic request data structure: " + JSON.stringify(data));
throw new Error("Invalid RPC request data");
}

// Fulfill the request with the updated data
route.fulfill({
Expand All @@ -107,18 +103,16 @@ export const test = base.extend<{ gui: GUI }>({
// Parse the request data to pull out RPC method and params
const data = JSON.parse(request.postData() as string);

// Set up provider object to interact with
const providerUrl: string = await page.evaluate("window.ethereum.provider.connection.url");
const provider = new ethers.providers.JsonRpcProvider(providerUrl, parseInt(chainId));

// Send the RPC request to Anvil and record the response
const resultData = await provider.send(data.method, data.params);

const updatedData = {
"jsonrpc": "2.0",
"id": data.id,
"result": resultData
};
// Hanlde different request types
let updatedData;
if (data.length && data[0].method !== undefined) {
updatedData = await handleArrayRequest(page, data);
} else if (!data.length && data.method !== undefined) {
updatedData = await handleSingleRequest(page, data);
} else {
console.log("Problematic request data structure: " + JSON.stringify(data));
throw new Error("Invalid RPC request data");
}

// Fulfill the request with the updated data
route.fulfill({
Expand All @@ -144,18 +138,16 @@ export const test = base.extend<{ gui: GUI }>({
// Parse the request data to pull out RPC method and params
const data = JSON.parse(request.postData() as string);

// Set up provider object to interact with
const providerUrl: string = await page.evaluate("window.ethereum.provider.connection.url");
const provider = new ethers.providers.JsonRpcProvider(providerUrl, parseInt(chainId));

// Send the RPC request to Anvil and record the response
const resultData = await provider.send(data.method, data.params);

const updatedData = {
"jsonrpc": "2.0",
"id": data.id,
"result": resultData
};
// Hanlde different request types
let updatedData;
if (data.length && data[0].method !== undefined) {
updatedData = await handleArrayRequest(page, data);
} else if (!data.length && data.method !== undefined) {
updatedData = await handleSingleRequest(page, data);
} else {
console.log("Problematic request data structure: " + JSON.stringify(data));
throw new Error("Invalid RPC request data");
}

// Fulfill the request with the updated data
route.fulfill({
Expand Down
2 changes: 1 addition & 1 deletion src/provider/provider.js

Large diffs are not rendered by default.

53 changes: 53 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Page } from "@playwright/test";
import { erc20TokenAbi } from "./constants/abis/ERC20ABI";
import { ethers } from "ethers";

Expand Down Expand Up @@ -291,3 +292,55 @@ export const findBalanceSlot = async (erc20Address: any, page: any) => {
await provider.send("evm_revert", [snapshot]);
}
}

/**
* Routes an array of RPC requests through the Anvil fork and returns the results
* @param page - The Playwright page
* @param data - The RPC request data
* @returns Array of RPC response data
*/
export const handleArrayRequest = async (page: Page, data: any): Promise<any> => {
// Set up provider object to interact with
const chainId: string = await page.evaluate("window.ethereum.chainId");
const providerUrl: string = await page.evaluate("window.ethereum.provider.connection.url");
const provider = new ethers.providers.JsonRpcProvider(providerUrl, parseInt(chainId));

const updatedResponseData = [];

// Send the RPC requests to Anvil and record the response
for (let i = 0; i < data.length; i++) {
const resultData = await provider.send(data[i].method, data[i].params);

updatedResponseData.push({
"jsonrpc": "2.0",
"id": data[i].id,
"result": resultData
});
}

return updatedResponseData;
}

/**
* Routes a single RPC request through the Anvil fork and returns the result
* @param page - The Playwright page
* @param data - The RPC request data
* @returns RPC response data object
*/
export const handleSingleRequest = async (page: Page, data: any): Promise<any> => {
// Set up provider object to interact with
const chainId: string = await page.evaluate("window.ethereum.chainId");
const providerUrl: string = await page.evaluate("window.ethereum.provider.connection.url");
const provider = new ethers.providers.JsonRpcProvider(providerUrl, parseInt(chainId));

// Send the RPC request to Anvil and record the response
const resultData = await provider.send(data.method, data.params);

const updatedResponseData = {
"jsonrpc": "2.0",
"id": data.id,
"result": resultData
};

return updatedResponseData;
}
38 changes: 32 additions & 6 deletions src/wallet/EIP1193Bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import { ethers } from "ethers";
*/
export class Eip1193Bridge extends EventEmitter {
signer: ethers.Signer;
provider: ethers.providers.Provider;
provider: ethers.providers.JsonRpcProvider;

/**
* @constructor
* @param signer - The signer to use for the bridge
* @param provider - The RPC provider to use for the bridge
*/
constructor(signer: ethers.Signer, provider: ethers.providers.Provider) {
constructor(signer: ethers.Signer, provider: ethers.providers.JsonRpcProvider) {
super();
this.signer = signer;
this.provider = provider;
Expand All @@ -36,7 +36,7 @@ export class Eip1193Bridge extends EventEmitter {
* Setter for the provider state variable
* @param provider - The RPC provider to use for the bridge
*/
setProvider(provider: ethers.providers.Provider) {
setProvider(provider: ethers.providers.JsonRpcProvider) {
this.provider = provider;
}

Expand Down Expand Up @@ -99,19 +99,36 @@ export class Eip1193Bridge extends EventEmitter {
return result;
}
case "eth_sendRawTransaction": {
delete params![0].from;
return await this.provider.sendTransaction(params![0]);
}
case "eth_call": {
const req = ethers.providers.JsonRpcProvider.hexlifyTransaction(params![0]);
return await this.provider.call(req, params![1]);
}
case "eth_estimateGas": {
if (params![1] && params![1] !== "latest") {
throw new Error("estimateGas does not support blockTag");
}

delete params![0].from;

const req = ethers.providers.JsonRpcProvider.hexlifyTransaction(params![0]);

const result = await this.signer.estimateGas(req);
return result.toHexString();
}

case "estimateGas": {
if (params![1] && params![1] !== "latest") {
throw new Error("estimateGas does not support blockTag");
}

delete params![0].from;

const req = ethers.providers.JsonRpcProvider.hexlifyTransaction(params![0]);
const result = await this.provider.estimateGas(req);

const result = await this.signer.estimateGas(req);
return result.toHexString();
}

Expand All @@ -125,10 +142,19 @@ export class Eip1193Bridge extends EventEmitter {
}
}
case "eth_getTransactionByHash": {
return await this.provider.getTransaction(params![0]);
const result = await this.provider.getTransaction(params![0]);
return result;
}
case "eth_getTransactionReceipt": {
return await this.provider.getTransactionReceipt(params![0]);
const result = await this.provider.getTransaction(params![0]);
return result;
}
case "eth_subscribe": {
if (params![0] === "newHeads") {
const result = await this.provider.send("eth_subscribe", params![0]);
return result;
}
break;
}

case "eth_sign": {
Expand Down
2 changes: 2 additions & 0 deletions src/wallet/MockWallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ export class MockWallet extends Eip1193Bridge {
}
return result;
} catch (e) {
console.log("Error with method: " + method);
console.log("Error with params: " + JSON.stringify(params));
console.error("MockWallet.send THROWS error", { e }, (e as any).stack);
} finally {}
}
Expand Down

0 comments on commit 6e20484

Please sign in to comment.