diff --git a/.eslintrc.json b/.eslintrc.json index 738b64b7..dd32e924 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -27,6 +27,7 @@ "import/no-cycle": "warn", "simple-import-sort/sort": "warn", "@typescript-eslint/explicit-function-return-type": ["warn", { "allowExpressions": true }], + "@typescript-eslint/no-empty-function": "off", "@typescript-eslint/no-empty-interface": "off", "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_", "varsIgnorePattern": "^_" }], diff --git a/packages/faucet/README.md b/packages/faucet/README.md index e600edeb..9cf560a3 100644 --- a/packages/faucet/README.md +++ b/packages/faucet/README.md @@ -21,7 +21,7 @@ FAUCET_CREDIT_AMOUNT_COSM=10 \ FAUCET_CREDIT_AMOUNT_STAKE=5 \ FAUCET_CONCURRENCY=3 \ FAUCET_MNEMONIC="economy stock theory fatal elder harbor betray wasp final emotion task crumble siren bottom lizard educate guess current outdoor pair theory focus wife stone" \ - ./bin/cosmwasm-faucet start cosmwasm "http://localhost:1317" + ./bin/cosmwasm-faucet start "http://localhost:1317" ``` ## Usage @@ -36,12 +36,10 @@ help Shows a help text and exits version Prints the version and exits generate Generates a random mnemonic, shows derived faucet addresses and exits - 1 Codec - 2 Chain ID + 1 Chain ID start Starts the faucet - 1 Codec - 2 Node base URL, e.g. wss://bov.friendnet-fast.iov.one + 1 Node base URL, e.g. http://localhost:1317 Environment variables @@ -99,7 +97,7 @@ DOCKER_HOST_IP=$(docker run --read-only --rm alpine ip route | awk 'NR==1 {print -e FAUCET_CONCURRENCY \ -p 8000:8000 \ cosmwasm/faucet:manual \ - start cosmwasm "http://$DOCKER_HOST_IP:1317" + start "http://$DOCKER_HOST_IP:1317" ``` ### Using the faucet diff --git a/packages/faucet/package.json b/packages/faucet/package.json index 13a21953..81bc9045 100644 --- a/packages/faucet/package.json +++ b/packages/faucet/package.json @@ -21,7 +21,7 @@ "access": "public" }, "scripts": { - "dev-start": "FAUCET_CREDIT_AMOUNT_COSM=10 FAUCET_CREDIT_AMOUNT_STAKE=5 FAUCET_CONCURRENCY=3 FAUCET_MNEMONIC=\"economy stock theory fatal elder harbor betray wasp final emotion task crumble siren bottom lizard educate guess current outdoor pair theory focus wife stone\" ./bin/cosmwasm-faucet start cosmwasm \"http://localhost:1317\"", + "dev-start": "FAUCET_CREDIT_AMOUNT_COSM=10 FAUCET_CREDIT_AMOUNT_STAKE=5 FAUCET_CONCURRENCY=3 FAUCET_MNEMONIC=\"economy stock theory fatal elder harbor betray wasp final emotion task crumble siren bottom lizard educate guess current outdoor pair theory focus wife stone\" ./bin/cosmwasm-faucet start \"http://localhost:1317\"", "docs": "shx rm -rf docs && typedoc --options typedoc.js", "format": "prettier --write --loglevel warn \"./src/**/*.ts\"", "lint": "eslint --max-warnings 0 \"**/*.{js,ts}\" && tslint -t verbose --project .", @@ -36,8 +36,7 @@ "@iov/bcp": "^2.0.0-alpha.7", "@iov/crypto": "^2.0.0-alpha.7", "@iov/encoding": "^2.0.0-alpha.7", - "@iov/lisk": "^2.0.0-alpha.7", - "@iov/multichain": "^2.0.0-alpha.7", + "@iov/keycontrol": "^2.0.0-alpha.7", "@koa/cors": "^3.0.0", "axios": "^0.19.0", "fast-deep-equal": "^3.1.1", diff --git a/packages/faucet/src/actions/generate.ts b/packages/faucet/src/actions/generate.ts index 2280bb95..e99c0262 100644 --- a/packages/faucet/src/actions/generate.ts +++ b/packages/faucet/src/actions/generate.ts @@ -2,22 +2,21 @@ import { ChainId } from "@iov/bcp"; import { Bip39, Random } from "@iov/crypto"; import { UserProfile } from "@iov/keycontrol"; -import { codecFromString } from "../codec"; import * as constants from "../constants"; import { setSecretAndCreateIdentities } from "../profile"; export async function generate(args: ReadonlyArray): Promise { - if (args.length < 2) { + if (args.length < 1) { throw Error( `Not enough arguments for action 'generate'. See '${constants.binaryName} help' or README for arguments.`, ); } - const codecName = codecFromString(args[0]); - const chainId = args[1] as ChainId; + + const chainId = args[0] as ChainId; const mnemonic = Bip39.encode(Random.getBytes(16)).toString(); console.info(`FAUCET_MNEMONIC="${mnemonic}"`); const profile = new UserProfile(); - await setSecretAndCreateIdentities(profile, mnemonic, chainId, codecName); + await setSecretAndCreateIdentities(profile, mnemonic, chainId); } diff --git a/packages/faucet/src/actions/help.ts b/packages/faucet/src/actions/help.ts index 8b7a6a5f..745e0ba3 100644 --- a/packages/faucet/src/actions/help.ts +++ b/packages/faucet/src/actions/help.ts @@ -11,12 +11,10 @@ help Shows a help text and exits version Prints the version and exits generate Generates a random mnemonic, shows derived faucet addresses and exits - 1 Codec - 2 Chain ID + 1 Chain ID start Starts the faucet - 1 Codec - 2 Node base URL, e.g. wss://bov.friendnet-fast.iov.one + 1 Node base URL, e.g. http://localhost:1317 Environment variables diff --git a/packages/faucet/src/actions/start/start.ts b/packages/faucet/src/actions/start/start.ts index fdb745fb..3d2ff2f3 100644 --- a/packages/faucet/src/actions/start/start.ts +++ b/packages/faucet/src/actions/start/start.ts @@ -1,26 +1,20 @@ // tslint:disable: no-object-mutation import { UserProfile } from "@iov/keycontrol"; -import { MultiChainSigner } from "@iov/multichain"; import cors = require("@koa/cors"); import Koa from "koa"; import bodyParser from "koa-bodyparser"; import { creditAmount, setFractionalDigits } from "../../cashflow"; -import { - codecDefaultFractionalDigits, - codecFromString, - codecImplementation, - createChainConnector, -} from "../../codec"; +import { codecDefaultFractionalDigits, codecImplementation, establishConnection } from "../../codec"; import * as constants from "../../constants"; import { logAccountsState, logSendJob } from "../../debugging"; import { - accountsOfFirstChain, availableTokensFromHolder, identitiesOfFirstWallet, - refillFirstChain, - sendOnFirstChain, - tokenTickersOfFirstChain, + loadAccounts, + loadTokenTickers, + refill, + send, } from "../../multichainhelpers"; import { setSecretAndCreateIdentities } from "../../profile"; import { SendJob } from "../../types"; @@ -35,13 +29,13 @@ function getCount(): number { } export async function start(args: ReadonlyArray): Promise { - if (args.length < 2) { + if (args.length < 1) { throw Error( `Not enough arguments for action 'start'. See '${constants.binaryName} help' or README for arguments.`, ); } - const codec = codecFromString(args[0]); - const blockchainBaseUrl: string = args[1]; + + const blockchainBaseUrl = args[0]; const port = constants.port; @@ -49,34 +43,33 @@ export async function start(args: ReadonlyArray): Promise { if (!constants.mnemonic) { throw new Error("The FAUCET_MNEMONIC environment variable is not set"); } - const signer = new MultiChainSigner(profile); console.info(`Connecting to blockchain ${blockchainBaseUrl} ...`); - const connection = (await signer.addChain(createChainConnector(codec, blockchainBaseUrl))).connection; + const connection = await establishConnection(blockchainBaseUrl); const connectedChainId = connection.chainId(); console.info(`Connected to network: ${connectedChainId}`); - setFractionalDigits(codecDefaultFractionalDigits(codec)); - await setSecretAndCreateIdentities(profile, constants.mnemonic, connectedChainId, codec); + setFractionalDigits(codecDefaultFractionalDigits()); + await setSecretAndCreateIdentities(profile, constants.mnemonic, connectedChainId); - const chainTokens = await tokenTickersOfFirstChain(signer); + const chainTokens = await loadTokenTickers(connection); console.info("Chain tokens:", chainTokens); - const accounts = await accountsOfFirstChain(profile, signer); + const accounts = await loadAccounts(profile, connection); logAccountsState(accounts); let availableTokens = availableTokensFromHolder(accounts[0]); console.info("Available tokens:", availableTokens); setInterval(async () => { - const updatedAccounts = await accountsOfFirstChain(profile, signer); + const updatedAccounts = await loadAccounts(profile, connection); availableTokens = availableTokensFromHolder(updatedAccounts[0]); console.info("Available tokens:", availableTokens); }, 60_000); const distibutorIdentities = identitiesOfFirstWallet(profile).slice(1); - await refillFirstChain(profile, signer); - setInterval(async () => refillFirstChain(profile, signer), 60_000); // ever 60 seconds + await refill(profile, connection); + setInterval(async () => refill(profile, connection), 60_000); // ever 60 seconds console.info("Creating webserver ..."); const api = new Koa(); @@ -95,7 +88,7 @@ export async function start(args: ReadonlyArray): Promise { "See https://github.com/iov-one/iov-faucet for all further information.\n"; break; case "/status": { - const updatedAccounts = await accountsOfFirstChain(profile, signer); + const updatedAccounts = await loadAccounts(profile, connection); context.response.body = { status: "ok", nodeUrl: blockchainBaseUrl, @@ -120,7 +113,7 @@ export async function start(args: ReadonlyArray): Promise { const requestBody = (context.request as any).body; const { address, ticker } = RequestParser.parseCreditBody(requestBody); - if (!codecImplementation(codec).isValidAddress(address)) { + if (!codecImplementation().isValidAddress(address)) { throw new HttpError(400, "Address is not in the expected format for this chain."); } @@ -138,8 +131,8 @@ export async function start(args: ReadonlyArray): Promise { amount: creditAmount(ticker), tokenTicker: ticker, }; - logSendJob(signer, job); - await sendOnFirstChain(profile, signer, job); + logSendJob(job); + await send(profile, connection, job); } catch (e) { console.error(e); throw new HttpError(500, "Sending tokens failed"); diff --git a/packages/faucet/src/codec.spec.ts b/packages/faucet/src/codec.spec.ts index 2176ec63..624bf357 100644 --- a/packages/faucet/src/codec.spec.ts +++ b/packages/faucet/src/codec.spec.ts @@ -1,14 +1 @@ -import { Codec, codecFromString } from "./codec"; - -describe("Codec", () => { - it("can convert string to codec", () => { - expect(codecFromString("lisk")).toEqual(Codec.Lisk); - expect(codecFromString("cosmwasm")).toEqual(Codec.CosmWasm); - - expect(() => codecFromString("")).toThrowError(/not supported/i); - expect(() => codecFromString("bns")).toThrowError(/not supported/i); - expect(() => codecFromString("abc")).toThrowError(/not supported/i); - expect(() => codecFromString("LISK")).toThrowError(/not supported/i); - expect(() => codecFromString("CosmWasm")).toThrowError(/not supported/i); - }); -}); +describe("codec", () => {}); diff --git a/packages/faucet/src/codec.ts b/packages/faucet/src/codec.ts index dab2a092..91b76481 100644 --- a/packages/faucet/src/codec.ts +++ b/packages/faucet/src/codec.ts @@ -1,76 +1,30 @@ -import { createCosmWasmConnector, TokenInfo } from "@cosmwasm/bcp"; -import { ChainConnector, TokenTicker, TxCodec } from "@iov/bcp"; -import { Slip10RawIndex } from "@iov/crypto"; -import { HdPaths } from "@iov/keycontrol"; -import { createLiskConnector } from "@iov/lisk"; +import { CosmWasmCodec, CosmWasmConnection, TokenInfo } from "@cosmwasm/bcp"; +import { TokenTicker, TxCodec } from "@iov/bcp"; -export const enum Codec { - Lisk, - CosmWasm, +const prefix = "cosmos"; +const tokens: readonly TokenInfo[] = [ + { + fractionalDigits: 6, + tokenName: "Fee Token", + tokenTicker: "COSM" as TokenTicker, + denom: "cosm", + }, + { + fractionalDigits: 6, + tokenName: "Staking Token", + tokenTicker: "STAKE" as TokenTicker, + denom: "stake", + }, +]; + +export async function establishConnection(url: string): Promise { + return CosmWasmConnection.establish(url, prefix, tokens); } -export function codecFromString(input: string): Codec { - switch (input) { - case "lisk": - return Codec.Lisk; - case "cosmwasm": - return Codec.CosmWasm; - default: - throw new Error(`Codec '${input}' not supported`); - } +export function codecImplementation(): TxCodec { + return new CosmWasmCodec(prefix, tokens); } -export function createPathBuilderForCodec(codec: Codec): (derivation: number) => readonly Slip10RawIndex[] { - const pathBuilder = (accountIndex: number): readonly Slip10RawIndex[] => { - switch (codec) { - case Codec.Lisk: - return HdPaths.bip44Like(134, accountIndex); - case Codec.CosmWasm: - return HdPaths.cosmos(accountIndex); - default: - throw new Error("No path builder for this codec found"); - } - }; - return pathBuilder; -} - -export function createChainConnector(codec: Codec, url: string): ChainConnector { - switch (codec) { - case Codec.Lisk: - return createLiskConnector(url); - case Codec.CosmWasm: { - const tokens: readonly TokenInfo[] = [ - { - fractionalDigits: 6, - tokenName: "Fee Token", - tokenTicker: "COSM" as TokenTicker, - denom: "cosm", - }, - { - fractionalDigits: 6, - tokenName: "Staking Token", - tokenTicker: "STAKE" as TokenTicker, - denom: "stake", - }, - ]; - return createCosmWasmConnector(url, "cosmos", tokens); - } - default: - throw new Error("No connector for this codec found"); - } -} - -export function codecImplementation(codec: Codec): TxCodec { - return createChainConnector(codec, "unused dummy url").codec; -} - -export function codecDefaultFractionalDigits(codec: Codec): number { - switch (codec) { - case Codec.Lisk: - return 8; - case Codec.CosmWasm: - return 6; - default: - throw new Error("Unknown codec"); - } +export function codecDefaultFractionalDigits(): number { + return 6; } diff --git a/packages/faucet/src/crypto.ts b/packages/faucet/src/crypto.ts deleted file mode 100644 index cfa370e4..00000000 --- a/packages/faucet/src/crypto.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Ed25519HdWallet, Secp256k1HdWallet, Wallet } from "@iov/keycontrol"; - -import { Codec } from "./codec"; - -export function createWalletForCodec(input: Codec, mnemonic: string): Wallet { - switch (input) { - case Codec.Lisk: - return Ed25519HdWallet.fromMnemonic(mnemonic); - case Codec.CosmWasm: - return Secp256k1HdWallet.fromMnemonic(mnemonic); - default: - throw new Error(`Codec '${input}' not supported`); - } -} diff --git a/packages/faucet/src/debugging.ts b/packages/faucet/src/debugging.ts index 1fb4c9ab..a5d7cf64 100644 --- a/packages/faucet/src/debugging.ts +++ b/packages/faucet/src/debugging.ts @@ -1,7 +1,7 @@ import { Account, Amount } from "@iov/bcp"; import { Decimal } from "@iov/encoding"; -import { MultiChainSigner } from "@iov/multichain"; +import { codecImplementation } from "./codec"; import { SendJob } from "./types"; /** A string representation of a coin in a human-readable format that can change at any time */ @@ -30,8 +30,8 @@ export function logAccountsState(accounts: ReadonlyArray): void { console.info("Distributors:\n" + distributors.map(r => ` ${debugAccount(r)}`).join("\n")); } -export function logSendJob(signer: MultiChainSigner, job: SendJob): void { - const from = signer.identityToAddress(job.sender); +export function logSendJob(job: SendJob): void { + const from = codecImplementation().identityToAddress(job.sender); const to = job.recipient; const amount = debugAmount(job.amount); console.info(`Sending ${amount} from ${from} to ${to} ...`); diff --git a/packages/faucet/src/multichainhelpers.ts b/packages/faucet/src/multichainhelpers.ts index d54b8891..a8fc46fe 100644 --- a/packages/faucet/src/multichainhelpers.ts +++ b/packages/faucet/src/multichainhelpers.ts @@ -1,5 +1,6 @@ import { Account, + BlockchainConnection, Identity, isBlockInfoFailed, isBlockInfoPending, @@ -7,9 +8,9 @@ import { TokenTicker, } from "@iov/bcp"; import { UserProfile } from "@iov/keycontrol"; -import { MultiChainSigner } from "@iov/multichain"; import { needsRefill, refillAmount } from "./cashflow"; +import { codecImplementation } from "./codec"; import { debugAccount, logAccountsState, logSendJob } from "./debugging"; import { SendJob } from "./types"; @@ -22,17 +23,17 @@ export function identitiesOfFirstWallet(profile: UserProfile): ReadonlyArray> { - const addresses = identitiesOfFirstWallet(profile).map(identity => signer.identityToAddress(identity)); - const chainId = signer.chainIds()[0]; + const codec = codecImplementation(); + const addresses = identitiesOfFirstWallet(profile).map(identity => codec.identityToAddress(identity)); // tslint:disable-next-line: readonly-array const out: Account[] = []; for (const address of addresses) { - const response = await signer.connection(chainId).getAccount({ address: address }); + const response = await connection.getAccount({ address: address }); if (response) { out.push({ address: response.address, @@ -49,35 +50,36 @@ export async function accountsOfFirstChain( return out; } -export async function tokenTickersOfFirstChain( - signer: MultiChainSigner, +export async function loadTokenTickers( + connection: BlockchainConnection, ): Promise> { - const chainId = signer.chainIds()[0]; - return (await signer.connection(chainId).getAllTokens()).map(token => token.tokenTicker); + return (await connection.getAllTokens()).map(token => token.tokenTicker); } /** * Creates and posts a send transaction. Then waits until the transaction is in a block. */ -export async function sendOnFirstChain( +export async function send( profile: UserProfile, - signer: MultiChainSigner, + connection: BlockchainConnection, job: SendJob, ): Promise { - const chainId = signer.chainIds()[0]; - const connection = signer.connection(chainId); + const codec = codecImplementation(); const sendWithFee = await connection.withDefaultFee({ kind: "bcp/send", - chainId: chainId, - sender: signer.identityToAddress(job.sender), + chainId: connection.chainId(), + sender: codec.identityToAddress(job.sender), senderPubkey: job.sender.pubkey, recipient: job.recipient, memo: "We ❤️ developers – iov.one", amount: job.amount, }); - const post = await signer.signAndPost(job.sender, sendWithFee); + const nonce = await connection.getNonce({ pubkey: job.sender.pubkey }); + const signed = await profile.signTransaction(job.sender, sendWithFee, codec, nonce); + + const post = await connection.postTx(codec.bytesToPost(signed)); const blockInfo = await post.blockInfo.waitFor(info => !isBlockInfoPending(info)); if (isBlockInfoFailed(blockInfo)) { throw new Error(`Sending tokens failed. Code: ${blockInfo.code}, message: ${blockInfo.message}`); @@ -88,15 +90,13 @@ export function availableTokensFromHolder(holderAccount: Account): ReadonlyArray return holderAccount.balance.map(coin => coin.tokenTicker); } -export async function refillFirstChain(profile: UserProfile, signer: MultiChainSigner): Promise { - const chainId = signer.chainIds()[0]; - - console.info(`Connected to network: ${chainId}`); - console.info(`Tokens on network: ${(await tokenTickersOfFirstChain(signer)).join(", ")}`); +export async function refill(profile: UserProfile, connection: BlockchainConnection): Promise { + console.info(`Connected to network: ${connection.chainId()}`); + console.info(`Tokens on network: ${(await loadTokenTickers(connection)).join(", ")}`); const holderIdentity = identitiesOfFirstWallet(profile)[0]; - const accounts = await accountsOfFirstChain(profile, signer); + const accounts = await loadAccounts(profile, connection); logAccountsState(accounts); const holderAccount = accounts[0]; const distributorAccounts = accounts.slice(1); @@ -124,13 +124,13 @@ export async function refillFirstChain(profile: UserProfile, signer: MultiChainS } if (jobs.length > 0) { for (const job of jobs) { - logSendJob(signer, job); - await sendOnFirstChain(profile, signer, job); + logSendJob(job); + await send(profile, connection, job); await sleep(50); } console.info("Done refilling accounts."); - logAccountsState(await accountsOfFirstChain(profile, signer)); + logAccountsState(await loadAccounts(profile, connection)); } else { console.info("Nothing to be done. Anyways, thanks for checking."); } diff --git a/packages/faucet/src/profile.ts b/packages/faucet/src/profile.ts index 36c0352e..b5c4b766 100644 --- a/packages/faucet/src/profile.ts +++ b/packages/faucet/src/profile.ts @@ -1,34 +1,30 @@ import { ChainId } from "@iov/bcp"; -import { UserProfile } from "@iov/keycontrol"; +import { HdPaths, Secp256k1HdWallet, UserProfile } from "@iov/keycontrol"; -import { Codec, codecImplementation, createPathBuilderForCodec } from "./codec"; +import { codecImplementation } from "./codec"; import * as constants from "./constants"; -import { createWalletForCodec } from "./crypto"; import { debugPath } from "./hdpaths"; export async function setSecretAndCreateIdentities( profile: UserProfile, mnemonic: string, chainId: ChainId, - codecName: Codec, ): Promise { if (profile.wallets.value.length !== 0) { throw new Error("Profile already contains wallets"); } - const wallet = profile.addWallet(createWalletForCodec(codecName, mnemonic)); - - const pathBuilder = createPathBuilderForCodec(codecName); + const wallet = profile.addWallet(Secp256k1HdWallet.fromMnemonic(mnemonic)); // first account is the token holder const numberOfIdentities = 1 + constants.concurrency; for (let i = 0; i < numberOfIdentities; i++) { // create - const path = pathBuilder(i); + const path = HdPaths.cosmos(i); const identity = await profile.createIdentity(wallet.id, chainId, path); // log const role = i === 0 ? "token holder " : `distributor ${i}`; - const address = codecImplementation(codecName).identityToAddress(identity); + const address = codecImplementation().identityToAddress(identity); console.info(`Created ${role} (${debugPath(path)}): ${address}`); } } diff --git a/yarn.lock b/yarn.lock index c0fb6f1d..80d687b2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -130,15 +130,6 @@ bn.js "^4.11.8" readonly-date "^1.0.0" -"@iov/jsonrpc@^2.0.0-alpha.7": - version "2.0.0-alpha.7" - resolved "https://registry.yarnpkg.com/@iov/jsonrpc/-/jsonrpc-2.0.0-alpha.7.tgz#7bff8e1f21d52ff07482212ded8cc00e01dda964" - integrity sha512-eVCfNi3Zg4ZUEXOxhzRb3kcoBupBGQWmU4pYu7OYBi3uvuUz8KP6kcIdsy+51+y/nqrnk3H2Ur7MWCzwsu215w== - dependencies: - "@iov/encoding" "^2.0.0-alpha.7" - "@iov/stream" "^2.0.0-alpha.7" - xstream "^11.10.0" - "@iov/keycontrol@^2.0.0-alpha.7": version "2.0.0-alpha.7" resolved "https://registry.yarnpkg.com/@iov/keycontrol/-/keycontrol-2.0.0-alpha.7.tgz#d115a1b536664afb64b40a6db87aaf19f8d07afd" @@ -159,35 +150,6 @@ type-tagger "^1.0.0" xstream "^11.10.0" -"@iov/lisk@^2.0.0-alpha.7": - version "2.0.0-alpha.7" - resolved "https://registry.yarnpkg.com/@iov/lisk/-/lisk-2.0.0-alpha.7.tgz#5ff6c617ac00e6be736ada34ad68dce0efd64637" - integrity sha512-m5mr2NDU7pxuS8d6SBXCZ1WBtCSXtV+EWqMEIuPSCJwZxnwmWotowX+WhSYn+dGyuvgTd7DpfQ5C6pliAyhcyQ== - dependencies: - "@iov/bcp" "^2.0.0-alpha.7" - "@iov/crypto" "^2.0.0-alpha.7" - "@iov/encoding" "^2.0.0-alpha.7" - "@iov/keycontrol" "^2.0.0-alpha.7" - "@iov/stream" "^2.0.0-alpha.7" - "@types/long" "^4.0.0" - axios "^0.19.0" - fast-deep-equal "^3.1.1" - long "^4.0.0" - readonly-date "^1.0.0" - xstream "^11.10.0" - -"@iov/multichain@^2.0.0-alpha.7": - version "2.0.0-alpha.7" - resolved "https://registry.yarnpkg.com/@iov/multichain/-/multichain-2.0.0-alpha.7.tgz#29ec9f61ec2fa60c17d462c9be48feb7196c28ba" - integrity sha512-hhEyqalADrQa4JS99JqawM7jWLYGqb52Ipq/49Zz5eDG9/nj9QyLn5nayWLTbm60ZXzHvvGr5oJpZx8Xb2PzfA== - dependencies: - "@iov/bcp" "^2.0.0-alpha.7" - "@iov/encoding" "^2.0.0-alpha.7" - "@iov/jsonrpc" "^2.0.0-alpha.7" - "@iov/keycontrol" "^2.0.0-alpha.7" - "@types/long" "^4.0.0" - long "^4.0.0" - "@iov/stream@^2.0.0-alpha.7": version "2.0.0-alpha.7" resolved "https://registry.yarnpkg.com/@iov/stream/-/stream-2.0.0-alpha.7.tgz#212c3f684f592ec04ac43e166183d946a49b895c" @@ -1124,11 +1086,6 @@ "@types/abstract-leveldown" "*" "@types/node" "*" -"@types/long@^4.0.0": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9" - integrity sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w== - "@types/memdown@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/memdown/-/memdown-3.0.0.tgz#2d909cb507afd341e3132d77dafa213347e47455"