Skip to content
This repository has been archived by the owner on Dec 27, 2022. It is now read-only.

[DNM] ChainRpcProvider class with fallback capabilities #509

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
8 changes: 4 additions & 4 deletions modules/browser-node/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { deployments, VectorChainService } from "@connext/vector-contracts";
import { VectorEngine } from "@connext/vector-engine";
import {
ChainAddresses,
ChainProviders,
ChainRpcProviders,
ChannelRpcMethods,
CreateUpdateDetails,
EngineEvent,
Expand Down Expand Up @@ -35,7 +35,7 @@ export type BrowserNodeSignerConfig = {
messagingUrl?: string;
logger?: BaseLogger;
signer: IChannelSigner;
chainProviders: ChainProviders;
chainProviders: ChainRpcProviders;
chainAddresses: ChainAddresses;
};

Expand All @@ -49,7 +49,7 @@ export class BrowserNode implements INodeService {
private supportedChains: number[] = [];
private routerPublicIdentifier?: string;
private iframeSrc?: string;
private chainProviders: ChainProviders = {};
private chainProviders: ChainRpcProviders = {};
private chainAddresses?: ChainAddresses;
private messagingUrl?: string;
private natsUrl?: string;
Expand All @@ -60,7 +60,7 @@ export class BrowserNode implements INodeService {
routerPublicIdentifier?: string;
supportedChains?: number[];
iframeSrc?: string;
chainProviders: ChainProviders;
chainProviders: ChainRpcProviders;
messagingUrl?: string;
natsUrl?: string;
authUrl?: string;
Expand Down
12 changes: 7 additions & 5 deletions modules/contracts/src.ts/constants.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
import { HDNode } from "@ethersproject/hdnode";
import { Wallet } from "@ethersproject/wallet";
import { JsonRpcProvider } from "@ethersproject/providers";
import { network, ethers }from "hardhat";
import { ChainRpcProvider } from "@connext/vector-types";
import { network, ethers } from "hardhat";
import pino from "pino";

// Get defaults from env
const chainProviders = JSON.parse(process.env.CHAIN_PROVIDERS ?? "{}");

const chainId = Object.keys(chainProviders)[0];
const url = Object.values(chainProviders)[0];
const urls = Object.values(chainProviders)[0];
const mnemonic = process.env.SUGAR_DADDY ?? "candy maple cake sugar pudding cream honey rich smooth crumble sweet treat";

export const defaultLogLevel = process.env.LOG_LEVEL || "info";
export const logger = pino({ level: defaultLogLevel });

export const networkName = network.name;

export const provider = url
? new JsonRpcProvider(url as string, parseInt(chainId))
: ethers.provider as JsonRpcProvider;
export const provider = urls
? new ChainRpcProvider(parseInt(chainId), (urls as string).split(","))
: new ChainRpcProvider(parseInt(chainId), [ethers.provider as JsonRpcProvider]);

const hdNode = HDNode.fromMnemonic(mnemonic).derivePath("m/44'/60'/0'/0");

Expand Down
16 changes: 8 additions & 8 deletions modules/contracts/src.ts/services/ethReader.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ChainError, FullChannelState, Result } from "@connext/vector-types";
import { ChainError, ChainRpcProvider, FullChannelState, Result } from "@connext/vector-types";
import { createTestChannelState, expect, getTestLoggers, mkHash } from "@connext/vector-utils";
import { JsonRpcProvider, TransactionReceipt } from "@ethersproject/providers";
import { TransactionReceipt } from "@ethersproject/providers";
import { AddressZero, One, Zero } from "@ethersproject/constants";
import { parseUnits } from "@ethersproject/units";
import { restore, reset, createStubInstance, SinonStubbedInstance } from "sinon";
Expand All @@ -9,8 +9,8 @@ import { EthereumChainReader, MIN_GAS_PRICE, BUMP_GAS_PRICE } from "./ethReader"

let ethReader: EthereumChainReader;
let channelState: FullChannelState;
let provider1337: SinonStubbedInstance<JsonRpcProvider>;
let provider1338: SinonStubbedInstance<JsonRpcProvider>;
let provider1337: SinonStubbedInstance<ChainRpcProvider>;
let provider1338: SinonStubbedInstance<ChainRpcProvider>;

const assertResult = (result: Result<any>, isError: boolean, unwrappedVal?: any) => {
if (isError) {
Expand Down Expand Up @@ -46,7 +46,7 @@ describe("ethReader", () => {
beforeEach(() => {
// eth service deps

const _provider = createStubInstance(JsonRpcProvider);
const _provider = createStubInstance(ChainRpcProvider);
_provider.getTransaction.resolves(_txResponse);
provider1337 = _provider;
provider1338 = _provider;
Expand All @@ -70,9 +70,9 @@ describe("ethReader", () => {
reset();
});

describe.skip("getChainProviders", () => {
it("happy: getChainProvider", async () => {
const result = await ethReader.getChainProviders();
describe.skip("getChainRpcProviders", () => {
it("happy: getChainRpcProvider", async () => {
const result = await ethReader.getChainRpcProviders();
console.log(result);
});
});
Expand Down
14 changes: 8 additions & 6 deletions modules/contracts/src.ts/services/ethReader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
IVectorChainReader,
Result,
ChainError,
ChainProviders,
ChainRpcProviders,
RegisteredTransfer,
TransferName,
ChannelDispute,
Expand All @@ -26,14 +26,15 @@ import {
CoreChannelState,
CoreTransferState,
TransferDispute,
ChainRpcProvider,
} from "@connext/vector-types";
import axios from "axios";
import { encodeBalance, encodeTransferResolver, encodeTransferState } from "@connext/vector-utils";
import { BigNumber } from "@ethersproject/bignumber";
import { parseUnits } from "@ethersproject/units";
import { AddressZero, HashZero } from "@ethersproject/constants";
import { Contract } from "@ethersproject/contracts";
import { JsonRpcProvider, TransactionRequest } from "@ethersproject/providers";
import { TransactionRequest } from "@ethersproject/providers";
import pino from "pino";

import { ChannelFactory, ChannelMastercopy, TransferDefinition, TransferRegistry, VectorChannel } from "../artifacts";
Expand All @@ -59,14 +60,15 @@ export class EthereumChainReader implements IVectorChainReader {
};
private contracts: Map<string, Contract> = new Map();
constructor(
public readonly chainProviders: { [chainId: string]: JsonRpcProvider },
// The chainProviders specified here are hydrated.
public readonly chainProviders: { [chainId: string]: ChainRpcProvider },
public readonly log: pino.BaseLogger,
) {}

getChainProviders(): Result<ChainProviders, ChainError> {
const ret: ChainProviders = {};
getChainRpcProviders(): Result<ChainRpcProviders, ChainError> {
const ret: ChainRpcProviders = {};
Object.entries(this.chainProviders).forEach(([name, value]) => {
ret[parseInt(name)] = value.connection.url;
ret[parseInt(name)] = value.providerUrls;
});
return Result.ok(ret);
}
Expand Down
9 changes: 5 additions & 4 deletions modules/contracts/src.ts/services/ethService.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
ChainError,
ChainRpcProvider,
FullChannelState,
IChainServiceStore,
IChannelSigner,
Expand All @@ -19,7 +20,7 @@ import {
mkHash,
} from "@connext/vector-utils";
import { AddressZero, One, Zero } from "@ethersproject/constants";
import { JsonRpcProvider, TransactionReceipt, TransactionResponse } from "@ethersproject/providers";
import { TransactionReceipt, TransactionResponse } from "@ethersproject/providers";
import { BigNumber } from "ethers";
import { parseUnits } from "ethers/lib/utils";
import { restore, reset, createStubInstance, SinonStubbedInstance, stub, SinonStub } from "sinon";
Expand All @@ -30,8 +31,8 @@ import { BIG_GAS_PRICE, EthereumChainService } from "./ethService";
let storeMock: SinonStubbedInstance<IChainServiceStore>;
let signer: SinonStubbedInstance<IChannelSigner>;
let ethService: EthereumChainService;
let provider1337: SinonStubbedInstance<JsonRpcProvider>;
let provider1338: SinonStubbedInstance<JsonRpcProvider>;
let provider1337: SinonStubbedInstance<ChainRpcProvider>;
let provider1338: SinonStubbedInstance<ChainRpcProvider>;

let sendTxWithRetriesMock: SinonStub;
let approveMock: SinonStub;
Expand Down Expand Up @@ -96,7 +97,7 @@ describe("ethService unit test", () => {
signer.connect.returns(signer as any);
(signer as any)._isSigner = true;

const _provider = createStubInstance(JsonRpcProvider);
const _provider = createStubInstance(ChainRpcProvider);
_provider.getTransaction.resolves(txResponse);
provider1337 = _provider;
provider1338 = _provider;
Expand Down
9 changes: 5 additions & 4 deletions modules/contracts/src.ts/services/ethService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
StringifiedTransactionResponse,
getConfirmationsForChain,
StoredTransaction,
ChainRpcProvider,
} from "@connext/vector-types";
import {
delay,
Expand All @@ -29,7 +30,7 @@ import {
import { Signer } from "@ethersproject/abstract-signer";
import { BigNumber } from "@ethersproject/bignumber";
import { Contract } from "@ethersproject/contracts";
import { JsonRpcProvider, TransactionReceipt, TransactionResponse } from "@ethersproject/providers";
import { TransactionReceipt, TransactionResponse } from "@ethersproject/providers";
import { Wallet } from "@ethersproject/wallet";
import { BaseLogger } from "pino";
import PriorityQueue from "p-queue";
Expand All @@ -54,7 +55,7 @@ export const BIG_GAS_PRICE = parseUnits("1500", "gwei");

// TODO: Deprecate. Note that this is used in autoRebalance.ts.
export const waitForTransaction = async (
provider: JsonRpcProvider,
provider: ChainRpcProvider,
transactionHash: string,
confirmations?: number,
timeout?: number,
Expand Down Expand Up @@ -84,7 +85,7 @@ export class EthereumChainService extends EthereumChainReader implements IVector
};
constructor(
private readonly store: IChainServiceStore,
chainProviders: { [chainId: string]: JsonRpcProvider },
chainProviders: { [chainId: string]: ChainRpcProvider },
signer: string | Signer,
log: BaseLogger,
private readonly defaultRetries = 3,
Expand Down Expand Up @@ -528,7 +529,7 @@ export class EthereumChainService extends EthereumChainReader implements IVector
* the tx will be resubmitted at the same nonce.
*/
public async waitForConfirmation(chainId: number, responses: TransactionResponse[]): Promise<TransactionReceipt> {
const provider: JsonRpcProvider = this.chainProviders[chainId];
const provider = this.chainProviders[chainId];
if (!provider) {
throw new ChainError(ChainError.reasons.ProviderNotFound);
}
Expand Down
2 changes: 1 addition & 1 deletion modules/engine/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -624,7 +624,7 @@ export class VectorEngine implements IVectorEngine {
);
}

const chainProviders = this.chainService.getChainProviders();
const chainProviders = this.chainService.getChainRpcProviders();
if (chainProviders.isError) {
return Result.fail(chainProviders.getError()!);
}
Expand Down
2 changes: 1 addition & 1 deletion modules/engine/src/isAlive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export async function sendIsAlive(
): Promise<void> {
const method = "sendIsAlive";
const channels = await store.getChannelStates();
const providers = chainService.getChainProviders();
const providers = chainService.getChainRpcProviders();
if (providers.isError) {
logger.error({ ...providers.getError(), method }, "Error getting chain providers");
return;
Expand Down
4 changes: 2 additions & 2 deletions modules/engine/src/testing/env.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { ChainProviders } from "@connext/vector-types";
import { ChainRpcProviders } from "@connext/vector-types";
import { Wallet } from "@ethersproject/wallet";
import pino from "pino";

type EngineTestEnv = {
chainProviders: ChainProviders;
chainProviders: ChainRpcProviders;
chainAddresses: any;
sugarDaddy: Wallet;
logLevel?: pino.Level;
Expand Down
2 changes: 1 addition & 1 deletion modules/engine/src/testing/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ describe("VectorEngine", () => {
});
chainService = Sinon.createStubInstance(VectorChainService);

chainService.getChainProviders.returns(Result.ok(env.chainProviders));
chainService.getChainRpcProviders.returns(Result.ok(env.chainProviders));
});

afterEach(() => Sinon.restore());
Expand Down
2 changes: 1 addition & 1 deletion modules/engine/src/testing/isAlive.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ describe("checkIn", () => {
messagingService = Sinon.createStubInstance(MemoryMessagingService);
chainService = Sinon.createStubInstance(VectorChainService);

chainService.getChainProviders.returns(Result.ok(env.chainProviders));
chainService.getChainRpcProviders.returns(Result.ok(env.chainProviders));
});

it("should send no checkIn messages if there are no channels", async () => {
Expand Down
4 changes: 2 additions & 2 deletions modules/iframe-app/src/ConnextManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
EngineParams,
jsonifyError,
} from "@connext/vector-types";
import { ChannelSigner, constructRpcRequest, safeJsonParse } from "@connext/vector-utils";
import { ChannelSigner, constructRpcRequest, parseProviders, safeJsonParse } from "@connext/vector-utils";
import { entropyToMnemonic } from "@ethersproject/hdnode";
import { keccak256 } from "@ethersproject/keccak256";
import { toUtf8Bytes } from "@ethersproject/strings";
Expand Down Expand Up @@ -89,7 +89,7 @@ export default class ConnextManager {
this.browserNode = await BrowserNode.connect({
signer,
chainAddresses: chainAddresses ?? config.chainAddresses,
chainProviders,
chainProviders: parseProviders(chainProviders),
logger: pino(),
messagingUrl: _messagingUrl,
authUrl: _authUrl,
Expand Down
6 changes: 3 additions & 3 deletions modules/protocol/src/testing/constants.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { JsonRpcProvider } from "@ethersproject/providers";
import { ChainRpcProvider } from "@connext/vector-types";
import { Wallet } from "@ethersproject/wallet";

import { env } from "./env";

export const chainId = parseInt(Object.keys(env.chainProviders)[0]);
export const tokenAddress = env.chainAddresses[chainId]?.testTokenAddress ?? "";
export const provider = new JsonRpcProvider(env.chainProviders[chainId], chainId);
export const tokenAddress = env.chainAddresses[chainId]?.testTokenAddress ?? "";
export const provider = new ChainRpcProvider(chainId, env.chainProviders[chainId].split(","));

export const sugarDaddy = Wallet.fromMnemonic(env.sugarDaddyMnemonic).connect(provider);
export const rando = Wallet.createRandom().connect(provider);
Expand Down
2 changes: 1 addition & 1 deletion modules/protocol/src/testing/vector.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe("Vector", () => {
chainReader = Sinon.createStubInstance(VectorChainReader);
chainReader.getChannelFactoryBytecode.resolves(Result.ok(mkHash()));
chainReader.getChannelMastercopyAddress.resolves(Result.ok(mkAddress()));
chainReader.getChainProviders.returns(Result.ok(env.chainProviders));
chainReader.getChainRpcProviders.returns(Result.ok(env.chainProviders));
lockService = Sinon.createStubInstance(MemoryLockService);
messagingService = Sinon.createStubInstance(MemoryMessagingService);
storeService = Sinon.createStubInstance(MemoryStoreService);
Expand Down
2 changes: 1 addition & 1 deletion modules/router/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export type RebalanceProfile = Static<typeof RebalanceProfileSchema>;
const VectorRouterConfigSchema = Type.Object({
adminToken: Type.String(),
allowedSwaps: Type.Array(AllowedSwapSchema),
chainProviders: Type.Dict(TUrl),
chainProviders: Type.Dict(Type.String()),
dbUrl: Type.Optional(TUrl),
nodeUrl: TUrl,
routerUrl: TUrl,
Expand Down
6 changes: 3 additions & 3 deletions modules/router/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import fastify from "fastify";
import pino from "pino";
import { Evt } from "evt";
import { VectorChainReader } from "@connext/vector-contracts";
import { EventCallbackConfig, hydrateProviders, RestServerNodeService, ChannelSigner } from "@connext/vector-utils";
import { EventCallbackConfig, hydrateProviders, parseProviders, RestServerNodeService, ChannelSigner } from "@connext/vector-utils";
import {
IsAlivePayload,
ConditionalTransferCreatedPayload,
Expand Down Expand Up @@ -149,8 +149,8 @@ const server = fastify({
collectDefaultMetrics({ prefix: "router_" });

let router: IRouter;
const store = new PrismaStore();
const hydratedProviders = hydrateProviders(config.chainProviders);
const store = new PrismaStore()
const hydratedProviders = hydrateProviders(parseProviders(config.chainProviders));
const chainService = new VectorChainReader(hydratedProviders, logger.child({ module: "RouterChainReader" }));
const messagingService = new NatsRouterMessagingService({
signer,
Expand Down
3 changes: 2 additions & 1 deletion modules/router/src/metrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
getMainnetEquivalent,
getExchangeRateInEth,
calculateExchangeWad,
parseProviders,
} from "@connext/vector-utils";
import { BigNumber, BigNumberish } from "@ethersproject/bignumber";
import { AddressZero } from "@ethersproject/constants";
Expand All @@ -35,7 +36,7 @@ const config = getConfig();
///// Helpers/Utils
export const wallet = Wallet.fromMnemonic(config.mnemonic);
export const signerAddress = wallet.address;
export const hydrated: HydratedProviders = hydrateProviders(config.chainProviders);
export const hydrated: HydratedProviders = hydrateProviders(parseProviders(config.chainProviders));
export const rebalancedTokens: {
[chainId: string]: {
[assetId: string]: {
Expand Down
4 changes: 2 additions & 2 deletions modules/router/src/services/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import {
jsonifyError,
IVectorChainReader,
DEFAULT_ROUTER_MAX_SAFE_PRICE_IMPACT,
ChainRpcProvider,
} from "@connext/vector-types";
import { JsonRpcProvider } from "@ethersproject/providers";
import { StableSwap } from "@connext/vector-contracts";
import { getAddress } from "@ethersproject/address";
import { BigNumber } from "@ethersproject/bignumber";
Expand Down Expand Up @@ -132,7 +132,7 @@ export const onSwapGivenIn = async (
logger: BaseLogger,
): Promise<Result<{ priceImpact: string; amountOut: BigNumber }, ConfigServiceError>> => {
const { stableAmmChainId, stableAmmAddress } = getConfig();
const stableAmmProvider: JsonRpcProvider = new JsonRpcProvider(getConfig().chainProviders[stableAmmChainId!]);
const stableAmmProvider: ChainRpcProvider = new ChainRpcProvider(stableAmmChainId!, [getConfig().chainProviders[stableAmmChainId!]]);

// if there's no swap, rate is 1:1
if (fromAssetId === toAssetId && fromChainId === toChainId) {
Expand Down
Loading