diff --git a/packages/faucet/README.md b/packages/faucet/README.md new file mode 100644 index 0000000000..cc80b73928 --- /dev/null +++ b/packages/faucet/README.md @@ -0,0 +1,99 @@ +# @cosmwasm/faucet + +The faucet is built as part of the monorepo. In the repo root do: + +``` +yarn install +yarn build +``` + +Then start it for a Wasmd development blockchain using: + +``` +cd packages/faucet +yarn dev-start +``` + +Advanced users that want to provide their custom config can start as follows: + +``` +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/cosm-faucet start cosmwasm "http://localhost:1317" +``` + +## Usage + +``` +sage: cosmwasm-faucet action [arguments...] + +Positional arguments per action are listed below. Arguments in parentheses are optional. + +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 + +start Starts the faucet + 1 Codec + 2 Node base URL, e.g. wss://bov.friendnet-fast.iov.one + +Environment variables + +FAUCET_CONCURRENCY Number of distributor accounts. Defaults to 5. +FAUCET_PORT Port of the webserver. Defaults to 8000. +FAUCET_MNEMONIC Secret mnemonic that serves as the base secret for the + faucet HD accounts +FAUCET_CREDIT_AMOUNT_TKN Send this amount of TKN to a user requesting TKN. TKN is + a placeholder for the token ticker. Defaults to 10. +FAUCET_REFILL_FACTOR Send factor times credit amount on refilling. Defauls to 8. +FAUCET_REFILL_THRESHOLD Refill when balance gets below factor times credit amount. + Defaults to 20. +``` + +### Faucet HD wallet + +The faucet uses standard HD paths for each blockchain, e.g. + +``` +IOV m/44'/234'/a' +Lisk m/44'/134'/a' +Ethereum m/44'/60'/0'/0/a +CosmWasm m/44'/118'/0'/0/a +``` + +where `a` is a 0-based index of the account. Account 0 is the token holder and +account 1...FAUCET_CONCURRENCY are the distributor accounts. + +This means the token holder account can be accessed using the Neuma wallet when +the same mnemonic is used. Accessing the distributor accounts will be possible +as soon as there is +[multi account support](https://github.com/iov-one/ponferrada/milestone/3). + +### Using the faucet + +Now that the faucet has been started up, you can send credit requests to it. +This can be done with a simple http POST request. These commands assume the +faucet is running locally, be sure to change it from `localhost` if your +situation is different. + +``` +curl --header "Content-Type: application/json" \ + --request POST \ + --data '{"ticker":"CASH","address":"tiov1k898u78hgs36uqw68dg7va5nfkgstu5z0fhz3f"}' \ + http://localhost:8000/credit +``` + +### Checking the faucets status + +The faucet provides a simple status check in the form of an http GET request. As +above, make sure to adjust the URL as necessary. + +``` +curl http://localhost:8000/status +``` diff --git a/packages/faucet/package.json b/packages/faucet/package.json index 3d2833ed97..9465a1ad35 100644 --- a/packages/faucet/package.json +++ b/packages/faucet/package.json @@ -21,6 +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/cosm-faucet start cosmwasm \"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 .", @@ -31,6 +32,7 @@ "test": "yarn build-or-skip && yarn test-node" }, "dependencies": { + "@cosmwasm/bcp": "^0.0.1", "@iov/bcp": "^2.0.0-alpha.7", "@iov/bns": "^2.0.0-alpha.7", "@iov/crypto": "^2.0.0-alpha.7", diff --git a/packages/faucet/src/actions/help.ts b/packages/faucet/src/actions/help.ts index 14cfd7adae..039655cc15 100644 --- a/packages/faucet/src/actions/help.ts +++ b/packages/faucet/src/actions/help.ts @@ -1,6 +1,8 @@ +const binaryName = "cosmwasm-faucet"; + export function help(): void { const out = ` -Usage: iov-faucet action [arguments...] +Usage: ${binaryName} action [arguments...] Positional arguments per action are listed below. Arguments in parentheses are optional. diff --git a/packages/faucet/src/cashflow.ts b/packages/faucet/src/cashflow.ts index 079a5c3711..27545ef965 100644 --- a/packages/faucet/src/cashflow.ts +++ b/packages/faucet/src/cashflow.ts @@ -66,6 +66,7 @@ export function gasPrice(codec: Codec): Amount | undefined { switch (codec) { case Codec.Bns: case Codec.Lisk: + case Codec.CosmWasm: return undefined; case Codec.Ethereum: return { @@ -74,7 +75,7 @@ export function gasPrice(codec: Codec): Amount | undefined { tokenTicker: "ETH" as TokenTicker, }; default: - throw new Error("No codec imlementation for this codec found"); + throw new Error("No gasPrice imlementation found for this codec"); } } @@ -82,6 +83,7 @@ export function gasLimit(codec: Codec): Amount | undefined { switch (codec) { case Codec.Bns: case Codec.Lisk: + case Codec.CosmWasm: return undefined; case Codec.Ethereum: return { @@ -90,6 +92,6 @@ export function gasLimit(codec: Codec): Amount | undefined { tokenTicker: "ETH" as TokenTicker, }; default: - throw new Error("Codec not supported"); + throw new Error("No gasLimit imlementation found for this codec"); } } diff --git a/packages/faucet/src/codec.ts b/packages/faucet/src/codec.ts index 1080a85e8c..b59b75bec7 100644 --- a/packages/faucet/src/codec.ts +++ b/packages/faucet/src/codec.ts @@ -1,14 +1,16 @@ -import { ChainConnector, TxCodec } from "@iov/bcp"; -import { bnsCodec, createBnsConnector } from "@iov/bns"; +import { createCosmWasmConnector, TokenInfo } from "@cosmwasm/bcp"; +import { ChainConnector, TokenTicker, TxCodec } from "@iov/bcp"; +import { createBnsConnector } from "@iov/bns"; import { Slip10RawIndex } from "@iov/crypto"; -import { createEthereumConnector, ethereumCodec } from "@iov/ethereum"; +import { createEthereumConnector } from "@iov/ethereum"; import { HdPaths } from "@iov/keycontrol"; -import { createLiskConnector, liskCodec } from "@iov/lisk"; +import { createLiskConnector } from "@iov/lisk"; export const enum Codec { Bns, Lisk, Ethereum, + CosmWasm, } export function codecFromString(input: string): Codec { @@ -19,24 +21,13 @@ export function codecFromString(input: string): Codec { return Codec.Lisk; case "ethereum": return Codec.Ethereum; + case "cosmwasm": + return Codec.CosmWasm; default: throw new Error(`Codec '${input}' not supported`); } } -export function codecImplementation(codec: Codec): TxCodec { - switch (codec) { - case Codec.Bns: - return bnsCodec; - case Codec.Lisk: - return liskCodec; - case Codec.Ethereum: - return ethereumCodec; - default: - throw new Error("No codec implementation for this codec found"); - } -} - export function createPathBuilderForCodec(codec: Codec): (derivation: number) => readonly Slip10RawIndex[] { const pathBuilder = (accountIndex: number): readonly Slip10RawIndex[] => { switch (codec) { @@ -46,6 +37,8 @@ export function createPathBuilderForCodec(codec: Codec): (derivation: number) => return HdPaths.bip44Like(134, accountIndex); case Codec.Ethereum: return HdPaths.ethereum(accountIndex); + case Codec.CosmWasm: + return HdPaths.cosmos(accountIndex); default: throw new Error("No path builder for this codec found"); } @@ -61,11 +54,32 @@ export function createChainConnector(codec: Codec, url: string): ChainConnector return createLiskConnector(url); case Codec.Ethereum: return createEthereumConnector(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.Bns: @@ -74,6 +88,8 @@ export function codecDefaultFractionalDigits(codec: Codec): number { return 8; case Codec.Ethereum: return 18; + case Codec.CosmWasm: + return 6; default: throw new Error("Unknown codec"); } diff --git a/packages/faucet/src/crypto.ts b/packages/faucet/src/crypto.ts index 59424ef90e..f210331098 100644 --- a/packages/faucet/src/crypto.ts +++ b/packages/faucet/src/crypto.ts @@ -8,6 +8,7 @@ export function createWalletForCodec(input: Codec, mnemonic: string): Wallet { case Codec.Lisk: return Ed25519HdWallet.fromMnemonic(mnemonic); case Codec.Ethereum: + case Codec.CosmWasm: return Secp256k1HdWallet.fromMnemonic(mnemonic); default: throw new Error(`Codec '${input}' not supported`);