Merge pull request #470 from CosmWasm/443-faucet-client

Add faucet-client package
This commit is contained in:
mergify[bot] 2020-10-14 11:27:21 +00:00 committed by GitHub
commit 0f3454a62b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 319 additions and 15 deletions

View File

@ -4,6 +4,7 @@
- @cosmjs/crypto: Export new convenience functions `keccak256`, `ripemd160`,
`sha1`, `sha256` and `sha512`.
- @cosmjs/faucet-client: Add new package which exports `FaucetClient` class.
## 0.23.0 (2020-10-09)

View File

@ -16,14 +16,6 @@ const defaultOptions: Options = {
const defaultFaucetUrl = "https://faucet.demo-10.cosmwasm.com/credit";
// TODO: hit faucet
// if (config.faucetUrl) {
// const acct = await client.getAccount();
// if (!acct?.balance?.length) {
// await ky.post(config.faucetUrl, { json: { ticker: "COSM", address } });
// }
// }
const connect = async (
mnemonic: string,
opts: Partial<Options>,
@ -56,12 +48,6 @@ const loadOrCreateMnemonic = (filename: string): string => {
}
};
const hitFaucet = async (faucetUrl: string, address: string, ticker: string): Promise<void> => {
const r = await axios.post(defaultFaucetUrl, { ticker, address });
console.log(r.status);
console.log(r.data);
};
const randomAddress = async (prefix: string): Promise<string> => {
const mnemonic = Bip39.encode(Random.getBytes(16)).toString();
return mnemonicToAddress(prefix, mnemonic);

View File

@ -43,6 +43,7 @@
"@cosmjs/cosmwasm": "^0.23.0",
"@cosmjs/crypto": "^0.23.0",
"@cosmjs/encoding": "^0.23.0",
"@cosmjs/faucet-client": "^0.23.0",
"@cosmjs/launchpad": "^0.23.0",
"@cosmjs/math": "^0.23.0",
"@cosmjs/utils": "^0.23.0",

View File

@ -27,7 +27,7 @@ export async function main(originalArgs: readonly string[]): Promise<void> {
type: "boolean",
},
selftest: {
describe: "Run a selftext and exit",
describe: "Run a selftest and exit",
type: "boolean",
},
})
@ -87,6 +87,7 @@ export async function main(originalArgs: readonly string[]): Promise<void> {
"@cosmjs/encoding",
["fromAscii", "fromBase64", "fromHex", "fromUtf8", "toAscii", "toBase64", "toHex", "toUtf8", "Bech32"],
],
["@cosmjs/faucet-client", ["FaucetClient"]],
[
"@cosmjs/launchpad",
[

View File

@ -0,0 +1 @@
../../.eslintignore

3
packages/faucet-client/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
build/
dist/
docs/

View File

@ -0,0 +1 @@
../../.nycrc.yml

View File

@ -0,0 +1,36 @@
# @cosmjs/faucet-client
[![npm version](https://img.shields.io/npm/v/@cosmjs/faucet-client.svg)](https://www.npmjs.com/package/@cosmjs/faucet-client)
## Running the tests
First of all you will need an instance of wasmd running. From the root directory of this repository:
```sh
./scripts/wasmd/start.sh && ./scripts/wasmd/init.sh
```
You will also need a faucet. From the root directory of this repository:
```sh
cd packages/faucet
yarn start-dev
```
The tests need to be told you are running the faucet via an environmental variable:
```sh
export FAUCET_ENABLED=1
```
Finally run the tests from this directory:
```sh
yarn test
```
## License
This package is part of the cosmjs repository, licensed under the Apache License
2.0 (see [NOTICE](https://github.com/CosmWasm/cosmjs/blob/master/NOTICE) and
[LICENSE](https://github.com/CosmWasm/cosmjs/blob/master/LICENSE)).

View File

@ -0,0 +1,33 @@
#!/usr/bin/env node
/* eslint-disable @typescript-eslint/naming-convention */
require("source-map-support").install();
const defaultSpecReporterConfig = require("../../jasmine-spec-reporter.config.json");
// setup Jasmine
const Jasmine = require("jasmine");
const jasmine = new Jasmine();
jasmine.loadConfig({
spec_dir: "build",
spec_files: ["**/*.spec.js"],
helpers: [],
random: false,
seed: null,
stopSpecOnExpectationFailure: false,
});
jasmine.jasmine.DEFAULT_TIMEOUT_INTERVAL = 15 * 1000;
// setup reporter
const { SpecReporter } = require("jasmine-spec-reporter");
const reporter = new SpecReporter({
...defaultSpecReporterConfig,
spec: {
...defaultSpecReporterConfig.spec,
displaySuccessful: !process.argv.includes("--quiet"),
},
});
// initialize and execute
jasmine.env.clearReporters();
jasmine.addReporter(reporter);
jasmine.execute();

View File

@ -0,0 +1,47 @@
module.exports = function (config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: ".",
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ["jasmine"],
// list of files / patterns to load in the browser
files: ["dist/web/tests.js"],
client: {
jasmine: {
random: false,
timeoutInterval: 15000,
},
},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ["progress", "kjhtml"],
// web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: false,
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: ["Firefox"],
browserNoActivityTimeout: 90000,
// Keep brower open for debugging. This is overridden by yarn scripts
singleRun: false,
});
};

View File

@ -0,0 +1 @@
Directory used to trigger lerna package updates for all packages

View File

@ -0,0 +1,49 @@
{
"name": "@cosmjs/faucet-client",
"version": "0.23.0",
"description": "The faucet client",
"contributors": [
"Will Clark <willclarktech@users.noreply.github.com>"
],
"license": "Apache-2.0",
"main": "build/index.js",
"types": "types/index.d.ts",
"files": [
"build/",
"types/",
"*.md",
"!*.spec.*",
"!**/testdata/"
],
"repository": {
"type": "git",
"url": "https://github.com/CosmWasm/cosmjs/tree/master/packages/faucet-client"
},
"publishConfig": {
"access": "public"
},
"scripts": {
"docs": "typedoc --options typedoc.js",
"lint": "eslint --max-warnings 0 \"**/*.{js,ts}\"",
"lint-fix": "eslint --max-warnings 0 \"**/*.{js,ts}\" --fix",
"format": "prettier --write --loglevel warn \"./src/**/*.ts\"",
"format-text": "prettier --write --prose-wrap always --print-width 80 \"./*.md\"",
"test-node": "node jasmine-testrunner.js",
"test-edge": "yarn pack-web && karma start --single-run --browsers Edge",
"test-firefox": "yarn pack-web && karma start --single-run --browsers Firefox",
"test-chrome": "yarn pack-web && karma start --single-run --browsers ChromeHeadless",
"test-safari": "yarn pack-web && karma start --single-run --browsers Safari",
"test": "yarn build-or-skip && yarn test-node",
"coverage": "nyc --reporter=text --reporter=lcov yarn test --quiet",
"move-types": "shx rm -rf ./types/* && shx mv build/types/* ./types && rm -rf ./types/testdata && shx rm -f ./types/*.spec.d.ts",
"format-types": "prettier --write --loglevel warn \"./types/**/*.d.ts\"",
"prebuild": "shx rm -rf ./build",
"build": "tsc",
"postbuild": "yarn move-types && yarn format-types",
"build-or-skip": "[ -n \"$SKIP_BUILD\" ] || yarn build",
"pack-web": "yarn build-or-skip && webpack --mode development --config webpack.web.config.js"
},
"dependencies": {
"axios": "^0.19.2"
}
}

View File

@ -0,0 +1,60 @@
import { FaucetClient } from "./faucetclient";
function pendingWithoutFaucet(): void {
if (!process.env.FAUCET_ENABLED) {
pending("Set FAUCET_ENABLED to enable tests that need a faucet");
}
}
describe("FaucetClient", () => {
const faucetUrl = "http://localhost:8000";
const primaryToken = "ucosm";
const secondaryToken = "ustake";
const defaultAddress = "cosmos14qemq0vw6y3gc3u3e0aty2e764u4gs5le3hada";
it("can be constructed", () => {
// http
expect(new FaucetClient("http://localhost:8000")).toBeTruthy();
expect(new FaucetClient("http://localhost:8000/")).toBeTruthy();
expect(new FaucetClient("http://localhost")).toBeTruthy();
expect(new FaucetClient("http://localhost/")).toBeTruthy();
// https
expect(new FaucetClient("https://localhost:8000")).toBeTruthy();
expect(new FaucetClient("https://localhost:8000/")).toBeTruthy();
expect(new FaucetClient("https://localhost")).toBeTruthy();
expect(new FaucetClient("https://localhost/")).toBeTruthy();
});
it("can be used to credit a wallet", async () => {
pendingWithoutFaucet();
const faucet = new FaucetClient(faucetUrl);
await faucet.credit(defaultAddress, primaryToken);
});
it("can be used to credit a wallet with a different token", async () => {
pendingWithoutFaucet();
const faucet = new FaucetClient(faucetUrl);
await faucet.credit(defaultAddress, secondaryToken);
});
it("throws for invalid ticker", async () => {
pendingWithoutFaucet();
const faucet = new FaucetClient(faucetUrl);
await faucet.credit(defaultAddress, "ETH").then(
() => fail("must not resolve"),
(error) => expect(error).toMatch(/token is not available/i),
);
});
it("throws for invalid address", async () => {
pendingWithoutFaucet();
const faucet = new FaucetClient(faucetUrl);
for (const address of ["be5cc2cc05db2cdb4313c18306a5157291cfdcd1", "1234L"]) {
await faucet.credit(address, primaryToken).then(
() => fail("must not resolve"),
(error) => expect(error).toMatch(/address is not in the expected format for this chain/i),
);
}
});
});

View File

@ -0,0 +1,33 @@
import axios from "axios";
export class FaucetClient {
private readonly baseUrl: string;
public constructor(baseUrl: string) {
if (!baseUrl.match(/^https?:\/\//)) {
throw new Error("Expected base url to start with http:// or https://");
}
// Strip trailing /
const strippedBaseUrl = baseUrl.replace(/(\/)+$/, "");
this.baseUrl = strippedBaseUrl;
}
public async credit(address: string, denom: string): Promise<void> {
const body = {
address: address,
denom: denom,
};
try {
await axios.post(this.baseUrl + "/credit", body);
} catch (error) {
if (error.response) {
// append response body to error message
throw new Error(`${error}; response body: ${JSON.stringify(error.response.data)}`);
} else {
throw error;
}
}
}
}

View File

@ -0,0 +1 @@
export { FaucetClient } from "./faucetclient";

View File

@ -0,0 +1,12 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"outDir": "build",
"declarationDir": "build/types",
"rootDir": "src"
},
"include": [
"src/**/*"
]
}

View File

@ -0,0 +1,13 @@
const packageJson = require("./package.json");
module.exports = {
inputFiles: ["./src"],
out: "docs",
exclude: "**/*.spec.ts",
name: `${packageJson.name} Documentation`,
readme: "README.md",
mode: "file",
excludeExternals: true,
excludeNotExported: true,
excludePrivate: true,
};

View File

@ -0,0 +1,5 @@
export declare class FaucetClient {
private readonly baseUrl;
constructor(baseUrl: string);
credit(address: string, denom: string): Promise<void>;
}

View File

@ -0,0 +1 @@
export { FaucetClient } from "./faucetclient";

View File

@ -0,0 +1,19 @@
const glob = require("glob");
const path = require("path");
const webpack = require("webpack");
const target = "web";
const distdir = path.join(__dirname, "dist", "web");
module.exports = [
{
// bundle used for Karma tests
target: target,
entry: glob.sync("./build/**/*.spec.js"),
output: {
path: distdir,
filename: "tests.js",
},
plugins: [new webpack.EnvironmentPlugin(["FAUCET_ENABLED"])],
},
];