diff --git a/README.md b/README.md index ac05c0d..049bf2e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ -

CosmJS

@@ -7,8 +6,9 @@ ## About -Cosmwasm.js was created to help new developers get started with their first dApps. -It is just a wrapper package to easily import needed features from CosmJS. +Cosmwasm.js was created to help new developers get started with their first +dApps. It is just a wrapper package to easily import needed features from +CosmJS. ## Get started @@ -49,17 +49,17 @@ import { SigningCosmWasmClient, Secp256k1HdWallet } from "cosmwasm"; const rpcEndpoint = "https://rpc.cliffnet.cosmwasm.com:443/"; // Using a random generated mnemonic -const mnemonic = "rifle same bitter control garage duck grab spare mountain doctor rubber cook"; +const mnemonic = + "rifle same bitter control garage duck grab spare mountain doctor rubber cook"; async function main() { - // Create a wallet const wallet = await Secp256k1HdWallet.fromMnemonic(mnemonic); // Using const client = await SigningCosmWasmClient.connectWithSigner( rpcEndpoint, - wallet + wallet, ); console.log(client); } @@ -67,6 +67,25 @@ async function main() { main(); ``` +### Connect with keplr and get a signing starget client + +```ts +import { setupWebKeplr } from "cosmwasm"; + +const config = { + chainId: "cliffnet-1", + rpcEndpoint: "https://rpc.cliffnet.cosmwasm.com:443/", + prefix: "wasm", +}; + +async function main() { + const client = await setupWebKeplr(config); + console.log(client); +} + +main(); +``` + ### Interacting with contracts ```ts @@ -76,7 +95,8 @@ import { CosmWasmClient } from "cosmwasm"; const rpcEndpoint = "https://rpc.cliffnet.cosmwasm.com:443/"; // This is your contract address -const contractAddr = "wasm19qws2lfd8pskyn0cfgpl5yjjyq3msy5402qr8nkzff9kdnkaepyqycedfh"; +const contractAddr = + "wasm19qws2lfd8pskyn0cfgpl5yjjyq3msy5402qr8nkzff9kdnkaepyqycedfh"; async function main() { const client = await CosmWasmClient.connect(rpcEndpoint); diff --git a/package.json b/package.json index 8422804..a358496 100644 --- a/package.json +++ b/package.json @@ -37,10 +37,12 @@ "@cosmjs/crypto": "0.27.1", "@cosmjs/encoding": "0.27.1", "@cosmjs/faucet-client": "0.27.1", + "@cosmjs/ledger-amino": "0.27.1", "@cosmjs/proto-signing": "0.27.1", "@cosmjs/stargate": "0.27.1" }, "devDependencies": { + "@types/ledgerhq__hw-transport": "^4.21.4", "@typescript-eslint/eslint-plugin": "^5.11.0", "@typescript-eslint/parser": "^5.11.0", "eslint": "^7.32.0", @@ -48,10 +50,10 @@ "eslint-config-standard": "^16.0.3", "eslint-plugin-import": "^2.25.4", "eslint-plugin-node": "^11.1.0", + "eslint-plugin-prettier": "^4.0.0", "eslint-plugin-promise": "^5.2.0", + "eslint-plugin-simple-import-sort": "^7.0.0", "prettier": "^2.5.1", - "typescript": "^4.5.5", - "eslint-plugin-prettier": "^4.0.0", - "eslint-plugin-simple-import-sort": "^7.0.0" + "typescript": "^4.5.5" } } diff --git a/src/helpers/setup.ts b/src/helpers/setup.ts new file mode 100644 index 0000000..f4f7031 --- /dev/null +++ b/src/helpers/setup.ts @@ -0,0 +1,159 @@ +/** + * Setup helper functions + * + * These are multiple helper function to get quickly started. + * There are currently 4 different functions to choose from: + * (a) Web / Keplr + * (b) Web / Ledger + * (c) Node / Local Mnemonic + * (d) Node / Ledger + */ +import { makeCosmoshubPath } from "../amino"; +import { SigningCosmWasmClient } from "../cosmwasm-stargate"; +import { LedgerSigner } from "../ledger-amino"; +import { DirectSecp256k1HdWallet } from "../proto-signing"; +import { GasPrice } from "../stargate"; + +/** + * All setup functions are using the same config pattern + */ +interface Config { + chainId: string; + rpcEndpoint: string; + prefix: string; + gasPrice?: GasPrice; +} + +// Window has to be re-declared to get keplr working +declare const window: any; + +/** + * (a) Web / Keplr + * Prompts keplr and returns a signing client after the user + * gave permissions. + * + * @param config + * @returns SigningCosmWasmClient + */ +export async function setupWebKeplr(config: Config): Promise { + // check browser compatibility + if (!window.keplr) { + throw new Error("Keplr is not supported or installed on this browser!"); + } + + // try to enable keplr with given chainId + await window.keplr.enable(config.chainId).catch(() => { + throw new Error("Keplr can't connect to this chainId!"); + }); + + const { prefix, gasPrice } = config; + + // Setup signer + const offlineSigner = await window.getOfflineSignerAuto(config.chainId); + + // Init SigningCosmWasmClient client + const signingClient = await SigningCosmWasmClient.connectWithSigner(config.rpcEndpoint, offlineSigner, { + prefix, + gasPrice, + }); + + return signingClient; +} + +/** + * (b) Web / Ledger + * Returns a signing client after the user gave permissions. + * + * @param config + * @returns SigningCosmWasmClient + */ +export async function setupWebLedger(config: Config, transport: any): Promise { + const { prefix, gasPrice } = config; + const interactiveTimeout = 120_000; + + // Prepare ledger + const ledgerTransport = await transport.create(interactiveTimeout, interactiveTimeout); + + // Setup signer + const offlineSigner = new LedgerSigner(ledgerTransport, { + hdPaths: [makeCosmoshubPath(0)], + prefix: prefix, + }); + + // Init SigningCosmWasmClient client + const client = await SigningCosmWasmClient.connectWithSigner(config.rpcEndpoint, offlineSigner, { + prefix, + gasPrice, + }); + + const chainId = await client.getChainId(); + + if (chainId !== config.chainId) { + throw Error("Given ChainId doesn't match the clients ChainID!"); + } + + return client; +} + +/** + * (c) Node / Local Mnemonic + * Using a local mnemonic and returns a signing clien + * + * @param config + * @param mnemonic + * @returns SigningCosmWasmClient + */ +export async function setupNodeLocal(config: Config, mnemonic: string): Promise { + const { prefix, gasPrice } = config; + + // Setup signer + const offlineSigner = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic, { prefix }); + + // Init SigningCosmWasmClient client + const client = await SigningCosmWasmClient.connectWithSigner(config.rpcEndpoint, offlineSigner, { + prefix, + gasPrice, + }); + + const chainId = await client.getChainId(); + + if (chainId !== config.chainId) { + throw Error("Given ChainId doesn't match the clients ChainID!"); + } + + return client; +} + +/** + * (d) Node / Ledger + * Returns a signing client after the user gave permissions. + * + * @param config + * @returns SigningCosmWasmClient + */ +export async function setupNodeLedger(config: Config, transport: any): Promise { + const { prefix, gasPrice } = config; + const interactiveTimeout = 120_000; + + // Prepare ledger + const ledgerTransport = await transport.create(interactiveTimeout, interactiveTimeout); + + // Setup signer + const offlineSigner = new LedgerSigner(ledgerTransport, { + hdPaths: [makeCosmoshubPath(0)], + prefix: prefix, + }); + + const client = await SigningCosmWasmClient.connectWithSigner(config.rpcEndpoint, offlineSigner, { + prefix: prefix, + gasPrice: gasPrice, + }); + + const chainId = await client.getChainId(); + + if (chainId !== config.chainId) { + throw Error("Given ChainId doesn't match the clients ChainID!"); + } + + return client; +} diff --git a/src/index.ts b/src/index.ts index 936aa0e..35b8847 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,6 @@ +/** + * Exporting all the defined CosmJS symbols + */ export * from "./amino"; export * from "./cosmwasm-stargate"; export * from "./crypto"; @@ -5,3 +8,8 @@ export * from "./encoding"; export * from "./faucet-client"; export * from "./proto-signing"; export * from "./stargate"; + +/** + * Exporting CosmWasmJS Helpers + */ +export { setupNodeLedger, setupNodeLocal, setupWebKeplr, setupWebLedger } from "./helpers/setup"; diff --git a/src/ledger-amino.ts b/src/ledger-amino.ts new file mode 100644 index 0000000..42c5ca0 --- /dev/null +++ b/src/ledger-amino.ts @@ -0,0 +1 @@ +export { LedgerSigner } from "@cosmjs/ledger-amino"; diff --git a/yarn.lock b/yarn.lock index 35ff675..61b1ade 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23,6 +23,13 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@babel/runtime@^7.11.2": + version "7.17.2" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz" + integrity sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw== + dependencies: + regenerator-runtime "^0.13.4" + "@confio/ics23@^0.6.3": version "0.6.5" resolved "https://registry.npmjs.org/@confio/ics23/-/ics23-0.6.5.tgz" @@ -101,6 +108,19 @@ "@cosmjs/stream" "0.27.1" xstream "^11.14.0" +"@cosmjs/ledger-amino@0.27.1": + version "0.27.1" + resolved "https://registry.npmjs.org/@cosmjs/ledger-amino/-/ledger-amino-0.27.1.tgz" + integrity sha512-MbRw37+q37xP6ICQZll1ulFkqW/rpUgkatnA0aOuFfvf9DivRO0XRXGM7sw/3aKInxt9+8M1DGNFWM3HchwExw== + dependencies: + "@cosmjs/amino" "0.27.1" + "@cosmjs/crypto" "0.27.1" + "@cosmjs/encoding" "0.27.1" + "@cosmjs/math" "0.27.1" + "@cosmjs/utils" "0.27.1" + ledger-cosmos-js "^2.1.8" + semver "^7.3.2" + "@cosmjs/math@0.27.1": version "0.27.1" resolved "https://registry.npmjs.org/@cosmjs/math/-/math-0.27.1.tgz" @@ -204,6 +224,35 @@ resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@ledgerhq/devices@^5.51.1": + version "5.51.1" + resolved "https://registry.npmjs.org/@ledgerhq/devices/-/devices-5.51.1.tgz" + integrity sha512-4w+P0VkbjzEXC7kv8T1GJ/9AVaP9I6uasMZ/JcdwZBS3qwvKo5A5z9uGhP5c7TvItzcmPb44b5Mw2kT+WjUuAA== + dependencies: + "@ledgerhq/errors" "^5.50.0" + "@ledgerhq/logs" "^5.50.0" + rxjs "6" + semver "^7.3.5" + +"@ledgerhq/errors@^5.50.0": + version "5.50.0" + resolved "https://registry.npmjs.org/@ledgerhq/errors/-/errors-5.50.0.tgz" + integrity sha512-gu6aJ/BHuRlpU7kgVpy2vcYk6atjB4iauP2ymF7Gk0ez0Y/6VSMVSJvubeEQN+IV60+OBK0JgeIZG7OiHaw8ow== + +"@ledgerhq/hw-transport@^5.25.0": + version "5.51.1" + resolved "https://registry.npmjs.org/@ledgerhq/hw-transport/-/hw-transport-5.51.1.tgz" + integrity sha512-6wDYdbWrw9VwHIcoDnqWBaDFyviyjZWv6H9vz9Vyhe4Qd7TIFmbTl/eWs6hZvtZBza9K8y7zD8ChHwRI4s9tSw== + dependencies: + "@ledgerhq/devices" "^5.51.1" + "@ledgerhq/errors" "^5.50.0" + events "^3.3.0" + +"@ledgerhq/logs@^5.50.0": + version "5.50.0" + resolved "https://registry.npmjs.org/@ledgerhq/logs/-/logs-5.50.0.tgz" + integrity sha512-swKHYCOZUGyVt4ge0u8a7AwNcA//h4nx5wIi0sruGye1IJ5Cva0GyK9L2/WdX+kWVTKp92ZiEo1df31lrWGPgA== + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" @@ -288,11 +337,23 @@ resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= +"@types/ledgerhq__hw-transport@^4.21.4": + version "4.21.4" + resolved "https://registry.npmjs.org/@types/ledgerhq__hw-transport/-/ledgerhq__hw-transport-4.21.4.tgz" + integrity sha512-vep+6yZnGv6owAthIY0w3f72w4dJIb4+yE5PCHveInTlZE9wukvU6Wc5Eig0OUUxcdhTazzeZx1xUaNVLqyQSg== + dependencies: + "@types/node" "*" + "@types/long@^4.0.1": version "4.0.1" resolved "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz" integrity sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w== +"@types/node@*", "@types/node@^13.7.0": + version "13.13.52" + resolved "https://registry.npmjs.org/@types/node/-/node-13.13.52.tgz" + integrity sha512-s3nugnZumCC//n4moGGe6tkNMyYEdaDBitVjwPxXmR5lnMG5dHePinH2EdxkG3Rh1ghFHHixAG4NJhpJW1rthQ== + "@types/node@11.11.6": version "11.11.6" resolved "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz" @@ -303,11 +364,6 @@ resolved "https://registry.npmjs.org/@types/node/-/node-17.0.15.tgz" integrity sha512-zWt4SDDv1S9WRBNxLFxFRHxdD9tvH8f5/kg5/IaLFdnSNXsDY4eL3Q3XXN+VxUnWIhyVFDwcsmAprvwXoM/ClA== -"@types/node@^13.7.0": - version "13.13.52" - resolved "https://registry.npmjs.org/@types/node/-/node-13.13.52.tgz" - integrity sha512-s3nugnZumCC//n4moGGe6tkNMyYEdaDBitVjwPxXmR5lnMG5dHePinH2EdxkG3Rh1ghFHHixAG4NJhpJW1rthQ== - "@typescript-eslint/eslint-plugin@^5.11.0": version "5.11.0" resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.11.0.tgz" @@ -839,7 +895,7 @@ eslint-plugin-node@^11.1.0: eslint-plugin-prettier@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz#8b99d1e4b8b24a762472b4567992023619cb98e0" + resolved "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz" integrity sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ== dependencies: prettier-linter-helpers "^1.0.0" @@ -851,7 +907,7 @@ eslint-plugin-promise@^5.2.0: eslint-plugin-simple-import-sort@^7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-7.0.0.tgz#a1dad262f46d2184a90095a60c66fef74727f0f8" + resolved "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-7.0.0.tgz" integrity sha512-U3vEDB5zhYPNfxT5TYR7u01dboFZp+HNpnGhkDB2g/2E4wZ/g1Q9Ton8UwCLfRV9yAKyYqDh62oHOamvkFxsvw== eslint-scope@^5.1.1: @@ -980,6 +1036,11 @@ esutils@^2.0.2: resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +events@^3.3.0: + version "3.3.0" + resolved "https://registry.npmjs.org/events/-/events-3.3.0.tgz" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" @@ -987,7 +1048,7 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: fast-diff@^1.1.2: version "1.2.0" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" + resolved "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz" integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== fast-glob@^3.2.9: @@ -1396,6 +1457,16 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" +ledger-cosmos-js@^2.1.8: + version "2.1.8" + resolved "https://registry.npmjs.org/ledger-cosmos-js/-/ledger-cosmos-js-2.1.8.tgz" + integrity sha512-Gl7SWMq+3R9OTkF1hLlg5+1geGOmcHX9OdS+INDsGNxSiKRWlsWCvQipGoDnRIQ6CPo2i/Ze58Dw0Mt/l3UYyA== + dependencies: + "@babel/runtime" "^7.11.2" + "@ledgerhq/hw-transport" "^5.25.0" + bech32 "^1.1.4" + ripemd160 "^2.0.2" + levn@^0.4.1: version "0.4.1" resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" @@ -1632,7 +1703,7 @@ prelude-ls@^1.2.1: prettier-linter-helpers@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + resolved "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz" integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== dependencies: fast-diff "^1.1.2" @@ -1716,6 +1787,11 @@ readonly-date@^1.0.0: resolved "https://registry.npmjs.org/readonly-date/-/readonly-date-1.0.0.tgz" integrity sha512-tMKIV7hlk0h4mO3JTmmVuIlJVXjKk3Sep9Bf5OH0O+758ruuVkUy2J9SttDLm91IEX/WHlXPSpxMGjPj4beMIQ== +regenerator-runtime@^0.13.4: + version "0.13.9" + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + regexpp@^3.0.0, regexpp@^3.1.0, regexpp@^3.2.0: version "3.2.0" resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz" @@ -1767,6 +1843,13 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +rxjs@6: + version "6.6.7" + resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz" + integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== + dependencies: + tslib "^1.9.0" + safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" @@ -1777,7 +1860,7 @@ semver@^6.1.0: resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.2.1, semver@^7.3.5: +semver@^7.2.1, semver@^7.3.2, semver@^7.3.5: version "7.3.5" resolved "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz" integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== @@ -1938,7 +2021,7 @@ tsconfig-paths@^3.12.0: minimist "^1.2.0" strip-bom "^3.0.0" -tslib@^1.8.1: +tslib@^1.8.1, tslib@^1.9.0: version "1.14.1" resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==