Skip to content
This repository has been archived by the owner on Apr 18, 2024. It is now read-only.

Commit

Permalink
Merge 175882c into b4ad996
Browse files Browse the repository at this point in the history
  • Loading branch information
bleaker0x committed Feb 23, 2022
2 parents b4ad996 + 175882c commit 1e9e4cb
Show file tree
Hide file tree
Showing 15 changed files with 468 additions and 74 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,11 @@
"@ethersproject/providers": "^5.5.0",
"@ethersproject/units": "^5.5.0",
"@ethersproject/wallet": "^5.5.0",
"@web3-react/abstract-connector": "^6.0.7",
"dotenv": "^10.0.0",
"ethers": "^5.5.1",
"lodash": "^4.17.21",
"node-fetch": "^3.2.0",
"utility-types": "^3.10.0"
},
"devDependencies": {
Expand Down
10 changes: 5 additions & 5 deletions src/bridge/bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import {
} from "../common/utils";

import type {ID} from "../internal/entity";
import {SwapType} from "../internal/swaptype";
import {newProviderForNetwork} from "../internal/rpcproviders";
import {SwapType} from "../internal/swaptype";
import {rpcProviderForNetwork} from "../internal/rpcproviders";

import type {
GenericZapBridgeContract,
Expand Down Expand Up @@ -115,7 +115,7 @@ export namespace Bridge {
private readonly bridgeConfigInstance = SynapseEntities.bridgeConfig();
private readonly zapBridgeInstance = SynapseEntities.l1BridgeZap({
chainId: ChainId.ETH,
signerOrProvider: newProviderForNetwork(ChainId.ETH),
signerOrProvider: rpcProviderForNetwork(ChainId.ETH),
});

readonly requiredConfirmations: number;
Expand All @@ -128,7 +128,7 @@ export namespace Bridge {

this.network = network instanceof Networks.Network ? network : Networks.fromChainId(network);
this.chainId = this.network.chainId;
this.provider = provider ?? newProviderForNetwork(this.chainId);
this.provider = provider ?? rpcProviderForNetwork(this.chainId);

this.requiredConfirmations = getRequiredConfirmationsForBridge(this.network);

Expand Down Expand Up @@ -419,7 +419,7 @@ export namespace Bridge {
private async calculateBridgeRate(args: BridgeParams): Promise<BridgeOutputEstimate> {
let {chainIdTo, amountFrom} = args;

const toChainZapParams = {chainId: chainIdTo, signerOrProvider: newProviderForNetwork(chainIdTo)};
const toChainZapParams = {chainId: chainIdTo, signerOrProvider: rpcProviderForNetwork(chainIdTo)};
const toChainZap: GenericZapBridgeContract = SynapseEntities.zapBridge(toChainZapParams);

const {
Expand Down
4 changes: 2 additions & 2 deletions src/bridge/erc20.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
ERC20Contract,
} from "../contracts";

import {newProviderForNetwork} from "../internal/rpcproviders";
import {rpcProviderForNetwork} from "../internal/rpcproviders";

import {
executePopulatedTransaction,
Expand Down Expand Up @@ -47,7 +47,7 @@ export namespace ERC20 {
this.address = args.tokenAddress;
this.chainId = args.chainId;

this.provider = newProviderForNetwork(this.chainId);
this.provider = rpcProviderForNetwork(this.chainId);
this.instance = ERC20Factory.connect(this.address, this.provider);
}

Expand Down
4 changes: 3 additions & 1 deletion src/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@ import type {Provider} from "@ethersproject/providers";
export type SignerOrProvider = Signer | Provider;

export interface ChainIdTypeMap<T> {[chainId: number]: T}
export type AddressMap = ChainIdTypeMap<string>
export type StringMap = ChainIdTypeMap<string>
export type DecimalsMap = ChainIdTypeMap<number>

export type AddressMap = StringMap
13 changes: 13 additions & 0 deletions src/common/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import {ChainId} from "./chainid";
import {SynapseContracts} from "./synapse_contracts";

import type {JsonRpcProvider} from "@ethersproject/providers";
import {setRpcUriForNetwork} from "../internal/rpcproviders";

import type {Signer} from "@ethersproject/abstract-signer";

import type {
Expand Down Expand Up @@ -44,3 +47,13 @@ const CHAINID_CONTRACTS_MAP: {[c: number]: SynapseContracts.SynapseContract} = {

export const contractsForChainId = (chainId: number): SynapseContracts.SynapseContract => CHAINID_CONTRACTS_MAP[chainId] ?? null

/**
* Sets the JSON-RPC URI for a given chain ID. All SDK functions which use internal, pre-initialized
* {@link JsonRpcProvider} instances which retrieve the {@link JsonRpcProvider} for the passed chain ID
* will henceforth use an instance which uses the passed URI.
* @param chainId
* @param uri
*/
export function setJsonRpcUriForNetwork(chainId: number, uri: string) {
setRpcUriForNetwork(chainId, uri);
}
6 changes: 3 additions & 3 deletions src/entities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
import type {SignerOrProvider} from "./common/types";
import {contractAddressFor} from "./common/utils";
import {ChainId} from "./common/chainid";
import {newProviderForNetwork} from "./internal/rpcproviders";
import {rpcProviderForNetwork} from "./internal/rpcproviders";


export const newSynapseBridgeInstance = (params: {
Expand Down Expand Up @@ -80,12 +80,12 @@ export namespace SynapseEntities {
}

export function bridgeConfig(): BridgeConfigContract {
const provider = newProviderForNetwork(ChainId.ETH);
const provider = rpcProviderForNetwork(ChainId.ETH);
return BridgeConfigFactory.connect(bridgeConfigAddress, provider)
}

export function poolConfig(): PoolConfigContract {
const provider = newProviderForNetwork(ChainId.ETH);
const provider = rpcProviderForNetwork(ChainId.ETH);
return PoolConfigFactory.connect(poolConfigAddress, provider)
}
}
153 changes: 153 additions & 0 deletions src/internal/minirpc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import fetch, {Response} from "node-fetch";


export class RequestError extends Error {
readonly code: number;
readonly data: any;

constructor(message: string, code: number, data: any) {
super(message)
this.code = code
this.data = data
this.name = this.constructor.name // dafuq
this.message = message // dafuq message
}
}

interface MiniRpcRequest {
jsonrpc: string,
id: number,
method: string,
params: any,
}

interface MiniRpcBatchItem {
request: MiniRpcRequest;
resolve: (value: unknown) => void;
reject: (reason?: any) => void,
}

export class MiniRpcProvider {
readonly isMetaMask: boolean;
readonly chainId: number;

readonly url: string;
readonly host: string;
readonly path: string;

readonly batchWaitTimeMs: number;

protected nextId: number;
protected batchTimeoutId: string | NodeJS.Timeout;
protected batch: MiniRpcBatchItem[];

constructor(chainId: number, url: string, batchWaitTimeMs?: number) {
this.isMetaMask = false
this.nextId = 1
this.batchTimeoutId = null
this.batch = []

this.chainId = chainId
this.url = url
const parsed = new URL(url)
this.host = parsed.host
this.path = parsed.pathname
// how long to wait to batch calls
this.batchWaitTimeMs = batchWaitTimeMs ?? 50
}

async request(method: string|MiniRpcRequest, params: any) {
const _method: string = typeof method === "string" ? method : method.method;

if (_method === 'eth_chainId') {
return `0x${this.chainId.toString(16)}`
}

const promise = new Promise((resolve, reject) => {
this.batch.push({
request: {
jsonrpc: '2.0',
id: this.nextId++,
method: _method,
params
},
resolve,
reject
})
});

this.batchTimeoutId = this.batchTimeoutId ?? setTimeout(this.clearBatch, this.batchWaitTimeMs);

return promise
}

sendAsync(request: MiniRpcRequest, callback: any) {
this.request(request.method, request.params)
.then(result => callback(null, { jsonrpc: '2.0', id: request.id, result }))
.catch(error => callback(error, null))
}

async clearBatch() {
const batch = this.batch;
this.batch = [];
this.batchTimeoutId = null;

const rejectBatchItem = (reason: any): (item: MiniRpcBatchItem) => void =>
({reject}) => reject(reason instanceof Error ? reason : new Error(reason));

let response: Response;
try {
response = await fetch(this.url, {
method: 'POST',
headers: {
'content-type': 'application/json',
accept: 'application/json'
},
body: JSON.stringify(batch.map(item => item.request))
});
} catch (error) {
batch.forEach(rejectBatchItem("Failed to send batch call"));
return
}

if (!response.ok) {
batch.forEach(rejectBatchItem(`${response.status}: ${response.statusText}`))
return
}

let json: any;
try {
json = await response.json();
} catch (error) {
batch.forEach(rejectBatchItem("Failed to parse JSON response"));
return
}

const byKey = batch.reduce((memo, current) => {
memo[current.request.id] = current
return memo
}, {});

try {
if (json?.error?.code === -32700) {
console.error(`${this.chainId} RPC gave invalid response`)
return
}

for (const result of json) {
const { resolve, reject, request: { method } } = byKey[result.id]

if (resolve && reject) {
if ("error" in result) {
reject(result?.error)
} else if ("result" in result) {
resolve(result.result)
} else {
reject(new RequestError(`Received unexpected JSON-RPC response to ${method} request.`, -32000, result))
}
}
}
} catch (e) {}

}
}
Loading

0 comments on commit 1e9e4cb

Please sign in to comment.