From fa5c62a7975780f68ac2273f18b61d259b8ad817 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 10 Jun 2020 15:43:54 +0200 Subject: [PATCH] Remove BCP package --- packages/bcp/.eslintignore | 1 - packages/bcp/.gitignore | 3 - packages/bcp/README.md | 12 - packages/bcp/jasmine-testrunner.js | 26 - packages/bcp/karma.conf.js | 47 -- packages/bcp/nonces/1580975947 | 0 packages/bcp/nonces/1580980830 | 0 packages/bcp/nonces/1581790180 | 0 packages/bcp/nonces/1582043857 | 0 packages/bcp/nonces/1582062520 | 0 packages/bcp/nonces/1582198421 | 0 packages/bcp/nonces/1582208955 | 0 packages/bcp/nonces/1582291410 | 0 packages/bcp/nonces/1583183690 | 0 packages/bcp/nonces/1583495327 | 0 packages/bcp/nonces/1583509277 | 0 packages/bcp/nonces/1583541822 | 0 packages/bcp/nonces/1583854671 | 0 packages/bcp/nonces/1583941462 | 0 packages/bcp/nonces/1584541301 | 0 packages/bcp/nonces/1584959328 | 0 packages/bcp/nonces/1589983882 | 0 packages/bcp/nonces/1589986013 | 0 packages/bcp/nonces/1590408566 | 0 packages/bcp/nonces/1591794433 | 0 packages/bcp/nonces/README.txt | 1 - packages/bcp/package.json | 56 -- packages/bcp/src/address.spec.ts | 37 - packages/bcp/src/address.ts | 24 - packages/bcp/src/caip5.spec.ts | 79 -- packages/bcp/src/caip5.ts | 40 - packages/bcp/src/cosmoscodec.spec.ts | 75 -- packages/bcp/src/cosmoscodec.ts | 104 --- packages/bcp/src/cosmosconnection.spec.ts | 893 ---------------------- packages/bcp/src/cosmosconnection.ts | 489 ------------ packages/bcp/src/cosmosconnector.ts | 21 - packages/bcp/src/decode.spec.ts | 401 ---------- packages/bcp/src/decode.ts | 187 ----- packages/bcp/src/encode.spec.ts | 310 -------- packages/bcp/src/encode.ts | 123 --- packages/bcp/src/index.ts | 4 - packages/bcp/src/testdata.spec.ts | 66 -- packages/bcp/src/testdata/cosmoshub.json | 44 -- packages/bcp/src/types.spec.ts | 15 - packages/bcp/src/types.ts | 52 -- packages/bcp/tsconfig.json | 12 - packages/bcp/typedoc.js | 14 - packages/bcp/types/address.d.ts | 2 - packages/bcp/types/caip5.d.ts | 13 - packages/bcp/types/cosmoscodec.d.ts | 24 - packages/bcp/types/cosmosconnection.d.ts | 78 -- packages/bcp/types/cosmosconnector.d.ts | 11 - packages/bcp/types/decode.d.ts | 52 -- packages/bcp/types/encode.d.ts | 12 - packages/bcp/types/index.d.ts | 4 - packages/bcp/types/types.d.ts | 18 - packages/bcp/webpack.web.config.js | 19 - yarn.lock | 169 +--- 58 files changed, 5 insertions(+), 3533 deletions(-) delete mode 120000 packages/bcp/.eslintignore delete mode 100644 packages/bcp/.gitignore delete mode 100644 packages/bcp/README.md delete mode 100755 packages/bcp/jasmine-testrunner.js delete mode 100644 packages/bcp/karma.conf.js delete mode 100644 packages/bcp/nonces/1580975947 delete mode 100644 packages/bcp/nonces/1580980830 delete mode 100644 packages/bcp/nonces/1581790180 delete mode 100644 packages/bcp/nonces/1582043857 delete mode 100644 packages/bcp/nonces/1582062520 delete mode 100644 packages/bcp/nonces/1582198421 delete mode 100644 packages/bcp/nonces/1582208955 delete mode 100644 packages/bcp/nonces/1582291410 delete mode 100644 packages/bcp/nonces/1583183690 delete mode 100644 packages/bcp/nonces/1583495327 delete mode 100644 packages/bcp/nonces/1583509277 delete mode 100644 packages/bcp/nonces/1583541822 delete mode 100644 packages/bcp/nonces/1583854671 delete mode 100644 packages/bcp/nonces/1583941462 delete mode 100644 packages/bcp/nonces/1584541301 delete mode 100644 packages/bcp/nonces/1584959328 delete mode 100644 packages/bcp/nonces/1589983882 delete mode 100644 packages/bcp/nonces/1589986013 delete mode 100644 packages/bcp/nonces/1590408566 delete mode 100644 packages/bcp/nonces/1591794433 delete mode 100644 packages/bcp/nonces/README.txt delete mode 100644 packages/bcp/package.json delete mode 100644 packages/bcp/src/address.spec.ts delete mode 100644 packages/bcp/src/address.ts delete mode 100644 packages/bcp/src/caip5.spec.ts delete mode 100644 packages/bcp/src/caip5.ts delete mode 100644 packages/bcp/src/cosmoscodec.spec.ts delete mode 100644 packages/bcp/src/cosmoscodec.ts delete mode 100644 packages/bcp/src/cosmosconnection.spec.ts delete mode 100644 packages/bcp/src/cosmosconnection.ts delete mode 100644 packages/bcp/src/cosmosconnector.ts delete mode 100644 packages/bcp/src/decode.spec.ts delete mode 100644 packages/bcp/src/decode.ts delete mode 100644 packages/bcp/src/encode.spec.ts delete mode 100644 packages/bcp/src/encode.ts delete mode 100644 packages/bcp/src/index.ts delete mode 100644 packages/bcp/src/testdata.spec.ts delete mode 100644 packages/bcp/src/testdata/cosmoshub.json delete mode 100644 packages/bcp/src/types.spec.ts delete mode 100644 packages/bcp/src/types.ts delete mode 100644 packages/bcp/tsconfig.json delete mode 100644 packages/bcp/typedoc.js delete mode 100644 packages/bcp/types/address.d.ts delete mode 100644 packages/bcp/types/caip5.d.ts delete mode 100644 packages/bcp/types/cosmoscodec.d.ts delete mode 100644 packages/bcp/types/cosmosconnection.d.ts delete mode 100644 packages/bcp/types/cosmosconnector.d.ts delete mode 100644 packages/bcp/types/decode.d.ts delete mode 100644 packages/bcp/types/encode.d.ts delete mode 100644 packages/bcp/types/index.d.ts delete mode 100644 packages/bcp/types/types.d.ts delete mode 100644 packages/bcp/webpack.web.config.js diff --git a/packages/bcp/.eslintignore b/packages/bcp/.eslintignore deleted file mode 120000 index 86039baf54..0000000000 --- a/packages/bcp/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -../../.eslintignore \ No newline at end of file diff --git a/packages/bcp/.gitignore b/packages/bcp/.gitignore deleted file mode 100644 index 68bf373524..0000000000 --- a/packages/bcp/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -build/ -dist/ -docs/ diff --git a/packages/bcp/README.md b/packages/bcp/README.md deleted file mode 100644 index aebf15ec82..0000000000 --- a/packages/bcp/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# @iov/cosmos-sdk - -[![npm version](https://img.shields.io/npm/v/@iov/cosmos-sdk.svg)](https://www.npmjs.com/package/@iov/cosmos-sdk) - -A [BCP](https://github.com/iov-one/iov-core/tree/master/packages/iov-bcp) implementation for Cosmos SDK 0.38. - -## 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)). diff --git a/packages/bcp/jasmine-testrunner.js b/packages/bcp/jasmine-testrunner.js deleted file mode 100755 index 9fada59b28..0000000000 --- a/packages/bcp/jasmine-testrunner.js +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env node - -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 }); - -// initialize and execute -jasmine.env.clearReporters(); -jasmine.addReporter(reporter); -jasmine.execute(); diff --git a/packages/bcp/karma.conf.js b/packages/bcp/karma.conf.js deleted file mode 100644 index 006da5fe6b..0000000000 --- a/packages/bcp/karma.conf.js +++ /dev/null @@ -1,47 +0,0 @@ -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, - }); -}; diff --git a/packages/bcp/nonces/1580975947 b/packages/bcp/nonces/1580975947 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/bcp/nonces/1580980830 b/packages/bcp/nonces/1580980830 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/bcp/nonces/1581790180 b/packages/bcp/nonces/1581790180 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/bcp/nonces/1582043857 b/packages/bcp/nonces/1582043857 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/bcp/nonces/1582062520 b/packages/bcp/nonces/1582062520 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/bcp/nonces/1582198421 b/packages/bcp/nonces/1582198421 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/bcp/nonces/1582208955 b/packages/bcp/nonces/1582208955 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/bcp/nonces/1582291410 b/packages/bcp/nonces/1582291410 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/bcp/nonces/1583183690 b/packages/bcp/nonces/1583183690 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/bcp/nonces/1583495327 b/packages/bcp/nonces/1583495327 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/bcp/nonces/1583509277 b/packages/bcp/nonces/1583509277 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/bcp/nonces/1583541822 b/packages/bcp/nonces/1583541822 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/bcp/nonces/1583854671 b/packages/bcp/nonces/1583854671 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/bcp/nonces/1583941462 b/packages/bcp/nonces/1583941462 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/bcp/nonces/1584541301 b/packages/bcp/nonces/1584541301 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/bcp/nonces/1584959328 b/packages/bcp/nonces/1584959328 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/bcp/nonces/1589983882 b/packages/bcp/nonces/1589983882 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/bcp/nonces/1589986013 b/packages/bcp/nonces/1589986013 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/bcp/nonces/1590408566 b/packages/bcp/nonces/1590408566 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/bcp/nonces/1591794433 b/packages/bcp/nonces/1591794433 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/bcp/nonces/README.txt b/packages/bcp/nonces/README.txt deleted file mode 100644 index 092fe732f1..0000000000 --- a/packages/bcp/nonces/README.txt +++ /dev/null @@ -1 +0,0 @@ -Directory used to trigger lerna package updates for all packages diff --git a/packages/bcp/package.json b/packages/bcp/package.json deleted file mode 100644 index 80309ab70e..0000000000 --- a/packages/bcp/package.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "name": "@iov/cosmos-sdk", - "version": "0.20.0", - "description": "Transaction codec and client to communicate with a Cosmos SDK 0.38 blockchain", - "contributors": [ - "Ethan Frey ", - "Simon Warta" - ], - "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/bcp" - }, - "private": true, - "scripts": { - "docs": "shx rm -rf docs && typedoc --options typedoc.js", - "format": "prettier --write --loglevel warn \"./src/**/*.ts\"", - "lint": "eslint --max-warnings 0 \"**/*.{js,ts}\"", - "lint-fix": "eslint --max-warnings 0 \"**/*.{js,ts}\" --fix", - "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\"", - "build": "shx rm -rf ./build && tsc && yarn move-types && yarn format-types", - "build-or-skip": "[ -n \"$SKIP_BUILD\" ] || yarn build", - "test-node": "node jasmine-testrunner.js", - "test-firefox": "yarn pack-web && karma start --single-run --browsers Firefox", - "test-chrome": "yarn pack-web && karma start --single-run --browsers ChromeHeadless", - "test": "yarn build-or-skip && yarn test-node", - "pack-web": "yarn build-or-skip && webpack --mode development --config webpack.web.config.js" - }, - "dependencies": { - "@cosmjs/crypto": "^0.20.0", - "@cosmjs/encoding": "^0.20.0", - "@cosmjs/math": "^0.20.0", - "@cosmjs/sdk38": "^0.20.0", - "@cosmjs/utils": "^0.20.0", - "@iov/bcp": "^2.3.2", - "@iov/stream": "^2.3.2", - "bn.js": "^5.1.1", - "fast-deep-equal": "^3.1.1", - "readonly-date": "^1.0.0", - "xstream": "^11.11.0" - }, - "devDependencies": { - "@iov/keycontrol": "^2.3.2", - "@types/bn.js": "^4.11.6" - } -} diff --git a/packages/bcp/src/address.spec.ts b/packages/bcp/src/address.spec.ts deleted file mode 100644 index d6dbe3ffa8..0000000000 --- a/packages/bcp/src/address.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { fromBase64, fromHex } from "@cosmjs/encoding"; -import { Algorithm, PubkeyBytes } from "@iov/bcp"; - -import { pubkeyToAddress } from "./address"; - -describe("address", () => { - describe("pubkeyToAddress", () => { - it("works for Secp256k1 compressed", () => { - const prefix = "cosmos"; - const pubkey = { - algo: Algorithm.Secp256k1, - data: fromBase64("AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP") as PubkeyBytes, - }; - expect(pubkeyToAddress(pubkey, prefix)).toEqual("cosmos1h806c7khnvmjlywdrkdgk2vrayy2mmvf9rxk2r"); - }); - - it("works for Secp256k1 uncompressed", () => { - const prefix = "cosmos"; - const pubkey = { - algo: Algorithm.Secp256k1, - data: fromBase64( - "BE8EGB7ro1ORuFhjOnZcSgwYlpe0DSFjVNUIkNNQxwKQE7WHpoHoNswYeoFkuYpYSKK4mzFzMV/dB0DVAy4lnNU=", - ) as PubkeyBytes, - }; - expect(pubkeyToAddress(pubkey, prefix)).toEqual("cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6"); - }); - - it("works for Ed25519", () => { - const prefix = "cosmos"; - const pubkey = { - algo: Algorithm.Ed25519, - data: fromHex("12ee6f581fe55673a1e9e1382a0829e32075a0aa4763c968bc526e1852e78c95") as PubkeyBytes, - }; - expect(pubkeyToAddress(pubkey, prefix)).toEqual("cosmos1pfq05em6sfkls66ut4m2257p7qwlk448h8mysz"); - }); - }); -}); diff --git a/packages/bcp/src/address.ts b/packages/bcp/src/address.ts deleted file mode 100644 index 413f8b14d6..0000000000 --- a/packages/bcp/src/address.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Secp256k1 } from "@cosmjs/crypto"; -import { toBase64 } from "@cosmjs/encoding"; -import { PubKey, pubkeyToAddress as sdkPubkeyToAddress, pubkeyType } from "@cosmjs/sdk38"; -import { Address, Algorithm, PubkeyBundle } from "@iov/bcp"; - -// See https://github.com/tendermint/tendermint/blob/f2ada0a604b4c0763bda2f64fac53d506d3beca7/docs/spec/blockchain/encoding.md#public-key-cryptography -export function pubkeyToAddress(pubkey: PubkeyBundle, prefix: string): Address { - let sdkKey: PubKey; - if (pubkey.algo === Algorithm.Secp256k1) { - sdkKey = { - type: pubkeyType.secp256k1, - value: toBase64(pubkey.data.length > 33 ? Secp256k1.compressPubkey(pubkey.data) : pubkey.data), - }; - } else if (pubkey.algo === Algorithm.Ed25519) { - sdkKey = { - type: pubkeyType.ed25519, - value: toBase64(pubkey.data), - }; - } else { - throw new Error(`Unsupported algorithm: ${pubkey.algo}`); - } - - return sdkPubkeyToAddress(sdkKey, prefix) as Address; -} diff --git a/packages/bcp/src/caip5.spec.ts b/packages/bcp/src/caip5.spec.ts deleted file mode 100644 index c47bb7cc23..0000000000 --- a/packages/bcp/src/caip5.spec.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { ChainId } from "@iov/bcp"; - -import { Caip5 } from "./caip5"; - -describe("Caip5", () => { - describe("encode", () => { - it("works for direct format", () => { - expect(Caip5.encode("foo")).toEqual("cosmos:foo"); - expect(Caip5.encode("aA1-")).toEqual("cosmos:aA1-"); - expect(Caip5.encode("12345678901234567890123456789012345678901234567")).toEqual( - "cosmos:12345678901234567890123456789012345678901234567", - ); - - // Test vectors from CAIP-5 - expect(Caip5.encode("cosmoshub-3")).toEqual("cosmos:cosmoshub-3"); - expect(Caip5.encode("Binance-Chain-Tigris")).toEqual("cosmos:Binance-Chain-Tigris"); - expect(Caip5.encode("x")).toEqual("cosmos:x"); - expect(Caip5.encode("hash-")).toEqual("cosmos:hash-"); - expect(Caip5.encode("hashed")).toEqual("cosmos:hashed"); - }); - - it("works for hashed format", () => { - // Test vectors from CAIP-5 - expect(Caip5.encode("hashed-")).toEqual("cosmos:hashed-c904589232422def"); - expect(Caip5.encode("hashed-123")).toEqual("cosmos:hashed-99df5cd68192b33e"); - expect(Caip5.encode("123456789012345678901234567890123456789012345678")).toEqual( - "cosmos:hashed-0204c92a0388779d", - ); - expect(Caip5.encode(" ")).toEqual("cosmos:hashed-36a9e7f1c95b82ff"); - expect(Caip5.encode("wonderland🧝‍♂️")).toEqual("cosmos:hashed-843d2fc87f40eeb9"); - }); - - it("throws for empty input", () => { - expect(() => Caip5.encode("")).toThrowError(/must not be empty/i); - }); - }); - - describe("decode", () => { - it("works for valid format", () => { - expect(Caip5.decode("cosmos:x" as ChainId)).toEqual("x"); - expect(Caip5.decode("cosmos:foo" as ChainId)).toEqual("foo"); - expect(Caip5.decode("cosmos:aA1-" as ChainId)).toEqual("aA1-"); - expect(Caip5.decode("cosmos:12345678901234567890123456789012345678901234567" as ChainId)).toEqual( - "12345678901234567890123456789012345678901234567", - ); - }); - - it("throws for invalid format", () => { - // wrong namespace - expect(() => Caip5.decode(":foobar" as ChainId)).toThrowError(/not compatible with CAIP-5/i); - expect(() => Caip5.decode("xyz:foobar" as ChainId)).toThrowError(/not compatible with CAIP-5/i); - expect(() => Caip5.decode("cosmos-hash:foobar" as ChainId)).toThrowError(/not compatible with CAIP-5/i); - - // reference too short - expect(() => Caip5.decode("cosmos:" as ChainId)).toThrowError(/not compatible with CAIP-5/i); - - // reference too long - expect(() => - Caip5.decode("cosmos:123456789012345678901234567890123456789012345678" as ChainId), - ).toThrowError(/not compatible with CAIP-5/i); - - // invalid chars - expect(() => Caip5.decode("cosmos:foo bar" as ChainId)).toThrowError(/not compatible with CAIP-5/i); - expect(() => Caip5.decode("cosmos:wonder🧝‍♂️" as ChainId)).toThrowError(/not compatible with CAIP-5/i); - }); - - it("throws for hashed chain IDs", () => { - expect(() => Caip5.decode("cosmos:hashed-" as ChainId)).toThrowError( - /hashed chain IDs cannot be decoded/i, - ); - expect(() => Caip5.decode("cosmos:hashed-abab" as ChainId)).toThrowError( - /hashed chain IDs cannot be decoded/i, - ); - expect(() => Caip5.decode("cosmos:hashed-6abb36860ec76c5a" as ChainId)).toThrowError( - /hashed chain IDs cannot be decoded/i, - ); - }); - }); -}); diff --git a/packages/bcp/src/caip5.ts b/packages/bcp/src/caip5.ts deleted file mode 100644 index 8c789ffe4f..0000000000 --- a/packages/bcp/src/caip5.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Sha256 } from "@cosmjs/crypto"; -import { toHex, toUtf8 } from "@cosmjs/encoding"; -import { ChainId } from "@iov/bcp"; - -const hashedPrefix = "hashed-"; - -/** - * Conversion between native chain IDs and CAIP-5 format - * - * @see https://github.com/ChainAgnostic/CAIPs/pull/9 - */ -export class Caip5 { - /** - * @param native The `chain_id` field from Tendermint's genesis file - */ - public static encode(native: string): ChainId { - if (!native) throw new Error("Input must not be empty"); - - if (!native.match(/^[-a-zA-Z0-9]{1,47}$/) || native.startsWith(hashedPrefix)) { - const hash = toHex(new Sha256(toUtf8(native)).digest()).slice(0, 16); - return `cosmos:${hashedPrefix}${hash}` as ChainId; - } else { - return `cosmos:${native}` as ChainId; - } - } - - public static decode(chainId: ChainId): string { - const match = chainId.match(/^cosmos:([-a-zA-Z0-9]{1,47})$/); - if (!match) { - throw new Error("Chain ID not compatible with CAIP-5"); - } - - const reference = match[1]; - if (reference.startsWith(hashedPrefix)) { - throw new Error("Hashed chain IDs cannot be decoded"); - } - - return reference; - } -} diff --git a/packages/bcp/src/cosmoscodec.spec.ts b/packages/bcp/src/cosmoscodec.spec.ts deleted file mode 100644 index 0540ca2838..0000000000 --- a/packages/bcp/src/cosmoscodec.spec.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { toUtf8 } from "@cosmjs/encoding"; -import { PostableBytes, PrehashType } from "@iov/bcp"; - -import { CosmosCodec } from "./cosmoscodec"; -import { chainId, nonce, sendTxJson, signedTxBin, signedTxEncodedJson, signedTxJson } from "./testdata.spec"; -import { BankToken } from "./types"; - -const defaultPrefix = "cosmos"; - -const defaultBankTokens: readonly BankToken[] = [ - { - fractionalDigits: 6, - ticker: "ATOM", - denom: "uatom", - }, -]; - -describe("CosmosCodec", () => { - const codec = new CosmosCodec(defaultPrefix, defaultBankTokens); - - describe("isValidAddress", () => { - it("accepts valid addresses", () => { - expect(codec.isValidAddress("cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6")).toEqual(true); - }); - - it("rejects invalid addresses", () => { - // Bad size - expect(codec.isValidAddress("cosmos10q82zkzzmaku5lazhsvxv7hsg4ntpuhh8289f")).toEqual(false); - // Bad checksum - expect(codec.isValidAddress("cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs7")).toEqual(false); - // Bad prefix - expect(codec.isValidAddress("cosmot10q82zkzzmaku5lazhsvxv7hsg4ntpuhd8j5266")).toEqual(false); - expect(codec.isValidAddress("cosmosvalcons10q82zkzzmaku5lazhsvxv7hsg4ntpuhdwadmss")).toEqual(false); - expect(codec.isValidAddress("cosmosvaloper17mggn4znyeyg25wd7498qxl7r2jhgue8u4qjcq")).toEqual(false); - }); - }); - - describe("bytesToSign", () => { - it("works for SendTransaction via bank module", () => { - const expected = { - bytes: toUtf8( - '{"account_number":"0","chain_id":"cosmoshub-3","fee":{"amount":[{"amount":"2500","denom":"uatom"}],"gas":"100000"},"memo":"","msgs":[{"type":"cosmos-sdk/MsgSend","value":{"amount":[{"amount":"35997500","denom":"uatom"}],"from_address":"cosmos1txqfn5jmcts0x0q7krdxj8tgf98tj0965vqlmq","to_address":"cosmos1nynns8ex9fq6sjjfj8k79ymkdz4sqth06xexae"}}],"sequence":"99"}', - ), - prehashType: PrehashType.Sha256, - }; - expect(codec.bytesToSign(sendTxJson, nonce)).toEqual(expected); - }); - }); - - describe("bytesToPost", () => { - it("works for SendTransaction via bank module", () => { - const encoded = codec.bytesToPost(signedTxJson); - expect(encoded).toEqual(signedTxEncodedJson); - }); - }); - - describe("parseBytes", () => { - it("throws when trying to decode a transaction without a nonce", () => { - expect(() => codec.parseBytes(signedTxBin as PostableBytes, chainId)).toThrowError( - /nonce is required/i, - ); - }); - - it("properly decodes transactions", () => { - const decoded = codec.parseBytes(signedTxEncodedJson as PostableBytes, chainId, nonce); - expect(decoded).toEqual(signedTxJson); - }); - - it("round trip works", () => { - const encoded = codec.bytesToPost(signedTxJson); - const decoded = codec.parseBytes(encoded, chainId, nonce); - expect(decoded).toEqual(signedTxJson); - }); - }); -}); diff --git a/packages/bcp/src/cosmoscodec.ts b/packages/bcp/src/cosmoscodec.ts deleted file mode 100644 index 2a4eaff006..0000000000 --- a/packages/bcp/src/cosmoscodec.ts +++ /dev/null @@ -1,104 +0,0 @@ -/* eslint-disable @typescript-eslint/camelcase */ -import { Bech32, fromUtf8, toUtf8 } from "@cosmjs/encoding"; -import { isStdTx, makeSignBytes, StdTx } from "@cosmjs/sdk38"; -import { - Address, - ChainId, - Identity, - Nonce, - PostableBytes, - PrehashType, - SignableBytes, - SignedTransaction, - SigningJob, - TransactionId, - TxCodec, - UnsignedTransaction, -} from "@iov/bcp"; - -import { pubkeyToAddress } from "./address"; -import { Caip5 } from "./caip5"; -import { parseSignedTx } from "./decode"; -import { buildSignedTx, buildUnsignedTx } from "./encode"; -import { BankToken, nonceToAccountNumber, nonceToSequence } from "./types"; - -function marshalTx(tx: StdTx): Uint8Array { - const json = JSON.stringify(tx); - return toUtf8(json); -} - -function unmarshalTx(data: Uint8Array): StdTx { - const decoded = JSON.parse(fromUtf8(data)); - if (!isStdTx(decoded)) { - throw new Error("Must be json encoded StdTx"); - } - return decoded; -} - -export class CosmosCodec implements TxCodec { - private readonly addressPrefix: string; - private readonly bankTokens: readonly BankToken[]; - - public constructor(addressPrefix: string, bankTokens: readonly BankToken[]) { - this.addressPrefix = addressPrefix; - this.bankTokens = bankTokens; - } - - public bytesToSign(unsigned: UnsignedTransaction, nonce: Nonce): SigningJob { - const built = buildUnsignedTx(unsigned, this.bankTokens); - - const signBytes = makeSignBytes( - built.value.msg, - built.value.fee, - Caip5.decode(unsigned.chainId), - built.value.memo || "", - nonceToAccountNumber(nonce), - nonceToSequence(nonce), - ); - - return { - bytes: signBytes as SignableBytes, - prehashType: PrehashType.Sha256, - }; - } - - // PostableBytes are JSON-encoded StdTx - public bytesToPost(signed: SignedTransaction): PostableBytes { - // TODO: change this as well (return StdTx, not AminoTx)? - const built = buildSignedTx(signed, this.bankTokens); - return marshalTx(built.value) as PostableBytes; - } - - // TODO: this needs some marshalling going on... - // Do we need to support this?? - public identifier(_signed: SignedTransaction): TransactionId { - throw new Error("Not yet implemented, requires amino encoding- talk to Ethan"); - // const bytes = this.bytesToPost(signed); - // const hash = new Sha256(bytes).digest(); - // return toHex(hash).toUpperCase() as TransactionId; - } - - public parseBytes(bytes: PostableBytes, chainId: ChainId, nonce?: Nonce): SignedTransaction { - if (nonce === undefined) { - throw new Error("Nonce is required"); - } - const parsed = unmarshalTx(bytes); - return parseSignedTx(parsed, chainId, nonce, this.bankTokens); - } - - public identityToAddress(identity: Identity): Address { - return pubkeyToAddress(identity.pubkey, this.addressPrefix); - } - - public isValidAddress(address: string): boolean { - try { - const { prefix, data } = Bech32.decode(address); - if (prefix !== this.addressPrefix) { - return false; - } - return data.length === 20; - } catch { - return false; - } - } -} diff --git a/packages/bcp/src/cosmosconnection.spec.ts b/packages/bcp/src/cosmosconnection.spec.ts deleted file mode 100644 index efcd9eb2a3..0000000000 --- a/packages/bcp/src/cosmosconnection.spec.ts +++ /dev/null @@ -1,893 +0,0 @@ -import { Random, Secp256k1, Secp256k1Signature, Sha256 } from "@cosmjs/crypto"; -import { Bech32, fromBase64 } from "@cosmjs/encoding"; -import { decodeSignature } from "@cosmjs/sdk38"; -import { assert } from "@cosmjs/utils"; -import { - Account, - Address, - Algorithm, - Amount, - ChainId, - ConfirmedTransaction, - isBlockInfoPending, - isBlockInfoSucceeded, - isConfirmedTransaction, - isSendTransaction, - PubkeyBytes, - SendTransaction, - TokenTicker, - TransactionId, - TransactionState, - UnsignedTransaction, -} from "@iov/bcp"; -import { HdPaths, Secp256k1HdWallet, UserProfile } from "@iov/keycontrol"; -import BN from "bn.js"; - -import { CosmosConnection, TokenConfiguration } from "./cosmosconnection"; -import { encodeFullSignature } from "./encode"; -import * as testdata from "./testdata.spec"; - -function pendingWithoutWasmd(): void { - if (!process.env.WASMD_ENABLED) { - return pending("Set WASMD_ENABLED to enable Cosmos node-based tests"); - } -} - -const defaultAddressPrefix = "cosmos"; - -function makeRandomAddress(): Address { - return Bech32.encode(defaultAddressPrefix, Random.getBytes(20)) as Address; -} - -const alice = { - address0: "cosmos14qemq0vw6y3gc3u3e0aty2e764u4gs5le3hada" as Address, - pubkey0: { - algo: Algorithm.Secp256k1, - data: fromBase64("A9cXhWb8ZpqCzkA8dQCPV29KdeRLV3rUYxrkHudLbQtS") as PubkeyBytes, - }, -}; - -/** - * We use a different test account than the faucet, since BCP errors when transactions - * with multiple messages are found. - */ -const bob = { - mnemonic: "remain fragile remove stamp quiz bus country dress critic mammal office need", - path0: HdPaths.cosmosHub(0), - pubkey: { - algo: Algorithm.Secp256k1, - data: fromBase64("A0d/GxY+UALE+miWJP0qyq4/EayG1G6tsg24v+cbD6By") as PubkeyBytes, - }, - address: "cosmos1lvrwcvrqlc5ktzp2c4t22xgkx29q3y83lktgzl" as Address, -}; - -describe("CosmosConnection", () => { - const cosm = "COSM" as TokenTicker; - const httpUrl = "http://localhost:1317"; - const defaultChainId = "cosmos:testing" as ChainId; - const defaultEmptyAddress = "cosmos1h806c7khnvmjlywdrkdgk2vrayy2mmvf9rxk2r" as Address; - const defaultRecipient = "cosmos1t70qnpr0az8tf7py83m4ue5y89w58lkjmx0yq2" as Address; - const defaultAmount: Amount = { - quantity: "7744887", - fractionalDigits: 6, - tokenTicker: cosm, - }; - - const unusedAccount = { - pubkey: { - algo: Algorithm.Secp256k1, - data: fromBase64("ArkCaFUJ/IH+vKBmNRCdUVl3mCAhbopk9jjW4Ko4OfRQ") as PubkeyBytes, - }, - address: "cosmos1cjsxept9rkggzxztslae9ndgpdyt2408lk850u" as Address, - }; - - // this is for wasmd blockchain - const defaultConfig: TokenConfiguration = { - bankTokens: [ - { - fractionalDigits: 6, - name: "Fee Token", - ticker: "COSM", - denom: "ucosm", - }, - { - fractionalDigits: 6, - name: "Staking Token", - ticker: "STAKE", - denom: "ustake", - }, - ], - }; - - const atomConfig: TokenConfiguration = { - bankTokens: [ - { - fractionalDigits: 6, - name: "Atom", - ticker: "ATOM", - denom: "uatom", - }, - ], - }; - - describe("establish", () => { - it("can connect to Cosmos via http", async () => { - pendingWithoutWasmd(); - const connection = await CosmosConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig); - expect(connection).toBeTruthy(); - connection.disconnect(); - }); - }); - - describe("chainId", () => { - it("displays the chain ID", async () => { - pendingWithoutWasmd(); - const connection = await CosmosConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig); - expect(connection.chainId).toEqual(defaultChainId); - connection.disconnect(); - }); - }); - - describe("height", () => { - it("displays the current height", async () => { - pendingWithoutWasmd(); - const connection = await CosmosConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig); - const height = await connection.height(); - expect(height).toBeGreaterThan(0); - connection.disconnect(); - }); - }); - - describe("getToken", () => { - it("displays a given token", async () => { - pendingWithoutWasmd(); - const connection = await CosmosConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig); - const token = await connection.getToken("COSM" as TokenTicker); - expect(token).toEqual({ - fractionalDigits: 6, - tokenName: "Fee Token", - tokenTicker: "COSM" as TokenTicker, - }); - connection.disconnect(); - }); - - it("resolves to undefined if the token is not supported", async () => { - pendingWithoutWasmd(); - const connection = await CosmosConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig); - const token = await connection.getToken("whatever" as TokenTicker); - expect(token).toBeUndefined(); - connection.disconnect(); - }); - }); - - describe("getAllTokens", () => { - it("resolves to a list of all supported tokens", async () => { - pendingWithoutWasmd(); - const connection = await CosmosConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig); - const tokens = await connection.getAllTokens(); - expect(tokens).toEqual([ - { - fractionalDigits: 6, - tokenName: "Fee Token", - tokenTicker: "COSM" as TokenTicker, - }, - { - fractionalDigits: 6, - tokenName: "Staking Token", - tokenTicker: "STAKE" as TokenTicker, - }, - ]); - connection.disconnect(); - }); - }); - - describe("identifier", () => { - it("calculates tx hash from PostableBytes", async () => { - pendingWithoutWasmd(); - const connection = await CosmosConnection.establish(httpUrl, defaultAddressPrefix, atomConfig); - const id = await connection.identifier(testdata.signedTxJson); - expect(id).toMatch(/^[0-9A-F]{64}$/); - expect(id).toEqual(testdata.txId); - }); - }); - - describe("getAccount", () => { - it("gets an empty account by address", async () => { - pendingWithoutWasmd(); - const connection = await CosmosConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig); - const account = await connection.getAccount({ address: defaultEmptyAddress }); - expect(account).toBeUndefined(); - connection.disconnect(); - }); - - it("gets an account by address", async () => { - pendingWithoutWasmd(); - const connection = await CosmosConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig); - const account = await connection.getAccount({ address: unusedAccount.address }); - assert(account, "Account must be defined"); - expect(account.address).toEqual(unusedAccount.address); - expect(account.pubkey).toBeUndefined(); - expect(account.balance).toEqual([ - { - tokenTicker: "COSM" as TokenTicker, - quantity: "1000000000", - fractionalDigits: 6, - }, - { - tokenTicker: "STAKE" as TokenTicker, - quantity: "1000000000", - fractionalDigits: 6, - }, - ]); - connection.disconnect(); - }); - - it("gets an account by pubkey", async () => { - pendingWithoutWasmd(); - const connection = await CosmosConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig); - const byAddress = await connection.getAccount({ address: unusedAccount.address }); - const byPubkey = await connection.getAccount({ pubkey: unusedAccount.pubkey }); - expect(byPubkey).toEqual(byAddress); // above we verified that by address works as expected - connection.disconnect(); - }); - - it("has a pubkey when getting account with transactions", async () => { - pendingWithoutWasmd(); - const connection = await CosmosConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig); - const account = await connection.getAccount({ address: alice.address0 }); - expect(account?.pubkey).toEqual(alice.pubkey0); - connection.disconnect(); - }); - }); - - describe("watchAccount", () => { - it("can watch account by address", (done) => { - pendingWithoutWasmd(); - const recipient = makeRandomAddress(); - const events = new Array(); - - (async () => { - const connection = await CosmosConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig); - const subscription = connection.watchAccount({ address: recipient }).subscribe({ - next: (event) => { - events.push(event); - - if (events.length === 3) { - const [event1, event2, event3] = events; - - expect(event1).toBeUndefined(); - - assert(event2, "Second event must not be undefined"); - expect(event2.address).toEqual(recipient); - expect(event2.pubkey).toBeUndefined(); - expect(event2.balance.length).toEqual(1); - expect(event2.balance[0].quantity).toEqual(defaultAmount.quantity); - expect(event2.balance[0].tokenTicker).toEqual(defaultAmount.tokenTicker); - - assert(event3, "Third event must not be undefined"); - expect(event3.address).toEqual(recipient); - expect(event3.pubkey).toBeUndefined(); - expect(event3.balance.length).toEqual(1); - expect(event3.balance[0].quantity).toEqual(new BN(defaultAmount.quantity).imuln(2).toString()); - expect(event3.balance[0].tokenTicker).toEqual(defaultAmount.tokenTicker); - - subscription.unsubscribe(); - connection.disconnect(); - done(); - } - }, - complete: done.fail, - error: done.fail, - }); - - const profile = new UserProfile(); - const wallet = profile.addWallet(Secp256k1HdWallet.fromMnemonic(bob.mnemonic)); - const sender = await profile.createIdentity(wallet.id, defaultChainId, bob.path0); - const senderAddress = connection.codec.identityToAddress(sender); - - for (const i of [0, 1]) { - const sendTx = await connection.withDefaultFee({ - kind: "bcp/send", - chainId: defaultChainId, - senderPubkey: sender.pubkey, - sender: senderAddress, - recipient: recipient, - amount: defaultAmount, - memo: `Trigger for new event ${i}`, - }); - const nonce = await connection.getNonce({ address: senderAddress }); - const signedTransaction = await profile.signTransaction(sender, sendTx, connection.codec, nonce); - const result = await connection.postTx(connection.codec.bytesToPost(signedTransaction)); - await result.blockInfo.waitFor((info) => !isBlockInfoPending(info)); - } - })().catch(done.fail); - }); - }); - - describe("getTx", () => { - it("can get a recently posted bank send transaction", async () => { - pendingWithoutWasmd(); - const connection = await CosmosConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig); - const profile = new UserProfile(); - const wallet = profile.addWallet(Secp256k1HdWallet.fromMnemonic(bob.mnemonic)); - const senderIdentity = await profile.createIdentity(wallet.id, defaultChainId, bob.path0); - const senderAddress = connection.codec.identityToAddress(senderIdentity); - - const unsigned = await connection.withDefaultFee({ - kind: "bcp/send", - chainId: defaultChainId, - sender: senderAddress, - recipient: defaultRecipient, - memo: "My first payment", - amount: { - quantity: "75000", - fractionalDigits: 6, - tokenTicker: cosm, - }, - }); - const nonce = await connection.getNonce({ address: senderAddress }); - const signed = await profile.signTransaction(senderIdentity, unsigned, connection.codec, nonce); - const postableBytes = connection.codec.bytesToPost(signed); - const response = await connection.postTx(postableBytes); - const { transactionId } = response; - await response.blockInfo.waitFor((info) => isBlockInfoSucceeded(info)); - - const getResponse = await connection.getTx(transactionId); - expect(getResponse.transactionId).toEqual(transactionId); - assert(isConfirmedTransaction(getResponse), "Expected transaction to succeed"); - assert(getResponse.log, "Log must be available"); - // we get a json response in the log for each msg, multiple events is good (transfer succeeded) - const [firstLog] = JSON.parse(getResponse.log); - expect(firstLog.events.length).toEqual(2); - - const { transaction, signatures } = getResponse; - assert(isSendTransaction(transaction), "Expected send transaction"); - expect(transaction).toEqual(unsigned); - expect(signatures.length).toEqual(1); - expect(signatures[0]).toEqual({ - nonce: signed.signatures[0].nonce, - pubkey: { - algo: signed.signatures[0].pubkey.algo, - data: Secp256k1.compressPubkey(signed.signatures[0].pubkey.data), - }, - signature: Secp256k1.trimRecoveryByte(signed.signatures[0].signature), - }); - - connection.disconnect(); - }); - - it("can get an old transaction", async () => { - pendingWithoutWasmd(); - const connection = await CosmosConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig); - - const results = await connection.searchTx({ sentFromOrTo: bob.address }); - const firstSearchResult = results.find(() => true); - assert(firstSearchResult, "At least one transaction sent by the faucet must be available."); - assert(isConfirmedTransaction(firstSearchResult), "Transaction must be confirmed."); - const { - transaction: searchedTransaction, - transactionId: searchedTransactionId, - height: searchedHeight, - } = firstSearchResult; - - const getResponse = await connection.getTx(searchedTransactionId); - assert(isConfirmedTransaction(getResponse), "Expected transaction to succeed"); - const { height, transactionId, log, transaction, signatures } = getResponse; - - // Test properties of getTx result: height, transactionId, log, transaction - expect(height).toEqual(searchedHeight); - expect(transactionId).toEqual(searchedTransactionId); - assert(log, "Log must be available"); - const [firstLog] = JSON.parse(log); - expect(firstLog.events.length).toEqual(2); - expect(transaction).toEqual(searchedTransaction); - - // Signature test ensures the nonce is correct - expect(signatures.length).toEqual(1); - const signBytes = connection.codec.bytesToSign(getResponse.transaction, signatures[0].nonce).bytes; - const { pubkey, signature } = decodeSignature(encodeFullSignature(signatures[0])); - const prehashed = new Sha256(signBytes).digest(); - const valid = await Secp256k1.verifySignature( - Secp256k1Signature.fromFixedLength(signature), - prehashed, - pubkey, - ); - expect(valid).toEqual(true); - - connection.disconnect(); - }); - - it("throws for non-existent transaction", async () => { - pendingWithoutWasmd(); - const connection = await CosmosConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig); - - const nonExistentId = "0000000000000000000000000000000000000000000000000000000000000000" as TransactionId; - await connection.getTx(nonExistentId).then( - () => fail("this must not succeed"), - (error) => expect(error).toMatch(/transaction does not exist/i), - ); - - connection.disconnect(); - }); - }); - - describe("searchTx", () => { - it("can post and search for a transaction", async () => { - pendingWithoutWasmd(); - const connection = await CosmosConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig); - const profile = new UserProfile(); - const wallet = profile.addWallet(Secp256k1HdWallet.fromMnemonic(bob.mnemonic)); - const sender = await profile.createIdentity(wallet.id, defaultChainId, bob.path0); - const senderAddress = connection.codec.identityToAddress(sender); - - const unsigned = await connection.withDefaultFee({ - kind: "bcp/send", - chainId: defaultChainId, - sender: senderAddress, - recipient: defaultRecipient, - memo: "My first payment", - amount: { - quantity: "75000", - fractionalDigits: 6, - tokenTicker: cosm, - }, - }); - const nonce = await connection.getNonce({ address: senderAddress }); - const signed = await profile.signTransaction(sender, unsigned, connection.codec, nonce); - const postableBytes = connection.codec.bytesToPost(signed); - const response = await connection.postTx(postableBytes); - const { transactionId } = response; - const blockInfo = await response.blockInfo.waitFor((info) => !isBlockInfoPending(info)); - expect(blockInfo.state).toEqual(TransactionState.Succeeded); - - // search by id - const byIdResults = await connection.searchTx({ id: transactionId }); - expect(byIdResults.length).toEqual(1); - const byIdResult = byIdResults[0]; - expect(byIdResult.transactionId).toEqual(transactionId); - assert(isConfirmedTransaction(byIdResult), "Expected transaction to succeed"); - assert(byIdResult.log, "Log must be available"); - const [firstByIdlog] = JSON.parse(byIdResult.log); - expect(firstByIdlog.events.length).toEqual(2); - expect(firstByIdlog.events[0].type).toEqual("message"); - expect(firstByIdlog.events[1].type).toEqual("transfer"); - const byIdTransaction = byIdResult.transaction; - assert(isSendTransaction(byIdTransaction), "Expected send transaction"); - expect(byIdTransaction).toEqual(unsigned); - - // search by sender address - const bySenderResults = await connection.searchTx({ sentFromOrTo: senderAddress }); - expect(bySenderResults).toBeTruthy(); - expect(bySenderResults.length).toBeGreaterThanOrEqual(1); - const bySenderResult = bySenderResults[bySenderResults.length - 1]; - expect(bySenderResult.transactionId).toEqual(transactionId); - assert(isConfirmedTransaction(bySenderResult), "Expected transaction to succeed"); - assert(bySenderResult.log, "Log must be available"); - const [firstBySenderLog] = JSON.parse(bySenderResult.log); - expect(firstBySenderLog.events.length).toEqual(2); - expect(firstBySenderLog.events[0].type).toEqual("message"); - expect(firstBySenderLog.events[1].type).toEqual("transfer"); - const bySenderTransaction = bySenderResult.transaction; - assert(isSendTransaction(bySenderTransaction), "Expected send transaction"); - expect(bySenderTransaction).toEqual(unsigned); - - // search by recipient address - const byRecipientResults = await connection.searchTx({ sentFromOrTo: defaultRecipient }); - expect(byRecipientResults.length).toBeGreaterThanOrEqual(1); - const byRecipientResult = byRecipientResults[byRecipientResults.length - 1]; - expect(byRecipientResult.transactionId).toEqual(transactionId); - assert(isConfirmedTransaction(byRecipientResult), "Expected transaction to succeed"); - assert(byRecipientResult.log, "Log must be available"); - const [firstByRecipientLog] = JSON.parse(bySenderResult.log); - expect(firstByRecipientLog.events.length).toEqual(2); - expect(firstByRecipientLog.events[0].type).toEqual("message"); - expect(firstByRecipientLog.events[1].type).toEqual("transfer"); - const byRecipeintTransaction = byRecipientResult.transaction; - assert(isSendTransaction(byRecipeintTransaction), "Expected send transaction"); - expect(byRecipeintTransaction).toEqual(unsigned); - - // search by height - const heightResults = await connection.searchTx({ height: byIdResult.height }); - expect(heightResults.length).toBeGreaterThanOrEqual(1); - expect(heightResults).toContain( - jasmine.objectContaining({ - transactionId: transactionId, - transaction: unsigned, - }), - ); - - connection.disconnect(); - }); - - it("can search by minHeight and maxHeight", async () => { - pendingWithoutWasmd(); - const connection = await CosmosConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig); - const profile = new UserProfile(); - const wallet = profile.addWallet(Secp256k1HdWallet.fromMnemonic(bob.mnemonic)); - const sender = await profile.createIdentity(wallet.id, defaultChainId, bob.path0); - const senderAddress = connection.codec.identityToAddress(sender); - - const recipient = makeRandomAddress(); - const unsigned = await connection.withDefaultFee({ - kind: "bcp/send", - chainId: defaultChainId, - sender: senderAddress, - recipient: recipient, - memo: "My first payment", - amount: { - quantity: "75000", - fractionalDigits: 6, - tokenTicker: cosm, - }, - }); - const nonce = await connection.getNonce({ address: senderAddress }); - const signed = await profile.signTransaction(sender, unsigned, connection.codec, nonce); - const postableBytes = connection.codec.bytesToPost(signed); - const response = await connection.postTx(postableBytes); - const { transactionId } = response; - const blockInfo = await response.blockInfo.waitFor((info) => !isBlockInfoPending(info)); - assert(isBlockInfoSucceeded(blockInfo)); - const { height } = blockInfo; - - // search by ID - { - const results = await connection.searchTx({ id: transactionId }); - expect(results.length).toEqual(1); - } - { - const results = await connection.searchTx({ id: transactionId, minHeight: height }); - expect(results.length).toEqual(1); - } - { - const results = await connection.searchTx({ id: transactionId, minHeight: height - 2 }); - expect(results.length).toEqual(1); - } - { - const results = await connection.searchTx({ id: transactionId, maxHeight: height }); - expect(results.length).toEqual(1); - } - { - const results = await connection.searchTx({ id: transactionId, maxHeight: height + 2 }); - expect(results.length).toEqual(1); - } - { - const results = await connection.searchTx({ - id: transactionId, - minHeight: height, - maxHeight: height, - }); - expect(results.length).toEqual(1); - } - { - const results = await connection.searchTx({ id: transactionId, minHeight: height + 1 }); - expect(results.length).toEqual(0); - } - { - const results = await connection.searchTx({ id: transactionId, maxHeight: height - 1 }); - expect(results.length).toEqual(0); - } - { - const results = await connection.searchTx({ - id: transactionId, - minHeight: height + 1, - maxHeight: Number.MAX_SAFE_INTEGER, - }); - expect(results.length).toEqual(0); - } - { - const results = await connection.searchTx({ id: transactionId, minHeight: 0, maxHeight: height - 1 }); - expect(results.length).toEqual(0); - } - - // search by recipient - { - const results = await connection.searchTx({ sentFromOrTo: recipient }); - expect(results.length).toEqual(1); - } - { - const results = await connection.searchTx({ sentFromOrTo: recipient, minHeight: height }); - expect(results.length).toEqual(1); - } - { - const results = await connection.searchTx({ sentFromOrTo: recipient, minHeight: height - 2 }); - expect(results.length).toEqual(1); - } - { - const results = await connection.searchTx({ sentFromOrTo: recipient, maxHeight: height }); - expect(results.length).toEqual(1); - } - { - const results = await connection.searchTx({ sentFromOrTo: recipient, maxHeight: height + 2 }); - expect(results.length).toEqual(1); - } - { - const results = await connection.searchTx({ sentFromOrTo: recipient, minHeight: height + 1 }); - expect(results.length).toEqual(0); - } - { - const results = await connection.searchTx({ sentFromOrTo: recipient, maxHeight: height - 1 }); - expect(results.length).toEqual(0); - } - { - const results = await connection.searchTx({ - sentFromOrTo: recipient, - minHeight: height, - maxHeight: height, - }); - expect(results.length).toEqual(1); - } - { - const results = await connection.searchTx({ sentFromOrTo: recipient, minHeight: height + 1 }); - expect(results.length).toEqual(0); - } - { - const results = await connection.searchTx({ sentFromOrTo: recipient, maxHeight: height - 1 }); - expect(results.length).toEqual(0); - } - { - const results = await connection.searchTx({ - sentFromOrTo: recipient, - minHeight: height + 1, - maxHeight: Number.MAX_SAFE_INTEGER, - }); - expect(results.length).toEqual(0); - } - { - const results = await connection.searchTx({ - sentFromOrTo: recipient, - minHeight: 0, - maxHeight: height - 1, - }); - expect(results.length).toEqual(0); - } - - // search by height - { - const results = await connection.searchTx({ height: height }); - expect(results.length).toBeGreaterThanOrEqual(1); - } - { - const results = await connection.searchTx({ height: height, minHeight: height }); - expect(results.length).toBeGreaterThanOrEqual(1); - } - { - const results = await connection.searchTx({ height: height, minHeight: height - 2 }); - expect(results.length).toBeGreaterThanOrEqual(1); - } - { - const results = await connection.searchTx({ height: height, maxHeight: height }); - expect(results.length).toBeGreaterThanOrEqual(1); - } - { - const results = await connection.searchTx({ height: height, maxHeight: height + 2 }); - expect(results.length).toBeGreaterThanOrEqual(1); - } - { - const results = await connection.searchTx({ height: height, minHeight: height + 1 }); - expect(results.length).toEqual(0); - } - { - const results = await connection.searchTx({ height: height, maxHeight: height - 1 }); - expect(results.length).toEqual(0); - } - { - const results = await connection.searchTx({ - height: height, - minHeight: height, - maxHeight: height, - }); - expect(results.length).toBeGreaterThanOrEqual(1); - } - { - const results = await connection.searchTx({ height: height, minHeight: height + 1 }); - expect(results.length).toEqual(0); - } - { - const results = await connection.searchTx({ height: height, maxHeight: height - 1 }); - expect(results.length).toEqual(0); - } - { - const results = await connection.searchTx({ - height: height, - minHeight: height + 1, - maxHeight: Number.MAX_SAFE_INTEGER, - }); - expect(results.length).toEqual(0); - } - { - const results = await connection.searchTx({ - height: height, - minHeight: 0, - maxHeight: height - 1, - }); - expect(results.length).toEqual(0); - } - - connection.disconnect(); - }); - }); - - describe("liveTx", () => { - it("can listen to transactions by recipient address (transactions in history and updates)", (done) => { - pendingWithoutWasmd(); - - (async () => { - const connection = await CosmosConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig); - - const profile = new UserProfile(); - const wallet = profile.addWallet(Secp256k1HdWallet.fromMnemonic(bob.mnemonic)); - const sender = await profile.createIdentity(wallet.id, defaultChainId, bob.path0); - - // send transactions - - const recipientAddress = makeRandomAddress(); - const sendA = await connection.withDefaultFee({ - kind: "bcp/send", - chainId: defaultChainId, - senderPubkey: sender.pubkey, - sender: connection.codec.identityToAddress(sender), - recipient: recipientAddress, - amount: defaultAmount, - memo: `liveTx() test A ${Math.random()}`, - }); - - const sendB = await connection.withDefaultFee({ - kind: "bcp/send", - chainId: defaultChainId, - senderPubkey: sender.pubkey, - sender: connection.codec.identityToAddress(sender), - recipient: recipientAddress, - amount: defaultAmount, - memo: `liveTx() test B ${Math.random()}`, - }); - - const sendC = await connection.withDefaultFee({ - kind: "bcp/send", - chainId: defaultChainId, - senderPubkey: sender.pubkey, - sender: connection.codec.identityToAddress(sender), - recipient: recipientAddress, - amount: defaultAmount, - memo: `liveTx() test C ${Math.random()}`, - }); - - const [nonceA, nonceB, nonceC] = await connection.getNonces({ pubkey: sender.pubkey }, 3); - const signedA = await profile.signTransaction(sender, sendA, connection.codec, nonceA); - const signedB = await profile.signTransaction(sender, sendB, connection.codec, nonceB); - const signedC = await profile.signTransaction(sender, sendC, connection.codec, nonceC); - const bytesToPostA = connection.codec.bytesToPost(signedA); - const bytesToPostB = connection.codec.bytesToPost(signedB); - const bytesToPostC = connection.codec.bytesToPost(signedC); - - // Post A and B. Unfortunately the REST server API does not support sending them in parallel because the sequence check fails. - const postResultA = await connection.postTx(bytesToPostA); - await postResultA.blockInfo.waitFor((info) => !isBlockInfoPending(info)); - const postResultB = await connection.postTx(bytesToPostB); - await postResultB.blockInfo.waitFor((info) => !isBlockInfoPending(info)); - - // setup listener after A and B are in block - const events = new Array>(); - const subscription = connection.liveTx({ sentFromOrTo: recipientAddress }).subscribe({ - next: (event) => { - assert(isConfirmedTransaction(event), "Confirmed transaction expected"); - events.push(event); - - assert(isSendTransaction(event.transaction), "Unexpected transaction type"); - expect(event.transaction.recipient).toEqual(recipientAddress); - - if (events.length === 3) { - expect(events[1].height).toEqual(events[0].height + 1); - expect(events[2].height).toBeGreaterThan(events[1].height); - - subscription.unsubscribe(); - connection.disconnect(); - done(); - } - }, - }); - - // Post C - await connection.postTx(bytesToPostC); - })().catch(done.fail); - }); - - it("can listen to transactions by ID (transaction in history)", (done) => { - pendingWithoutWasmd(); - - (async () => { - const connection = await CosmosConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig); - - const profile = new UserProfile(); - const wallet = profile.addWallet(Secp256k1HdWallet.fromMnemonic(bob.mnemonic)); - const sender = await profile.createIdentity(wallet.id, defaultChainId, bob.path0); - - const recipientAddress = makeRandomAddress(); - const send = await connection.withDefaultFee({ - kind: "bcp/send", - chainId: defaultChainId, - senderPubkey: sender.pubkey, - sender: connection.codec.identityToAddress(sender), - recipient: recipientAddress, - amount: defaultAmount, - memo: `liveTx() test ${Math.random()}`, - }); - - const nonce = await connection.getNonce({ pubkey: sender.pubkey }); - const signed = await profile.signTransaction(sender, send, connection.codec, nonce); - const bytesToPost = connection.codec.bytesToPost(signed); - - const postResult = await connection.postTx(bytesToPost); - const transactionId = postResult.transactionId; - - // Wait for a block - await postResult.blockInfo.waitFor((info) => !isBlockInfoPending(info)); - - // setup listener after transaction is in block - const events = new Array>(); - const subscription = connection.liveTx({ id: transactionId }).subscribe({ - next: (event) => { - assert(isConfirmedTransaction(event), "Confirmed transaction expected"); - events.push(event); - - assert(isSendTransaction(event.transaction), "Unexpected transaction type"); - expect(event.transaction.recipient).toEqual(recipientAddress); - expect(event.transactionId).toEqual(transactionId); - - subscription.unsubscribe(); - connection.disconnect(); - done(); - }, - }); - })().catch(done.fail); - }); - - it("can listen to transactions by ID (transaction in updates)", (done) => { - pendingWithoutWasmd(); - - (async () => { - const connection = await CosmosConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig); - - const profile = new UserProfile(); - const wallet = profile.addWallet(Secp256k1HdWallet.fromMnemonic(bob.mnemonic)); - const sender = await profile.createIdentity(wallet.id, defaultChainId, bob.path0); - - // send transactions - - const recipientAddress = makeRandomAddress(); - const send = await connection.withDefaultFee({ - kind: "bcp/send", - chainId: defaultChainId, - senderPubkey: sender.pubkey, - sender: connection.codec.identityToAddress(sender), - recipient: recipientAddress, - amount: defaultAmount, - memo: `liveTx() test ${Math.random()}`, - }); - - const nonce = await connection.getNonce({ pubkey: sender.pubkey }); - const signed = await profile.signTransaction(sender, send, connection.codec, nonce); - const bytesToPost = connection.codec.bytesToPost(signed); - - const postResult = await connection.postTx(bytesToPost); - const transactionId = postResult.transactionId; - - // setup listener before transaction is in block - const events = new Array>(); - const subscription = connection.liveTx({ id: transactionId }).subscribe({ - next: (event) => { - assert(isConfirmedTransaction(event), "Confirmed transaction expected"); - events.push(event); - - assert(isSendTransaction(event.transaction), "Unexpected transaction type"); - expect(event.transaction.recipient).toEqual(recipientAddress); - expect(event.transactionId).toEqual(transactionId); - - subscription.unsubscribe(); - connection.disconnect(); - done(); - }, - }); - })().catch(done.fail); - }); - }); -}); diff --git a/packages/bcp/src/cosmosconnection.ts b/packages/bcp/src/cosmosconnection.ts deleted file mode 100644 index 32036c6c83..0000000000 --- a/packages/bcp/src/cosmosconnection.ts +++ /dev/null @@ -1,489 +0,0 @@ -import { fromUtf8 } from "@cosmjs/encoding"; -import { Uint53 } from "@cosmjs/math"; -import { - CosmosClient, - findSequenceForSignedTx, - IndexedTx, - isMsgSend, - isStdTx, - SearchTxFilter, -} from "@cosmjs/sdk38"; -import { - Account, - AccountQuery, - AddressQuery, - BlockchainConnection, - BlockHeader, - BlockId, - BlockInfo, - ChainId, - ConfirmedAndSignedTransaction, - ConfirmedTransaction, - FailedTransaction, - Fee, - isConfirmedTransaction, - isPubkeyQuery, - isSendTransaction, - Nonce, - PostableBytes, - PostTxResponse, - PubkeyQuery, - SignedTransaction, - Token, - TokenTicker, - TransactionId, - TransactionQuery, - TransactionState, - TxCodec, - UnsignedTransaction, -} from "@iov/bcp"; -import { concat, DefaultValueProducer, ValueAndUpdates } from "@iov/stream"; -import equal from "fast-deep-equal"; -import { ReadonlyDate } from "readonly-date"; -import { Producer, Stream } from "xstream"; - -import { pubkeyToAddress } from "./address"; -import { Caip5 } from "./caip5"; -import { CosmosCodec } from "./cosmoscodec"; -import { decodeAmount, decodePubkey, parseTxsResponseSigned, parseTxsResponseUnsigned } from "./decode"; -import { buildSignedTx } from "./encode"; -import { accountToNonce, BankToken } from "./types"; - -// poll every 0.5 seconds (block time 1s) -const defaultPollInterval = 500; - -export interface TokenConfiguration { - /** Supported tokens of the Cosmos SDK bank module */ - readonly bankTokens: ReadonlyArray; -} - -function isDefined(value: X | undefined): value is X { - return value !== undefined; -} - -function deduplicate(input: ReadonlyArray, comparator: (a: T, b: T) => number): Array { - const out = new Array(); - for (const element of input) { - if (out.find((o) => comparator(o, element) === 0) === undefined) { - out.push(element); - } - } - return out; -} - -/** Compares transaxtion by height. If the height is equal, compare by hash to ensure deterministic order */ -function compareByHeightAndHash(a: IndexedTx, b: IndexedTx): number { - if (a.height === b.height) { - return a.hash.localeCompare(b.hash); - } else { - return a.height - b.height; - } -} - -/** Account and undefined are valid events. The third option means no event fired yet */ -type LastWatchAccountEvent = Account | undefined | "no_event_fired_yet"; - -export class CosmosConnection implements BlockchainConnection { - // we must know prefix and tokens a priori to understand the chain - public static async establish( - url: string, - addressPrefix: string, - tokens: TokenConfiguration, - ): Promise { - const cosmosClient = new CosmosClient(url); - const chainData = await this.initialize(cosmosClient); - return new CosmosConnection(cosmosClient, chainData, addressPrefix, tokens); - } - - private static async initialize(cosmosClient: CosmosClient): Promise { - const rawChainId = await cosmosClient.getChainId(); - return Caip5.encode(rawChainId); - } - - public readonly chainId: ChainId; - public readonly codec: TxCodec; - - private readonly cosmosClient: CosmosClient; - private readonly addressPrefix: string; - private readonly bankTokens: readonly BankToken[]; - - // these are derived from arguments (cached for use in multiple functions) - private readonly feeToken: BankToken | undefined; - private readonly supportedTokens: readonly Token[]; - - private constructor( - cosmosClient: CosmosClient, - chainId: ChainId, - addressPrefix: string, - tokens: TokenConfiguration, - ) { - this.cosmosClient = cosmosClient; - this.chainId = chainId; - this.codec = new CosmosCodec(addressPrefix, tokens.bankTokens); - this.addressPrefix = addressPrefix; - this.bankTokens = tokens.bankTokens; - this.feeToken = this.bankTokens.find(() => true); - this.supportedTokens = tokens.bankTokens - .map((info) => ({ - tokenTicker: info.ticker as TokenTicker, - tokenName: info.name, - fractionalDigits: info.fractionalDigits, - })) - .sort((a, b) => a.tokenTicker.localeCompare(b.tokenTicker)); - } - - public disconnect(): void { - return; - } - - public async height(): Promise { - return this.cosmosClient.getHeight(); - } - - public async getToken(searchTicker: TokenTicker): Promise { - return (await this.getAllTokens()).find(({ tokenTicker }) => tokenTicker === searchTicker); - } - - public async getAllTokens(): Promise { - return this.supportedTokens; - } - - /** - * This is a replacement for the unimplemented CosmosCodec.identifier. Here we have more - * context and network available, which we might use to implement the API in an async way. - */ - public async identifier(signed: SignedTransaction): Promise { - const tx = buildSignedTx(signed, this.bankTokens); - const id = await this.cosmosClient.getIdentifier(tx); - return id as TransactionId; - } - - public async getAccount(query: AccountQuery): Promise { - const address = isPubkeyQuery(query) ? pubkeyToAddress(query.pubkey, this.addressPrefix) : query.address; - const bankAccount = await this.cosmosClient.getAccount(address); - - const supportedBankCoins = (bankAccount?.balance || []).filter(({ denom }) => - this.bankTokens.find((token) => token.denom === denom), - ); - - if (!bankAccount) { - return undefined; - } else { - const balance = [ - ...supportedBankCoins.map((coin) => decodeAmount(this.bankTokens, coin)), - ].sort((a, b) => a.tokenTicker.localeCompare(b.tokenTicker)); - const pubkey = bankAccount?.pubkey ? decodePubkey(bankAccount.pubkey) : undefined; - return { - address: address, - balance: balance, - pubkey: pubkey, - }; - } - } - - public watchAccount(query: AccountQuery): Stream { - let lastEvent: LastWatchAccountEvent = "no_event_fired_yet"; - let pollInternal: NodeJS.Timeout | undefined; - const producer: Producer = { - start: async (listener) => { - const poll = async (): Promise => { - try { - const event = await this.getAccount(query); - if (!equal(event, lastEvent)) { - listener.next(event); - lastEvent = event; - } - } catch (error) { - listener.error(error); - } - }; - - pollInternal = setInterval(poll, defaultPollInterval); - await poll(); - }, - stop: () => { - if (pollInternal) { - clearInterval(pollInternal); - pollInternal = undefined; - } - }, - }; - return Stream.create(producer); - } - - public async getNonce(query: AddressQuery | PubkeyQuery): Promise { - const address = isPubkeyQuery(query) ? pubkeyToAddress(query.pubkey, this.addressPrefix) : query.address; - const { accountNumber, sequence } = await this.cosmosClient.getNonce(address); - return accountToNonce(accountNumber, sequence); - } - - public async getNonces(query: AddressQuery | PubkeyQuery, count: number): Promise { - const checkedCount = new Uint53(count).toNumber(); - if (checkedCount === 0) { - return []; - } - const firstNonce = await this.getNonce(query); - // Note: this still works with the encoded format (see types/accountToNonce) as least-significant digits are sequence - return [...new Array(checkedCount)].map((_, i) => (firstNonce + i) as Nonce); - } - - public async getBlockHeader(height: number): Promise { - const { id, header, txs } = await this.cosmosClient.getBlock(height); - return { - id: id as BlockId, - height: header.height, - time: new ReadonlyDate(header.time), - transactionCount: txs.length, - }; - } - - public watchBlockHeaders(): Stream { - throw new Error("not implemented"); - } - - public async getTx( - id: TransactionId, - ): Promise | FailedTransaction> { - const results = await this.cosmosClient.searchTx({ id: id }); - switch (results.length) { - case 0: - throw new Error("Transaction does not exist"); - case 1: - return this.parseAndPopulateTxResponseSigned(results[0]); - default: - throw new Error("Got unexpected amount of search results"); - } - } - - public async postTx(tx: PostableBytes): Promise { - const txAsJson = JSON.parse(fromUtf8(tx)); - if (!isStdTx(txAsJson)) throw new Error("Postable bytes must contain a JSON encoded StdTx"); - const { transactionHash, rawLog } = await this.cosmosClient.postTx(txAsJson); - const transactionId = transactionHash as TransactionId; - const firstEvent: BlockInfo = { state: TransactionState.Pending }; - let blockInfoInterval: NodeJS.Timeout; - let lastEventSent: BlockInfo; - const producer = new DefaultValueProducer(firstEvent, { - onStarted: () => { - blockInfoInterval = setInterval(async () => { - const searchResult = (await this.searchTx({ id: transactionId })).find(() => true); - if (searchResult) { - const event: BlockInfo = isConfirmedTransaction(searchResult) - ? { - state: TransactionState.Succeeded, - height: searchResult.height, - confirmations: searchResult.confirmations, - } - : { - state: TransactionState.Failed, - height: searchResult.height, - code: searchResult.code, - message: searchResult.message, - }; - if (!equal(event, lastEventSent)) { - producer.update(event); - lastEventSent = event; - } - } - }, defaultPollInterval); - }, - onStop: () => clearInterval(blockInfoInterval), - }); - return { - blockInfo: new ValueAndUpdates(producer), - transactionId: transactionId, - log: rawLog, - }; - } - - public async searchTx({ - height, - id, - maxHeight, - minHeight, - sentFromOrTo, - signedBy, - tags, - }: TransactionQuery): Promise | FailedTransaction)[]> { - if ([signedBy, tags].some(isDefined)) { - throw new Error("Transaction query by signedBy or tags not yet supported"); - } - - if ([id, height, sentFromOrTo].filter(isDefined).length !== 1) { - throw new Error( - "Transaction query by id, height and sentFromOrTo is mutually exclusive. Exactly one must be set.", - ); - } - - const filter: SearchTxFilter = { minHeight: minHeight, maxHeight: maxHeight }; - - let txs: readonly IndexedTx[]; - if (id) { - txs = await this.cosmosClient.searchTx({ id: id }, filter); - } else if (height) { - txs = await this.cosmosClient.searchTx({ height: height }, filter); - } else if (sentFromOrTo) { - const pendingRequests = new Array>(); - pendingRequests.push(this.cosmosClient.searchTx({ sentFromOrTo: sentFromOrTo }, filter)); - const responses = await Promise.all(pendingRequests); - const allResults = responses.reduce((accumulator, results) => accumulator.concat(results), []); - txs = deduplicate(allResults, (a, b) => a.hash.localeCompare(b.hash)).sort(compareByHeightAndHash); - } else { - throw new Error("Unsupported query"); - } - - return txs.map((tx) => this.parseAndPopulateTxResponseUnsigned(tx)); - } - - public listenTx( - _query: TransactionQuery, - ): Stream | FailedTransaction> { - throw new Error("not implemented"); - } - - public liveTx( - query: TransactionQuery, - ): Stream | FailedTransaction> { - if ([query.height, query.signedBy, query.tags].some(isDefined)) { - throw new Error("Transaction query by height, signedBy or tags not yet supported"); - } - - if (query.id) { - if (query.minHeight || query.maxHeight) { - throw new Error("Query by minHeight/maxHeight not supported together with ID"); - } - - // concat never() because we want non-completing streams consistently - return concat(this.waitForTransaction(query.id), Stream.never()); - } else if (query.sentFromOrTo) { - let pollInternal: NodeJS.Timeout | undefined; - const producer: Producer | FailedTransaction> = { - start: async (listener) => { - let minHeight = query.minHeight || 0; - const maxHeight = query.maxHeight || Number.MAX_SAFE_INTEGER; - - const poll = async (): Promise => { - const result = await this.searchTx({ - sentFromOrTo: query.sentFromOrTo, - minHeight: minHeight, - maxHeight: maxHeight, - }); - for (const item of result) { - listener.next(item); - if (item.height >= minHeight) { - // we assume we got all matching transactions from block `item.height` now - minHeight = item.height + 1; - } - } - }; - - await poll(); - pollInternal = setInterval(poll, defaultPollInterval); - }, - stop: () => { - if (pollInternal) { - clearInterval(pollInternal); - pollInternal = undefined; - } - }, - }; - return Stream.create(producer); - } else { - throw new Error("Unsupported query."); - } - } - - public async getFeeQuote(tx: UnsignedTransaction): Promise { - if (!isSendTransaction(tx)) { - throw new Error("Received transaction of unsupported kind."); - } - if (!this.feeToken) throw new Error("This connection has no fee token configured."); - return { - tokens: { - fractionalDigits: this.feeToken.fractionalDigits, - quantity: "5000", - tokenTicker: this.feeToken.ticker as TokenTicker, - }, - gasLimit: "200000", - }; - } - - public async withDefaultFee(tx: T): Promise { - return { - ...tx, - fee: await this.getFeeQuote(tx), - }; - } - - private parseAndPopulateTxResponseUnsigned( - response: IndexedTx, - ): ConfirmedTransaction | FailedTransaction { - return parseTxsResponseUnsigned(this.chainId, response.height, response, this.bankTokens); - } - - private async parseAndPopulateTxResponseSigned( - response: IndexedTx, - ): Promise | FailedTransaction> { - const firstMsg = response.tx.value.msg.find(() => true); - if (!firstMsg) throw new Error("Got transaction without a first message. What is going on here?"); - - let senderAddress: string; - if (isMsgSend(firstMsg)) { - senderAddress = firstMsg.value.from_address; - } else { - throw new Error(`Got unsupported type of message: ${firstMsg.type}`); - } - - const { accountNumber, sequence: currentSequence } = await this.cosmosClient.getNonce(senderAddress); - const sequenceForTx = await findSequenceForSignedTx( - response.tx, - Caip5.decode(this.chainId), - accountNumber, - currentSequence, - ); - if (sequenceForTx === undefined) throw new Error("Cound not find matching sequence for this transaction"); - - const nonce = accountToNonce(accountNumber, sequenceForTx); - - return parseTxsResponseSigned(this.chainId, response.height, nonce, response, this.bankTokens); - } - - private waitForTransaction( - id: TransactionId, - ): Stream | FailedTransaction> { - let pollInternal: NodeJS.Timeout | undefined; - const producer: Producer | FailedTransaction> = { - start: (listener) => { - setInterval(async () => { - try { - const results = await this.searchTx({ id: id }); - switch (results.length) { - case 0: - // okay, we'll try again - break; - case 1: - listener.next(results[0]); - listener.complete(); - break; - default: - throw new Error(`Got unexpected number of search results: ${results.length}`); - } - } catch (error) { - if (pollInternal) { - clearTimeout(pollInternal); - pollInternal = undefined; - } - listener.error(error); - } - }, defaultPollInterval); - }, - stop: () => { - if (pollInternal) { - clearTimeout(pollInternal); - pollInternal = undefined; - } - }, - }; - return Stream.create(producer); - } -} diff --git a/packages/bcp/src/cosmosconnector.ts b/packages/bcp/src/cosmosconnector.ts deleted file mode 100644 index 680a1b2036..0000000000 --- a/packages/bcp/src/cosmosconnector.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { ChainConnector, ChainId } from "@iov/bcp"; - -import { CosmosCodec } from "./cosmoscodec"; -import { CosmosConnection, TokenConfiguration } from "./cosmosconnection"; - -/** - * A helper to connect to a cosmos-based chain at a given url - */ -export function createCosmosConnector( - url: string, - addressPrefix: string, - tokenConfig: TokenConfiguration, - expectedChainId?: ChainId, -): ChainConnector { - const codec = new CosmosCodec(addressPrefix, tokenConfig.bankTokens); - return { - establishConnection: async () => CosmosConnection.establish(url, addressPrefix, tokenConfig), - codec: codec, - expectedChainId: expectedChainId, - }; -} diff --git a/packages/bcp/src/decode.spec.ts b/packages/bcp/src/decode.spec.ts deleted file mode 100644 index ef4f96b1af..0000000000 --- a/packages/bcp/src/decode.spec.ts +++ /dev/null @@ -1,401 +0,0 @@ -/* eslint-disable @typescript-eslint/camelcase */ -import { fromBase64, fromHex } from "@cosmjs/encoding"; -import { Coin, IndexedTx, Msg, PubKey, StdSignature } from "@cosmjs/sdk38"; -import { Address, Algorithm, SendTransaction, TokenTicker } from "@iov/bcp"; - -import { - decodeAmount, - decodeFullSignature, - decodePubkey, - decodeSignature, - parseFee, - parseMsg, - parseSignedTx, - parseTxsResponseSigned, - parseTxsResponseUnsigned, - parseUnsignedTx, -} from "./decode"; -import * as testdata from "./testdata.spec"; -import cosmoshub from "./testdata/cosmoshub.json"; -import { BankToken } from "./types"; - -describe("decode", () => { - const defaultPubkey = { - algo: Algorithm.Secp256k1, - data: fromBase64("AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP"), - }; - const defaultSignature = fromBase64( - "1nUcIH0CLT0/nQ0mBTDrT6kMG20NY/PsH7P2gc4bpYNGLEYjBmdWevXUJouSE/9A/60QG9cYeqyTe5kFDeIPxQ==", - ); - const defaultFullSignature = { - nonce: testdata.nonce, - pubkey: defaultPubkey, - signature: defaultSignature, - }; - const defaultAmount = { - fractionalDigits: 6, - quantity: "11657995", - tokenTicker: "ATOM" as TokenTicker, - }; - const defaultMemo = "Best greetings"; - const defaultSendTransaction: SendTransaction = { - kind: "bcp/send", - chainId: testdata.chainId, - sender: "cosmos1h806c7khnvmjlywdrkdgk2vrayy2mmvf9rxk2r" as Address, - recipient: "cosmos1z7g5w84ynmjyg0kqpahdjqpj7yq34v3suckp0e" as Address, - amount: defaultAmount, - memo: defaultMemo, - }; - const defaultFee = { - tokens: { - fractionalDigits: 6, - quantity: "5000", - tokenTicker: "ATOM" as TokenTicker, - }, - gasLimit: "200000", - }; - const defaultTokens: readonly BankToken[] = [ - { - fractionalDigits: 6, - ticker: "ATOM", - denom: "uatom", - }, - ]; - - describe("decodePubkey", () => { - it("works for secp256k1", () => { - const pubkey: PubKey = { - type: "tendermint/PubKeySecp256k1", - value: "AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP", - }; - expect(decodePubkey(pubkey)).toEqual(defaultPubkey); - }); - - it("works for ed25519", () => { - const pubkey: PubKey = { - type: "tendermint/PubKeyEd25519", - value: "s69CnMgLTpuRyEfecjws3mWssBrOICUx8C2O1DkKSto=", - }; - expect(decodePubkey(pubkey)).toEqual({ - algo: Algorithm.Ed25519, - data: fromHex("b3af429cc80b4e9b91c847de723c2cde65acb01ace202531f02d8ed4390a4ada"), - }); - }); - - it("throws for unsupported types", () => { - // https://github.com/tendermint/tendermint/blob/v0.33.0/crypto/sr25519/codec.go#L12 - const pubkey: PubKey = { - type: "tendermint/PubKeySr25519", - value: "N4FJNPE5r/Twz55kO1QEIxyaGF5/HTXH6WgLQJWsy1o=", - }; - expect(() => decodePubkey(pubkey)).toThrowError(/unsupported pubkey type/i); - }); - }); - - describe("decodeSignature", () => { - it("works", () => { - const signature = - "1nUcIH0CLT0/nQ0mBTDrT6kMG20NY/PsH7P2gc4bpYNGLEYjBmdWevXUJouSE/9A/60QG9cYeqyTe5kFDeIPxQ=="; - expect(decodeSignature(signature)).toEqual(defaultSignature); - }); - }); - - describe("decodeFullSignature", () => { - it("works", () => { - const fullSignature: StdSignature = { - pub_key: { - type: "tendermint/PubKeySecp256k1", - value: "AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP", - }, - signature: "1nUcIH0CLT0/nQ0mBTDrT6kMG20NY/PsH7P2gc4bpYNGLEYjBmdWevXUJouSE/9A/60QG9cYeqyTe5kFDeIPxQ==", - }; - expect(decodeFullSignature(fullSignature, testdata.nonce)).toEqual(defaultFullSignature); - }); - }); - - describe("decodeAmount", () => { - it("works", () => { - const amount: Coin = { - denom: "uatom", - amount: "11657995", - }; - expect(decodeAmount(defaultTokens, amount)).toEqual(defaultAmount); - }); - }); - - describe("parseMsg", () => { - it("works for bank send transaction", () => { - const msg: Msg = { - type: "cosmos-sdk/MsgSend", - value: { - from_address: "cosmos1h806c7khnvmjlywdrkdgk2vrayy2mmvf9rxk2r", - to_address: "cosmos1z7g5w84ynmjyg0kqpahdjqpj7yq34v3suckp0e", - amount: [ - { - denom: "uatom", - amount: "11657995", - }, - ], - }, - }; - expect(parseMsg(msg, defaultMemo, testdata.chainId, defaultTokens)).toEqual(defaultSendTransaction); - }); - }); - - describe("parseFee", () => { - it("works", () => { - const fee = { - amount: [ - { - denom: "uatom", - amount: "5000", - }, - ], - gas: "200000", - }; - expect(parseFee(fee, defaultTokens)).toEqual(defaultFee); - }); - }); - - describe("parseUnsignedTx", () => { - it("works for bank send transaction", () => { - expect(parseUnsignedTx(cosmoshub.tx.value, testdata.chainId, defaultTokens)).toEqual( - testdata.sendTxJson, - ); - }); - }); - - describe("parseSignedTx", () => { - it("works", () => { - expect(parseSignedTx(cosmoshub.tx.value, testdata.chainId, testdata.nonce, defaultTokens)).toEqual( - testdata.signedTxJson, - ); - }); - }); - - describe("parseTxsResponseUnsigned", () => { - it("works", () => { - const currentHeight = 2923; - const txsResponse: IndexedTx = { - height: 2823, - hash: testdata.txId, - code: 0, - rawLog: '[{"msg_index":0,"success":true,"log":""}]', - logs: [], - tx: cosmoshub.tx, - timestamp: "2020-02-14T11:35:41Z", - }; - const expected = { - transaction: testdata.sendTxJson, - height: 2823, - confirmations: 101, - transactionId: testdata.txId, - log: '[{"msg_index":0,"success":true,"log":""}]', - }; - expect(parseTxsResponseUnsigned(testdata.chainId, currentHeight, txsResponse, defaultTokens)).toEqual( - expected, - ); - }); - }); - - describe("parseTxsResponseSigned", () => { - it("works", () => { - const currentHeight = 2923; - const txsResponse: IndexedTx = { - height: 2823, - hash: testdata.txId, - code: 0, - rawLog: '[{"msg_index":0,"success":true,"log":""}]', - logs: [], - tx: cosmoshub.tx, - timestamp: "2020-02-14T11:35:41Z", - }; - const expected = { - ...testdata.signedTxJson, - height: 2823, - confirmations: 101, - transactionId: testdata.txId, - log: '[{"msg_index":0,"success":true,"log":""}]', - }; - expect( - parseTxsResponseSigned(testdata.chainId, currentHeight, testdata.nonce, txsResponse, defaultTokens), - ).toEqual(expected); - }); - }); -}); - -/* - -Some output from sample rest queries: - -$ wasmcli tx send $(wasmcli keys show validator -a) $(wasmcli keys show fred -a) 98765stake -y -{ - "height": "4", - "txhash": "8A4613D62884EF8BB9BCCDDA3833D560701908BF17FE82A570EECCBACEF94A91", - "raw_log": "[{\"msg_index\":0,\"log\":\"\",\"events\":[{\"type\":\"message\",\"attributes\":[{\"key\":\"action\",\"value\":\"send\"},{\"key\":\"sender\",\"value\":\"cosmos16qu479grzwanyzav6xvtzncgdjkwhqw7vy2pje\"},{\"key\":\"module\",\"value\":\"bank\"}]},{\"type\":\"transfer\",\"attributes\":[{\"key\":\"recipient\",\"value\":\"cosmos1ltkhnmdcqemmd2tkhnx7qx66tq7e0wykw2j85k\"},{\"key\":\"amount\",\"value\":\"98765stake\"}]}]}]", - "logs": [ - { - "msg_index": 0, - "log": "", - "events": [ - { - "type": "message", - "attributes": [ - { - "key": "action", - "value": "send" - }, - { - "key": "sender", - "value": "cosmos16qu479grzwanyzav6xvtzncgdjkwhqw7vy2pje" - }, - { - "key": "module", - "value": "bank" - } - ] - }, - { - "type": "transfer", - "attributes": [ - { - "key": "recipient", - "value": "cosmos1ltkhnmdcqemmd2tkhnx7qx66tq7e0wykw2j85k" - }, - { - "key": "amount", - "value": "98765stake" - } - ] - } - ] - } - ], - "gas_wanted": "200000", - "gas_used": "53254" -} - - -$ wasmcli query tx 8A4613D62884EF8BB9BCCDDA3833D560701908BF17FE82A570EECCBACEF94A91 -{ - "height": "4", - "txhash": "8A4613D62884EF8BB9BCCDDA3833D560701908BF17FE82A570EECCBACEF94A91", - "raw_log": "[{\"msg_index\":0,\"log\":\"\",\"events\":[{\"type\":\"message\",\"attributes\":[{\"key\":\"action\",\"value\":\"send\"},{\"key\":\"sender\",\"value\":\"cosmos16qu479grzwanyzav6xvtzncgdjkwhqw7vy2pje\"},{\"key\":\"module\",\"value\":\"bank\"}]},{\"type\":\"transfer\",\"attributes\":[{\"key\":\"recipient\",\"value\":\"cosmos1ltkhnmdcqemmd2tkhnx7qx66tq7e0wykw2j85k\"},{\"key\":\"amount\",\"value\":\"98765stake\"}]}]}]", - "logs": [ - { - "msg_index": 0, - "log": "", - "events": [ - { - "type": "message", - "attributes": [ - { - "key": "action", - "value": "send" - }, - { - "key": "sender", - "value": "cosmos16qu479grzwanyzav6xvtzncgdjkwhqw7vy2pje" - }, - { - "key": "module", - "value": "bank" - } - ] - }, - { - "type": "transfer", - "attributes": [ - { - "key": "recipient", - "value": "cosmos1ltkhnmdcqemmd2tkhnx7qx66tq7e0wykw2j85k" - }, - { - "key": "amount", - "value": "98765stake" - } - ] - } - ] - } - ], - "gas_wanted": "200000", - "gas_used": "53254", - "tx": { - "type": "cosmos-sdk/StdTx", - "value": { - "msg": [ - { - "type": "cosmos-sdk/MsgSend", - "value": { - "from_address": "cosmos16qu479grzwanyzav6xvtzncgdjkwhqw7vy2pje", - "to_address": "cosmos1ltkhnmdcqemmd2tkhnx7qx66tq7e0wykw2j85k", - "amount": [ - { - "denom": "stake", - "amount": "98765" - } - ] - } - } - ], - "fee": { - "amount": [], - "gas": "200000" - }, - "signatures": [ - { - "pub_key": { - "type": "tendermint/PubKeySecp256k1", - "value": "A11L8EitFnA6YsZ2QSnbMNmK+qI2kxyevDtSfhPqOwcp" - }, - "signature": "qCeKoqZeaL0LThKrUXHLgu72jwTiF+DseSBjcKHtcONE0kIdybwYJpuYg3Jj71hmfync+daHNdqgJlPRma0pPA==" - } - ], - "memo": "" - } - }, - "timestamp": "2020-02-03T17:06:58Z" -} - - -$ wasmcli query account $(wasmcli keys show fred -a) -{ - "type": "cosmos-sdk/Account", - "value": { - "address": "cosmos1ltkhnmdcqemmd2tkhnx7qx66tq7e0wykw2j85k", - "coins": [ - { - "denom": "stake", - "amount": "98765" - } - ], - "public_key": "", - "account_number": 7, - "sequence": 0 - } -} - - -$ wasmcli query account $(wasmcli keys show validator -a) -{ - "type": "cosmos-sdk/Account", - "value": { - "address": "cosmos16qu479grzwanyzav6xvtzncgdjkwhqw7vy2pje", - "coins": [ - { - "denom": "stake", - "amount": "899901235" - }, - { - "denom": "validatortoken", - "amount": "1000000000" - } - ], - "public_key": "cosmospub1addwnpepqdw5huzg45t8qwnzcemyz2wmxrvc474zx6f3e84u8df8uyl28vrjjnp9v4p", - "account_number": 3, - "sequence": 2 - } -} - - */ diff --git a/packages/bcp/src/decode.ts b/packages/bcp/src/decode.ts deleted file mode 100644 index d1812bd807..0000000000 --- a/packages/bcp/src/decode.ts +++ /dev/null @@ -1,187 +0,0 @@ -import { fromBase64 } from "@cosmjs/encoding"; -import { Decimal } from "@cosmjs/math"; -import { - Coin, - IndexedTx, - isMsgSend, - isStdTx, - Msg, - PubKey, - pubkeyType, - StdFee, - StdSignature, - StdTx, -} from "@cosmjs/sdk38"; -import { - Address, - Algorithm, - Amount, - ChainId, - ConfirmedAndSignedTransaction, - ConfirmedTransaction, - Fee, - FullSignature, - Nonce, - PubkeyBundle, - PubkeyBytes, - SendTransaction, - SignatureBytes, - SignedTransaction, - TokenTicker, - TransactionId, - UnsignedTransaction, -} from "@iov/bcp"; - -import { BankToken } from "./types"; - -export function decodePubkey(pubkey: PubKey): PubkeyBundle { - switch (pubkey.type) { - case pubkeyType.secp256k1: - return { - algo: Algorithm.Secp256k1, - data: fromBase64(pubkey.value) as PubkeyBytes, - }; - case pubkeyType.ed25519: - return { - algo: Algorithm.Ed25519, - data: fromBase64(pubkey.value) as PubkeyBytes, - }; - default: - throw new Error("Unsupported pubkey type"); - } -} - -export function decodeSignature(signature: string): SignatureBytes { - return fromBase64(signature) as SignatureBytes; -} - -export function decodeFullSignature(signature: StdSignature, nonce: number): FullSignature { - return { - nonce: nonce as Nonce, - pubkey: decodePubkey(signature.pub_key), - signature: decodeSignature(signature.signature), - }; -} - -export function coinToDecimal(tokens: readonly BankToken[], coin: Coin): readonly [Decimal, string] { - const match = tokens.find(({ denom }) => denom === coin.denom); - if (!match) { - throw Error(`unknown denom: ${coin.denom}`); - } - const value = Decimal.fromAtomics(coin.amount, match.fractionalDigits); - return [value, match.ticker]; -} - -export function decodeAmount(tokens: readonly BankToken[], coin: Coin): Amount { - const [value, ticker] = coinToDecimal(tokens, coin); - return { - quantity: value.atomics, - fractionalDigits: value.fractionalDigits, - tokenTicker: ticker as TokenTicker, - }; -} - -export function parseMsg( - msg: Msg, - memo: string | undefined, - chainId: ChainId, - tokens: readonly BankToken[], -): UnsignedTransaction { - if (isMsgSend(msg)) { - if (msg.value.amount.length !== 1) { - throw new Error("Only MsgSend with one amount is supported"); - } - const send: SendTransaction = { - kind: "bcp/send", - chainId: chainId, - sender: msg.value.from_address as Address, - recipient: msg.value.to_address as Address, - amount: decodeAmount(tokens, msg.value.amount[0]), - memo: memo, - }; - return send; - } else { - // Unknown transaction type - const unknown = { - chainId: chainId, - kind: "bcp/unknown", - }; - return unknown; - } -} - -export function parseFee(fee: StdFee, tokens: readonly BankToken[]): Fee { - if (fee.amount.length !== 1) { - throw new Error("Only fee with one amount is supported"); - } - return { - tokens: decodeAmount(tokens, fee.amount[0]), - gasLimit: fee.gas, - }; -} - -export function parseUnsignedTx( - txValue: StdTx, - chainId: ChainId, - tokens: readonly BankToken[], -): UnsignedTransaction { - if (!isStdTx(txValue)) { - throw new Error("Only StdTx is supported"); - } - if (txValue.msg.length !== 1) { - throw new Error("Only single-message transactions currently supported"); - } - - const msg = parseMsg(txValue.msg[0], txValue.memo, chainId, tokens); - const fee = parseFee(txValue.fee, tokens); - - return { - ...msg, - chainId: chainId, - fee: fee, - }; -} - -export function parseSignedTx( - txValue: StdTx, - chainId: ChainId, - nonce: Nonce, - tokens: readonly BankToken[], -): SignedTransaction { - const [primarySignature] = txValue.signatures.map((signature) => decodeFullSignature(signature, nonce)); - return { - transaction: parseUnsignedTx(txValue, chainId, tokens), - signatures: [primarySignature], - }; -} - -export function parseTxsResponseUnsigned( - chainId: ChainId, - currentHeight: number, - response: IndexedTx, - tokens: readonly BankToken[], -): ConfirmedTransaction { - return { - transaction: parseUnsignedTx(response.tx.value, chainId, tokens), - height: response.height, - confirmations: currentHeight - response.height + 1, - transactionId: response.hash as TransactionId, - log: response.rawLog, - }; -} - -export function parseTxsResponseSigned( - chainId: ChainId, - currentHeight: number, - nonce: Nonce, - response: IndexedTx, - tokens: readonly BankToken[], -): ConfirmedAndSignedTransaction { - return { - ...parseSignedTx(response.tx.value, chainId, nonce, tokens), - height: response.height, - confirmations: currentHeight - response.height + 1, - transactionId: response.hash as TransactionId, - log: response.rawLog, - }; -} diff --git a/packages/bcp/src/encode.spec.ts b/packages/bcp/src/encode.spec.ts deleted file mode 100644 index c31fc5077f..0000000000 --- a/packages/bcp/src/encode.spec.ts +++ /dev/null @@ -1,310 +0,0 @@ -/* eslint-disable @typescript-eslint/camelcase */ -import { fromBase64 } from "@cosmjs/encoding"; -import { - Address, - Algorithm, - Amount, - ChainId, - Nonce, - PubkeyBytes, - SendTransaction, - SignatureBytes, - SignedTransaction, - TokenTicker, -} from "@iov/bcp"; - -import { - buildSignedTx, - buildUnsignedTx, - encodeFee, - encodeFullSignature, - encodePubkey, - toBankCoin, -} from "./encode"; -import { BankToken } from "./types"; - -describe("encode", () => { - const atom = "ATOM" as TokenTicker; - // https://rpc.cosmos.network:26657/tx?hash=0x2268EB5AB730B45F8426078827BB5BB49819CE2B0D74B2C1D191070BADB379F1&prove=true - const defaultPubkey = { - algo: Algorithm.Secp256k1, - data: fromBase64("AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP") as PubkeyBytes, - }; - const defaultChainId = "not-used" as ChainId; - const defaultSender = "cosmos1h806c7khnvmjlywdrkdgk2vrayy2mmvf9rxk2r" as Address; - const defaultRecipient = "cosmos1z7g5w84ynmjyg0kqpahdjqpj7yq34v3suckp0e" as Address; - const defaultAmount: Amount = { - fractionalDigits: 6, - quantity: "11657995", - tokenTicker: atom, - }; - const defaultMemo = "hello cosmos hub"; - const defaultTokens: readonly BankToken[] = [ - { - fractionalDigits: 6, - ticker: "ATOM", - denom: "uatom", - }, - ]; - - describe("encodePubkey", () => { - it("works for compressed public key", () => { - expect(encodePubkey(defaultPubkey)).toEqual({ - type: "tendermint/PubKeySecp256k1", - value: "AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP", - }); - }); - }); - - describe("toBankCoin", () => { - it("encodes an amount", () => { - expect(toBankCoin(defaultAmount, defaultTokens)).toEqual({ - denom: "uatom", - amount: "11657995", - }); - }); - }); - - describe("encodeFee", () => { - it("throws without tokens", () => { - const fee = { - gasLimit: "200000", - }; - expect(() => encodeFee(fee, defaultTokens)).toThrowError(/cannot encode fee without tokens/i); - }); - - it("throws without gas limit", () => { - const fee = { - tokens: { - fractionalDigits: 6, - quantity: "5000", - tokenTicker: atom, - }, - }; - expect(() => encodeFee(fee, defaultTokens)).toThrowError(/cannot encode fee without gas limit/i); - }); - - it("encodes a fee", () => { - const fee = { - tokens: { - fractionalDigits: 6, - quantity: "5000", - tokenTicker: atom, - }, - gasLimit: "200000", - }; - expect(encodeFee(fee, defaultTokens)).toEqual({ - amount: [{ denom: "uatom", amount: "5000" }], - gas: "200000", - }); - }); - }); - - describe("encodeFullSignature", () => { - it("encodes a full signature", () => { - const signature = { - nonce: 0 as Nonce, - pubkey: { - algo: Algorithm.Secp256k1, - data: fromBase64("AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP") as PubkeyBytes, - }, - signature: fromBase64( - "1nUcIH0CLT0/nQ0mBTDrT6kMG20NY/PsH7P2gc4bpYNGLEYjBmdWevXUJouSE/9A/60QG9cYeqyTe5kFDeIPxQ==", - ) as SignatureBytes, - }; - expect(encodeFullSignature(signature)).toEqual({ - pub_key: { - type: "tendermint/PubKeySecp256k1", - value: "AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP", - }, - signature: "1nUcIH0CLT0/nQ0mBTDrT6kMG20NY/PsH7P2gc4bpYNGLEYjBmdWevXUJouSE/9A/60QG9cYeqyTe5kFDeIPxQ==", - }); - }); - - it("compresses uncompressed public keys", () => { - const signature = { - nonce: 0 as Nonce, - pubkey: { - algo: Algorithm.Secp256k1, - data: fromBase64( - "BE8EGB7ro1ORuFhjOnZcSgwYlpe0DSFjVNUIkNNQxwKQE7WHpoHoNswYeoFkuYpYSKK4mzFzMV/dB0DVAy4lnNU=", - ) as PubkeyBytes, - }, - signature: fromBase64( - "1nUcIH0CLT0/nQ0mBTDrT6kMG20NY/PsH7P2gc4bpYNGLEYjBmdWevXUJouSE/9A/60QG9cYeqyTe5kFDeIPxQ==", - ) as SignatureBytes, - }; - expect(encodeFullSignature(signature)).toEqual({ - pub_key: { - type: "tendermint/PubKeySecp256k1", - value: "A08EGB7ro1ORuFhjOnZcSgwYlpe0DSFjVNUIkNNQxwKQ", - }, - signature: "1nUcIH0CLT0/nQ0mBTDrT6kMG20NY/PsH7P2gc4bpYNGLEYjBmdWevXUJouSE/9A/60QG9cYeqyTe5kFDeIPxQ==", - }); - }); - - it("removes recovery values from signature data", () => { - const signature = { - nonce: 0 as Nonce, - pubkey: { - algo: Algorithm.Secp256k1, - data: fromBase64("AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP") as PubkeyBytes, - }, - signature: Uint8Array.from([ - ...fromBase64( - "1nUcIH0CLT0/nQ0mBTDrT6kMG20NY/PsH7P2gc4bpYNGLEYjBmdWevXUJouSE/9A/60QG9cYeqyTe5kFDeIPxQ==", - ), - 99, - ]) as SignatureBytes, - }; - expect(encodeFullSignature(signature)).toEqual({ - pub_key: { - type: "tendermint/PubKeySecp256k1", - value: "AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP", - }, - signature: "1nUcIH0CLT0/nQ0mBTDrT6kMG20NY/PsH7P2gc4bpYNGLEYjBmdWevXUJouSE/9A/60QG9cYeqyTe5kFDeIPxQ==", - }); - }); - }); - - describe("buildUnsignedTx", () => { - it("throws for unsupported transaction", () => { - const tx = { - kind: "bns/return_escrow", - chainId: defaultChainId, - escrowId: "defg", - }; - expect(() => buildUnsignedTx(tx, defaultTokens)).toThrowError( - /received transaction of unsupported kind/i, - ); - }); - - it("throws for a send transaction without fee", () => { - // This will be rejected by the REST server. Better throw early to avoid hard to debug errors. - const tx = { - kind: "bcp/send", - chainId: defaultChainId, - amount: defaultAmount, - sender: defaultSender, - recipient: defaultRecipient, - memo: defaultMemo, - }; - expect(() => buildUnsignedTx(tx, defaultTokens)).toThrowError(/transaction fee must be set/i); - }); - - it("builds a send transaction with fee", () => { - const tx = { - kind: "bcp/send", - chainId: defaultChainId, - amount: defaultAmount, - sender: defaultSender, - recipient: defaultRecipient, - memo: defaultMemo, - fee: { - tokens: { - fractionalDigits: 6, - quantity: "5000", - tokenTicker: atom, - }, - gasLimit: "200000", - }, - }; - expect(buildUnsignedTx(tx, defaultTokens)).toEqual({ - type: "cosmos-sdk/StdTx", - value: { - msg: [ - { - type: "cosmos-sdk/MsgSend", - value: { - from_address: "cosmos1h806c7khnvmjlywdrkdgk2vrayy2mmvf9rxk2r", - to_address: "cosmos1z7g5w84ynmjyg0kqpahdjqpj7yq34v3suckp0e", - amount: [ - { - denom: "uatom", - amount: "11657995", - }, - ], - }, - }, - ], - fee: { - amount: [{ denom: "uatom", amount: "5000" }], - gas: "200000", - }, - signatures: [], - memo: defaultMemo, - }, - }); - }); - }); - - describe("buildSignedTx", () => { - it("builds a send transaction", () => { - const tx: SignedTransaction = { - transaction: { - kind: "bcp/send", - chainId: defaultChainId, - amount: defaultAmount, - sender: defaultSender, - recipient: defaultRecipient, - memo: defaultMemo, - fee: { - tokens: { - fractionalDigits: 6, - quantity: "5000", - tokenTicker: atom, - }, - gasLimit: "200000", - }, - }, - signatures: [ - { - nonce: 0 as Nonce, - pubkey: { - algo: Algorithm.Secp256k1, - data: fromBase64("AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP") as PubkeyBytes, - }, - signature: fromBase64( - "1nUcIH0CLT0/nQ0mBTDrT6kMG20NY/PsH7P2gc4bpYNGLEYjBmdWevXUJouSE/9A/60QG9cYeqyTe5kFDeIPxQ==", - ) as SignatureBytes, - }, - ], - }; - expect(buildSignedTx(tx, defaultTokens)).toEqual({ - type: "cosmos-sdk/StdTx", - value: { - msg: [ - { - type: "cosmos-sdk/MsgSend", - value: { - from_address: "cosmos1h806c7khnvmjlywdrkdgk2vrayy2mmvf9rxk2r", - to_address: "cosmos1z7g5w84ynmjyg0kqpahdjqpj7yq34v3suckp0e", - amount: [ - { - denom: "uatom", - amount: "11657995", - }, - ], - }, - }, - ], - fee: { - amount: [{ denom: "uatom", amount: "5000" }], - gas: "200000", - }, - signatures: [ - { - pub_key: { - type: "tendermint/PubKeySecp256k1", - value: "AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP", - }, - signature: - "1nUcIH0CLT0/nQ0mBTDrT6kMG20NY/PsH7P2gc4bpYNGLEYjBmdWevXUJouSE/9A/60QG9cYeqyTe5kFDeIPxQ==", - }, - ], - memo: defaultMemo, - }, - }); - }); - }); -}); diff --git a/packages/bcp/src/encode.ts b/packages/bcp/src/encode.ts deleted file mode 100644 index 371ecc9570..0000000000 --- a/packages/bcp/src/encode.ts +++ /dev/null @@ -1,123 +0,0 @@ -/* eslint-disable @typescript-eslint/camelcase */ -import { Secp256k1 } from "@cosmjs/crypto"; -import { toBase64 } from "@cosmjs/encoding"; -import { - Coin, - CosmosSdkTx, - encodeSecp256k1Pubkey, - encodeSecp256k1Signature, - PubKey, - pubkeyType, - StdFee, - StdSignature, -} from "@cosmjs/sdk38"; -import { - Algorithm, - Amount, - Fee, - FullSignature, - isSendTransaction, - PubkeyBundle, - SignedTransaction, - UnsignedTransaction, -} from "@iov/bcp"; - -import { BankToken } from "./types"; - -// TODO: This function seems to be unused and is not well tested (e.g. uncompressed secp256k1 or ed25519) -export function encodePubkey(pubkey: PubkeyBundle): PubKey { - switch (pubkey.algo) { - case Algorithm.Secp256k1: - return encodeSecp256k1Pubkey(pubkey.data); - case Algorithm.Ed25519: - return { - type: pubkeyType.ed25519, - value: toBase64(pubkey.data), - }; - default: - throw new Error("Unsupported pubkey algo"); - } -} - -export function toBankCoin(amount: Amount, tokens: readonly BankToken[]): Coin { - const match = tokens.find((token) => token.ticker === amount.tokenTicker); - if (!match) throw Error(`unknown ticker: ${amount.tokenTicker}`); - if (match.fractionalDigits !== amount.fractionalDigits) { - throw new Error( - "Mismatch in fractional digits between token and value. If you really want, implement a conversion here. However, this indicates a bug in the caller code.", - ); - } - return { - denom: match.denom, - amount: amount.quantity, - }; -} - -export function encodeFee(fee: Fee, tokens: readonly BankToken[]): StdFee { - if (fee.tokens === undefined) { - throw new Error("Cannot encode fee without tokens"); - } - if (fee.gasLimit === undefined) { - throw new Error("Cannot encode fee without gas limit"); - } - return { - amount: [toBankCoin(fee.tokens, tokens)], - gas: fee.gasLimit, - }; -} - -export function encodeFullSignature(fullSignature: FullSignature): StdSignature { - switch (fullSignature.pubkey.algo) { - case Algorithm.Secp256k1: { - const compressedPubkey = Secp256k1.compressPubkey(fullSignature.pubkey.data); - const normalizedSignature = Secp256k1.trimRecoveryByte(fullSignature.signature); - return encodeSecp256k1Signature(compressedPubkey, normalizedSignature); - } - default: - throw new Error("Unsupported signing algorithm"); - } -} - -export function buildUnsignedTx(tx: UnsignedTransaction, bankTokens: readonly BankToken[]): CosmosSdkTx { - if (!isSendTransaction(tx)) { - throw new Error("Received transaction of unsupported kind"); - } - - const matchingBankToken = bankTokens.find((t) => t.ticker === tx.amount.tokenTicker); - - if (!tx.fee) throw new Error("Transaction fee must be set"); - - if (matchingBankToken) { - return { - type: "cosmos-sdk/StdTx", - value: { - msg: [ - { - type: "cosmos-sdk/MsgSend", - value: { - from_address: tx.sender, - to_address: tx.recipient, - amount: [toBankCoin(tx.amount, bankTokens)], - }, - }, - ], - memo: tx.memo || "", - signatures: [], - fee: encodeFee(tx.fee, bankTokens), - }, - }; - } else { - throw new Error("Cannot encode this type of transaction"); - } -} - -export function buildSignedTx(tx: SignedTransaction, bankTokens: readonly BankToken[]): CosmosSdkTx { - const built = buildUnsignedTx(tx.transaction, bankTokens); - return { - ...built, - value: { - ...built.value, - signatures: tx.signatures.map(encodeFullSignature), - }, - }; -} diff --git a/packages/bcp/src/index.ts b/packages/bcp/src/index.ts deleted file mode 100644 index 7ca0a53fb1..0000000000 --- a/packages/bcp/src/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { CosmosCodec } from "./cosmoscodec"; -export { CosmosConnection, TokenConfiguration } from "./cosmosconnection"; -export { createCosmosConnector } from "./cosmosconnector"; -export { BankToken } from "./types"; diff --git a/packages/bcp/src/testdata.spec.ts b/packages/bcp/src/testdata.spec.ts deleted file mode 100644 index c95749a0c5..0000000000 --- a/packages/bcp/src/testdata.spec.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { fromBase64, toUtf8 } from "@cosmjs/encoding"; -import { - Address, - Algorithm, - ChainId, - FullSignature, - Nonce, - PubkeyBundle, - PubkeyBytes, - SendTransaction, - SignatureBytes, - SignedTransaction, - TokenTicker, - TransactionId, -} from "@iov/bcp"; - -import data from "./testdata/cosmoshub.json"; - -export const pubJson: PubkeyBundle = { - algo: Algorithm.Secp256k1, - data: fromBase64(data.tx.value.signatures[0].pub_key.value) as PubkeyBytes, -}; - -export const chainId = "cosmos:cosmoshub-3" as ChainId; - -export const nonce = 99 as Nonce; - -export const sendTxJson: SendTransaction = { - kind: "bcp/send", - chainId: chainId, - sender: data.tx.value.msg[0].value.from_address as Address, - recipient: data.tx.value.msg[0].value.to_address as Address, - memo: data.tx.value.memo, - amount: { - fractionalDigits: 6, - quantity: data.tx.value.msg[0].value.amount[0].amount, - tokenTicker: "ATOM" as TokenTicker, - }, - fee: { - tokens: { - fractionalDigits: 6, - quantity: data.tx.value.fee.amount[0].amount, - tokenTicker: "ATOM" as TokenTicker, - }, - gasLimit: data.tx.value.fee.gas, - }, -}; - -export const signedTxSig: FullSignature = { - nonce: nonce, - pubkey: pubJson, - signature: fromBase64(data.tx.value.signatures[0].signature) as SignatureBytes, -}; - -export const signedTxJson: SignedTransaction = { - transaction: sendTxJson, - signatures: [signedTxSig], -}; - -export const signedTxBin = fromBase64(data.tx_data); - -export const txId = data.id as TransactionId; - -export const signedTxEncodedJson = toUtf8( - `{"msg":[{"type":"cosmos-sdk/MsgSend","value":{"from_address":"cosmos1txqfn5jmcts0x0q7krdxj8tgf98tj0965vqlmq","to_address":"cosmos1nynns8ex9fq6sjjfj8k79ymkdz4sqth06xexae","amount":[{"denom":"uatom","amount":"35997500"}]}}],"memo":"","signatures":[{"pub_key":{"type":"tendermint/PubKeySecp256k1","value":"A5qFcJBJvEK/fOmEAY0DHNWwSRZ9TEfNZyH8VoVvDtAq"},"signature":"NK1Oy4EUGAsoC03c1wi9GG03JC/39LEdautC5Jk643oIbEPqeXHMwaqbdvO/Jws0X/NAXaN8SAy2KNY5Qml+5Q=="}],"fee":{"amount":[{"denom":"uatom","amount":"2500"}],"gas":"100000"}}`, -); diff --git a/packages/bcp/src/testdata/cosmoshub.json b/packages/bcp/src/testdata/cosmoshub.json deleted file mode 100644 index cb33539c18..0000000000 --- a/packages/bcp/src/testdata/cosmoshub.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "//source": "https://hubble.figment.network/cosmos/chains/cosmoshub-3/blocks/415777/transactions/2BD600EA6090FC75FD844CA73542CC90A828770F4C01C5B483C3C1C43CCB65F4?format=json", - "tx": { - "type": "cosmos-sdk/StdTx", - "value": { - "msg": [ - { - "type": "cosmos-sdk/MsgSend", - "value": { - "from_address": "cosmos1txqfn5jmcts0x0q7krdxj8tgf98tj0965vqlmq", - "to_address": "cosmos1nynns8ex9fq6sjjfj8k79ymkdz4sqth06xexae", - "amount": [ - { - "denom": "uatom", - "amount": "35997500" - } - ] - } - } - ], - "fee": { - "amount": [ - { - "denom": "uatom", - "amount": "2500" - } - ], - "gas": "100000" - }, - "signatures": [ - { - "pub_key": { - "type": "tendermint/PubKeySecp256k1", - "value": "A5qFcJBJvEK/fOmEAY0DHNWwSRZ9TEfNZyH8VoVvDtAq" - }, - "signature": "NK1Oy4EUGAsoC03c1wi9GG03JC/39LEdautC5Jk643oIbEPqeXHMwaqbdvO/Jws0X/NAXaN8SAy2KNY5Qml+5Q==" - } - ], - "memo": "" - } - }, - "tx_data": "ygEoKBapCkOoo2GaChRZgJnSW8Lg8zwesNppHWhJTrk8uhIUmSc4HyYqQahKSZHt4pN2aKsALu8aEQoFdWF0b20SCDM1OTk3NTAwEhMKDQoFdWF0b20SBDI1MDAQoI0GGmoKJuta6YchA5qFcJBJvEK/fOmEAY0DHNWwSRZ9TEfNZyH8VoVvDtAqEkA0rU7LgRQYCygLTdzXCL0YbTckL/f0sR1q60LkmTrjeghsQ+p5cczBqpt2878nCzRf80Bdo3xIDLYo1jlCaX7l", - "id": "2BD600EA6090FC75FD844CA73542CC90A828770F4C01C5B483C3C1C43CCB65F4" -} diff --git a/packages/bcp/src/types.spec.ts b/packages/bcp/src/types.spec.ts deleted file mode 100644 index a5025437aa..0000000000 --- a/packages/bcp/src/types.spec.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* eslint-disable @typescript-eslint/camelcase */ -import { accountToNonce, nonceToAccountNumber, nonceToSequence } from "./types"; - -describe("nonceEncoding", () => { - it("works for input in range", () => { - const nonce = accountToNonce(1234, 7890); - expect(nonceToAccountNumber(nonce)).toEqual(1234); - expect(nonceToSequence(nonce)).toEqual(7890); - }); - - it("errors on input too large", () => { - expect(() => accountToNonce(1234567890, 7890)).toThrow(); - expect(() => accountToNonce(178, 97320247923)).toThrow(); - }); -}); diff --git a/packages/bcp/src/types.ts b/packages/bcp/src/types.ts deleted file mode 100644 index 9ceb2f1cbd..0000000000 --- a/packages/bcp/src/types.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { Nonce } from "@iov/bcp"; - -export interface BankToken { - readonly denom: string; - readonly ticker: string; - /** - * The number of fractional digits the token supports. - * - * A quantity is expressed as atomic units. 10^fractionalDigits of those - * atomic units make up 1 token. - * - * E.g. in Ethereum 10^18 wei are 1 ETH and from the quantity 123000000000000000000 - * the last 18 digits are the fractional part and the rest the wole part. - */ - readonly fractionalDigits: number; -} - -// eslint-disable-next-line no-bitwise -const maxAcct = 1 << 23; -// eslint-disable-next-line no-bitwise -const maxSeq = 1 << 20; - -// this (lossily) encodes the two pieces of info (uint64) needed to sign into -// one (53-bit) number. Cross your fingers. -export function accountToNonce(accountNumber: number, sequence: number): Nonce { - // we allow 23 bits (8 million) for accounts, and 20 bits (1 million) for tx/account - // let's fix this soon - if (accountNumber > maxAcct) { - throw new Error("Account number is greater than 2^23, must update Nonce handler"); - } - if (sequence > maxSeq) { - throw new Error("Sequence is greater than 2^20, must update Nonce handler"); - } - - const val = accountNumber * maxSeq + sequence; - return val as Nonce; -} - -// this extracts info from nonce for signing -export function nonceToAccountNumber(nonce: Nonce): number { - const acct = nonce / maxSeq; - if (acct > maxAcct) { - throw new Error("Invalid Nonce, account number is higher than can safely be encoded in Nonce"); - } - return Math.round(acct); -} - -// this extracts info from nonce for signing -export function nonceToSequence(nonce: Nonce): number { - const seq = nonce % maxSeq; - return Math.round(seq); -} diff --git a/packages/bcp/tsconfig.json b/packages/bcp/tsconfig.json deleted file mode 100644 index 167e8c0226..0000000000 --- a/packages/bcp/tsconfig.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "baseUrl": ".", - "outDir": "build", - "declarationDir": "build/types", - "rootDir": "src" - }, - "include": [ - "src/**/*" - ] -} diff --git a/packages/bcp/typedoc.js b/packages/bcp/typedoc.js deleted file mode 100644 index e2387c7de4..0000000000 --- a/packages/bcp/typedoc.js +++ /dev/null @@ -1,14 +0,0 @@ -const packageJson = require("./package.json"); - -module.exports = { - src: ["./src"], - out: "docs", - exclude: "**/*.spec.ts", - target: "es6", - name: `${packageJson.name} Documentation`, - readme: "README.md", - mode: "file", - excludeExternals: true, - excludeNotExported: true, - excludePrivate: true, -}; diff --git a/packages/bcp/types/address.d.ts b/packages/bcp/types/address.d.ts deleted file mode 100644 index 98fa0ca9a7..0000000000 --- a/packages/bcp/types/address.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -import { Address, PubkeyBundle } from "@iov/bcp"; -export declare function pubkeyToAddress(pubkey: PubkeyBundle, prefix: string): Address; diff --git a/packages/bcp/types/caip5.d.ts b/packages/bcp/types/caip5.d.ts deleted file mode 100644 index 60de2281ce..0000000000 --- a/packages/bcp/types/caip5.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { ChainId } from "@iov/bcp"; -/** - * Conversion between native chain IDs and CAIP-5 format - * - * @see https://github.com/ChainAgnostic/CAIPs/pull/9 - */ -export declare class Caip5 { - /** - * @param native The `chain_id` field from Tendermint's genesis file - */ - static encode(native: string): ChainId; - static decode(chainId: ChainId): string; -} diff --git a/packages/bcp/types/cosmoscodec.d.ts b/packages/bcp/types/cosmoscodec.d.ts deleted file mode 100644 index fe39164520..0000000000 --- a/packages/bcp/types/cosmoscodec.d.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { - Address, - ChainId, - Identity, - Nonce, - PostableBytes, - SignedTransaction, - SigningJob, - TransactionId, - TxCodec, - UnsignedTransaction, -} from "@iov/bcp"; -import { BankToken } from "./types"; -export declare class CosmosCodec implements TxCodec { - private readonly addressPrefix; - private readonly bankTokens; - constructor(addressPrefix: string, bankTokens: readonly BankToken[]); - bytesToSign(unsigned: UnsignedTransaction, nonce: Nonce): SigningJob; - bytesToPost(signed: SignedTransaction): PostableBytes; - identifier(_signed: SignedTransaction): TransactionId; - parseBytes(bytes: PostableBytes, chainId: ChainId, nonce?: Nonce): SignedTransaction; - identityToAddress(identity: Identity): Address; - isValidAddress(address: string): boolean; -} diff --git a/packages/bcp/types/cosmosconnection.d.ts b/packages/bcp/types/cosmosconnection.d.ts deleted file mode 100644 index 63c65b585f..0000000000 --- a/packages/bcp/types/cosmosconnection.d.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { - Account, - AccountQuery, - AddressQuery, - BlockchainConnection, - BlockHeader, - ChainId, - ConfirmedAndSignedTransaction, - ConfirmedTransaction, - FailedTransaction, - Fee, - Nonce, - PostableBytes, - PostTxResponse, - PubkeyQuery, - SignedTransaction, - Token, - TokenTicker, - TransactionId, - TransactionQuery, - TxCodec, - UnsignedTransaction, -} from "@iov/bcp"; -import { Stream } from "xstream"; -import { BankToken } from "./types"; -export interface TokenConfiguration { - /** Supported tokens of the Cosmos SDK bank module */ - readonly bankTokens: ReadonlyArray< - BankToken & { - readonly name: string; - } - >; -} -export declare class CosmosConnection implements BlockchainConnection { - static establish(url: string, addressPrefix: string, tokens: TokenConfiguration): Promise; - private static initialize; - readonly chainId: ChainId; - readonly codec: TxCodec; - private readonly cosmosClient; - private readonly addressPrefix; - private readonly bankTokens; - private readonly feeToken; - private readonly supportedTokens; - private constructor(); - disconnect(): void; - height(): Promise; - getToken(searchTicker: TokenTicker): Promise; - getAllTokens(): Promise; - /** - * This is a replacement for the unimplemented CosmosCodec.identifier. Here we have more - * context and network available, which we might use to implement the API in an async way. - */ - identifier(signed: SignedTransaction): Promise; - getAccount(query: AccountQuery): Promise; - watchAccount(query: AccountQuery): Stream; - getNonce(query: AddressQuery | PubkeyQuery): Promise; - getNonces(query: AddressQuery | PubkeyQuery, count: number): Promise; - getBlockHeader(height: number): Promise; - watchBlockHeaders(): Stream; - getTx(id: TransactionId): Promise | FailedTransaction>; - postTx(tx: PostableBytes): Promise; - searchTx({ - height, - id, - maxHeight, - minHeight, - sentFromOrTo, - signedBy, - tags, - }: TransactionQuery): Promise | FailedTransaction)[]>; - listenTx(_query: TransactionQuery): Stream | FailedTransaction>; - liveTx(query: TransactionQuery): Stream | FailedTransaction>; - getFeeQuote(tx: UnsignedTransaction): Promise; - withDefaultFee(tx: T): Promise; - private parseAndPopulateTxResponseUnsigned; - private parseAndPopulateTxResponseSigned; - private waitForTransaction; -} diff --git a/packages/bcp/types/cosmosconnector.d.ts b/packages/bcp/types/cosmosconnector.d.ts deleted file mode 100644 index b18d6d5484..0000000000 --- a/packages/bcp/types/cosmosconnector.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ChainConnector, ChainId } from "@iov/bcp"; -import { CosmosConnection, TokenConfiguration } from "./cosmosconnection"; -/** - * A helper to connect to a cosmos-based chain at a given url - */ -export declare function createCosmosConnector( - url: string, - addressPrefix: string, - tokenConfig: TokenConfiguration, - expectedChainId?: ChainId, -): ChainConnector; diff --git a/packages/bcp/types/decode.d.ts b/packages/bcp/types/decode.d.ts deleted file mode 100644 index b2825da96a..0000000000 --- a/packages/bcp/types/decode.d.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { Decimal } from "@cosmjs/math"; -import { Coin, IndexedTx, Msg, PubKey, StdFee, StdSignature, StdTx } from "@cosmjs/sdk38"; -import { - Amount, - ChainId, - ConfirmedAndSignedTransaction, - ConfirmedTransaction, - Fee, - FullSignature, - Nonce, - PubkeyBundle, - SignatureBytes, - SignedTransaction, - UnsignedTransaction, -} from "@iov/bcp"; -import { BankToken } from "./types"; -export declare function decodePubkey(pubkey: PubKey): PubkeyBundle; -export declare function decodeSignature(signature: string): SignatureBytes; -export declare function decodeFullSignature(signature: StdSignature, nonce: number): FullSignature; -export declare function coinToDecimal(tokens: readonly BankToken[], coin: Coin): readonly [Decimal, string]; -export declare function decodeAmount(tokens: readonly BankToken[], coin: Coin): Amount; -export declare function parseMsg( - msg: Msg, - memo: string | undefined, - chainId: ChainId, - tokens: readonly BankToken[], -): UnsignedTransaction; -export declare function parseFee(fee: StdFee, tokens: readonly BankToken[]): Fee; -export declare function parseUnsignedTx( - txValue: StdTx, - chainId: ChainId, - tokens: readonly BankToken[], -): UnsignedTransaction; -export declare function parseSignedTx( - txValue: StdTx, - chainId: ChainId, - nonce: Nonce, - tokens: readonly BankToken[], -): SignedTransaction; -export declare function parseTxsResponseUnsigned( - chainId: ChainId, - currentHeight: number, - response: IndexedTx, - tokens: readonly BankToken[], -): ConfirmedTransaction; -export declare function parseTxsResponseSigned( - chainId: ChainId, - currentHeight: number, - nonce: Nonce, - response: IndexedTx, - tokens: readonly BankToken[], -): ConfirmedAndSignedTransaction; diff --git a/packages/bcp/types/encode.d.ts b/packages/bcp/types/encode.d.ts deleted file mode 100644 index a2d77376b4..0000000000 --- a/packages/bcp/types/encode.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Coin, CosmosSdkTx, PubKey, StdFee, StdSignature } from "@cosmjs/sdk38"; -import { Amount, Fee, FullSignature, PubkeyBundle, SignedTransaction, UnsignedTransaction } from "@iov/bcp"; -import { BankToken } from "./types"; -export declare function encodePubkey(pubkey: PubkeyBundle): PubKey; -export declare function toBankCoin(amount: Amount, tokens: readonly BankToken[]): Coin; -export declare function encodeFee(fee: Fee, tokens: readonly BankToken[]): StdFee; -export declare function encodeFullSignature(fullSignature: FullSignature): StdSignature; -export declare function buildUnsignedTx( - tx: UnsignedTransaction, - bankTokens: readonly BankToken[], -): CosmosSdkTx; -export declare function buildSignedTx(tx: SignedTransaction, bankTokens: readonly BankToken[]): CosmosSdkTx; diff --git a/packages/bcp/types/index.d.ts b/packages/bcp/types/index.d.ts deleted file mode 100644 index 7ca0a53fb1..0000000000 --- a/packages/bcp/types/index.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { CosmosCodec } from "./cosmoscodec"; -export { CosmosConnection, TokenConfiguration } from "./cosmosconnection"; -export { createCosmosConnector } from "./cosmosconnector"; -export { BankToken } from "./types"; diff --git a/packages/bcp/types/types.d.ts b/packages/bcp/types/types.d.ts deleted file mode 100644 index 15d96e7dcb..0000000000 --- a/packages/bcp/types/types.d.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Nonce } from "@iov/bcp"; -export interface BankToken { - readonly denom: string; - readonly ticker: string; - /** - * The number of fractional digits the token supports. - * - * A quantity is expressed as atomic units. 10^fractionalDigits of those - * atomic units make up 1 token. - * - * E.g. in Ethereum 10^18 wei are 1 ETH and from the quantity 123000000000000000000 - * the last 18 digits are the fractional part and the rest the wole part. - */ - readonly fractionalDigits: number; -} -export declare function accountToNonce(accountNumber: number, sequence: number): Nonce; -export declare function nonceToAccountNumber(nonce: Nonce): number; -export declare function nonceToSequence(nonce: Nonce): number; diff --git a/packages/bcp/webpack.web.config.js b/packages/bcp/webpack.web.config.js deleted file mode 100644 index 7373cace4f..0000000000 --- a/packages/bcp/webpack.web.config.js +++ /dev/null @@ -1,19 +0,0 @@ -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(["WASMD_ENABLED"])], - }, -]; diff --git a/yarn.lock b/yarn.lock index ded15fabf4..8d908ed23f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -92,71 +92,6 @@ unique-filename "^1.1.1" which "^1.3.1" -"@iov/bcp@^2.3.2": - version "2.3.2" - resolved "https://registry.yarnpkg.com/@iov/bcp/-/bcp-2.3.2.tgz#23dc92839951beb239ec6ed56490d7534d67451c" - integrity sha512-o9ae5Q8jHgGyxsUnyoRcL200YVbDEYXAb6ZaAFad5/aFjhVawjTDSgya+vL8zI+t8BBixJZcXOjeDaqLtWRQAw== - dependencies: - "@iov/crypto" "^2.3.2" - "@iov/encoding" "^2.3.2" - "@iov/stream" "^2.3.2" - type-tagger "^1.0.0" - xstream "^11.10.0" - -"@iov/crypto@^2.3.2": - version "2.3.2" - resolved "https://registry.yarnpkg.com/@iov/crypto/-/crypto-2.3.2.tgz#0f65623d29d1df7e35620bbbeede70f1d0797ff9" - integrity sha512-inHHZa9kr+4K88ZhqOQC/LVlZBcZlE0Kkj97ynWGzaR4CCdCFa0KOkx2vef2CH0J6wbfC13e6b93/MuQyGiUAw== - dependencies: - "@iov/encoding" "^2.3.2" - bip39 "^3.0.2" - bn.js "^4.11.8" - elliptic "^6.4.0" - js-sha3 "^0.8.0" - libsodium-wrappers "^0.7.6" - pbkdf2 "^3.0.16" - ripemd160 "^2.0.2" - sha.js "^2.4.11" - type-tagger "^1.0.0" - unorm "^1.5.0" - -"@iov/encoding@^2.3.2": - version "2.3.2" - resolved "https://registry.yarnpkg.com/@iov/encoding/-/encoding-2.3.2.tgz#4b37966af0345a6bc904bb58189dc1ea9d14ad9b" - integrity sha512-viioqo1flTkG4Oxb0PvoBXGozHq9fObAgAL4dRHJe9zmChE77EBX2Y5u0nabd2JwAhEbir56AtsrUe4dOrtd5w== - dependencies: - base64-js "^1.3.0" - bech32 "^1.1.4" - bn.js "^4.11.8" - readonly-date "^1.0.0" - -"@iov/keycontrol@^2.3.2": - version "2.3.2" - resolved "https://registry.yarnpkg.com/@iov/keycontrol/-/keycontrol-2.3.2.tgz#42b556476c489e45b01ec47ec9ed28f287f5199e" - integrity sha512-Ile1c+ceAwefulNZ2pYu1TFeoFcx4S2oJTS57sFDNJzDDjn5xvEgNpdn4xkDDdGvkQOnexiMNifeCjInHBJpjQ== - dependencies: - "@iov/bcp" "^2.3.2" - "@iov/crypto" "^2.3.2" - "@iov/encoding" "^2.3.2" - "@iov/stream" "^2.3.2" - "@types/abstract-leveldown" "^5.0.1" - "@types/levelup" "^3.1.0" - "@types/node" "^10.12.18" - "@types/random-js" "^1.0.31" - levelup "^4.0.0" - long "^4.0.0" - random-js "^1.0.8" - readonly-date "^1.0.0" - type-tagger "^1.0.0" - xstream "^11.10.0" - -"@iov/stream@^2.3.2": - version "2.3.2" - resolved "https://registry.yarnpkg.com/@iov/stream/-/stream-2.3.2.tgz#472063f3a4fcd1e97de0ae99189f98b94825afac" - integrity sha512-nOq5OKwK2rWnyzXpGTAKZToCU0jmTjEC05owVzmBfw3+7hmjlExrGGbLncjcMWzbvp2VVpHc2l01Tr+qpzr8Vw== - dependencies: - xstream "^11.10.0" - "@koa/cors@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@koa/cors/-/cors-3.0.0.tgz#df021b4df2dadf1e2b04d7c8ddf93ba2d42519cb" @@ -955,11 +890,6 @@ dependencies: "@types/node" ">= 8" -"@types/abstract-leveldown@*", "@types/abstract-leveldown@^5.0.1": - version "5.0.1" - resolved "https://registry.yarnpkg.com/@types/abstract-leveldown/-/abstract-leveldown-5.0.1.tgz#3c7750d0186b954c7f2d2f6acc8c3c7ba0c3412e" - integrity sha512-wYxU3kp5zItbxKmeRYCEplS2MW7DzyBnxPGj+GJVHZEUZiK/nn5Ei1sUFgURDh+X051+zsGe28iud3oHjrYWQQ== - "@types/accepts@*": version "1.3.5" resolved "https://registry.yarnpkg.com/@types/accepts/-/accepts-1.3.5.tgz#c34bec115cfc746e04fe5a059df4ce7e7b391575" @@ -1122,14 +1052,6 @@ dependencies: "@types/koa" "*" -"@types/levelup@^3.1.0": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@types/levelup/-/levelup-3.1.1.tgz#f7cc08f248f14cb6c92914e91bceb8761020e8f0" - integrity sha512-LjvlfctJYj23Xuqq3jCT8ZPSUSSgDcRJg8+XFDBasoYzefFbB4cHzlDmBVjc2rBOYvklpYHJRayD0jBsbJLD9w== - dependencies: - "@types/abstract-leveldown" "*" - "@types/node" "*" - "@types/libsodium-wrappers@^0.7.7": version "0.7.7" resolved "https://registry.yarnpkg.com/@types/libsodium-wrappers/-/libsodium-wrappers-0.7.7.tgz#cdb25e85458612ec80f0157c3815fac187d0b6d2" @@ -1155,11 +1077,6 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-11.11.6.tgz#df929d1bb2eee5afdda598a41930fe50b43eaa6a" integrity sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ== -"@types/node@^10.12.18": - version "10.17.17" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.17.tgz#7a183163a9e6ff720d86502db23ba4aade5999b8" - integrity sha512-gpNnRnZP3VWzzj5k3qrpRC6Rk3H/uclhAVo1aIvwzK5p5cOrs9yEyQ8H/HBsBY0u5rrWxXEiVPQ0dEB6pkjE8Q== - "@types/pako@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@types/pako/-/pako-1.0.1.tgz#33b237f3c9aff44d0f82fe63acffa4a365ef4a61" @@ -1172,11 +1089,6 @@ dependencies: "@types/node" "*" -"@types/random-js@^1.0.31": - version "1.0.31" - resolved "https://registry.yarnpkg.com/@types/random-js/-/random-js-1.0.31.tgz#18a8bcc075afa504421e638fcbe021f27e802941" - integrity sha512-EAM56DrKw3VhcE4HV0/YlVKeJI07We4Mz1ra6TNtZpaMoiBVMA2bkLEcoFpYOyxoDXfVZWojxkR617LTqtRI0A== - "@types/range-parser@*": version "1.2.3" resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" @@ -1442,15 +1354,6 @@ abbrev@1: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== -abstract-leveldown@~6.2.1: - version "6.2.2" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.2.2.tgz#677425beeb28204367c7639e264e93ea4b49971a" - integrity sha512-/a+Iwj0rn//CX0EJOasNyZJd2o8xur8Ce9C57Sznti/Ilt/cb6Qd8/k98A4ZOklXgTG+iAYYUs1OTG0s1eH+zQ== - dependencies: - level-concat-iterator "~2.0.0" - level-supports "~1.0.0" - xtend "~4.0.0" - accepts@^1.3.5, accepts@~1.3.4: version "1.3.7" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" @@ -1906,11 +1809,6 @@ bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.11.8, bn.js@^4.4.0: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== -bn.js@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.1.tgz#48efc4031a9c4041b9c99c6941d903463ab62eb5" - integrity sha512-IUTD/REb78Z2eodka1QZyyEk66pciRcP6Sroka0aI3tG/iwIdYLrBD62RsubR7vqdt3WyX8p4jxeatzmRSphtA== - body-parser@^1.19.0: version "1.19.0" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" @@ -2834,14 +2732,6 @@ defaults@^1.0.3: dependencies: clone "^1.0.2" -deferred-leveldown@~5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-5.3.0.tgz#27a997ad95408b61161aa69bd489b86c71b78058" - integrity sha512-a59VOT+oDy7vtAbLRCZwWgxu2BaCfd5Hk7wxJd48ei7I+nsg8Orlb9CLG0PMZienk9BSUKgeAqkO2+Lw+1+Ukw== - dependencies: - abstract-leveldown "~6.2.1" - inherits "^2.0.3" - define-properties@^1.1.2, define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -3155,7 +3045,7 @@ err-code@^1.0.0: resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960" integrity sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA= -errno@^0.1.3, errno@~0.1.1, errno@~0.1.7: +errno@^0.1.3, errno@~0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg== @@ -4311,7 +4201,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -4967,45 +4857,6 @@ lerna@^3.20.2: import-local "^2.0.0" npmlog "^4.1.2" -level-concat-iterator@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/level-concat-iterator/-/level-concat-iterator-2.0.1.tgz#1d1009cf108340252cb38c51f9727311193e6263" - integrity sha512-OTKKOqeav2QWcERMJR7IS9CUo1sHnke2C0gkSmcR7QuEtFNLLzHQAvnMw8ykvEcv0Qtkg0p7FOwP1v9e5Smdcw== - -level-errors@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-2.0.1.tgz#2132a677bf4e679ce029f517c2f17432800c05c8" - integrity sha512-UVprBJXite4gPS+3VznfgDSU8PTRuVX0NXwoWW50KLxd2yw4Y1t2JUR5In1itQnudZqRMT9DlAM3Q//9NCjCFw== - dependencies: - errno "~0.1.1" - -level-iterator-stream@~4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/level-iterator-stream/-/level-iterator-stream-4.0.2.tgz#7ceba69b713b0d7e22fcc0d1f128ccdc8a24f79c" - integrity sha512-ZSthfEqzGSOMWoUGhTXdX9jv26d32XJuHz/5YnuHZzH6wldfWMOVwI9TBtKcya4BKTyTt3XVA0A3cF3q5CY30Q== - dependencies: - inherits "^2.0.4" - readable-stream "^3.4.0" - xtend "^4.0.2" - -level-supports@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-1.0.1.tgz#2f530a596834c7301622521988e2c36bb77d122d" - integrity sha512-rXM7GYnW8gsl1vedTJIbzOrRv85c/2uCMpiiCzO2fndd06U/kUXEEU9evYn4zFggBOg36IsBW8LzqIpETwwQzg== - dependencies: - xtend "^4.0.2" - -levelup@^4.0.0: - version "4.3.2" - resolved "https://registry.yarnpkg.com/levelup/-/levelup-4.3.2.tgz#31c5b1b29f146d1d35d692e01a6da4d28fa55ebd" - integrity sha512-cRTjU4ktWo59wf13PHEiOayHC3n0dOh4i5+FHr4tv4MX9+l7mqETicNq3Aj07HKlLdk0z5muVoDL2RD+ovgiyA== - dependencies: - deferred-leveldown "~5.3.0" - level-errors "~2.0.0" - level-iterator-stream "~4.0.0" - level-supports "~1.0.0" - xtend "~4.0.0" - levn@^0.3.0, levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" @@ -5180,11 +5031,6 @@ log4js@^6.2.1: rfdc "^1.1.4" streamroller "^2.2.4" -long@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" - integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== - loud-rejection@^1.0.0: version "1.6.0" resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" @@ -6447,11 +6293,6 @@ quick-lru@^1.0.0: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8" integrity sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g= -random-js@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/random-js/-/random-js-1.0.8.tgz#968fd689a6f25d6c0aac766283de2f688c9c190a" - integrity sha1-lo/WiabyXWwKrHZig94vaIycGQo= - randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -6591,7 +6432,7 @@ read@1, read@~1.0.1: string_decoder "~1.1.1" util-deprecate "~1.0.1" -"readable-stream@2 || 3", readable-stream@^3.0.2, readable-stream@^3.4.0: +"readable-stream@2 || 3", readable-stream@^3.0.2: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -8155,14 +7996,14 @@ xmlhttprequest-ssl@~1.5.4: resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4= -xstream@^11.10.0, xstream@^11.11.0: +xstream@^11.11.0: version "11.11.0" resolved "https://registry.yarnpkg.com/xstream/-/xstream-11.11.0.tgz#2c963cf0a6cb3eafecb57eaeae16c9850235b422" integrity sha512-0zF3PLsHrmbToPBgX1jYZFNw+t5octSFJgVRH44HGlGBBjY7gscvDQOZvty8IQV15Snia1RcLPECWDfEaE4aXg== dependencies: symbol-observable "1.2.0" -xtend@^4.0.0, xtend@^4.0.2, xtend@~4.0.0, xtend@~4.0.1: +xtend@^4.0.0, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==