UNPKG

locklift

Version:

Node JS framework for working with Ever contracts. Inspired by Truffle and Hardhat. Helps you to build, test, run and maintain your smart contracts.

243 lines (214 loc) 7.66 kB
import { ProviderRpcClient } from "everscale-inpage-provider"; import { Clock, EverscaleStandaloneClient, SimpleAccountsStorage, SimpleKeystore, } from "everscale-standalone-client/nodejs"; import chalk from "chalk"; import { Keys } from "./internal/keys"; import { ConfigState, LockliftConfig, NetworkValue } from "./internal/config"; import * as utils from "./utils"; import { Transactions } from "./utils"; import { Factory, FactoryType, Giver } from "./internal/factory"; import { createTracing, Tracing } from "./internal/tracing"; import { createTimeMovement, TimeMovement } from "./internal/timeMovement"; import { LockliftContext } from "./internal/context/lockliftContext"; import "./chaiPlugin/types"; import { initializeExtenders } from "./plugins/utils"; import { getGiverKeyPair } from "./internal/giver/utils"; import { getGiver } from "./internal/giver"; import { logger } from "./internal/logger"; import { TracingTransport } from "./internal/tracing/transport"; import { LockliftNetwork } from "@broxus/locklift-network"; import { ConnectionData } from "everscale-standalone-client"; import { Network } from "./internal/network"; import { ForkService } from "./internal/network/forkService"; export * from "everscale-inpage-provider"; export type { Signer } from "everscale-standalone-client"; export { Dimension, zeroAddress } from "./constants"; export type { LockliftConfig } from "./internal/config"; export type { Giver } from "./internal/factory"; export { toNano, fromNano, getRandomNonce, convertAmount } from "./utils"; export { WalletTypes } from "./types"; export { TraceType, InteractionType } from "./internal/tracing/types"; export { lockliftChai } from "./chaiPlugin"; export { NetworkValue, ConfigState } from "./internal/config"; export class Locklift<FactorySource extends FactoryType> { public readonly utils = utils; #giver?: Giver; #factory: Factory<FactorySource> | undefined; #context: LockliftContext | undefined; #testing: TimeMovement | undefined; #tracing: Tracing | undefined; #network: Network | undefined; private constructor( public readonly provider: ProviderRpcClient, public readonly keystore: SimpleKeystore, private readonly clock: Clock, public readonly transactions: Transactions, ) {} set tracing(tracing: Tracing) { this.#tracing = tracing; } get tracing(): Tracing { if (!this.#tracing) { throw new Error("Testing module not provided"); } return this.#tracing; } set testing(testing: TimeMovement) { this.#testing = testing; } get testing(): TimeMovement { if (!this.#testing) { throw new Error("Testing module not provided"); } return this.#testing; } set context(context: LockliftContext) { this.#context = context; } get context(): LockliftContext { if (!this.#context) { throw new Error("Context not provided, need to provide the network name"); } return this.#context; } set factory(factory: Factory<FactorySource>) { this.#factory = factory; } get factory(): Factory<FactorySource> { if (!this.#factory) { throw new Error("Factory didn't provided"); } return this.#factory; } set network(network: Network) { this.#network = network; } get network(): Network { if (!this.#network) { throw new Error("Network didn't provided"); } return this.#network; } set giver(giver: Giver) { this.#giver = giver; } get giver(): Giver { if (!this.#giver) { throw new Error("Giver not initialized, need to provide the network name"); } return this.#giver; } public static async setup<T extends FactoryType>( config: LockliftConfig<ConfigState.INTERNAL>, network?: keyof LockliftConfig["networks"], ): Promise<Locklift<T>> { if (network && !config.networks[network]) { throw new Error(`Network ${network} not found in config`); } const networkConfig = config.networks[network as string] as NetworkValue<ConfigState.INTERNAL> | undefined; let keystore = new SimpleKeystore(); if (networkConfig) { const giverKeys = getGiverKeyPair(networkConfig.giver); const keys = await Keys.generate(networkConfig.keys); keystore = new SimpleKeystore( [...keys].reduce( (acc, keyPair, idx) => ({ ...acc, [idx]: keyPair, }), {}, ), ); keystore.addKeyPair("giver", giverKeys); } const forkService = networkConfig?.fork && (await ForkService.init({ forkSource: networkConfig.fork.source, forkContractsConfig: networkConfig.fork.contracts, })); const proxyNetwork = new LockliftNetwork({ accountFetcher: networkConfig?.fork && forkService?.accountFetcher, networkConfig: networkConfig?.blockchainConfig, }); await proxyNetwork.initialize(); if ( !!networkConfig && isProxyConnection(networkConfig?.connection) && networkConfig?.connection?.data?.connectionFactory === undefined ) { networkConfig.connection.data.connectionFactory = proxyNetwork.connectionFactory; } const accountsStorage = new SimpleAccountsStorage(); const clock = new Clock(); const provider = new ProviderRpcClient({ provider: EverscaleStandaloneClient.create({ connection: networkConfig?.connection, keystore, clock, accountsStorage, message: networkConfig?.clientConfig?.message, initInput: networkConfig?.clientConfig?.initInput, }).then(client => { if (isProxyConnection(networkConfig?.connection)) { client.setPollingInterval(5); } return client; }), }); try { await provider.ensureInitialized(); } catch (e: any) { logger.printError(`${chalk.bold(`${e.message}`)}`); process.exit(1); } const transactions = new Transactions(provider); const locklift = new Locklift<T>(provider, keystore, clock, transactions); const giver = networkConfig && (await getGiver(networkConfig.giver, provider, accountsStorage)); if (giver) { locklift.giver = giver; } const factory = await Factory.setup<T>( provider, () => locklift.giver, accountsStorage, forkService?.preFetchedAccounts, ); locklift.factory = factory; const tracingTransport = (() => { switch (networkConfig?.connection.type) { case "graphql": return TracingTransport.fromGqlConnection(networkConfig.connection.data.endpoints[0], provider); case "jrpc": return TracingTransport.fromJrpcConnection(provider); case "proxy": return TracingTransport.fromProxyConnection(provider); } })() as TracingTransport; locklift.network = new Network(proxyNetwork, (await keystore.getSigner("0"))!, accountsStorage, provider); locklift.tracing = createTracing({ ever: provider, features: transactions, network: proxyNetwork, factory, tracingTransport, }); if (networkConfig && network) { const timeMovement = await createTimeMovement(clock, networkConfig); const context = new LockliftContext({ config: networkConfig, name: network }); locklift.testing = timeMovement; locklift.context = context; } await initializeExtenders({ locklift, config, network }); return locklift; } } const isProxyConnection = <T extends ConnectionData>( connectionData: T | undefined, ): connectionData is Extract<T, { type: "proxy" }> => { return connectionData?.type === "proxy"; };