Skip to content
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
8 changes: 8 additions & 0 deletions .github/workflows/wrapper-ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ jobs:
with:
node-version: '${{ steps.nvm.outputs.NVMRC }}'

- name: Install dependencies of provider
run: yarn install --nonInteractive --frozen-lockfile --prefer-offline
working-directory: ./provider/implementations/js

- name: Build provider
run: yarn build
working-directory: ./provider/implementations/js

- name: Install dependencies
run: yarn install --nonInteractive --frozen-lockfile --prefer-offline
working-directory: ./wrapper
Expand Down
13 changes: 6 additions & 7 deletions provider/implementations/js/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@polywrap/ethereum-provider-js",
"description": "Ethereum Provider JS Plugin",
"version": "0.2.4",
"version": "0.3.0",
"license": "MIT",
"main": "build/index.js",
"files": [
Expand All @@ -18,19 +18,19 @@
"dependencies": {
"@ethersproject/address": "5.7.0",
"@ethersproject/providers": "5.7.0",
"@polywrap/core-js": "0.10.0-pre.10",
"@polywrap/plugin-js": "0.10.0-pre.10",
"@polywrap/core-js": "0.10.0-pre.12",
"@polywrap/plugin-js": "0.10.0-pre.12",
"ethers": "5.7.0"
},
"peerDependencies": {
"@polywrap/core-js": "0.10.x",
"@polywrap/plugin-js": "0.10.x"
},
"devDependencies": {
"polywrap": "0.10.0-pre.10",
"polywrap": "0.10.0-pre.12",
"@types/jest": "26.0.8",
"@polywrap/client-js": "0.10.0-pre.10",
"@polywrap/test-env-js": "0.10.0-pre.10",
"@polywrap/client-js": "0.10.0-pre.12",
"@polywrap/cli-js": "0.10.0-pre.12",
"eth-ens-namehash": "2.0.8",
"jest": "26.6.3",
"js-sha3": "0.8.0",
Expand All @@ -43,4 +43,3 @@
"access": "public"
}
}

3 changes: 3 additions & 0 deletions provider/implementations/js/polywrap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ project:
source:
module: ./src/index.ts
schema: ./src/schema.graphql
import_abis:
- uri: wrap://ens/wraps.eth:ethereum-provider@2.0.0
abi: ../../interface/src/schema.graphql
13 changes: 13 additions & 0 deletions provider/implementations/js/src/Connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ export interface ConnectionConfig {
signer?: EthereumSigner;
}

export enum SignerType {
CUSTOM_SIGNER,
PROVIDER_SIGNER
}

export class Connection {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: initialized within setProvider
Expand Down Expand Up @@ -112,4 +117,12 @@ export class Connection {
);
}
}

public getSignerType(): SignerType {
if (Signer.isSigner(this._config.signer)) {
return SignerType.CUSTOM_SIGNER
}

return SignerType.PROVIDER_SIGNER
}
}
2 changes: 1 addition & 1 deletion provider/implementations/js/src/Connections.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Connection, EthereumProvider } from "./Connection";
import { IProvider_Connection as SchemaConnection } from "./wrap";
import { Connection as SchemaConnection } from "./wrap";

import { getNetwork } from "@ethersproject/providers";
import {KnownNetwork, KnownNetworkId} from "./networks";
Expand Down
127 changes: 82 additions & 45 deletions provider/implementations/js/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,22 @@ import {
Module,
manifest,
CoreClient,
IProvider_Module_Args_request as Args_request,
IProvider_Module_Args_signMessage as Args_signMessage,
IProvider_Module_Args_signTransaction as Args_signTransaction,
IProvider_Module_Args_address as Args_address,
IProvider_Module_Args_chainId as Args_chainId,
IProvider_Module_Args_waitForTransaction as Args_waitForTransaction,
IProvider_Connection as SchemaConnection
Args_request,
Args_signMessage,
Args_signTransaction,
Args_waitForTransaction,
Connection as SchemaConnection,
Args_signerAddress,
} from "./wrap";
import { PluginFactory, PluginPackage } from "@polywrap/plugin-js";
import { Connection } from "./Connection";
import { Connection, SignerType } from "./Connection";
import { Connections } from "./Connections";
import {
eth_sendTransaction
} from "./rpc";

import { PluginFactory, PluginPackage } from "@polywrap/plugin-js";
import { ethers } from "ethers";

export * from "./Connection";
export * from "./Connections";

Expand All @@ -25,7 +29,7 @@ export class EthereumProviderPlugin extends Module<ProviderConfig> {
private _connections: Connections;

constructor(config: ProviderConfig) {
super(config)
super(config);
this._connections = config.connections;
}

Expand All @@ -34,30 +38,54 @@ export class EthereumProviderPlugin extends Module<ProviderConfig> {
_client: CoreClient
): Promise<string> {
const connection = await this._getConnection(args.connection);
const params = JSON.parse(args?.params ?? "[]");
const paramsStr = args?.params ?? "[]";
const provider = connection.getProvider();

// Optimizations, utilizing the cache within ethers
if (args.method === "eth_chainId") {
const network = await provider.getNetwork();
const result = JSON.stringify("0x" + network.chainId.toString(16));
return result;
}

if (
args.method === "eth_sendTransaction" &&
connection.getSignerType() == SignerType.CUSTOM_SIGNER
) {
const signer = await connection.getSigner();
const parameters = eth_sendTransaction.deserializeParameters(
paramsStr
);
const request = eth_sendTransaction.toEthers(
parameters[0]
);
const res = await signer.sendTransaction(request);
return JSON.stringify(res.hash);
}

const params = JSON.parse(paramsStr);

try {
const req = await provider.send(args.method, params);
const req = await provider.send(
args.method,
params
);
return JSON.stringify(req);
} catch (err) {
/**
* Hotfix:
* Ethers-rs defines the type of EIP 1559 tx
* as 0x02, but metamask expects it as 0x2,
* hence, the need of this workaround. Related:
* https://github.com/foundry-rs/foundry/issues/3890.
*
* https://github.com/MetaMask/metamask-extension/issues/18076
*
* We check if the parameters comes as array, if the error
* contains 0x2 and if the type is 0x02, then we change it
*/
const paramsIsArray = Array.isArray(params) && params.length > 0;
const messageContains0x2 = err && err.message && err.message.indexOf("0x2") > -1;
if (
messageContains0x2 &&
paramsIsArray &&
params[0].type === "0x02"
) {
const messageContains0x2 =
err && err.message && err.message.indexOf("0x2") > -1;
if (messageContains0x2 && paramsIsArray && params[0].type === "0x02") {
params[0].type = "0x2";
const req = await provider.send(args.method, params);
return JSON.stringify(req);
Expand All @@ -83,6 +111,18 @@ export class EthereumProviderPlugin extends Module<ProviderConfig> {
return true;
}

public async signerAddress(
args: Args_signerAddress,
_client: CoreClient
): Promise<string | null> {
try {
const connection = await this._getConnection(args.connection);
return await connection.getSigner().getAddress();
} catch (_error) {
return null;
}
}

public async signMessage(
args: Args_signMessage,
_client: CoreClient
Expand All @@ -99,50 +139,47 @@ export class EthereumProviderPlugin extends Module<ProviderConfig> {
const request = this._parseTransaction(args.rlp);
const signedTxHex = await connection.getSigner().signTransaction(request);
const signedTx = ethers.utils.parseTransaction(signedTxHex);
return ethers.utils.joinSignature(signedTx as { r: string; s: string; v: number | undefined });
}

public async address(
args: Args_address,
_client: CoreClient
): Promise<string> {
const connection = await this._getConnection(args.connection);
return await connection.getSigner().getAddress();
}

public async chainId(
args: Args_chainId,
_client: CoreClient
): Promise<string> {
const connection = await this._getConnection(args.connection);
const network = await connection.getProvider().getNetwork();
return network.chainId.toString();
return ethers.utils.joinSignature(
signedTx as { r: string; s: string; v: number | undefined }
);
}

private async _getConnection(connection?: SchemaConnection | null): Promise<Connection> {
private async _getConnection(
connection?: SchemaConnection | null
): Promise<Connection> {
return this._connections.getConnection(connection ?? this.env.connection);
}

private _parseTransaction(rlp: Uint8Array): ethers.providers.TransactionRequest {
private _parseTransaction(
rlp: Uint8Array
): ethers.providers.TransactionRequest {
const tx = ethers.utils.parseTransaction(rlp);

// r, s, v can sometimes be set to 0, but ethers will throw if the keys exist at all
let request: Record<string, any> = { ...tx, r: undefined, s: undefined, v: undefined };
let request: Record<string, any> = {
...tx,
r: undefined,
s: undefined,
v: undefined,
};

// remove undefined and null values
request = Object.keys(request).reduce((prev, curr) => {
const val = request[curr];
if (val !== undefined && val !== null) prev[curr] = val
if (val !== undefined && val !== null) prev[curr] = val;
return prev;
}, {} as Record<string, unknown>)
}, {} as Record<string, unknown>);

return request;
}
}

export const ethereumProviderPlugin: PluginFactory<ProviderConfig> = (
config: ProviderConfig
) => new PluginPackage<ProviderConfig>(new EthereumProviderPlugin(config), manifest);
) =>
new PluginPackage<ProviderConfig>(
new EthereumProviderPlugin(config),
manifest
);

export const plugin = ethereumProviderPlugin;

Loading