From 102488cb068f87fbc52c2f8f68c8b53074aa87d2 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 30 Jan 2020 08:03:10 +0100 Subject: [PATCH 01/10] Remove Lisk support --- packages/faucet/package.json | 1 - packages/faucet/src/codec.spec.ts | 2 +- packages/faucet/src/codec.ts | 10 ---------- packages/faucet/src/crypto.ts | 4 +--- yarn.lock | 17 ----------------- 5 files changed, 2 insertions(+), 32 deletions(-) diff --git a/packages/faucet/package.json b/packages/faucet/package.json index 13a21953..d051943e 100644 --- a/packages/faucet/package.json +++ b/packages/faucet/package.json @@ -36,7 +36,6 @@ "@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", "@koa/cors": "^3.0.0", "axios": "^0.19.0", diff --git a/packages/faucet/src/codec.spec.ts b/packages/faucet/src/codec.spec.ts index 2176ec63..5928ce09 100644 --- a/packages/faucet/src/codec.spec.ts +++ b/packages/faucet/src/codec.spec.ts @@ -2,10 +2,10 @@ 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("lisk")).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); diff --git a/packages/faucet/src/codec.ts b/packages/faucet/src/codec.ts index dab2a092..035a3680 100644 --- a/packages/faucet/src/codec.ts +++ b/packages/faucet/src/codec.ts @@ -2,17 +2,13 @@ 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"; export const enum Codec { - Lisk, CosmWasm, } export function codecFromString(input: string): Codec { switch (input) { - case "lisk": - return Codec.Lisk; case "cosmwasm": return Codec.CosmWasm; default: @@ -23,8 +19,6 @@ export function codecFromString(input: string): Codec { 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: @@ -36,8 +30,6 @@ export function createPathBuilderForCodec(codec: Codec): (derivation: number) => export function createChainConnector(codec: Codec, url: string): ChainConnector { switch (codec) { - case Codec.Lisk: - return createLiskConnector(url); case Codec.CosmWasm: { const tokens: readonly TokenInfo[] = [ { @@ -66,8 +58,6 @@ export function codecImplementation(codec: Codec): TxCodec { export function codecDefaultFractionalDigits(codec: Codec): number { switch (codec) { - case Codec.Lisk: - return 8; case Codec.CosmWasm: return 6; default: diff --git a/packages/faucet/src/crypto.ts b/packages/faucet/src/crypto.ts index cfa370e4..a68c7d41 100644 --- a/packages/faucet/src/crypto.ts +++ b/packages/faucet/src/crypto.ts @@ -1,11 +1,9 @@ -import { Ed25519HdWallet, Secp256k1HdWallet, Wallet } from "@iov/keycontrol"; +import { 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: diff --git a/yarn.lock b/yarn.lock index c0fb6f1d..32607f41 100644 --- a/yarn.lock +++ b/yarn.lock @@ -159,23 +159,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" From ddf2bf1c2ffde4d94cf877e021cd3009281f8394 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 30 Jan 2020 08:17:35 +0100 Subject: [PATCH 02/10] Remove codec parameter --- .eslintrc.json | 1 + packages/faucet/README.md | 10 ++- packages/faucet/package.json | 2 +- packages/faucet/src/actions/generate.ts | 9 ++- packages/faucet/src/actions/help.ts | 6 +- packages/faucet/src/actions/start/start.ts | 21 +++--- packages/faucet/src/codec.spec.ts | 15 +---- packages/faucet/src/codec.ts | 78 ++++++---------------- packages/faucet/src/crypto.ts | 12 ---- packages/faucet/src/profile.ts | 14 ++-- 10 files changed, 46 insertions(+), 122 deletions(-) delete mode 100644 packages/faucet/src/crypto.ts 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 d051943e..dcde5915 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 .", 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..94396c1e 100644 --- a/packages/faucet/src/actions/start/start.ts +++ b/packages/faucet/src/actions/start/start.ts @@ -6,12 +6,7 @@ import Koa from "koa"; import bodyParser from "koa-bodyparser"; import { creditAmount, setFractionalDigits } from "../../cashflow"; -import { - codecDefaultFractionalDigits, - codecFromString, - codecImplementation, - createChainConnector, -} from "../../codec"; +import { codecDefaultFractionalDigits, codecImplementation, createChainConnector } from "../../codec"; import * as constants from "../../constants"; import { logAccountsState, logSendJob } from "../../debugging"; import { @@ -35,13 +30,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; @@ -51,13 +46,13 @@ export async function start(args: ReadonlyArray): Promise { } const signer = new MultiChainSigner(profile); console.info(`Connecting to blockchain ${blockchainBaseUrl} ...`); - const connection = (await signer.addChain(createChainConnector(codec, blockchainBaseUrl))).connection; + const connection = (await signer.addChain(createChainConnector(blockchainBaseUrl))).connection; 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); console.info("Chain tokens:", chainTokens); @@ -120,7 +115,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."); } diff --git a/packages/faucet/src/codec.spec.ts b/packages/faucet/src/codec.spec.ts index 5928ce09..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("cosmwasm")).toEqual(Codec.CosmWasm); - - expect(() => codecFromString("")).toThrowError(/not supported/i); - expect(() => codecFromString("lisk")).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 035a3680..624a92b1 100644 --- a/packages/faucet/src/codec.ts +++ b/packages/faucet/src/codec.ts @@ -1,66 +1,28 @@ import { createCosmWasmConnector, TokenInfo } from "@cosmwasm/bcp"; import { ChainConnector, TokenTicker, TxCodec } from "@iov/bcp"; -import { Slip10RawIndex } from "@iov/crypto"; -import { HdPaths } from "@iov/keycontrol"; -export const enum Codec { - CosmWasm, +export function createChainConnector(url: string): ChainConnector { + 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); } -export function codecFromString(input: string): Codec { - switch (input) { - case "cosmwasm": - return Codec.CosmWasm; - default: - throw new Error(`Codec '${input}' not supported`); - } +export function codecImplementation(): TxCodec { + return createChainConnector("unused dummy url").codec; } -export function createPathBuilderForCodec(codec: Codec): (derivation: number) => readonly Slip10RawIndex[] { - const pathBuilder = (accountIndex: number): readonly Slip10RawIndex[] => { - switch (codec) { - 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.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.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 a68c7d41..00000000 --- a/packages/faucet/src/crypto.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Secp256k1HdWallet, Wallet } from "@iov/keycontrol"; - -import { Codec } from "./codec"; - -export function createWalletForCodec(input: Codec, mnemonic: string): Wallet { - switch (input) { - case Codec.CosmWasm: - return Secp256k1HdWallet.fromMnemonic(mnemonic); - default: - throw new Error(`Codec '${input}' not supported`); - } -} 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}`); } } From fbbbbcaeff2b4a3b6166852726c6ca805093f8a8 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 30 Jan 2020 10:22:56 +0100 Subject: [PATCH 03/10] Implement sendOnFirstChain without MultiChainSigner --- packages/faucet/src/actions/start/start.ts | 4 ++-- packages/faucet/src/debugging.ts | 6 +++--- packages/faucet/src/multichainhelpers.ts | 21 +++++++++++++-------- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/packages/faucet/src/actions/start/start.ts b/packages/faucet/src/actions/start/start.ts index 94396c1e..43789c4b 100644 --- a/packages/faucet/src/actions/start/start.ts +++ b/packages/faucet/src/actions/start/start.ts @@ -133,8 +133,8 @@ export async function start(args: ReadonlyArray): Promise { amount: creditAmount(ticker), tokenTicker: ticker, }; - logSendJob(signer, job); - await sendOnFirstChain(profile, signer, job); + logSendJob(job); + await sendOnFirstChain(profile, connection, job); } catch (e) { console.error(e); throw new HttpError(500, "Sending tokens failed"); 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..cedcac8d 100644 --- a/packages/faucet/src/multichainhelpers.ts +++ b/packages/faucet/src/multichainhelpers.ts @@ -1,5 +1,6 @@ import { Account, + BlockchainConnection, Identity, isBlockInfoFailed, isBlockInfoPending, @@ -10,6 +11,7 @@ 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"; @@ -61,23 +63,25 @@ export async function tokenTickersOfFirstChain( */ export async function sendOnFirstChain( 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}`); @@ -90,6 +94,7 @@ export function availableTokensFromHolder(holderAccount: Account): ReadonlyArray export async function refillFirstChain(profile: UserProfile, signer: MultiChainSigner): Promise { const chainId = signer.chainIds()[0]; + const connection = signer.connection(chainId); console.info(`Connected to network: ${chainId}`); console.info(`Tokens on network: ${(await tokenTickersOfFirstChain(signer)).join(", ")}`); @@ -124,8 +129,8 @@ 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 sendOnFirstChain(profile, connection, job); await sleep(50); } From 11dc128d39537a7c93f6f9f9d7743799c7015cc0 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 30 Jan 2020 10:25:15 +0100 Subject: [PATCH 04/10] Implement accountsOfFirstChain without MultiChainSigner --- packages/faucet/src/actions/start/start.ts | 6 +++--- packages/faucet/src/multichainhelpers.ts | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/faucet/src/actions/start/start.ts b/packages/faucet/src/actions/start/start.ts index 43789c4b..4b5303ab 100644 --- a/packages/faucet/src/actions/start/start.ts +++ b/packages/faucet/src/actions/start/start.ts @@ -57,13 +57,13 @@ export async function start(args: ReadonlyArray): Promise { const chainTokens = await tokenTickersOfFirstChain(signer); console.info("Chain tokens:", chainTokens); - const accounts = await accountsOfFirstChain(profile, signer); + const accounts = await accountsOfFirstChain(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 accountsOfFirstChain(profile, connection); availableTokens = availableTokensFromHolder(updatedAccounts[0]); console.info("Available tokens:", availableTokens); }, 60_000); @@ -90,7 +90,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 accountsOfFirstChain(profile, connection); context.response.body = { status: "ok", nodeUrl: blockchainBaseUrl, diff --git a/packages/faucet/src/multichainhelpers.ts b/packages/faucet/src/multichainhelpers.ts index cedcac8d..42b7898c 100644 --- a/packages/faucet/src/multichainhelpers.ts +++ b/packages/faucet/src/multichainhelpers.ts @@ -26,15 +26,15 @@ 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, @@ -101,7 +101,7 @@ export async function refillFirstChain(profile: UserProfile, signer: MultiChainS const holderIdentity = identitiesOfFirstWallet(profile)[0]; - const accounts = await accountsOfFirstChain(profile, signer); + const accounts = await accountsOfFirstChain(profile, connection); logAccountsState(accounts); const holderAccount = accounts[0]; const distributorAccounts = accounts.slice(1); @@ -135,7 +135,7 @@ export async function refillFirstChain(profile: UserProfile, signer: MultiChainS } console.info("Done refilling accounts."); - logAccountsState(await accountsOfFirstChain(profile, signer)); + logAccountsState(await accountsOfFirstChain(profile, connection)); } else { console.info("Nothing to be done. Anyways, thanks for checking."); } From 36e86543cbf244f613914a7751e9c2cffe643843 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 30 Jan 2020 10:48:26 +0100 Subject: [PATCH 05/10] Let tokenTickersOfFirstChain not depend on MultiChainSigner --- packages/faucet/src/actions/start/start.ts | 2 +- packages/faucet/src/multichainhelpers.ts | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/faucet/src/actions/start/start.ts b/packages/faucet/src/actions/start/start.ts index 4b5303ab..64da6e5a 100644 --- a/packages/faucet/src/actions/start/start.ts +++ b/packages/faucet/src/actions/start/start.ts @@ -54,7 +54,7 @@ export async function start(args: ReadonlyArray): Promise { setFractionalDigits(codecDefaultFractionalDigits()); await setSecretAndCreateIdentities(profile, constants.mnemonic, connectedChainId); - const chainTokens = await tokenTickersOfFirstChain(signer); + const chainTokens = await tokenTickersOfFirstChain(connection); console.info("Chain tokens:", chainTokens); const accounts = await accountsOfFirstChain(profile, connection); diff --git a/packages/faucet/src/multichainhelpers.ts b/packages/faucet/src/multichainhelpers.ts index 42b7898c..5040cafc 100644 --- a/packages/faucet/src/multichainhelpers.ts +++ b/packages/faucet/src/multichainhelpers.ts @@ -52,10 +52,9 @@ export async function accountsOfFirstChain( } export async function tokenTickersOfFirstChain( - signer: MultiChainSigner, + 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); } /** @@ -97,7 +96,7 @@ export async function refillFirstChain(profile: UserProfile, signer: MultiChainS const connection = signer.connection(chainId); console.info(`Connected to network: ${chainId}`); - console.info(`Tokens on network: ${(await tokenTickersOfFirstChain(signer)).join(", ")}`); + console.info(`Tokens on network: ${(await tokenTickersOfFirstChain(connection)).join(", ")}`); const holderIdentity = identitiesOfFirstWallet(profile)[0]; From 6ea963c87db132e98e1002bd18666882897604ab Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 30 Jan 2020 10:51:16 +0100 Subject: [PATCH 06/10] Remove remaining uses of MultiChainSigner --- packages/faucet/src/actions/start/start.ts | 8 +++----- packages/faucet/src/multichainhelpers.ts | 11 +++++------ 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/packages/faucet/src/actions/start/start.ts b/packages/faucet/src/actions/start/start.ts index 64da6e5a..fcf90141 100644 --- a/packages/faucet/src/actions/start/start.ts +++ b/packages/faucet/src/actions/start/start.ts @@ -1,6 +1,5 @@ // 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"; @@ -44,9 +43,8 @@ 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(blockchainBaseUrl))).connection; + const connection = await createChainConnector(blockchainBaseUrl).establishConnection(); const connectedChainId = connection.chainId(); console.info(`Connected to network: ${connectedChainId}`); @@ -70,8 +68,8 @@ export async function start(args: ReadonlyArray): Promise { const distibutorIdentities = identitiesOfFirstWallet(profile).slice(1); - await refillFirstChain(profile, signer); - setInterval(async () => refillFirstChain(profile, signer), 60_000); // ever 60 seconds + await refillFirstChain(profile, connection); + setInterval(async () => refillFirstChain(profile, connection), 60_000); // ever 60 seconds console.info("Creating webserver ..."); const api = new Koa(); diff --git a/packages/faucet/src/multichainhelpers.ts b/packages/faucet/src/multichainhelpers.ts index 5040cafc..f292d228 100644 --- a/packages/faucet/src/multichainhelpers.ts +++ b/packages/faucet/src/multichainhelpers.ts @@ -8,7 +8,6 @@ import { TokenTicker, } from "@iov/bcp"; import { UserProfile } from "@iov/keycontrol"; -import { MultiChainSigner } from "@iov/multichain"; import { needsRefill, refillAmount } from "./cashflow"; import { codecImplementation } from "./codec"; @@ -91,11 +90,11 @@ 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]; - const connection = signer.connection(chainId); - - console.info(`Connected to network: ${chainId}`); +export async function refillFirstChain( + profile: UserProfile, + connection: BlockchainConnection, +): Promise { + console.info(`Connected to network: ${connection.chainId()}`); console.info(`Tokens on network: ${(await tokenTickersOfFirstChain(connection)).join(", ")}`); const holderIdentity = identitiesOfFirstWallet(profile)[0]; From 3fff813810b63797b672a8b47255a19da8e990f0 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 30 Jan 2020 10:52:29 +0100 Subject: [PATCH 07/10] Remove dependency on @iov/multichain --- packages/faucet/package.json | 1 - yarn.lock | 26 -------------------------- 2 files changed, 27 deletions(-) diff --git a/packages/faucet/package.json b/packages/faucet/package.json index dcde5915..b37d78af 100644 --- a/packages/faucet/package.json +++ b/packages/faucet/package.json @@ -36,7 +36,6 @@ "@iov/bcp": "^2.0.0-alpha.7", "@iov/crypto": "^2.0.0-alpha.7", "@iov/encoding": "^2.0.0-alpha.7", - "@iov/multichain": "^2.0.0-alpha.7", "@koa/cors": "^3.0.0", "axios": "^0.19.0", "fast-deep-equal": "^3.1.1", diff --git a/yarn.lock b/yarn.lock index 32607f41..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,18 +150,6 @@ type-tagger "^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" @@ -1107,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" From cb3df5742613f96e1774647ca627f9fb910588a9 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 30 Jan 2020 11:00:44 +0100 Subject: [PATCH 08/10] Add missing runtime dependency @iov/keycontrol to faucet --- packages/faucet/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/faucet/package.json b/packages/faucet/package.json index b37d78af..81bc9045 100644 --- a/packages/faucet/package.json +++ b/packages/faucet/package.json @@ -36,6 +36,7 @@ "@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", "@koa/cors": "^3.0.0", "axios": "^0.19.0", "fast-deep-equal": "^3.1.1", From 84c5998ca80d960eb9934716e87a655e3449d588 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 30 Jan 2020 12:25:43 +0100 Subject: [PATCH 09/10] Remove references to "first chain" --- packages/faucet/src/actions/start/start.ts | 22 +++++++++++----------- packages/faucet/src/multichainhelpers.ts | 19 ++++++++----------- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/packages/faucet/src/actions/start/start.ts b/packages/faucet/src/actions/start/start.ts index fcf90141..c86b2637 100644 --- a/packages/faucet/src/actions/start/start.ts +++ b/packages/faucet/src/actions/start/start.ts @@ -9,12 +9,12 @@ import { codecDefaultFractionalDigits, codecImplementation, createChainConnector 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"; @@ -52,24 +52,24 @@ export async function start(args: ReadonlyArray): Promise { setFractionalDigits(codecDefaultFractionalDigits()); await setSecretAndCreateIdentities(profile, constants.mnemonic, connectedChainId); - const chainTokens = await tokenTickersOfFirstChain(connection); + const chainTokens = await loadTokenTickers(connection); console.info("Chain tokens:", chainTokens); - const accounts = await accountsOfFirstChain(profile, connection); + 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, connection); + 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, connection); - setInterval(async () => refillFirstChain(profile, connection), 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(); @@ -88,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, connection); + const updatedAccounts = await loadAccounts(profile, connection); context.response.body = { status: "ok", nodeUrl: blockchainBaseUrl, @@ -132,7 +132,7 @@ export async function start(args: ReadonlyArray): Promise { tokenTicker: ticker, }; logSendJob(job); - await sendOnFirstChain(profile, connection, job); + await send(profile, connection, job); } catch (e) { console.error(e); throw new HttpError(500, "Sending tokens failed"); diff --git a/packages/faucet/src/multichainhelpers.ts b/packages/faucet/src/multichainhelpers.ts index f292d228..a8fc46fe 100644 --- a/packages/faucet/src/multichainhelpers.ts +++ b/packages/faucet/src/multichainhelpers.ts @@ -23,7 +23,7 @@ export function identitiesOfFirstWallet(profile: UserProfile): ReadonlyArray> { @@ -50,7 +50,7 @@ export async function accountsOfFirstChain( return out; } -export async function tokenTickersOfFirstChain( +export async function loadTokenTickers( connection: BlockchainConnection, ): Promise> { return (await connection.getAllTokens()).map(token => token.tokenTicker); @@ -59,7 +59,7 @@ export async function tokenTickersOfFirstChain( /** * 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, connection: BlockchainConnection, job: SendJob, @@ -90,16 +90,13 @@ export function availableTokensFromHolder(holderAccount: Account): ReadonlyArray return holderAccount.balance.map(coin => coin.tokenTicker); } -export async function refillFirstChain( - profile: UserProfile, - connection: BlockchainConnection, -): Promise { +export async function refill(profile: UserProfile, connection: BlockchainConnection): Promise { console.info(`Connected to network: ${connection.chainId()}`); - console.info(`Tokens on network: ${(await tokenTickersOfFirstChain(connection)).join(", ")}`); + console.info(`Tokens on network: ${(await loadTokenTickers(connection)).join(", ")}`); const holderIdentity = identitiesOfFirstWallet(profile)[0]; - const accounts = await accountsOfFirstChain(profile, connection); + const accounts = await loadAccounts(profile, connection); logAccountsState(accounts); const holderAccount = accounts[0]; const distributorAccounts = accounts.slice(1); @@ -128,12 +125,12 @@ export async function refillFirstChain( if (jobs.length > 0) { for (const job of jobs) { logSendJob(job); - await sendOnFirstChain(profile, connection, job); + await send(profile, connection, job); await sleep(50); } console.info("Done refilling accounts."); - logAccountsState(await accountsOfFirstChain(profile, connection)); + logAccountsState(await loadAccounts(profile, connection)); } else { console.info("Nothing to be done. Anyways, thanks for checking."); } From c41f42193e9b8f1387039ae9e67145956ae52d93 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 30 Jan 2020 12:35:30 +0100 Subject: [PATCH 10/10] Simplify codecImplementation() and establishConnection() --- packages/faucet/src/actions/start/start.ts | 4 +-- packages/faucet/src/codec.ts | 40 ++++++++++++---------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/packages/faucet/src/actions/start/start.ts b/packages/faucet/src/actions/start/start.ts index c86b2637..3d2ff2f3 100644 --- a/packages/faucet/src/actions/start/start.ts +++ b/packages/faucet/src/actions/start/start.ts @@ -5,7 +5,7 @@ import Koa from "koa"; import bodyParser from "koa-bodyparser"; import { creditAmount, setFractionalDigits } from "../../cashflow"; -import { codecDefaultFractionalDigits, codecImplementation, createChainConnector } from "../../codec"; +import { codecDefaultFractionalDigits, codecImplementation, establishConnection } from "../../codec"; import * as constants from "../../constants"; import { logAccountsState, logSendJob } from "../../debugging"; import { @@ -44,7 +44,7 @@ export async function start(args: ReadonlyArray): Promise { throw new Error("The FAUCET_MNEMONIC environment variable is not set"); } console.info(`Connecting to blockchain ${blockchainBaseUrl} ...`); - const connection = await createChainConnector(blockchainBaseUrl).establishConnection(); + const connection = await establishConnection(blockchainBaseUrl); const connectedChainId = connection.chainId(); console.info(`Connected to network: ${connectedChainId}`); diff --git a/packages/faucet/src/codec.ts b/packages/faucet/src/codec.ts index 624a92b1..91b76481 100644 --- a/packages/faucet/src/codec.ts +++ b/packages/faucet/src/codec.ts @@ -1,26 +1,28 @@ -import { createCosmWasmConnector, TokenInfo } from "@cosmwasm/bcp"; -import { ChainConnector, TokenTicker, TxCodec } from "@iov/bcp"; +import { CosmWasmCodec, CosmWasmConnection, TokenInfo } from "@cosmwasm/bcp"; +import { TokenTicker, TxCodec } from "@iov/bcp"; -export function createChainConnector(url: string): ChainConnector { - 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); +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 codecImplementation(): TxCodec { - return createChainConnector("unused dummy url").codec; + return new CosmWasmCodec(prefix, tokens); } export function codecDefaultFractionalDigits(): number {