Remove @cosmjs/cosmwasm and @cosmjs/cosmwasm-launchpad

This commit is contained in:
Simon Warta 2021-07-22 14:44:41 +02:00
parent 6d99d32350
commit 3912aaff88
141 changed files with 23 additions and 6239 deletions

228
.pnp.js generated
View File

@ -30,14 +30,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"name": "@cosmjs/cli",
"reference": "workspace:packages/cli"
},
{
"name": "@cosmjs/cosmwasm",
"reference": "workspace:packages/cosmwasm"
},
{
"name": "@cosmjs/cosmwasm-launchpad",
"reference": "workspace:packages/cosmwasm-launchpad"
},
{
"name": "@cosmjs/cosmwasm-stargate",
"reference": "workspace:packages/cosmwasm-stargate"
@ -104,8 +96,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"fallbackExclusionList": [
["@cosmjs/amino", ["workspace:packages/amino"]],
["@cosmjs/cli", ["workspace:packages/cli"]],
["@cosmjs/cosmwasm", ["workspace:packages/cosmwasm"]],
["@cosmjs/cosmwasm-launchpad", ["workspace:packages/cosmwasm-launchpad"]],
["@cosmjs/cosmwasm-stargate", ["workspace:packages/cosmwasm-stargate"]],
["@cosmjs/crypto", ["workspace:packages/crypto"]],
["@cosmjs/encoding", ["workspace:packages/encoding"]],
@ -236,14 +226,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"@cosmjs/cli",
"workspace:packages/cli"
],
[
"@cosmjs/cosmwasm",
"workspace:packages/cosmwasm"
],
[
"@cosmjs/cosmwasm-launchpad",
"workspace:packages/cosmwasm-launchpad"
],
[
"@cosmjs/cosmwasm-stargate",
"workspace:packages/cosmwasm-stargate"
@ -2873,7 +2855,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"packageLocation": "./",
"packageDependencies": [
["@cosmjs/amino", "workspace:packages/amino"],
["@cosmjs/cosmwasm-launchpad", "workspace:packages/cosmwasm-launchpad"],
["@cosmjs/cosmwasm-stargate", "workspace:packages/cosmwasm-stargate"],
["@cosmjs/crypto", "workspace:packages/crypto"],
["@cosmjs/encoding", "workspace:packages/encoding"],
@ -3273,7 +3254,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"packageDependencies": [
["@cosmjs/cli", "workspace:packages/cli"],
["@cosmjs/amino", "workspace:packages/amino"],
["@cosmjs/cosmwasm-launchpad", "workspace:packages/cosmwasm-launchpad"],
["@cosmjs/cosmwasm-stargate", "workspace:packages/cosmwasm-stargate"],
["@cosmjs/crypto", "workspace:packages/crypto"],
["@cosmjs/encoding", "workspace:packages/encoding"],
@ -3318,80 +3298,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"linkType": "SOFT",
}]
]],
["@cosmjs/cosmwasm", [
["workspace:packages/cosmwasm", {
"packageLocation": "./packages/cosmwasm/",
"packageDependencies": [
["@cosmjs/cosmwasm", "workspace:packages/cosmwasm"],
["@cosmjs/cosmwasm-launchpad", "workspace:packages/cosmwasm-launchpad"],
["@types/eslint-plugin-prettier", "npm:3.1.0"],
["@typescript-eslint/eslint-plugin", "virtual:4f1584ad4aba8733a24be7c8aebbffafef25607f2d00f4b314cf96717145c692763628a31c2b85d4686fbb091ff21ebffa3cc337399c042c19a32b9bdb786464#npm:4.28.4"],
["@typescript-eslint/parser", "virtual:4f1584ad4aba8733a24be7c8aebbffafef25607f2d00f4b314cf96717145c692763628a31c2b85d4686fbb091ff21ebffa3cc337399c042c19a32b9bdb786464#npm:4.28.4"],
["eslint", "npm:7.26.0"],
["eslint-config-prettier", "virtual:4f1584ad4aba8733a24be7c8aebbffafef25607f2d00f4b314cf96717145c692763628a31c2b85d4686fbb091ff21ebffa3cc337399c042c19a32b9bdb786464#npm:8.3.0"],
["eslint-import-resolver-node", "npm:0.3.4"],
["eslint-plugin-import", "virtual:4f1584ad4aba8733a24be7c8aebbffafef25607f2d00f4b314cf96717145c692763628a31c2b85d4686fbb091ff21ebffa3cc337399c042c19a32b9bdb786464#npm:2.23.2"],
["eslint-plugin-prettier", "virtual:4f1584ad4aba8733a24be7c8aebbffafef25607f2d00f4b314cf96717145c692763628a31c2b85d4686fbb091ff21ebffa3cc337399c042c19a32b9bdb786464#npm:3.4.0"],
["eslint-plugin-simple-import-sort", "virtual:4f1584ad4aba8733a24be7c8aebbffafef25607f2d00f4b314cf96717145c692763628a31c2b85d4686fbb091ff21ebffa3cc337399c042c19a32b9bdb786464#npm:7.0.0"],
["prettier", "npm:2.3.2"],
["typedoc", "virtual:4f1584ad4aba8733a24be7c8aebbffafef25607f2d00f4b314cf96717145c692763628a31c2b85d4686fbb091ff21ebffa3cc337399c042c19a32b9bdb786464#npm:0.21.4"],
["typescript", "patch:typescript@npm%3A4.3.5#builtin<compat/typescript>::version=4.3.5&hash=ddfc1b"]
],
"linkType": "SOFT",
}]
]],
["@cosmjs/cosmwasm-launchpad", [
["workspace:packages/cosmwasm-launchpad", {
"packageLocation": "./packages/cosmwasm-launchpad/",
"packageDependencies": [
["@cosmjs/cosmwasm-launchpad", "workspace:packages/cosmwasm-launchpad"],
["@cosmjs/crypto", "workspace:packages/crypto"],
["@cosmjs/encoding", "workspace:packages/encoding"],
["@cosmjs/launchpad", "workspace:packages/launchpad"],
["@cosmjs/math", "workspace:packages/math"],
["@cosmjs/utils", "workspace:packages/utils"],
["@istanbuljs/nyc-config-typescript", "virtual:4f1584ad4aba8733a24be7c8aebbffafef25607f2d00f4b314cf96717145c692763628a31c2b85d4686fbb091ff21ebffa3cc337399c042c19a32b9bdb786464#npm:1.0.1"],
["@types/eslint-plugin-prettier", "npm:3.1.0"],
["@types/jasmine", "npm:3.7.4"],
["@types/karma-firefox-launcher", "npm:2.1.0"],
["@types/karma-jasmine", "npm:4.0.0"],
["@types/karma-jasmine-html-reporter", "npm:1.5.1"],
["@types/node", "npm:15.3.1"],
["@types/pako", "npm:1.0.1"],
["@typescript-eslint/eslint-plugin", "virtual:4f1584ad4aba8733a24be7c8aebbffafef25607f2d00f4b314cf96717145c692763628a31c2b85d4686fbb091ff21ebffa3cc337399c042c19a32b9bdb786464#npm:4.28.4"],
["@typescript-eslint/parser", "virtual:4f1584ad4aba8733a24be7c8aebbffafef25607f2d00f4b314cf96717145c692763628a31c2b85d4686fbb091ff21ebffa3cc337399c042c19a32b9bdb786464#npm:4.28.4"],
["eslint", "npm:7.26.0"],
["eslint-config-prettier", "virtual:4f1584ad4aba8733a24be7c8aebbffafef25607f2d00f4b314cf96717145c692763628a31c2b85d4686fbb091ff21ebffa3cc337399c042c19a32b9bdb786464#npm:8.3.0"],
["eslint-import-resolver-node", "npm:0.3.4"],
["eslint-plugin-import", "virtual:4f1584ad4aba8733a24be7c8aebbffafef25607f2d00f4b314cf96717145c692763628a31c2b85d4686fbb091ff21ebffa3cc337399c042c19a32b9bdb786464#npm:2.23.2"],
["eslint-plugin-prettier", "virtual:4f1584ad4aba8733a24be7c8aebbffafef25607f2d00f4b314cf96717145c692763628a31c2b85d4686fbb091ff21ebffa3cc337399c042c19a32b9bdb786464#npm:3.4.0"],
["eslint-plugin-simple-import-sort", "virtual:4f1584ad4aba8733a24be7c8aebbffafef25607f2d00f4b314cf96717145c692763628a31c2b85d4686fbb091ff21ebffa3cc337399c042c19a32b9bdb786464#npm:7.0.0"],
["esm", "npm:3.2.25"],
["glob", "npm:7.1.7"],
["jasmine", "npm:3.7.0"],
["jasmine-core", "npm:3.7.1"],
["jasmine-spec-reporter", "npm:6.0.0"],
["karma", "npm:6.3.2"],
["karma-chrome-launcher", "npm:3.1.0"],
["karma-firefox-launcher", "npm:2.1.0"],
["karma-jasmine", "virtual:4f1584ad4aba8733a24be7c8aebbffafef25607f2d00f4b314cf96717145c692763628a31c2b85d4686fbb091ff21ebffa3cc337399c042c19a32b9bdb786464#npm:4.0.1"],
["karma-jasmine-html-reporter", "virtual:4f1584ad4aba8733a24be7c8aebbffafef25607f2d00f4b314cf96717145c692763628a31c2b85d4686fbb091ff21ebffa3cc337399c042c19a32b9bdb786464#npm:1.6.0"],
["nyc", "npm:15.1.0"],
["pako", "npm:2.0.3"],
["prettier", "npm:2.3.2"],
["readonly-date", "npm:1.0.0"],
["ses", "npm:0.11.1"],
["source-map-support", "npm:0.5.19"],
["stream-browserify", "npm:3.0.0"],
["ts-node", "virtual:4f1584ad4aba8733a24be7c8aebbffafef25607f2d00f4b314cf96717145c692763628a31c2b85d4686fbb091ff21ebffa3cc337399c042c19a32b9bdb786464#npm:8.10.2"],
["typedoc", "virtual:4f1584ad4aba8733a24be7c8aebbffafef25607f2d00f4b314cf96717145c692763628a31c2b85d4686fbb091ff21ebffa3cc337399c042c19a32b9bdb786464#npm:0.21.4"],
["typescript", "patch:typescript@npm%3A4.3.5#builtin<compat/typescript>::version=4.3.5&hash=ddfc1b"],
["webpack", "virtual:395f1354ea29de80eb111225ff7f72912127acf779ae2110ad0ceee26819d65678b5f21be5a4c99566f19c05b63bb8c464db1c3c0ca922c2f45f91ad734637ee#npm:5.37.1"],
["webpack-cli", "virtual:395f1354ea29de80eb111225ff7f72912127acf779ae2110ad0ceee26819d65678b5f21be5a4c99566f19c05b63bb8c464db1c3c0ca922c2f45f91ad734637ee#npm:4.7.0"]
],
"linkType": "SOFT",
}]
]],
["@cosmjs/cosmwasm-stargate", [
["workspace:packages/cosmwasm-stargate", {
"packageLocation": "./packages/cosmwasm-stargate/",
@ -5477,23 +5383,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
],
"linkType": "HARD",
}],
["virtual:84adca422dcfddfebe74232825b4d9a5ef615fdab14f3f17f1a545c4531bd06dc6868a9c1d1e3abce6a67873f8d3e04c605bfaaf12cc7fa1a0495f9f023c0ec3#npm:1.0.3", {
"packageLocation": "./.yarn/$$virtual/@webpack-cli-configtest-virtual-d4999b5de1/0/cache/@webpack-cli-configtest-npm-1.0.3-b6e357f778-df71875431.zip/node_modules/@webpack-cli/configtest/",
"packageDependencies": [
["@webpack-cli/configtest", "virtual:84adca422dcfddfebe74232825b4d9a5ef615fdab14f3f17f1a545c4531bd06dc6868a9c1d1e3abce6a67873f8d3e04c605bfaaf12cc7fa1a0495f9f023c0ec3#npm:1.0.3"],
["@types/webpack", null],
["@types/webpack-cli", null],
["webpack", "virtual:395f1354ea29de80eb111225ff7f72912127acf779ae2110ad0ceee26819d65678b5f21be5a4c99566f19c05b63bb8c464db1c3c0ca922c2f45f91ad734637ee#npm:5.37.1"],
["webpack-cli", "virtual:395f1354ea29de80eb111225ff7f72912127acf779ae2110ad0ceee26819d65678b5f21be5a4c99566f19c05b63bb8c464db1c3c0ca922c2f45f91ad734637ee#npm:4.7.0"]
],
"packagePeers": [
"@types/webpack-cli",
"@types/webpack",
"webpack-cli",
"webpack"
],
"linkType": "HARD",
}],
["virtual:87e4e29d0a073486e83efd3fb6ccb7905fedbae979a2f77544c4e7ebf5a6bf9cb2ec8ed5b3be875e151cdf6e30b7c3d3d2c148a069709cbac3edecc2314b098d#npm:1.0.3", {
"packageLocation": "./.yarn/$$virtual/@webpack-cli-configtest-virtual-c83273e6dc/0/cache/@webpack-cli-configtest-npm-1.0.3-b6e357f778-df71875431.zip/node_modules/@webpack-cli/configtest/",
"packageDependencies": [
@ -5737,20 +5626,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
],
"linkType": "HARD",
}],
["virtual:84adca422dcfddfebe74232825b4d9a5ef615fdab14f3f17f1a545c4531bd06dc6868a9c1d1e3abce6a67873f8d3e04c605bfaaf12cc7fa1a0495f9f023c0ec3#npm:1.2.4", {
"packageLocation": "./.yarn/$$virtual/@webpack-cli-info-virtual-b4f729ae1e/0/cache/@webpack-cli-info-npm-1.2.4-e4a2135f37-7a1b167669.zip/node_modules/@webpack-cli/info/",
"packageDependencies": [
["@webpack-cli/info", "virtual:84adca422dcfddfebe74232825b4d9a5ef615fdab14f3f17f1a545c4531bd06dc6868a9c1d1e3abce6a67873f8d3e04c605bfaaf12cc7fa1a0495f9f023c0ec3#npm:1.2.4"],
["@types/webpack-cli", null],
["envinfo", "npm:7.8.1"],
["webpack-cli", "virtual:395f1354ea29de80eb111225ff7f72912127acf779ae2110ad0ceee26819d65678b5f21be5a4c99566f19c05b63bb8c464db1c3c0ca922c2f45f91ad734637ee#npm:4.7.0"]
],
"packagePeers": [
"@types/webpack-cli",
"webpack-cli"
],
"linkType": "HARD",
}],
["virtual:87e4e29d0a073486e83efd3fb6ccb7905fedbae979a2f77544c4e7ebf5a6bf9cb2ec8ed5b3be875e151cdf6e30b7c3d3d2c148a069709cbac3edecc2314b098d#npm:1.2.4", {
"packageLocation": "./.yarn/$$virtual/@webpack-cli-info-virtual-fe46807215/0/cache/@webpack-cli-info-npm-1.2.4-e4a2135f37-7a1b167669.zip/node_modules/@webpack-cli/info/",
"packageDependencies": [
@ -5977,21 +5852,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
],
"linkType": "HARD",
}],
["virtual:84adca422dcfddfebe74232825b4d9a5ef615fdab14f3f17f1a545c4531bd06dc6868a9c1d1e3abce6a67873f8d3e04c605bfaaf12cc7fa1a0495f9f023c0ec3#npm:1.4.0", {
"packageLocation": "./.yarn/$$virtual/@webpack-cli-serve-virtual-de2ba025af/0/cache/@webpack-cli-serve-npm-1.4.0-1f566be693-0a2495e2f1.zip/node_modules/@webpack-cli/serve/",
"packageDependencies": [
["@webpack-cli/serve", "virtual:84adca422dcfddfebe74232825b4d9a5ef615fdab14f3f17f1a545c4531bd06dc6868a9c1d1e3abce6a67873f8d3e04c605bfaaf12cc7fa1a0495f9f023c0ec3#npm:1.4.0"],
["@types/webpack-cli", null],
["webpack-cli", "virtual:395f1354ea29de80eb111225ff7f72912127acf779ae2110ad0ceee26819d65678b5f21be5a4c99566f19c05b63bb8c464db1c3c0ca922c2f45f91ad734637ee#npm:4.7.0"],
["webpack-dev-server", null]
],
"packagePeers": [
"@types/webpack-cli",
"webpack-cli",
"webpack-dev-server"
],
"linkType": "HARD",
}],
["virtual:87e4e29d0a073486e83efd3fb6ccb7905fedbae979a2f77544c4e7ebf5a6bf9cb2ec8ed5b3be875e151cdf6e30b7c3d3d2c148a069709cbac3edecc2314b098d#npm:1.4.0", {
"packageLocation": "./.yarn/$$virtual/@webpack-cli-serve-virtual-960c087e04/0/cache/@webpack-cli-serve-npm-1.4.0-1f566be693-0a2495e2f1.zip/node_modules/@webpack-cli/serve/",
"packageDependencies": [
@ -7116,7 +6976,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"packageDependencies": [
["cosmjs-monorepo-root", "workspace:."],
["@cosmjs/amino", "workspace:packages/amino"],
["@cosmjs/cosmwasm-launchpad", "workspace:packages/cosmwasm-launchpad"],
["@cosmjs/cosmwasm-stargate", "workspace:packages/cosmwasm-stargate"],
["@cosmjs/crypto", "workspace:packages/crypto"],
["@cosmjs/encoding", "workspace:packages/encoding"],
@ -12014,25 +11873,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
],
"linkType": "HARD",
}],
["virtual:139b584ca8199b231f3129ecc7e443fe9bbe8e7998f9ebec0596357d086f652fd437a0a38af20036f53bd7e9193cf4614624133c9c35ef007cf2ce7c818c0ad6#npm:5.1.2", {
"packageLocation": "./.yarn/$$virtual/terser-webpack-plugin-virtual-c7f41a226c/0/cache/terser-webpack-plugin-npm-5.1.2-59f409825a-f65229fc60.zip/node_modules/terser-webpack-plugin/",
"packageDependencies": [
["terser-webpack-plugin", "virtual:139b584ca8199b231f3129ecc7e443fe9bbe8e7998f9ebec0596357d086f652fd437a0a38af20036f53bd7e9193cf4614624133c9c35ef007cf2ce7c818c0ad6#npm:5.1.2"],
["@types/webpack", null],
["jest-worker", "npm:26.6.2"],
["p-limit", "npm:3.1.0"],
["schema-utils", "npm:3.0.0"],
["serialize-javascript", "npm:5.0.1"],
["source-map", "npm:0.6.1"],
["terser", "npm:5.7.0"],
["webpack", "virtual:395f1354ea29de80eb111225ff7f72912127acf779ae2110ad0ceee26819d65678b5f21be5a4c99566f19c05b63bb8c464db1c3c0ca922c2f45f91ad734637ee#npm:5.37.1"]
],
"packagePeers": [
"@types/webpack",
"webpack"
],
"linkType": "HARD",
}],
["virtual:2c148355187bb60dc28d99d6e8c71135442f7f75eee654fdcef714a856c04749d4bcd6c6f9a8235fa3df92a4b10c63458ab01bcf229754141703842a78ec781f#npm:5.1.2", {
"packageLocation": "./.yarn/$$virtual/terser-webpack-plugin-virtual-bcb1a7a129/0/cache/terser-webpack-plugin-npm-5.1.2-59f409825a-f65229fc60.zip/node_modules/terser-webpack-plugin/",
"packageDependencies": [
@ -12834,40 +12674,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
],
"linkType": "HARD",
}],
["virtual:395f1354ea29de80eb111225ff7f72912127acf779ae2110ad0ceee26819d65678b5f21be5a4c99566f19c05b63bb8c464db1c3c0ca922c2f45f91ad734637ee#npm:5.37.1", {
"packageLocation": "./.yarn/$$virtual/webpack-virtual-139b584ca8/0/cache/webpack-npm-5.37.1-1e75a59f6f-5fe030ea3f.zip/node_modules/webpack/",
"packageDependencies": [
["webpack", "virtual:395f1354ea29de80eb111225ff7f72912127acf779ae2110ad0ceee26819d65678b5f21be5a4c99566f19c05b63bb8c464db1c3c0ca922c2f45f91ad734637ee#npm:5.37.1"],
["@types/eslint-scope", "npm:3.7.0"],
["@types/estree", "npm:0.0.47"],
["@webassemblyjs/ast", "npm:1.11.0"],
["@webassemblyjs/wasm-edit", "npm:1.11.0"],
["@webassemblyjs/wasm-parser", "npm:1.11.0"],
["acorn", "npm:8.2.4"],
["browserslist", "npm:4.16.6"],
["chrome-trace-event", "npm:1.0.3"],
["enhanced-resolve", "npm:5.8.2"],
["es-module-lexer", "npm:0.4.1"],
["eslint-scope", "npm:5.1.1"],
["events", "npm:3.3.0"],
["glob-to-regexp", "npm:0.4.1"],
["graceful-fs", "npm:4.2.6"],
["json-parse-better-errors", "npm:1.0.2"],
["loader-runner", "npm:4.2.0"],
["mime-types", "npm:2.1.30"],
["neo-async", "npm:2.6.2"],
["schema-utils", "npm:3.0.0"],
["tapable", "npm:2.2.0"],
["terser-webpack-plugin", "virtual:139b584ca8199b231f3129ecc7e443fe9bbe8e7998f9ebec0596357d086f652fd437a0a38af20036f53bd7e9193cf4614624133c9c35ef007cf2ce7c818c0ad6#npm:5.1.2"],
["watchpack", "npm:2.2.0"],
["webpack-cli", "virtual:395f1354ea29de80eb111225ff7f72912127acf779ae2110ad0ceee26819d65678b5f21be5a4c99566f19c05b63bb8c464db1c3c0ca922c2f45f91ad734637ee#npm:4.7.0"],
["webpack-sources", "npm:2.2.0"]
],
"packagePeers": [
"webpack-cli"
],
"linkType": "HARD",
}],
["virtual:4f1584ad4aba8733a24be7c8aebbffafef25607f2d00f4b314cf96717145c692763628a31c2b85d4686fbb091ff21ebffa3cc337399c042c19a32b9bdb786464#npm:5.37.1", {
"packageLocation": "./.yarn/$$virtual/webpack-virtual-830f2cc1c2/0/cache/webpack-npm-5.37.1-1e75a59f6f-5fe030ea3f.zip/node_modules/webpack/",
"packageDependencies": [
@ -13387,40 +13193,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
],
"linkType": "HARD",
}],
["virtual:395f1354ea29de80eb111225ff7f72912127acf779ae2110ad0ceee26819d65678b5f21be5a4c99566f19c05b63bb8c464db1c3c0ca922c2f45f91ad734637ee#npm:4.7.0", {
"packageLocation": "./.yarn/$$virtual/webpack-cli-virtual-84adca422d/0/cache/webpack-cli-npm-4.7.0-cb3d7c34ff-6b935cda02.zip/node_modules/webpack-cli/",
"packageDependencies": [
["webpack-cli", "virtual:395f1354ea29de80eb111225ff7f72912127acf779ae2110ad0ceee26819d65678b5f21be5a4c99566f19c05b63bb8c464db1c3c0ca922c2f45f91ad734637ee#npm:4.7.0"],
["@discoveryjs/json-ext", "npm:0.5.3"],
["@types/webpack", null],
["@webpack-cli/configtest", "virtual:84adca422dcfddfebe74232825b4d9a5ef615fdab14f3f17f1a545c4531bd06dc6868a9c1d1e3abce6a67873f8d3e04c605bfaaf12cc7fa1a0495f9f023c0ec3#npm:1.0.3"],
["@webpack-cli/generators", null],
["@webpack-cli/info", "virtual:84adca422dcfddfebe74232825b4d9a5ef615fdab14f3f17f1a545c4531bd06dc6868a9c1d1e3abce6a67873f8d3e04c605bfaaf12cc7fa1a0495f9f023c0ec3#npm:1.2.4"],
["@webpack-cli/migrate", null],
["@webpack-cli/serve", "virtual:84adca422dcfddfebe74232825b4d9a5ef615fdab14f3f17f1a545c4531bd06dc6868a9c1d1e3abce6a67873f8d3e04c605bfaaf12cc7fa1a0495f9f023c0ec3#npm:1.4.0"],
["colorette", "npm:1.2.2"],
["commander", "npm:7.2.0"],
["execa", "npm:5.0.0"],
["fastest-levenshtein", "npm:1.0.12"],
["import-local", "npm:3.0.2"],
["interpret", "npm:2.2.0"],
["rechoir", "npm:0.7.0"],
["v8-compile-cache", "npm:2.3.0"],
["webpack", "virtual:395f1354ea29de80eb111225ff7f72912127acf779ae2110ad0ceee26819d65678b5f21be5a4c99566f19c05b63bb8c464db1c3c0ca922c2f45f91ad734637ee#npm:5.37.1"],
["webpack-bundle-analyzer", null],
["webpack-dev-server", null],
["webpack-merge", "npm:5.7.3"]
],
"packagePeers": [
"@types/webpack",
"@webpack-cli/generators",
"@webpack-cli/migrate",
"webpack-bundle-analyzer",
"webpack-dev-server",
"webpack"
],
"linkType": "HARD",
}],
["virtual:4f1584ad4aba8733a24be7c8aebbffafef25607f2d00f4b314cf96717145c692763628a31c2b85d4686fbb091ff21ebffa3cc337399c042c19a32b9bdb786464#npm:4.7.0", {
"packageLocation": "./.yarn/$$virtual/webpack-cli-virtual-0dffb89908/0/cache/webpack-cli-npm-4.7.0-cb3d7c34ff-6b935cda02.zip/node_modules/webpack-cli/",
"packageDependencies": [

View File

@ -51,6 +51,10 @@ and this project adheres to
`defaultGasPrice` and `buildFeeTable`.
- @cosmjs/tendermint-rpc: `Client` has been removed. Please use
`Tendermint33Client` or `Tendermint34Client`, depending on your needs.
- @cosmjs/cosmwasm: Package removed ([#786]).
- @cosmjs/cosmwasm-launchpad: Package removed ([#786]).
[#786]: https://github.com/cosmos/cosmjs/issues/786
### Fixed

View File

@ -91,14 +91,14 @@ In the `scripts/` folder, a bunch of blockchains and other backend systems are
started for testing purposes. Some ports need to be changed from the default in
order to avoid conflicts. Here is an overview of the ports used:
| Port | Application | Usage |
| ----- | --------------------- | ------------------------------------------------------ |
| 1317 | wasmd LCD API | @cosmjs/launchpad and @cosmjs/cosmwasm-launchpad tests |
| 1318 | simapp LCD API | Manual Stargate debugging |
| 1319 | wasmd LCD API | Manual Stargate debugging |
| 4444 | socketserver | @cosmjs/sockets tests |
| 4445 | socketserver slow | @cosmjs/sockets tests |
| 11133 | Tendermint 0.33 RPC | @cosmjs/tendermint-rpc tests |
| 11134 | Tendermint 0.34 RPC | @cosmjs/tendermint-rpc tests |
| 26658 | simapp Tendermint RPC | Stargate client tests |
| 26659 | wasmd Tendermint RPC | @cosmjs/cosmwasm-stargate tests |
| Port | Application | Usage |
| ----- | --------------------- | ------------------------------- |
| 1317 | wasmd LCD API | @cosmjs/launchpad tests |
| 1318 | simapp LCD API | Manual Stargate debugging |
| 1319 | wasmd LCD API | Manual Stargate debugging |
| 4444 | socketserver | @cosmjs/sockets tests |
| 4445 | socketserver slow | @cosmjs/sockets tests |
| 11133 | Tendermint 0.33 RPC | @cosmjs/tendermint-rpc tests |
| 11134 | Tendermint 0.34 RPC | @cosmjs/tendermint-rpc tests |
| 26658 | simapp Tendermint RPC | Stargate client tests |
| 26659 | wasmd Tendermint RPC | @cosmjs/cosmwasm-stargate tests |

View File

@ -44,14 +44,14 @@ CosmJS is a library that consists of many smaller npm packages within the
[@cosmjs namespace](https://www.npmjs.com/org/cosmjs), a so called monorepo.
Here are some of them to get an idea:
| Package | Description | Latest |
| ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| [@cosmjs/launchpad](packages/launchpad) | A client library for the Cosmos SDK 0.37 (cosmoshub-3), 0.38 and 0.39 (Launchpad) | [![npm version](https://img.shields.io/npm/v/@cosmjs/launchpad.svg)](https://www.npmjs.com/package/@cosmjs/launchpad) |
| [@cosmjs/faucet](packages/faucet) | A faucet application for node.js | [![npm version](https://img.shields.io/npm/v/@cosmjs/faucet.svg)](https://www.npmjs.com/package/@cosmjs/faucet) |
| [@cosmjs/cosmwasm-launchpad](packages/cosmwasm) | Client for chains with the CosmWasm module enabled | [![npm version](https://img.shields.io/npm/v/@cosmjs/cosmwasm-launchpad.svg)](https://www.npmjs.com/package/@cosmjs/cosmwasm-launchpad) |
| [@cosmjs/crypto](packages/crypto) | Cryptography for blockchain projects, e.g. hashing (SHA-2, Keccak256, Ripemd160), signing (secp256k1, ed25519), HD key derivation (BIPO39, SLIP-0010), KDFs and symmetric encryption for key storage (PBKDF2, Argon2, XChaCha20Poly1305) | [![npm version](https://img.shields.io/npm/v/@cosmjs/crypto.svg)](https://www.npmjs.com/package/@cosmjs/crypto) |
| [@cosmjs/encoding](packages/encoding) | Encoding helpers for blockchain projects | [![npm version](https://img.shields.io/npm/v/@cosmjs/encoding.svg)](https://www.npmjs.com/package/@cosmjs/encoding) |
| [@cosmjs/math](packages/math) | Safe integers; decimals for handling financial amounts | [![npm version](https://img.shields.io/npm/v/@cosmjs/math.svg)](https://www.npmjs.com/package/@cosmjs/math) |
| Package | Description | Latest |
| ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| [@cosmjs/launchpad](packages/launchpad) | A client library for the Cosmos SDK 0.37 (cosmoshub-3), 0.38 and 0.39 (Launchpad) | [![npm version](https://img.shields.io/npm/v/@cosmjs/launchpad.svg)](https://www.npmjs.com/package/@cosmjs/launchpad) |
| [@cosmjs/faucet](packages/faucet) | A faucet application for node.js | [![npm version](https://img.shields.io/npm/v/@cosmjs/faucet.svg)](https://www.npmjs.com/package/@cosmjs/faucet) |
| [@cosmjs/cosmwasm-stargate](packages/cosmwasm-stargate) | Client for Stargate chains with the CosmWasm module enabled | [![npm version](https://img.shields.io/npm/v/@cosmjs/cosmwasm-stargate.svg)](https://www.npmjs.com/package/@cosmjs/cosmwasm-stargate) |
| [@cosmjs/crypto](packages/crypto) | Cryptography for blockchain projects, e.g. hashing (SHA-2, Keccak256, Ripemd160), signing (secp256k1, ed25519), HD key derivation (BIPO39, SLIP-0010), KDFs and symmetric encryption for key storage (PBKDF2, Argon2, XChaCha20Poly1305) | [![npm version](https://img.shields.io/npm/v/@cosmjs/crypto.svg)](https://www.npmjs.com/package/@cosmjs/crypto) |
| [@cosmjs/encoding](packages/encoding) | Encoding helpers for blockchain projects | [![npm version](https://img.shields.io/npm/v/@cosmjs/encoding.svg)](https://www.npmjs.com/package/@cosmjs/encoding) |
| [@cosmjs/math](packages/math) | Safe integers; decimals for handling financial amounts | [![npm version](https://img.shields.io/npm/v/@cosmjs/math.svg)](https://www.npmjs.com/package/@cosmjs/math) |
### Modularity

View File

@ -38,7 +38,6 @@
},
"devDependencies": {
"@cosmjs/amino": "workspace:packages/amino",
"@cosmjs/cosmwasm-launchpad": "workspace:packages/cosmwasm-launchpad",
"@cosmjs/cosmwasm-stargate": "workspace:packages/cosmwasm-stargate",
"@cosmjs/crypto": "workspace:packages/crypto",
"@cosmjs/encoding": "workspace:packages/encoding",

View File

@ -40,7 +40,6 @@
],
"dependencies": {
"@cosmjs/amino": "workspace:packages/amino",
"@cosmjs/cosmwasm-launchpad": "workspace:packages/cosmwasm-launchpad",
"@cosmjs/cosmwasm-stargate": "workspace:packages/cosmwasm-stargate",
"@cosmjs/crypto": "workspace:packages/crypto",
"@cosmjs/encoding": "workspace:packages/encoding",

View File

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

View File

@ -1,92 +0,0 @@
module.exports = {
env: {
es6: true,
jasmine: true,
node: true,
worker: true,
},
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: 2018,
project: "./tsconfig.eslint.json",
tsconfigRootDir: __dirname,
},
plugins: ["@typescript-eslint", "prettier", "simple-import-sort", "import"],
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"prettier",
"plugin:prettier/recommended",
"plugin:import/typescript",
],
rules: {
curly: ["warn", "multi-line", "consistent"],
"no-bitwise": "warn",
"no-console": ["warn", { allow: ["error", "info", "table", "warn"] }],
"no-param-reassign": "warn",
"no-shadow": "off", // disabled in favour of @typescript-eslint/no-shadow, see https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-shadow.md
"no-unused-vars": "off", // disabled in favour of @typescript-eslint/no-unused-vars, see https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unused-vars.md
"prefer-const": "warn",
radix: ["warn", "always"],
"spaced-comment": ["warn", "always", { line: { markers: ["/ <reference"] } }],
"import/no-cycle": "warn",
"simple-import-sort/imports": "warn",
"@typescript-eslint/array-type": ["warn", { default: "array-simple" }],
"@typescript-eslint/await-thenable": "warn",
"@typescript-eslint/ban-types": "warn",
"@typescript-eslint/explicit-function-return-type": ["warn", { allowExpressions: true }],
"@typescript-eslint/explicit-member-accessibility": "warn",
"@typescript-eslint/naming-convention": [
"warn",
{
selector: "default",
format: ["strictCamelCase"],
},
{
selector: "typeLike",
format: ["StrictPascalCase"],
},
{
selector: "enumMember",
format: ["StrictPascalCase"],
},
{
selector: "variable",
format: ["strictCamelCase"],
leadingUnderscore: "allow",
},
{
selector: "parameter",
format: ["strictCamelCase"],
leadingUnderscore: "allow",
},
],
"@typescript-eslint/no-dynamic-delete": "warn",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-empty-interface": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-floating-promises": "warn",
"@typescript-eslint/no-parameter-properties": "warn",
"@typescript-eslint/no-shadow": "warn",
"@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_", varsIgnorePattern: "^_" }],
"@typescript-eslint/no-unnecessary-type-assertion": "warn",
"@typescript-eslint/no-use-before-define": "warn",
"@typescript-eslint/prefer-readonly": "warn",
},
overrides: [
{
files: "**/*.js",
rules: {
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/explicit-member-accessibility": "off",
},
},
{
files: "**/*.spec.ts",
rules: {
"@typescript-eslint/no-non-null-assertion": "off",
},
},
],
};

View File

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

View File

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

View File

@ -1,30 +0,0 @@
# @cosmjs/cosmwasm-launchpad
[![npm version](https://img.shields.io/npm/v/@cosmjs/cosmwasm-launchpad.svg)](https://www.npmjs.com/package/@cosmjs/cosmwasm-launchpad)
An SDK to build CosmWasm clients.
## Compatibility
| CosmWasm | x/wasm | @cosmjs/cosmwasm-launchpad |
| --------- | --------- | -------------------------- |
| 0.10-0.11 | 0.10-0.11 | `^0.23.0` |
| 0.10 | 0.10 | `^0.22.0` |
| 0.9 | 0.9 | `^0.21.0` |
| 0.8 | 0.8 | `^0.20.1` |
## Development
Updating Hackatom development contract in `src/testdata/contract.json`:
```sh
cd packages/cosmwasm-launchpad
export HACKATOM_URL=https://github.com/CosmWasm/cosmwasm/releases/download/v0.11.0-alpha4/hackatom.wasm
echo "{\"// source\": \"$HACKATOM_URL\", \"data\": \"$(curl -sS --location $HACKATOM_URL | base64 | tr -d '[:space:]')\" }" | jq > src/testdata/contract.json
```
## License
This package is part of the cosmjs repository, licensed under the Apache License
2.0 (see [NOTICE](https://github.com/cosmos/cosmjs/blob/main/NOTICE) and
[LICENSE](https://github.com/cosmos/cosmjs/blob/main/LICENSE)).

View File

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

View File

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

View File

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

View File

@ -1,87 +0,0 @@
{
"name": "@cosmjs/cosmwasm-launchpad",
"version": "0.25.5",
"description": "CosmWasm SDK for Launchpad",
"contributors": [
"Ethan Frey <ethanfrey@users.noreply.github.com>",
"Will Clark <willclarktech@users.noreply.github.com>"
],
"license": "Apache-2.0",
"main": "build/index.js",
"types": "build/index.d.ts",
"files": [
"build/",
"*.md",
"!*.spec.*",
"!**/testdata/"
],
"repository": {
"type": "git",
"url": "https://github.com/cosmos/cosmjs/tree/main/packages/cosmwasm-launchpad"
},
"publishConfig": {
"access": "public"
},
"scripts": {
"docs": "typedoc --options typedoc.js",
"lint": "eslint --max-warnings 0 \"./**/*.ts\" \"./*.js\"",
"lint-fix": "eslint --fix --max-warnings 0 \"./**/*.ts\" \"./*.js\"",
"format": "prettier --write --loglevel warn \"./src/**/*.ts\"",
"format-text": "prettier --write \"./*.md\"",
"build": "rm -rf ./build && tsc",
"build-or-skip": "[ -n \"$SKIP_BUILD\" ] || yarn build",
"test-node": "node --require esm 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",
"coverage": "nyc --reporter=text --reporter=lcov yarn test --quiet",
"pack-web": "yarn build-or-skip && webpack --mode development --config webpack.web.config.js"
},
"dependencies": {
"@cosmjs/crypto": "workspace:packages/crypto",
"@cosmjs/encoding": "workspace:packages/encoding",
"@cosmjs/launchpad": "workspace:packages/launchpad",
"@cosmjs/math": "workspace:packages/math",
"@cosmjs/utils": "workspace:packages/utils",
"pako": "^2.0.2"
},
"devDependencies": {
"@istanbuljs/nyc-config-typescript": "^1.0.1",
"@types/eslint-plugin-prettier": "^3",
"@types/jasmine": "^3.6.10",
"@types/karma-firefox-launcher": "^2",
"@types/karma-jasmine": "^4",
"@types/karma-jasmine-html-reporter": "^1",
"@types/node": "^15.0.1",
"@types/pako": "^1.0.1",
"@typescript-eslint/eslint-plugin": "^4.28",
"@typescript-eslint/parser": "^4.28",
"eslint": "^7.5",
"eslint-config-prettier": "^8.3.0",
"eslint-import-resolver-node": "^0.3.4",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-simple-import-sort": "^7.0.0",
"esm": "^3.2.25",
"glob": "^7.1.6",
"jasmine": "^3.5",
"jasmine-core": "^3.7.1",
"jasmine-spec-reporter": "^6",
"karma": "^6.1.1",
"karma-chrome-launcher": "^3.1.0",
"karma-firefox-launcher": "^2.1.0",
"karma-jasmine": "^4.0.1",
"karma-jasmine-html-reporter": "^1.5.4",
"nyc": "^15.1.0",
"prettier": "^2.3.2",
"readonly-date": "^1.0.0",
"ses": "^0.11.0",
"source-map-support": "^0.5.19",
"stream-browserify": "^3.0.0",
"ts-node": "^8",
"typedoc": "^0.21",
"typescript": "~4.3",
"webpack": "^5.32.0",
"webpack-cli": "^4.6.0"
}
}

View File

@ -1,63 +0,0 @@
import { isValidBuilder } from "./builder";
describe("builder", () => {
describe("isValidBuilder", () => {
// Valid cases
it("returns true for simple examples", () => {
expect(isValidBuilder("myorg/super-optimizer:0.1.2")).toEqual(true);
expect(isValidBuilder("myorg/super-optimizer:42")).toEqual(true);
});
it("supports images with multi level names", () => {
expect(isValidBuilder("myorg/department-x/office-y/technology-z/super-optimizer:0.1.2")).toEqual(true);
});
it("returns true for tags with lower and upper chars", () => {
expect(isValidBuilder("myorg/super-optimizer:0.1.2-alpha")).toEqual(true);
expect(isValidBuilder("myorg/super-optimizer:0.1.2-Alpha")).toEqual(true);
});
// Invalid cases
it("returns false for missing or empty tag", () => {
expect(isValidBuilder("myorg/super-optimizer")).toEqual(false);
expect(isValidBuilder("myorg/super-optimizer:")).toEqual(false);
});
it("returns false for name components starting or ending with a separator", () => {
expect(isValidBuilder(".myorg/super-optimizer:42")).toEqual(false);
expect(isValidBuilder("-myorg/super-optimizer:42")).toEqual(false);
expect(isValidBuilder("_myorg/super-optimizer:42")).toEqual(false);
expect(isValidBuilder("myorg./super-optimizer:42")).toEqual(false);
expect(isValidBuilder("myorg-/super-optimizer:42")).toEqual(false);
expect(isValidBuilder("myorg_/super-optimizer:42")).toEqual(false);
expect(isValidBuilder("myorg/.super-optimizer:42")).toEqual(false);
expect(isValidBuilder("myorg/-super-optimizer:42")).toEqual(false);
expect(isValidBuilder("myorg/_super-optimizer:42")).toEqual(false);
expect(isValidBuilder("myorg/super-optimizer.:42")).toEqual(false);
expect(isValidBuilder("myorg/super-optimizer-:42")).toEqual(false);
expect(isValidBuilder("myorg/super-optimizer_:42")).toEqual(false);
});
it("returns false for upper case character in name component", () => {
expect(isValidBuilder("mYorg/super-optimizer:42")).toEqual(false);
expect(isValidBuilder("myorg/super-Optimizer:42")).toEqual(false);
});
it("returns false for long images", () => {
expect(
isValidBuilder(
"myorgisnicenicenicenicenicenicenicenicenicenicenicenicenicenicenicenicenicenicenicenicenicenicenicenicenicenice/super-optimizer:42",
),
).toEqual(false);
});
it("returns false for images with no organization", () => {
// Those are valid dockerhub images from https://hub.docker.com/_/ubuntu and https://hub.docker.com/_/rust
// but not valid in the context of CosmWasm Verify
expect(isValidBuilder("ubuntu:xenial-20200212")).toEqual(false);
expect(isValidBuilder("rust:1.40.0")).toEqual(false);
});
});
});

View File

@ -1,20 +0,0 @@
// A docker image regexp. We remove support for non-standard registries for simplicity.
// https://docs.docker.com/engine/reference/commandline/tag/#extended-description
//
// An image name is made up of slash-separated name components (optionally prefixed by a registry hostname).
// Name components may contain lowercase characters, digits and separators.
// A separator is defined as a period, one or two underscores, or one or more dashes. A name component may not start or end with a separator.
//
// A tag name must be valid ASCII and may contain lowercase and uppercase letters, digits, underscores, periods and dashes.
// A tag name may not start with a period or a dash and may contain a maximum of 128 characters.
const dockerImagePattern = new RegExp(
"^[a-z0-9][a-z0-9._-]*[a-z0-9](/[a-z0-9][a-z0-9._-]*[a-z0-9])+:[a-zA-Z0-9_][a-zA-Z0-9_.-]{0,127}$",
);
/** Max length in bytes/characters (regexp enforces all ASCII, even if that is not required by the standard) */
const builderMaxLength = 128;
export function isValidBuilder(builder: string): boolean {
if (builder.length > builderMaxLength) return false;
return !!builder.match(dockerImagePattern);
}

View File

@ -1,77 +0,0 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { Coin } from "@cosmjs/launchpad";
interface BankSendMsg {
readonly send: {
readonly from_address: string;
readonly to_address: string;
readonly amount: readonly Coin[];
};
}
export interface BankMsg {
readonly bank: BankSendMsg;
}
export interface CustomMsg {
readonly custom: Record<string, unknown>;
}
interface StakingDelegateMsg {
readonly delegate: {
readonly validator: string;
readonly amount: Coin;
};
}
interface StakingRedelegateMsg {
readonly redelgate: {
readonly src_validator: string;
readonly dst_validator: string;
readonly amount: Coin;
};
}
interface StakingUndelegateMsg {
readonly undelegate: {
readonly validator: string;
readonly amount: Coin;
};
}
interface StakingWithdrawMsg {
readonly withdraw: {
readonly validator: string;
readonly recipient?: string;
};
}
export interface StakingMsg {
readonly staking: StakingDelegateMsg | StakingRedelegateMsg | StakingUndelegateMsg | StakingWithdrawMsg;
}
interface WasmExecuteMsg {
readonly execute: {
readonly contract_address: string;
readonly msg: any;
readonly send: readonly Coin[];
};
}
interface WasmInstantiateMsg {
readonly instantiate: {
readonly code_id: string;
readonly msg: any;
readonly send: readonly Coin[];
readonly label?: string;
};
}
export interface WasmMsg {
readonly wasm: WasmExecuteMsg | WasmInstantiateMsg;
}
/** These definitions are derived from CosmWasm:
* https://github.com/CosmWasm/cosmwasm/blob/v0.12.0/packages/std/src/results/cosmos_msg.rs#L10-L23
*/
export type CosmosMsg = BankMsg | CustomMsg | StakingMsg | WasmMsg;

View File

@ -1,453 +0,0 @@
/* eslint-disable @typescript-eslint/naming-convention */
import {
coins,
isBroadcastTxFailure,
isMsgSend,
LcdClient,
makeSignDoc,
makeStdTx,
MsgSend,
Secp256k1HdWallet,
WrappedStdTx,
} from "@cosmjs/launchpad";
import { assert, sleep } from "@cosmjs/utils";
import { CosmWasmClient } from "./cosmwasmclient";
import { isMsgExecuteContract, isMsgInstantiateContract } from "./msgs";
import { SigningCosmWasmClient } from "./signingcosmwasmclient";
import {
alice,
deployedErc20,
erc20Enabled,
fromOneElementArray,
launchpad,
launchpadEnabled,
makeRandomAddress,
pendingWithoutErc20,
pendingWithoutLaunchpad,
} from "./testutils.spec";
interface TestTxSend {
readonly sender: string;
readonly recipient: string;
readonly hash: string;
readonly height: number;
readonly tx: WrappedStdTx;
}
interface TestTxExecute {
readonly sender: string;
readonly contract: string;
readonly hash: string;
readonly height: number;
readonly tx: WrappedStdTx;
}
describe("CosmWasmClient.getTx and .searchTx", () => {
let sendSuccessful: TestTxSend | undefined;
let sendSelfSuccessful: TestTxSend | undefined;
let sendUnsuccessful: TestTxSend | undefined;
let execute: TestTxExecute | undefined;
beforeAll(async () => {
if (launchpadEnabled() && erc20Enabled()) {
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new SigningCosmWasmClient(launchpad.endpoint, alice.address0, wallet);
{
const recipient = makeRandomAddress();
const amount = coins(1234567, "ucosm");
const result = await client.sendTokens(recipient, amount);
await sleep(75); // wait until tx is indexed
const txDetails = await new LcdClient(launchpad.endpoint).txById(result.transactionHash);
sendSuccessful = {
sender: alice.address0,
recipient: recipient,
hash: result.transactionHash,
height: Number.parseInt(txDetails.height, 10),
tx: txDetails.tx,
};
}
{
const recipient = alice.address0;
const amount = coins(2345678, "ucosm");
const result = await client.sendTokens(recipient, amount);
await sleep(75); // wait until tx is indexed
const txDetails = await new LcdClient(launchpad.endpoint).txById(result.transactionHash);
sendSelfSuccessful = {
sender: alice.address0,
recipient: recipient,
hash: result.transactionHash,
height: Number.parseInt(txDetails.height, 10),
tx: txDetails.tx,
};
}
{
const memo = "Sending more than I can afford";
const recipient = makeRandomAddress();
const amount = coins(123456700000000, "ucosm");
const sendMsg: MsgSend = {
type: "cosmos-sdk/MsgSend",
value: {
from_address: alice.address0,
to_address: recipient,
amount: amount,
},
};
const fee = {
amount: coins(2000, "ucosm"),
gas: "80000", // 80k
};
const { accountNumber, sequence } = await client.getSequence();
const chainId = await client.getChainId();
const signDoc = makeSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence);
const { signed, signature } = await wallet.signAmino(alice.address0, signDoc);
const tx: WrappedStdTx = {
type: "cosmos-sdk/StdTx",
value: makeStdTx(signed, signature),
};
const transactionId = await client.getIdentifier(tx);
const result = await client.broadcastTx(tx.value);
if (isBroadcastTxFailure(result)) {
sendUnsuccessful = {
sender: alice.address0,
recipient: recipient,
hash: transactionId,
height: result.height,
tx: tx,
};
}
}
{
const hashInstance = deployedErc20.instances[0];
const msg = {
approve: {
spender: makeRandomAddress(),
amount: "12",
},
};
const result = await client.execute(hashInstance, msg);
await sleep(75); // wait until tx is indexed
const txDetails = await new LcdClient(launchpad.endpoint).txById(result.transactionHash);
execute = {
sender: alice.address0,
contract: hashInstance,
hash: result.transactionHash,
height: Number.parseInt(txDetails.height, 10),
tx: txDetails.tx,
};
}
}
});
describe("getTx", () => {
it("can get successful tx by ID", async () => {
pendingWithoutLaunchpad();
pendingWithoutErc20();
assert(sendSuccessful, "value must be set in beforeAll()");
const client = new CosmWasmClient(launchpad.endpoint);
const result = await client.getTx(sendSuccessful.hash);
expect(result).toEqual(
jasmine.objectContaining({
height: sendSuccessful.height,
hash: sendSuccessful.hash,
code: 0,
tx: sendSuccessful.tx,
}),
);
});
it("can get unsuccessful tx by ID", async () => {
pendingWithoutLaunchpad();
pendingWithoutErc20();
assert(sendUnsuccessful, "value must be set in beforeAll()");
const client = new CosmWasmClient(launchpad.endpoint);
const result = await client.getTx(sendUnsuccessful.hash);
expect(result).toEqual(
jasmine.objectContaining({
height: sendUnsuccessful.height,
hash: sendUnsuccessful.hash,
code: 5,
tx: sendUnsuccessful.tx,
}),
);
});
it("can get by ID (non existent)", async () => {
pendingWithoutLaunchpad();
pendingWithoutErc20();
const client = new CosmWasmClient(launchpad.endpoint);
const nonExistentId = "0000000000000000000000000000000000000000000000000000000000000000";
const result = await client.getTx(nonExistentId);
expect(result).toBeNull();
});
});
describe("with SearchByHeightQuery", () => {
it("can search successful tx by height", async () => {
pendingWithoutLaunchpad();
pendingWithoutErc20();
assert(sendSuccessful, "value must be set in beforeAll()");
const client = new CosmWasmClient(launchpad.endpoint);
const result = await client.searchTx({ height: sendSuccessful.height });
expect(result.length).toBeGreaterThanOrEqual(1);
expect(result).toContain(
jasmine.objectContaining({
height: sendSuccessful.height,
hash: sendSuccessful.hash,
code: 0,
tx: sendSuccessful.tx,
}),
);
});
it("can search unsuccessful tx by height", async () => {
pendingWithoutLaunchpad();
pendingWithoutErc20();
assert(sendUnsuccessful, "value must be set in beforeAll()");
const client = new CosmWasmClient(launchpad.endpoint);
const result = await client.searchTx({ height: sendUnsuccessful.height });
expect(result.length).toBeGreaterThanOrEqual(1);
expect(result).toContain(
jasmine.objectContaining({
height: sendUnsuccessful.height,
hash: sendUnsuccessful.hash,
code: 5,
tx: sendUnsuccessful.tx,
}),
);
});
});
describe("with SearchBySentFromOrToQuery", () => {
it("can search by sender", async () => {
pendingWithoutLaunchpad();
pendingWithoutErc20();
assert(sendSuccessful, "value must be set in beforeAll()");
const client = new CosmWasmClient(launchpad.endpoint);
const results = await client.searchTx({ sentFromOrTo: sendSuccessful.sender });
expect(results.length).toBeGreaterThanOrEqual(1);
// Check basic structure of all results
for (const result of results) {
const containsMsgWithSender = !!result.tx.value.msg.find(
(msg) => isMsgSend(msg) && msg.value.from_address == sendSuccessful!.sender,
);
const containsMsgWithRecipient = !!result.tx.value.msg.find(
(msg) => isMsgSend(msg) && msg.value.to_address === sendSuccessful!.sender,
);
expect(containsMsgWithSender || containsMsgWithRecipient).toEqual(true);
}
// Check details of most recent result (not sent to self)
expect(results[results.length - 2]).toEqual(
jasmine.objectContaining({
height: sendSuccessful.height,
hash: sendSuccessful.hash,
tx: sendSuccessful.tx,
}),
);
});
it("can search by recipient", async () => {
pendingWithoutLaunchpad();
pendingWithoutErc20();
assert(sendSuccessful, "value must be set in beforeAll()");
const client = new CosmWasmClient(launchpad.endpoint);
const results = await client.searchTx({ sentFromOrTo: sendSuccessful.recipient });
expect(results.length).toBeGreaterThanOrEqual(1);
// Check basic structure of all results
for (const result of results) {
const msg = fromOneElementArray(result.tx.value.msg);
assert(isMsgSend(msg), `${result.hash} (height ${result.height}) is not a bank send transaction`);
expect(
msg.value.to_address === sendSuccessful.recipient ||
msg.value.from_address == sendSuccessful.recipient,
).toEqual(true);
}
// Check details of most recent result
expect(results[results.length - 1]).toEqual(
jasmine.objectContaining({
height: sendSuccessful.height,
hash: sendSuccessful.hash,
tx: sendSuccessful.tx,
}),
);
});
it("can search by sender or recipient (sorted and deduplicated)", async () => {
pendingWithoutLaunchpad();
pendingWithoutErc20();
assert(sendSelfSuccessful, "value must be set in beforeAll()");
const txhash = sendSelfSuccessful.hash;
const client = new CosmWasmClient(launchpad.endpoint);
const results = await client.searchTx({ sentFromOrTo: sendSelfSuccessful.recipient });
expect(Array.from(results).sort((tx1, tx2) => tx1.height - tx2.height)).toEqual(results);
expect(results.filter((result) => result.hash === txhash).length).toEqual(1);
});
it("can search by recipient and filter by minHeight", async () => {
pendingWithoutLaunchpad();
pendingWithoutErc20();
assert(sendSuccessful);
const client = new CosmWasmClient(launchpad.endpoint);
const query = { sentFromOrTo: sendSuccessful.recipient };
{
const result = await client.searchTx(query, { minHeight: 0 });
expect(result.length).toEqual(1);
}
{
const result = await client.searchTx(query, { minHeight: sendSuccessful.height - 1 });
expect(result.length).toEqual(1);
}
{
const result = await client.searchTx(query, { minHeight: sendSuccessful.height });
expect(result.length).toEqual(1);
}
{
const result = await client.searchTx(query, { minHeight: sendSuccessful.height + 1 });
expect(result.length).toEqual(0);
}
});
it("can search by recipient and filter by maxHeight", async () => {
pendingWithoutLaunchpad();
pendingWithoutErc20();
assert(sendSuccessful);
const client = new CosmWasmClient(launchpad.endpoint);
const query = { sentFromOrTo: sendSuccessful.recipient };
{
const result = await client.searchTx(query, { maxHeight: 9999999999999 });
expect(result.length).toEqual(1);
}
{
const result = await client.searchTx(query, { maxHeight: sendSuccessful.height + 1 });
expect(result.length).toEqual(1);
}
{
const result = await client.searchTx(query, { maxHeight: sendSuccessful.height });
expect(result.length).toEqual(1);
}
{
const result = await client.searchTx(query, { maxHeight: sendSuccessful.height - 1 });
expect(result.length).toEqual(0);
}
});
});
describe("with SearchByTagsQuery", () => {
it("can search by transfer.recipient", async () => {
pendingWithoutLaunchpad();
pendingWithoutErc20();
assert(sendSuccessful, "value must be set in beforeAll()");
const client = new CosmWasmClient(launchpad.endpoint);
const results = await client.searchTx({
tags: [{ key: "transfer.recipient", value: sendSuccessful.recipient }],
});
expect(results.length).toBeGreaterThanOrEqual(1);
// Check basic structure of all results
for (const result of results) {
const msg = fromOneElementArray(result.tx.value.msg);
assert(isMsgSend(msg), `${result.hash} (height ${result.height}) is not a bank send transaction`);
expect(msg.value.to_address).toEqual(sendSuccessful.recipient);
}
// Check details of most recent result
expect(results[results.length - 1]).toEqual(
jasmine.objectContaining({
height: sendSuccessful.height,
hash: sendSuccessful.hash,
tx: sendSuccessful.tx,
}),
);
});
it("can search by message.contract_address", async () => {
pendingWithoutLaunchpad();
pendingWithoutErc20();
assert(execute, "value must be set in beforeAll()");
const client = new CosmWasmClient(launchpad.endpoint);
const results = await client.searchTx({
tags: [{ key: "message.contract_address", value: execute.contract }],
});
expect(results.length).toBeGreaterThanOrEqual(1);
// Check basic structure of all results
for (const result of results) {
const msg = fromOneElementArray(result.tx.value.msg);
assert(
isMsgExecuteContract(msg) || isMsgInstantiateContract(msg),
`${result.hash} (at ${result.height}) not an execute or instantiate msg`,
);
}
// Check that the first result is the instantiation
const first = fromOneElementArray(results[0].tx.value.msg);
assert(isMsgInstantiateContract(first), "First contract search result must be an instantiation");
expect(first).toEqual({
type: "wasm/MsgInstantiateContract",
value: {
sender: alice.address0,
code_id: deployedErc20.codeId.toString(),
label: "HASH",
init_msg: jasmine.objectContaining({ symbol: "HASH" }),
init_funds: [],
},
});
// Check details of most recent result
expect(results[results.length - 1]).toEqual(
jasmine.objectContaining({
height: execute.height,
hash: execute.hash,
tx: execute.tx,
}),
);
});
it("can search by message.contract_address + message.action", async () => {
pendingWithoutLaunchpad();
pendingWithoutErc20();
assert(execute, "value must be set in beforeAll()");
const client = new CosmWasmClient(launchpad.endpoint);
const results = await client.searchTx({
tags: [
{ key: "message.contract_address", value: execute.contract },
{ key: "message.action", value: "execute" },
],
});
expect(results.length).toBeGreaterThanOrEqual(1);
// Check basic structure of all results
for (const result of results) {
const msg = fromOneElementArray(result.tx.value.msg);
assert(isMsgExecuteContract(msg), `${result.hash} (at ${result.height}) not an execute msg`);
expect(msg.value.contract).toEqual(execute.contract);
}
// Check details of most recent result
expect(results[results.length - 1]).toEqual(
jasmine.objectContaining({
height: execute.height,
hash: execute.hash,
tx: execute.tx,
}),
);
});
});
});

View File

@ -1,467 +0,0 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { sha256 } from "@cosmjs/crypto";
import { Bech32, fromHex, fromUtf8, toAscii, toBase64 } from "@cosmjs/encoding";
import {
assertIsBroadcastTxSuccess,
isWrappedStdTx,
logs,
makeSignDoc,
makeStdTx,
MsgSend,
Secp256k1HdWallet,
StdFee,
} from "@cosmjs/launchpad";
import { assert, sleep } from "@cosmjs/utils";
import { ReadonlyDate } from "readonly-date";
import { Code, CosmWasmClient, PrivateCosmWasmClient } from "./cosmwasmclient";
import { SigningCosmWasmClient } from "./signingcosmwasmclient";
import cosmoshub from "./testdata/cosmoshub.json";
import {
alice,
deployedHackatom,
getHackatom,
launchpad,
launchpadEnabled,
makeRandomAddress,
pendingWithoutLaunchpad,
tendermintIdMatcher,
unused,
} from "./testutils.spec";
const blockTime = 1_000; // ms
interface HackatomInstance {
readonly initMsg: {
readonly verifier: string;
readonly beneficiary: string;
};
readonly address: string;
}
describe("CosmWasmClient", () => {
describe("makeReadOnly", () => {
it("can be constructed", () => {
const client = new CosmWasmClient(launchpad.endpoint);
expect(client).toBeTruthy();
});
});
describe("getChainId", () => {
it("works", async () => {
pendingWithoutLaunchpad();
const client = new CosmWasmClient(launchpad.endpoint);
expect(await client.getChainId()).toEqual(launchpad.chainId);
});
it("caches chain ID", async () => {
pendingWithoutLaunchpad();
const client = new CosmWasmClient(launchpad.endpoint);
const openedClient = client as unknown as PrivateCosmWasmClient;
const getCodeSpy = spyOn(openedClient.lcdClient, "nodeInfo").and.callThrough();
expect(await client.getChainId()).toEqual(launchpad.chainId); // from network
expect(await client.getChainId()).toEqual(launchpad.chainId); // from cache
expect(getCodeSpy).toHaveBeenCalledTimes(1);
});
});
describe("getHeight", () => {
it("gets height via last block", async () => {
pendingWithoutLaunchpad();
const client = new CosmWasmClient(launchpad.endpoint);
const openedClient = client as unknown as PrivateCosmWasmClient;
const blockLatestSpy = spyOn(openedClient.lcdClient, "blocksLatest").and.callThrough();
const height1 = await client.getHeight();
expect(height1).toBeGreaterThan(0);
await sleep(blockTime * 1.4); // tolerate chain being 40% slower than expected
const height2 = await client.getHeight();
expect(height2).toBeGreaterThanOrEqual(height1 + 1);
expect(height2).toBeLessThanOrEqual(height1 + 2);
expect(blockLatestSpy).toHaveBeenCalledTimes(2);
});
it("gets height via authAccount once an address is known", async () => {
pendingWithoutLaunchpad();
const client = new CosmWasmClient(launchpad.endpoint);
const openedClient = client as unknown as PrivateCosmWasmClient;
const blockLatestSpy = spyOn(openedClient.lcdClient, "blocksLatest").and.callThrough();
const authAccountsSpy = spyOn(openedClient.lcdClient.auth, "account").and.callThrough();
const height1 = await client.getHeight();
expect(height1).toBeGreaterThan(0);
await client.getCodes(); // warm up the client
const height2 = await client.getHeight();
expect(height2).toBeGreaterThan(0);
await sleep(blockTime * 1.3); // tolerate chain being 30% slower than expected
const height3 = await client.getHeight();
expect(height3).toBeGreaterThanOrEqual(height2 + 1);
expect(height3).toBeLessThanOrEqual(height2 + 2);
expect(blockLatestSpy).toHaveBeenCalledTimes(1);
expect(authAccountsSpy).toHaveBeenCalledTimes(2);
});
});
describe("getSequence", () => {
it("works", async () => {
pendingWithoutLaunchpad();
const client = new CosmWasmClient(launchpad.endpoint);
expect(await client.getSequence(unused.address)).toEqual({
accountNumber: unused.accountNumber,
sequence: unused.sequence,
});
});
it("throws for missing accounts", async () => {
pendingWithoutLaunchpad();
const client = new CosmWasmClient(launchpad.endpoint);
const missing = makeRandomAddress();
await client.getSequence(missing).then(
() => fail("this must not succeed"),
(error) => expect(error).toMatch(/account does not exist on chain/i),
);
});
});
describe("getAccount", () => {
it("works", async () => {
pendingWithoutLaunchpad();
const client = new CosmWasmClient(launchpad.endpoint);
expect(await client.getAccount(unused.address)).toEqual({
address: unused.address,
accountNumber: unused.accountNumber,
sequence: unused.sequence,
pubkey: undefined,
balance: [
{ denom: "ucosm", amount: "1000000000" },
{ denom: "ustake", amount: "1000000000" },
],
});
});
it("returns undefined for missing accounts", async () => {
pendingWithoutLaunchpad();
const client = new CosmWasmClient(launchpad.endpoint);
const missing = makeRandomAddress();
expect(await client.getAccount(missing)).toBeUndefined();
});
});
describe("getBlock", () => {
it("works for latest block", async () => {
pendingWithoutLaunchpad();
const client = new CosmWasmClient(launchpad.endpoint);
const response = await client.getBlock();
// id
expect(response.id).toMatch(tendermintIdMatcher);
// header
expect(response.header.height).toBeGreaterThanOrEqual(1);
expect(response.header.chainId).toEqual(await client.getChainId());
expect(new ReadonlyDate(response.header.time).getTime()).toBeLessThan(ReadonlyDate.now());
expect(new ReadonlyDate(response.header.time).getTime()).toBeGreaterThanOrEqual(
ReadonlyDate.now() - 5_000,
);
// txs
expect(Array.isArray(response.txs)).toEqual(true);
});
it("works for block by height", async () => {
pendingWithoutLaunchpad();
const client = new CosmWasmClient(launchpad.endpoint);
const height = (await client.getBlock()).header.height;
const response = await client.getBlock(height - 1);
// id
expect(response.id).toMatch(tendermintIdMatcher);
// header
expect(response.header.height).toEqual(height - 1);
expect(response.header.chainId).toEqual(await client.getChainId());
expect(new ReadonlyDate(response.header.time).getTime()).toBeLessThan(ReadonlyDate.now());
expect(new ReadonlyDate(response.header.time).getTime()).toBeGreaterThanOrEqual(
ReadonlyDate.now() - 5_000,
);
// txs
expect(Array.isArray(response.txs)).toEqual(true);
});
});
describe("getIdentifier", () => {
it("works", async () => {
pendingWithoutLaunchpad();
const client = new CosmWasmClient(launchpad.endpoint);
assert(isWrappedStdTx(cosmoshub.tx));
expect(await client.getIdentifier(cosmoshub.tx)).toEqual(cosmoshub.id);
});
});
describe("broadcastTx", () => {
it("works", async () => {
pendingWithoutLaunchpad();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new CosmWasmClient(launchpad.endpoint);
const memo = "My first contract on chain";
const sendMsg: MsgSend = {
type: "cosmos-sdk/MsgSend",
value: {
from_address: alice.address0,
to_address: makeRandomAddress(),
amount: [
{
denom: "ucosm",
amount: "1234567",
},
],
},
};
const fee: StdFee = {
amount: [
{
amount: "5000",
denom: "ucosm",
},
],
gas: "890000",
};
const chainId = await client.getChainId();
const { accountNumber, sequence } = await client.getSequence(alice.address0);
const signDoc = makeSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence);
const { signed, signature } = await wallet.signAmino(alice.address0, signDoc);
const signedTx = makeStdTx(signed, signature);
const result = await client.broadcastTx(signedTx);
assertIsBroadcastTxSuccess(result);
const amountAttr = logs.findAttribute(result.logs, "transfer", "amount");
expect(amountAttr.value).toEqual("1234567ucosm");
expect(result.transactionHash).toMatch(/^[0-9A-F]{64}$/);
});
});
describe("getCodes", () => {
it("works", async () => {
pendingWithoutLaunchpad();
const client = new CosmWasmClient(launchpad.endpoint);
const result = await client.getCodes();
expect(result.length).toBeGreaterThanOrEqual(1);
const [first] = result;
expect(first).toEqual({
id: deployedHackatom.codeId,
source: deployedHackatom.source,
builder: deployedHackatom.builder,
checksum: deployedHackatom.checksum,
creator: alice.address0,
});
});
});
describe("getCodeDetails", () => {
it("works", async () => {
pendingWithoutLaunchpad();
const client = new CosmWasmClient(launchpad.endpoint);
const result = await client.getCodeDetails(1);
const expectedInfo: Code = {
id: deployedHackatom.codeId,
source: deployedHackatom.source,
builder: deployedHackatom.builder,
checksum: deployedHackatom.checksum,
creator: alice.address0,
};
// check info
expect(result).toEqual(jasmine.objectContaining(expectedInfo));
// check data
expect(sha256(result.data)).toEqual(fromHex(expectedInfo.checksum));
});
it("caches downloads", async () => {
pendingWithoutLaunchpad();
const client = new CosmWasmClient(launchpad.endpoint);
const openedClient = client as unknown as PrivateCosmWasmClient;
const getCodeSpy = spyOn(openedClient.lcdClient.wasm, "getCode").and.callThrough();
const result1 = await client.getCodeDetails(deployedHackatom.codeId); // from network
const result2 = await client.getCodeDetails(deployedHackatom.codeId); // from cache
expect(result2).toEqual(result1);
expect(getCodeSpy).toHaveBeenCalledTimes(1);
});
});
describe("getContracts", () => {
it("works", async () => {
pendingWithoutLaunchpad();
const client = new CosmWasmClient(launchpad.endpoint);
const result = await client.getContracts(1);
expect(result.length).toBeGreaterThanOrEqual(3);
const [zero, one, two] = result;
expect(zero).toEqual({
address: deployedHackatom.instances[0].address,
codeId: deployedHackatom.codeId,
creator: alice.address0,
admin: undefined,
label: deployedHackatom.instances[0].label,
});
expect(one).toEqual({
address: deployedHackatom.instances[1].address,
codeId: deployedHackatom.codeId,
creator: alice.address0,
admin: undefined,
label: deployedHackatom.instances[1].label,
});
expect(two).toEqual({
address: deployedHackatom.instances[2].address,
codeId: deployedHackatom.codeId,
creator: alice.address0,
admin: alice.address1,
label: deployedHackatom.instances[2].label,
});
});
});
describe("getContract", () => {
it("works for instance without admin", async () => {
pendingWithoutLaunchpad();
const client = new CosmWasmClient(launchpad.endpoint);
const zero = await client.getContract(deployedHackatom.instances[0].address);
expect(zero).toEqual({
address: deployedHackatom.instances[0].address,
codeId: deployedHackatom.codeId,
creator: alice.address0,
label: deployedHackatom.instances[0].label,
admin: undefined,
});
});
it("works for instance with admin", async () => {
pendingWithoutLaunchpad();
const client = new CosmWasmClient(launchpad.endpoint);
const two = await client.getContract(deployedHackatom.instances[2].address);
expect(two).toEqual(
jasmine.objectContaining({
address: deployedHackatom.instances[2].address,
codeId: deployedHackatom.codeId,
creator: alice.address0,
label: deployedHackatom.instances[2].label,
admin: alice.address1,
}),
);
});
});
describe("queryContractRaw", () => {
const configKey = toAscii("config");
const otherKey = toAscii("this_does_not_exist");
let contract: HackatomInstance | undefined;
beforeAll(async () => {
if (launchpadEnabled()) {
pendingWithoutLaunchpad();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new SigningCosmWasmClient(launchpad.endpoint, alice.address0, wallet);
const { codeId } = await client.upload(getHackatom().data);
const initMsg = { verifier: makeRandomAddress(), beneficiary: makeRandomAddress() };
const { contractAddress } = await client.instantiate(codeId, initMsg, "random hackatom");
contract = { initMsg: initMsg, address: contractAddress };
}
});
it("can query existing key", async () => {
pendingWithoutLaunchpad();
assert(contract);
const client = new CosmWasmClient(launchpad.endpoint);
const raw = await client.queryContractRaw(contract.address, configKey);
assert(raw, "must get result");
expect(JSON.parse(fromUtf8(raw))).toEqual({
verifier: toBase64(Bech32.decode(contract.initMsg.verifier).data),
beneficiary: toBase64(Bech32.decode(contract.initMsg.beneficiary).data),
funder: toBase64(Bech32.decode(alice.address0).data),
});
});
it("can query non-existent key", async () => {
pendingWithoutLaunchpad();
assert(contract);
const client = new CosmWasmClient(launchpad.endpoint);
const raw = await client.queryContractRaw(contract.address, otherKey);
expect(raw).toBeNull();
});
it("errors for non-existent contract", async () => {
pendingWithoutLaunchpad();
assert(contract);
const nonExistentAddress = makeRandomAddress();
const client = new CosmWasmClient(launchpad.endpoint);
await client.queryContractRaw(nonExistentAddress, configKey).then(
() => fail("must not succeed"),
(error) => expect(error).toMatch(`No contract found at address "${nonExistentAddress}"`),
);
});
});
describe("queryContractSmart", () => {
let contract: HackatomInstance | undefined;
beforeAll(async () => {
if (launchpadEnabled()) {
pendingWithoutLaunchpad();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new SigningCosmWasmClient(launchpad.endpoint, alice.address0, wallet);
const { codeId } = await client.upload(getHackatom().data);
const initMsg = { verifier: makeRandomAddress(), beneficiary: makeRandomAddress() };
const { contractAddress } = await client.instantiate(codeId, initMsg, "a different hackatom");
contract = { initMsg: initMsg, address: contractAddress };
}
});
it("works", async () => {
pendingWithoutLaunchpad();
assert(contract);
const client = new CosmWasmClient(launchpad.endpoint);
const resultDocument = await client.queryContractSmart(contract.address, { verifier: {} });
expect(resultDocument).toEqual({ verifier: contract.initMsg.verifier });
});
it("errors for malformed query message", async () => {
pendingWithoutLaunchpad();
assert(contract);
const client = new CosmWasmClient(launchpad.endpoint);
await client.queryContractSmart(contract.address, { broken: {} }).then(
() => fail("must not succeed"),
(error) =>
expect(error).toMatch(
/query wasm contract failed: Error parsing into type hackatom::contract::QueryMsg: unknown variant/i,
),
);
});
it("errors for non-existent contract", async () => {
pendingWithoutLaunchpad();
const nonExistentAddress = makeRandomAddress();
const client = new CosmWasmClient(launchpad.endpoint);
await client.queryContractSmart(nonExistentAddress, { verifier: {} }).then(
() => fail("must not succeed"),
(error) => expect(error).toMatch(`No contract found at address "${nonExistentAddress}"`),
);
});
});
});

View File

@ -1,472 +0,0 @@
import { sha256 } from "@cosmjs/crypto";
import { fromBase64, fromHex, toHex } from "@cosmjs/encoding";
import {
AuthExtension,
BroadcastMode,
BroadcastTxResult,
Coin,
IndexedTx,
LcdClient,
logs,
normalizePubkey,
PubKey,
setupAuthExtension,
StdTx,
uint64ToNumber,
WrappedStdTx,
} from "@cosmjs/launchpad";
import { Uint53 } from "@cosmjs/math";
import { setupWasmExtension, WasmExtension } from "./lcdapi/wasm";
import { JsonObject } from "./types";
export interface GetSequenceResult {
readonly accountNumber: number;
readonly sequence: number;
}
export interface Account {
/** Bech32 account address */
readonly address: string;
readonly balance: readonly Coin[];
readonly pubkey: PubKey | undefined;
readonly accountNumber: number;
readonly sequence: number;
}
export interface SearchByIdQuery {
readonly id: string;
}
export interface SearchByHeightQuery {
readonly height: number;
}
export interface SearchBySentFromOrToQuery {
readonly sentFromOrTo: string;
}
/**
* This query type allows you to pass arbitrary key/value pairs to the backend. It is
* more powerful and slightly lower level than the other search options.
*/
export interface SearchByTagsQuery {
readonly tags: ReadonlyArray<{ readonly key: string; readonly value: string }>;
}
export type SearchTxQuery = SearchByHeightQuery | SearchBySentFromOrToQuery | SearchByTagsQuery;
function isSearchByHeightQuery(query: SearchTxQuery): query is SearchByHeightQuery {
return (query as SearchByHeightQuery).height !== undefined;
}
function isSearchBySentFromOrToQuery(query: SearchTxQuery): query is SearchBySentFromOrToQuery {
return (query as SearchBySentFromOrToQuery).sentFromOrTo !== undefined;
}
function isSearchByTagsQuery(query: SearchTxQuery): query is SearchByTagsQuery {
return (query as SearchByTagsQuery).tags !== undefined;
}
export interface SearchTxFilter {
readonly minHeight?: number;
readonly maxHeight?: number;
}
export interface Code {
readonly id: number;
/** Bech32 account address */
readonly creator: string;
/** Hex-encoded sha256 hash of the code stored here */
readonly checksum: string;
/**
* An URL to a .tar.gz archive of the source code of the contract, which can be used to reproducibly build the Wasm bytecode.
*
* @see https://github.com/CosmWasm/cosmwasm-verify
*/
readonly source?: string;
/**
* A docker image (including version) to reproducibly build the Wasm bytecode from the source code.
*
* @example ```cosmwasm/rust-optimizer:0.8.0```
* @see https://github.com/CosmWasm/cosmwasm-verify
*/
readonly builder?: string;
}
export interface CodeDetails extends Code {
/** The original Wasm bytes */
readonly data: Uint8Array;
}
export interface Contract {
readonly address: string;
readonly codeId: number;
/** Bech32 account address */
readonly creator: string;
/** Bech32-encoded admin address */
readonly admin: string | undefined;
readonly label: string;
}
export interface ContractCodeHistoryEntry {
/** The source of this history entry */
readonly operation: "Genesis" | "Init" | "Migrate";
readonly codeId: number;
readonly msg: Record<string, unknown>;
}
export interface BlockHeader {
readonly version: {
readonly block: string;
readonly app: string;
};
readonly height: number;
readonly chainId: string;
/** An RFC 3339 time string like e.g. '2020-02-15T10:39:10.4696305Z' */
readonly time: string;
}
export interface Block {
/** The ID is a hash of the block header (uppercase hex) */
readonly id: string;
readonly header: BlockHeader;
/** Array of raw transactions */
readonly txs: readonly Uint8Array[];
}
/** Use for testing only */
export interface PrivateCosmWasmClient {
readonly lcdClient: LcdClient & AuthExtension & WasmExtension;
}
export class CosmWasmClient {
protected readonly lcdClient: LcdClient & AuthExtension & WasmExtension;
/** Any address the chain considers valid (valid bech32 with proper prefix) */
protected anyValidAddress: string | undefined;
private readonly codesCache = new Map<number, CodeDetails>();
private chainId: string | undefined;
/**
* Creates a new client to interact with a CosmWasm blockchain.
*
* This instance does a lot of caching. In order to benefit from that you should try to use one instance
* for the lifetime of your application. When switching backends, a new instance must be created.
*
* @param apiUrl The URL of a Cosmos SDK light client daemon API (sometimes called REST server or REST API)
* @param broadcastMode Defines at which point of the transaction processing the broadcastTx method returns
*/
public constructor(apiUrl: string, broadcastMode = BroadcastMode.Block) {
this.lcdClient = LcdClient.withExtensions(
{ apiUrl: apiUrl, broadcastMode: broadcastMode },
setupAuthExtension,
setupWasmExtension,
);
}
public async getChainId(): Promise<string> {
if (!this.chainId) {
const response = await this.lcdClient.nodeInfo();
const chainId = response.node_info.network;
if (!chainId) throw new Error("Chain ID must not be empty");
this.chainId = chainId;
}
return this.chainId;
}
public async getHeight(): Promise<number> {
if (this.anyValidAddress) {
const { height } = await this.lcdClient.auth.account(this.anyValidAddress);
return parseInt(height, 10);
} else {
// Note: this gets inefficient when blocks contain a lot of transactions since it
// requires downloading and deserializing all transactions in the block.
const latest = await this.lcdClient.blocksLatest();
return parseInt(latest.block.header.height, 10);
}
}
/**
* Returns a 32 byte upper-case hex transaction hash (typically used as the transaction ID)
*/
public async getIdentifier(tx: WrappedStdTx): Promise<string> {
// We consult the REST API because we don't have a local amino encoder
const response = await this.lcdClient.encodeTx(tx);
const hash = sha256(fromBase64(response.tx));
return toHex(hash).toUpperCase();
}
/**
* Returns account number and sequence.
*
* Throws if the account does not exist on chain.
*
* @param address returns data for this address. When unset, the client's sender adddress is used.
*/
public async getSequence(address: string): Promise<GetSequenceResult> {
const account = await this.getAccount(address);
if (!account) {
throw new Error(
"Account does not exist on chain. Send some tokens there before trying to query sequence.",
);
}
return {
accountNumber: account.accountNumber,
sequence: account.sequence,
};
}
public async getAccount(address: string): Promise<Account | undefined> {
const account = await this.lcdClient.auth.account(address);
const value = account.result.value;
if (value.address === "") {
return undefined;
} else {
this.anyValidAddress = value.address;
return {
address: value.address,
balance: value.coins,
pubkey: normalizePubkey(value.public_key) || undefined,
accountNumber: uint64ToNumber(value.account_number),
sequence: uint64ToNumber(value.sequence),
};
}
}
/**
* Gets block header and meta
*
* @param height The height of the block. If undefined, the latest height is used.
*/
public async getBlock(height?: number): Promise<Block> {
const response =
height !== undefined ? await this.lcdClient.blocks(height) : await this.lcdClient.blocksLatest();
return {
id: response.block_id.hash,
header: {
version: response.block.header.version,
time: response.block.header.time,
height: parseInt(response.block.header.height, 10),
chainId: response.block.header.chain_id,
},
txs: (response.block.data.txs || []).map(fromBase64),
};
}
public async getTx(id: string): Promise<IndexedTx | null> {
const results = await this.txsQuery(`tx.hash=${id}`);
return results[0] ?? null;
}
public async searchTx(query: SearchTxQuery, filter: SearchTxFilter = {}): Promise<readonly IndexedTx[]> {
const minHeight = filter.minHeight || 0;
const maxHeight = filter.maxHeight || Number.MAX_SAFE_INTEGER;
if (maxHeight < minHeight) return []; // optional optimization
function withFilters(originalQuery: string): string {
return `${originalQuery}&tx.minheight=${minHeight}&tx.maxheight=${maxHeight}`;
}
let txs: readonly IndexedTx[];
if (isSearchByHeightQuery(query)) {
// optional optimization to avoid network request
if (query.height < minHeight || query.height > maxHeight) {
txs = [];
} else {
txs = await this.txsQuery(`tx.height=${query.height}`);
}
} else if (isSearchBySentFromOrToQuery(query)) {
// We cannot get both in one request (see https://github.com/cosmos/gaia/issues/75)
const sentQuery = withFilters(`message.module=bank&message.sender=${query.sentFromOrTo}`);
const receivedQuery = withFilters(`message.module=bank&transfer.recipient=${query.sentFromOrTo}`);
const [sent, received] = (await Promise.all([
this.txsQuery(sentQuery),
this.txsQuery(receivedQuery),
])) as [IndexedTx[], IndexedTx[]];
let mergedTxs: readonly IndexedTx[] = [];
/* eslint-disable @typescript-eslint/no-non-null-assertion */
// sent/received are presorted
while (sent.length && received.length) {
const next =
sent[0].hash === received[0].hash
? sent.shift()! && received.shift()!
: sent[0].height <= received[0].height
? sent.shift()!
: received.shift()!;
mergedTxs = [...mergedTxs, next];
}
/* eslint-enable @typescript-eslint/no-non-null-assertion */
// At least one of sent/received is empty by now
txs = [...mergedTxs, ...sent, ...received];
} else if (isSearchByTagsQuery(query)) {
const rawQuery = withFilters(query.tags.map((t) => `${t.key}=${t.value}`).join("&"));
txs = await this.txsQuery(rawQuery);
} else {
throw new Error("Unknown query type");
}
// backend sometimes messes up with min/max height filtering
const filtered = txs.filter((tx) => tx.height >= minHeight && tx.height <= maxHeight);
return filtered;
}
public async broadcastTx(tx: StdTx): Promise<BroadcastTxResult> {
const result = await this.lcdClient.broadcastTx(tx);
if (!result.txhash.match(/^([0-9A-F][0-9A-F])+$/)) {
throw new Error("Received ill-formatted txhash. Must be non-empty upper-case hex");
}
return result.code !== undefined
? {
height: Uint53.fromString(result.height).toNumber(),
transactionHash: result.txhash,
code: result.code,
rawLog: result.raw_log || "",
}
: {
logs: result.logs ? logs.parseLogs(result.logs) : [],
rawLog: result.raw_log || "",
transactionHash: result.txhash,
data: result.data ? fromHex(result.data) : undefined,
};
}
public async getCodes(): Promise<readonly Code[]> {
const result = await this.lcdClient.wasm.listCodeInfo();
return result.map((entry): Code => {
this.anyValidAddress = entry.creator;
return {
id: entry.id,
creator: entry.creator,
checksum: toHex(fromHex(entry.data_hash)),
source: entry.source || undefined,
builder: entry.builder || undefined,
};
});
}
public async getCodeDetails(codeId: number): Promise<CodeDetails> {
const cached = this.codesCache.get(codeId);
if (cached) return cached;
const getCodeResult = await this.lcdClient.wasm.getCode(codeId);
const codeDetails: CodeDetails = {
id: getCodeResult.id,
creator: getCodeResult.creator,
checksum: toHex(fromHex(getCodeResult.data_hash)),
source: getCodeResult.source || undefined,
builder: getCodeResult.builder || undefined,
data: fromBase64(getCodeResult.data),
};
this.codesCache.set(codeId, codeDetails);
return codeDetails;
}
public async getContracts(codeId: number): Promise<readonly Contract[]> {
const result = await this.lcdClient.wasm.listContractsByCodeId(codeId);
return result.map(
(entry): Contract => ({
address: entry.address,
codeId: entry.code_id,
creator: entry.creator,
admin: entry.admin,
label: entry.label,
}),
);
}
/**
* Throws an error if no contract was found at the address
*/
public async getContract(address: string): Promise<Contract> {
const result = await this.lcdClient.wasm.getContractInfo(address);
if (!result) throw new Error(`No contract found at address "${address}"`);
return {
address: result.address,
codeId: result.code_id,
creator: result.creator,
admin: result.admin,
label: result.label,
};
}
/**
* Throws an error if no contract was found at the address
*/
public async getContractCodeHistory(address: string): Promise<readonly ContractCodeHistoryEntry[]> {
const result = await this.lcdClient.wasm.getContractCodeHistory(address);
if (!result) throw new Error(`No contract history found for address "${address}"`);
return result.map(
(entry): ContractCodeHistoryEntry => ({
operation: entry.operation,
codeId: entry.code_id,
msg: entry.msg,
}),
);
}
/**
* Returns the data at the key if present (raw contract dependent storage data)
* or null if no data at this key.
*
* Promise is rejected when contract does not exist.
*/
public async queryContractRaw(address: string, key: Uint8Array): Promise<Uint8Array | null> {
// just test contract existence
const _info = await this.getContract(address);
return this.lcdClient.wasm.queryContractRaw(address, key);
}
/**
* Makes a smart query on the contract, returns the parsed JSON document.
*
* Promise is rejected when contract does not exist.
* Promise is rejected for invalid query format.
* Promise is rejected for invalid response format.
*/
public async queryContractSmart(address: string, queryMsg: Record<string, unknown>): Promise<JsonObject> {
try {
return await this.lcdClient.wasm.queryContractSmart(address, queryMsg);
} catch (error) {
if (error instanceof Error) {
if (error.message.startsWith("not found: contract")) {
throw new Error(`No contract found at address "${address}"`);
} else {
throw error;
}
} else {
throw error;
}
}
}
private async txsQuery(query: string): Promise<readonly IndexedTx[]> {
// TODO: we need proper pagination support
const limit = 100;
const result = await this.lcdClient.txsQuery(`${query}&limit=${limit}`);
const pages = parseInt(result.page_total, 10);
if (pages > 1) {
throw new Error(
`Found more results on the backend than we can process currently. Results: ${result.total_count}, supported: ${limit}`,
);
}
return result.txs.map(
(restItem): IndexedTx => ({
height: parseInt(restItem.height, 10),
hash: restItem.txhash,
code: restItem.code || 0,
rawLog: restItem.raw_log,
logs: logs.parseLogs(restItem.logs || []),
tx: restItem.tx,
timestamp: restItem.timestamp,
}),
);
}
}

View File

@ -1,118 +0,0 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { coins, Secp256k1HdWallet } from "@cosmjs/launchpad";
import { Cw1CosmWasmClient } from "./cw1cosmwasmclient";
import {
alice,
deployedCw1,
launchpad,
makeRandomAddress,
pendingWithoutCw1,
pendingWithoutLaunchpad,
} from "./testutils.spec";
describe("Cw1CosmWasmClient", () => {
const contractAddress = deployedCw1.instances[0];
const defaultToAddress = makeRandomAddress();
const defaultMsg = {
bank: {
send: {
from_address: contractAddress,
to_address: defaultToAddress,
amount: coins(1, "ucosm"),
},
},
};
describe("constructor", () => {
it("can be constructed", async () => {
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw1CosmWasmClient(launchpad.endpoint, alice.address0, wallet, contractAddress);
expect(client).toBeTruthy();
});
});
describe("canSend", () => {
it("returns true if client signer can send", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw1();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw1CosmWasmClient(
launchpad.endpoint,
alice.address0,
wallet,
deployedCw1.instances[0],
);
const result = await client.canSend(defaultMsg);
expect(result).toEqual(true);
});
it("returns false if client signer cannot send", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw1();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw1CosmWasmClient(
launchpad.endpoint,
alice.address1,
wallet,
deployedCw1.instances[0],
);
const result = await client.canSend(defaultMsg);
expect(result).toEqual(false);
});
it("returns true if supplied signer can send", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw1();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw1CosmWasmClient(
launchpad.endpoint,
alice.address1,
wallet,
deployedCw1.instances[0],
);
const result = await client.canSend(defaultMsg, alice.address0);
expect(result).toEqual(true);
});
it("returns false if supplied signer cannot send", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw1();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw1CosmWasmClient(
launchpad.endpoint,
alice.address0,
wallet,
deployedCw1.instances[0],
);
const result = await client.canSend(defaultMsg, alice.address1);
expect(result).toEqual(false);
});
});
describe("executeCw1", () => {
it("works", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw1();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw1CosmWasmClient(
launchpad.endpoint,
alice.address0,
wallet,
deployedCw1.instances[0],
);
const result = await client.executeCw1([defaultMsg]);
expect(result.transactionHash).toBeTruthy();
});
});
});

View File

@ -1,45 +0,0 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { Account, BroadcastMode, GasLimits, GasPrice, OfflineSigner } from "@cosmjs/launchpad";
import { CosmosMsg } from "./cosmosmsg";
import { CosmWasmFeeTable, ExecuteResult, SigningCosmWasmClient } from "./signingcosmwasmclient";
export class Cw1CosmWasmClient extends SigningCosmWasmClient {
public readonly cw1ContractAddress: string;
public constructor(
apiUrl: string,
signerAddress: string,
signer: OfflineSigner,
cw1ContractAddress: string,
gasPrice?: GasPrice,
gasLimits?: Partial<GasLimits<CosmWasmFeeTable>>,
broadcastMode?: BroadcastMode,
) {
super(apiUrl, signerAddress, signer, gasPrice, gasLimits, broadcastMode);
this.cw1ContractAddress = cw1ContractAddress;
}
public override async getAccount(address?: string): Promise<Account | undefined> {
return super.getAccount(address || this.cw1ContractAddress);
}
public async canSend(msg: CosmosMsg, address = this.signerAddress): Promise<boolean> {
const result = await this.queryContractSmart(this.cw1ContractAddress, {
can_send: {
sender: address,
msg: msg,
},
});
return result.can_send;
}
public async executeCw1(msgs: readonly CosmosMsg[], memo = ""): Promise<ExecuteResult> {
const handleMsg = {
execute: {
msgs: msgs,
},
};
return this.execute(this.cw1ContractAddress, handleMsg, memo);
}
}

View File

@ -1,323 +0,0 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { coin, coins, Secp256k1HdWallet } from "@cosmjs/launchpad";
import { Cw1SubkeyCosmWasmClient } from "./cw1subkeycosmwasmclient";
import {
alice,
deployedCw1,
launchpad,
makeRandomAddress,
pendingWithoutCw1,
pendingWithoutLaunchpad,
} from "./testutils.spec";
describe("Cw1SubkeyCosmWasmClient", () => {
describe("getAdmins", () => {
it("works", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw1();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw1SubkeyCosmWasmClient(
launchpad.endpoint,
alice.address0,
wallet,
deployedCw1.instances[0],
);
const result = await client.getAdmins();
expect(result).toEqual([alice.address0]);
});
});
describe("isAdmin", () => {
it("returns true if client signer is admin", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw1();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw1SubkeyCosmWasmClient(
launchpad.endpoint,
alice.address0,
wallet,
deployedCw1.instances[0],
);
const result = await client.isAdmin();
expect(result).toEqual(true);
});
it("returns false if client signer is not admin", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw1();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw1SubkeyCosmWasmClient(
launchpad.endpoint,
alice.address1,
wallet,
deployedCw1.instances[0],
);
const result = await client.isAdmin();
expect(result).toEqual(false);
});
it("returns true if supplied signer is admin", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw1();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw1SubkeyCosmWasmClient(
launchpad.endpoint,
alice.address1,
wallet,
deployedCw1.instances[0],
);
const result = await client.isAdmin(alice.address0);
expect(result).toEqual(true);
});
it("returns false if supplied signer is not admin", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw1();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw1SubkeyCosmWasmClient(
launchpad.endpoint,
alice.address0,
wallet,
deployedCw1.instances[0],
);
const result = await client.isAdmin(alice.address1);
expect(result).toEqual(false);
});
});
describe("getAllAllowances", () => {
it("works", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw1();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw1SubkeyCosmWasmClient(
launchpad.endpoint,
alice.address0,
wallet,
deployedCw1.instances[0],
);
const result = await client.getAllAllowances();
expect(result).toBeTruthy();
});
});
describe("getAllowance", () => {
it("works for client signer", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw1();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw1SubkeyCosmWasmClient(
launchpad.endpoint,
alice.address0,
wallet,
deployedCw1.instances[0],
);
const result = await client.getAllowance();
expect(result).toEqual({ balance: [], expires: { never: {} } });
});
});
describe("getAllPermissions", () => {
it("works", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw1();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw1SubkeyCosmWasmClient(
launchpad.endpoint,
alice.address0,
wallet,
deployedCw1.instances[0],
);
const result = await client.getAllPermissions();
expect(result.length).toEqual(1);
// TODO: test content of permissions
});
});
describe("getPermissions", () => {
it("works for client signer", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw1();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw1SubkeyCosmWasmClient(
launchpad.endpoint,
alice.address0,
wallet,
deployedCw1.instances[0],
);
const result = await client.getPermissions();
expect(result).toEqual({
delegate: false,
redelegate: false,
undelegate: false,
withdraw: false,
});
});
it("works for supplied signer", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw1();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw1SubkeyCosmWasmClient(
launchpad.endpoint,
alice.address0,
wallet,
deployedCw1.instances[0],
);
const result = await client.getPermissions(alice.address1);
expect(result).toEqual({
delegate: false,
redelegate: false,
undelegate: false,
withdraw: false,
});
});
});
describe("addAdmin and removeAdmin", () => {
it("works", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw1();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw1SubkeyCosmWasmClient(
launchpad.endpoint,
alice.address0,
wallet,
deployedCw1.instances[0],
);
const newAdmin = makeRandomAddress();
expect(await client.isAdmin(newAdmin)).toBeFalse();
const addResult = await client.addAdmin(newAdmin);
expect(addResult.transactionHash).toBeTruthy();
expect(await client.isAdmin(newAdmin)).toBeTrue();
const removeResult = await client.removeAdmin(newAdmin);
expect(removeResult.transactionHash).toBeTruthy();
expect(await client.isAdmin(newAdmin)).toBeFalse();
});
});
describe("increaseAllowance and decreaseAllowance", () => {
it("works", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw1();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw1SubkeyCosmWasmClient(
launchpad.endpoint,
alice.address0,
wallet,
deployedCw1.instances[0],
);
const spender = makeRandomAddress();
expect(await client.getAllowance(spender)).toEqual({ balance: [], expires: { never: {} } });
const increaseAmount = coin(100, "ucosm");
const increaseResult = await client.increaseAllowance(spender, increaseAmount);
expect(increaseResult.transactionHash).toBeTruthy();
expect(await client.getAllowance(spender)).toEqual({
balance: [increaseAmount],
expires: { never: {} },
});
const decreaseAmount = coin(20, "ucosm");
const decreaseResult = await client.decreaseAllowance(spender, decreaseAmount);
expect(decreaseResult.transactionHash).toBeTruthy();
expect(await client.getAllowance(spender)).toEqual({
balance: coins(80, "ucosm"),
expires: { never: {} },
});
});
it("works with expiration", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw1();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw1SubkeyCosmWasmClient(
launchpad.endpoint,
alice.address0,
wallet,
deployedCw1.instances[0],
);
const spender = makeRandomAddress();
expect(await client.getAllowance(spender)).toEqual({ balance: [], expires: { never: {} } });
const increaseAmount = coin(100, "ucosm");
const increaseExpiration = { at_height: 88888888888 };
const increaseResult = await client.increaseAllowance(spender, increaseAmount, increaseExpiration);
expect(increaseResult.transactionHash).toBeTruthy();
expect(await client.getAllowance(spender)).toEqual({
balance: [increaseAmount],
expires: increaseExpiration,
});
const decreaseAmount = coin(20, "ucosm");
const decreaseExpiration = { at_height: 99999999999 };
const decreaseResult = await client.decreaseAllowance(spender, decreaseAmount, decreaseExpiration);
expect(decreaseResult.transactionHash).toBeTruthy();
expect(await client.getAllowance(spender)).toEqual({
balance: coins(80, "ucosm"),
expires: decreaseExpiration,
});
});
});
describe("setPermissions", () => {
it("works", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw1();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw1SubkeyCosmWasmClient(
launchpad.endpoint,
alice.address0,
wallet,
deployedCw1.instances[0],
);
const spender = makeRandomAddress();
const defaultPermissions = {
delegate: false,
redelegate: false,
undelegate: false,
withdraw: false,
};
expect(await client.getPermissions(spender)).toEqual(defaultPermissions);
const newPermissions = {
delegate: true,
redelegate: true,
undelegate: true,
withdraw: false,
};
const setPermissionsResult = await client.setPermissions(spender, newPermissions);
expect(setPermissionsResult.transactionHash).toBeTruthy();
expect(await client.getPermissions(spender)).toEqual(newPermissions);
const resetPermissionsResult = await client.setPermissions(spender, defaultPermissions);
expect(resetPermissionsResult.transactionHash).toBeTruthy();
expect(await client.getPermissions(spender)).toEqual(defaultPermissions);
});
});
});

View File

@ -1,152 +0,0 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { Coin } from "@cosmjs/launchpad";
import { Cw1CosmWasmClient } from "./cw1cosmwasmclient";
import { Expiration } from "./interfaces";
import { ExecuteResult } from "./signingcosmwasmclient";
/**
* @see https://github.com/CosmWasm/cosmwasm-plus/blob/v0.3.2/contracts/cw1-subkeys/src/msg.rs#L88
*/
export interface Cw1SubkeyAllowanceInfo {
readonly balance: readonly Coin[];
readonly expires: Expiration;
}
/**
* @see https://github.com/CosmWasm/cosmwasm-plus/blob/v0.3.2/contracts/cw1-subkeys/src/msg.rs#L83
*/
interface AllAllowancesResponse {
readonly allowances: readonly Cw1SubkeyAllowanceInfo[];
}
/**
* @see https://github.com/CosmWasm/cosmwasm-plus/blob/v0.3.2/contracts/cw1-subkeys/src/state.rs#L15
*/
export interface Cw1SubkeyPermissions {
readonly delegate: boolean;
readonly redelegate: boolean;
readonly undelegate: boolean;
readonly withdraw: boolean;
}
/**
* @see https://github.com/CosmWasm/cosmwasm-plus/blob/v0.3.2/contracts/cw1-subkeys/src/msg.rs#L95
*/
export interface Cw1SubkeyPermissionsInfo {
/** Spender address */
readonly spender: string;
readonly permissions: readonly Cw1SubkeyPermissions[];
}
/**
* @see https://github.com/CosmWasm/cosmwasm-plus/blob/v0.3.2/contracts/cw1-subkeys/src/msg.rs#L101
*/
interface AllPermissionsResponse {
readonly permissions: readonly Cw1SubkeyPermissionsInfo[];
}
export class Cw1SubkeyCosmWasmClient extends Cw1CosmWasmClient {
private async setAdmins(admins: readonly string[], memo = ""): Promise<ExecuteResult> {
const handleMsg = {
update_admins: {
admins: admins,
},
};
return this.execute(this.cw1ContractAddress, handleMsg, memo);
}
public async getAdmins(): Promise<readonly string[]> {
const { admins } = await this.queryContractSmart(this.cw1ContractAddress, { admin_list: {} });
return admins;
}
public async isAdmin(address = this.signerAddress): Promise<boolean> {
const admins = await this.getAdmins();
return admins.includes(address);
}
public async getAllAllowances(): Promise<readonly Cw1SubkeyAllowanceInfo[]> {
const response: AllAllowancesResponse = await this.queryContractSmart(this.cw1ContractAddress, {
all_allowances: {},
});
return response.allowances;
}
public async getAllowance(address = this.signerAddress): Promise<Cw1SubkeyAllowanceInfo> {
return this.queryContractSmart(this.cw1ContractAddress, {
allowance: { spender: address },
});
}
public async getAllPermissions(): Promise<readonly Cw1SubkeyPermissionsInfo[]> {
const response: AllPermissionsResponse = await this.queryContractSmart(this.cw1ContractAddress, {
all_permissions: {},
});
return response.permissions;
}
public async getPermissions(address = this.signerAddress): Promise<Cw1SubkeyPermissions> {
return this.queryContractSmart(this.cw1ContractAddress, {
permissions: { spender: address },
});
}
public async addAdmin(address: string, memo = ""): Promise<ExecuteResult> {
const admins = await this.getAdmins();
const newAdmins = admins.includes(address) ? admins : [...admins, address];
return this.setAdmins(newAdmins, memo);
}
public async removeAdmin(address: string, memo = ""): Promise<ExecuteResult> {
const admins = await this.getAdmins();
const newAdmins = admins.filter((admin) => admin !== address);
return this.setAdmins(newAdmins, memo);
}
public async increaseAllowance(
address: string,
amount: Coin,
expires?: Expiration,
memo = "",
): Promise<ExecuteResult> {
const handleMsg = {
increase_allowance: {
spender: address,
amount: amount,
expires: expires,
},
};
return this.execute(this.cw1ContractAddress, handleMsg, memo);
}
public async decreaseAllowance(
address: string,
amount: Coin,
expires?: Expiration,
memo = "",
): Promise<ExecuteResult> {
const handleMsg = {
decrease_allowance: {
spender: address,
amount: amount,
expires: expires,
},
};
return this.execute(this.cw1ContractAddress, handleMsg, memo);
}
public async setPermissions(
address: string,
permissions: Cw1SubkeyPermissions,
memo = "",
): Promise<ExecuteResult> {
const handleMsg = {
set_permissions: {
spender: address,
permissions: permissions,
},
};
return this.execute(this.cw1ContractAddress, handleMsg, memo);
}
}

View File

@ -1,348 +0,0 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { makeCosmoshubPath, Secp256k1HdWallet } from "@cosmjs/launchpad";
import { assert } from "@cosmjs/utils";
import { Cw3CosmWasmClient, Vote } from "./cw3cosmwasmclient";
import {
alice,
cw3Enabled,
deployedCw3,
launchpad,
launchpadEnabled,
makeRandomAddress,
pendingWithoutCw3,
pendingWithoutLaunchpad,
} from "./testutils.spec";
describe("Cw3CosmWasmClient", () => {
describe("constructor", () => {
it("can be constructed", async () => {
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw3CosmWasmClient(
launchpad.endpoint,
alice.address0,
wallet,
deployedCw3.instances[0],
);
expect(client).toBeTruthy();
});
});
describe("queries", () => {
const contractAddress = deployedCw3.instances[0];
const toAddress = makeRandomAddress();
const msg = {
bank: {
send: {
from_address: contractAddress,
to_address: toAddress,
amount: [
{
amount: "1",
denom: "ucosm",
},
],
},
},
};
let proposalId: number | undefined;
let expirationHeight: number | undefined;
beforeAll(async () => {
if (launchpadEnabled() && cw3Enabled()) {
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw3CosmWasmClient(launchpad.endpoint, alice.address0, wallet, contractAddress);
const currentHeight = await client.getHeight();
expirationHeight = currentHeight + 1;
const { logs } = await client.createMultisigProposal(
"My proposal",
"A proposal to propose proposing proposals",
[msg],
undefined,
{ at_height: expirationHeight },
);
const wasmEvents = logs[0].events.find((event) => event.type === "wasm");
assert(wasmEvents, "Wasm events not found in logs");
const proposalIdAttribute = wasmEvents.attributes.find((log) => log.key === "proposal_id");
assert(proposalIdAttribute, "Proposal ID not found in logs");
proposalId = parseInt(proposalIdAttribute.value, 10);
}
});
it("getThreshold", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw3();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw3CosmWasmClient(
launchpad.endpoint,
alice.address0,
wallet,
deployedCw3.instances[0],
);
const result = await client.getThreshold();
expect(result).toEqual({ absolute_count: { weight_needed: 1, total_weight: 3 } });
});
it("getProposal", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw3();
assert(proposalId, "value must be set in beforeAll()");
assert(expirationHeight, "value must be set in beforeAll()");
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw3CosmWasmClient(launchpad.endpoint, alice.address0, wallet, contractAddress);
const result = await client.getProposal(proposalId);
expect(result).toEqual({
id: proposalId,
title: "My proposal",
description: "A proposal to propose proposing proposals",
msgs: [msg],
expires: { at_height: expirationHeight },
status: "passed",
});
});
it("listProposals", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw3();
assert(proposalId, "value must be set in beforeAll()");
assert(expirationHeight, "value must be set in beforeAll()");
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw3CosmWasmClient(launchpad.endpoint, alice.address0, wallet, contractAddress);
const result = await client.listProposals({ startAfter: proposalId - 1, limit: 1 });
expect(result).toEqual({
proposals: [
{
id: proposalId,
title: "My proposal",
description: "A proposal to propose proposing proposals",
msgs: [msg],
expires: { at_height: expirationHeight },
status: "passed",
},
],
});
});
it("reverseProposals", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw3();
assert(proposalId, "value must be set in beforeAll()");
assert(expirationHeight, "value must be set in beforeAll()");
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw3CosmWasmClient(launchpad.endpoint, alice.address0, wallet, contractAddress);
const result = await client.reverseProposals({ limit: 1 });
expect(result).toEqual({
proposals: [
{
id: proposalId,
title: "My proposal",
description: "A proposal to propose proposing proposals",
msgs: [msg],
expires: { at_height: expirationHeight },
status: "passed",
},
],
});
});
it("getVote", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw3();
assert(proposalId, "value must be set in beforeAll()");
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw3CosmWasmClient(launchpad.endpoint, alice.address0, wallet, contractAddress);
const result = await client.getVote(proposalId, alice.address0);
expect(result).toEqual({ vote: Vote.Yes });
});
it("listVotes", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw3();
assert(proposalId, "value must be set in beforeAll()");
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw3CosmWasmClient(launchpad.endpoint, alice.address0, wallet, contractAddress);
const result = await client.listVotes(proposalId);
expect(result).toEqual({ votes: [{ voter: alice.address0, vote: Vote.Yes, weight: 1 }] });
});
it("getVoter", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw3();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw3CosmWasmClient(launchpad.endpoint, alice.address0, wallet, contractAddress);
const result = await client.getVoter(alice.address0);
expect(result).toEqual({ addr: alice.address0, weight: 1 });
});
it("listVoters", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw3();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw3CosmWasmClient(launchpad.endpoint, alice.address0, wallet, contractAddress);
const result = await client.listVoters();
expect(result.voters.length).toEqual(3);
expect(result.voters).toEqual(
jasmine.arrayContaining([
{ addr: alice.address0, weight: 1 },
{ addr: alice.address1, weight: 1 },
{ addr: alice.address2, weight: 1 },
]),
);
});
});
describe("Proposal lifecycle", () => {
it("proposal is accepted (proposer has enough weight alone)", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw3();
const contractAddress = deployedCw3.instances[0];
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new Cw3CosmWasmClient(launchpad.endpoint, alice.address0, wallet, contractAddress);
const toAddress = makeRandomAddress();
const msg = {
bank: {
send: {
from_address: contractAddress,
to_address: toAddress,
amount: [
{
amount: "1",
denom: "ucosm",
},
],
},
},
};
await client.createMultisigProposal("My proposal", "A proposal to propose proposing proposals", [msg]);
const { proposals } = await client.reverseProposals({ limit: 1 });
const proposalId = proposals[0].id;
const executeResult = await client.executeMultisigProposal(proposalId);
expect(executeResult).toBeTruthy();
});
it("proposal is accepted (proposer does not have enough weight alone)", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw3();
const contractAddress = deployedCw3.instances[1];
const proposerWallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const proposer = new Cw3CosmWasmClient(
launchpad.endpoint,
alice.address0,
proposerWallet,
contractAddress,
);
const voterWallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic, {
hdPaths: [makeCosmoshubPath(1)],
});
const voter = new Cw3CosmWasmClient(launchpad.endpoint, alice.address1, voterWallet, contractAddress);
const toAddress = makeRandomAddress();
const msg = {
bank: {
send: {
from_address: contractAddress,
to_address: toAddress,
amount: [
{
amount: "1",
denom: "ucosm",
},
],
},
},
};
await proposer.createMultisigProposal("My proposal", "A proposal to propose proposing proposals", [
msg,
]);
const { proposals } = await voter.reverseProposals({ limit: 1 });
const proposalId = proposals[0].id;
await expectAsync(proposer.executeMultisigProposal(proposalId)).toBeRejectedWithError(
/proposal must have passed and not yet been executed/i,
);
const voteResult = await voter.voteMultisigProposal(proposalId, Vote.Yes);
expect(voteResult).toBeTruthy();
const executeResult = await proposer.executeMultisigProposal(proposalId);
expect(executeResult).toBeTruthy();
});
it("proposal is rejected", async () => {
pendingWithoutLaunchpad();
pendingWithoutCw3();
const contractAddress = deployedCw3.instances[1];
const proposerWallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const proposer = new Cw3CosmWasmClient(
launchpad.endpoint,
alice.address0,
proposerWallet,
contractAddress,
);
const voter1Wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic, {
hdPaths: [makeCosmoshubPath(1)],
});
const voter1 = new Cw3CosmWasmClient(launchpad.endpoint, alice.address1, voter1Wallet, contractAddress);
const voter2Wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic, {
hdPaths: [makeCosmoshubPath(2)],
});
const voter2 = new Cw3CosmWasmClient(launchpad.endpoint, alice.address2, voter2Wallet, contractAddress);
const toAddress = makeRandomAddress();
const msg = {
bank: {
send: {
from_address: contractAddress,
to_address: toAddress,
amount: [
{
amount: "1",
denom: "ucosm",
},
],
},
},
};
const currentHeight = await proposer.getHeight();
await proposer.createMultisigProposal(
"My proposal",
"A proposal to propose proposing proposals",
[msg],
{
at_height: currentHeight,
},
{
at_height: currentHeight + 5,
},
);
const { proposals } = await voter1.reverseProposals({ limit: 1 });
const proposalId = proposals[0].id;
const vote1Result = await voter1.voteMultisigProposal(proposalId, Vote.Abstain);
expect(vote1Result).toBeTruthy();
const vote2Result = await voter2.voteMultisigProposal(proposalId, Vote.No);
expect(vote2Result).toBeTruthy();
await expectAsync(proposer.executeMultisigProposal(proposalId)).toBeRejectedWithError(
/proposal must have passed and not yet been executed/i,
);
const closeResult = await proposer.closeMultisigProposal(proposalId);
expect(closeResult).toBeTruthy();
});
});
});

View File

@ -1,201 +0,0 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { BroadcastMode, GasLimits, GasPrice, OfflineSigner } from "@cosmjs/launchpad";
import { CosmosMsg } from "./cosmosmsg";
import { Account } from "./cosmwasmclient";
import { Expiration } from "./interfaces";
import { CosmWasmFeeTable, ExecuteResult, SigningCosmWasmClient } from "./signingcosmwasmclient";
/**
* @see https://github.com/CosmWasm/cosmwasm-plus/blob/v0.3.2/packages/cw3/src/msg.rs#L35
*/
export enum Vote {
Yes = "yes",
No = "no",
Abstain = "abstain",
Veto = "veto",
}
export interface ThresholdResult {
readonly absolute_count: {
readonly weight_needed: number;
readonly total_weight: number;
};
}
export interface ProposalResult {
readonly id: number;
readonly title: string;
readonly description: string;
readonly msgs: readonly CosmosMsg[];
readonly expires: Expiration;
readonly status: string;
}
export interface ProposalsResult {
readonly proposals: readonly ProposalResult[];
}
export interface VoteResult {
readonly vote: Vote;
}
export interface VotesResult {
readonly votes: ReadonlyArray<{ readonly vote: Vote; readonly voter: string; readonly weight: number }>;
}
export interface VoterResult {
readonly addr: string;
readonly weight: number;
}
export interface VotersResult {
readonly voters: readonly VoterResult[];
}
interface StartBeforeNumberPaginationOptions {
readonly startBefore?: number;
readonly limit?: number;
}
interface StartAfterNumberPaginationOptions {
readonly startAfter?: number;
readonly limit?: number;
}
interface StartAfterStringPaginationOptions {
readonly startAfter?: string;
readonly limit?: number;
}
export class Cw3CosmWasmClient extends SigningCosmWasmClient {
public readonly cw3ContractAddress: string;
public constructor(
apiUrl: string,
signerAddress: string,
signer: OfflineSigner,
cw3ContractAddress: string,
gasPrice?: GasPrice,
gasLimits?: Partial<GasLimits<CosmWasmFeeTable>>,
broadcastMode?: BroadcastMode,
) {
super(apiUrl, signerAddress, signer, gasPrice, gasLimits, broadcastMode);
this.cw3ContractAddress = cw3ContractAddress;
}
public override getAccount(address?: string): Promise<Account | undefined> {
return super.getAccount(address || this.cw3ContractAddress);
}
public getThreshold(): Promise<ThresholdResult> {
return this.queryContractSmart(this.cw3ContractAddress, { threshold: {} });
}
public getProposal(proposalId: number): Promise<ProposalResult> {
return this.queryContractSmart(this.cw3ContractAddress, { proposal: { proposal_id: proposalId } });
}
public listProposals({
startAfter,
limit,
}: StartAfterNumberPaginationOptions = {}): Promise<ProposalsResult> {
return this.queryContractSmart(this.cw3ContractAddress, {
list_proposals: {
start_after: startAfter,
limit: limit,
},
});
}
public reverseProposals({
startBefore,
limit,
}: StartBeforeNumberPaginationOptions = {}): Promise<ProposalsResult> {
return this.queryContractSmart(this.cw3ContractAddress, {
reverse_proposals: {
start_before: startBefore,
limit: limit,
},
});
}
public getVote(proposalId: number, voter: string): Promise<VoteResult> {
return this.queryContractSmart(this.cw3ContractAddress, {
vote: {
proposal_id: proposalId,
voter: voter,
},
});
}
public listVotes(
proposalId: number,
{ startAfter, limit }: StartAfterStringPaginationOptions = {},
): Promise<VotesResult> {
return this.queryContractSmart(this.cw3ContractAddress, {
list_votes: {
proposal_id: proposalId,
start_after: startAfter,
limit: limit,
},
});
}
public getVoter(address: string): Promise<VoterResult> {
return this.queryContractSmart(this.cw3ContractAddress, {
voter: {
address: address,
},
});
}
public listVoters({ startAfter, limit }: StartAfterStringPaginationOptions = {}): Promise<VotersResult> {
return this.queryContractSmart(this.cw3ContractAddress, {
list_voters: {
start_after: startAfter,
limit: limit,
},
});
}
public createMultisigProposal(
title: string,
description: string,
msgs: readonly CosmosMsg[],
earliest?: Expiration,
latest?: Expiration,
memo = "",
): Promise<ExecuteResult> {
const handleMsg = {
propose: {
title: title,
description: description,
msgs: msgs,
earliest: earliest,
latest: latest,
},
};
return this.execute(this.cw3ContractAddress, handleMsg, memo);
}
public voteMultisigProposal(proposalId: number, vote: Vote, memo = ""): Promise<ExecuteResult> {
const handleMsg = {
vote: {
proposal_id: proposalId,
vote: vote,
},
};
return this.execute(this.cw3ContractAddress, handleMsg, memo);
}
public executeMultisigProposal(proposalId: number, memo = ""): Promise<ExecuteResult> {
const handleMsg = { execute: { proposal_id: proposalId } };
return this.execute(this.cw3ContractAddress, handleMsg, memo);
}
public closeMultisigProposal(proposalId: number, memo = ""): Promise<ExecuteResult> {
const handleMsg = { close: { proposal_id: proposalId } };
return this.execute(this.cw3ContractAddress, handleMsg, memo);
}
}

View File

@ -1,59 +0,0 @@
export { isValidBuilder } from "./builder";
export { Expiration } from "./interfaces";
export { setupWasmExtension, WasmExtension } from "./lcdapi/wasm";
export { BankMsg, CosmosMsg, CustomMsg, StakingMsg, WasmMsg } from "./cosmosmsg";
export {
Account,
Block,
BlockHeader,
Code,
CodeDetails,
Contract,
ContractCodeHistoryEntry,
CosmWasmClient,
GetSequenceResult,
SearchByHeightQuery,
SearchBySentFromOrToQuery,
SearchByTagsQuery,
SearchTxQuery,
SearchTxFilter,
} from "./cosmwasmclient";
export { Cw1CosmWasmClient } from "./cw1cosmwasmclient";
export {
Cw3CosmWasmClient,
ProposalResult,
ProposalsResult,
ThresholdResult,
Vote,
VoteResult,
VotesResult,
VoterResult,
VotersResult,
} from "./cw3cosmwasmclient";
export {
ChangeAdminResult,
ExecuteResult,
CosmWasmFeeTable,
InstantiateOptions,
InstantiateResult,
MigrateResult,
SigningCosmWasmClient,
UploadMeta,
UploadResult,
} from "./signingcosmwasmclient";
export {
isMsgClearAdmin,
isMsgExecuteContract,
isMsgInstantiateContract,
isMsgMigrateContract,
isMsgUpdateAdmin,
isMsgStoreCode,
MsgClearAdmin,
MsgExecuteContract,
MsgInstantiateContract,
MsgMigrateContract,
MsgUpdateAdmin,
MsgStoreCode,
} from "./msgs";
export { JsonObject, parseWasmData, WasmData } from "./types";

View File

@ -1,15 +0,0 @@
/* eslint-disable @typescript-eslint/naming-convention */
/**
* @see https://github.com/CosmWasm/cosmwasm-plus/blob/v0.3.2/packages/cw0/src/expiration.rs#L14
*/
export type Expiration =
| {
readonly at_height: number;
}
| {
readonly at_time: number;
}
| {
readonly never: Record<any, never>;
};

View File

@ -1 +0,0 @@
export { Expiration } from "./cw0";

View File

@ -1,547 +0,0 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { sha256 } from "@cosmjs/crypto";
import { Bech32, fromAscii, fromHex, fromUtf8, toAscii, toBase64, toHex } from "@cosmjs/encoding";
import {
assertIsBroadcastTxSuccess,
AuthExtension,
BroadcastTxResult,
BroadcastTxsResponse,
Coin,
coin,
coins,
LcdClient,
logs,
makeSignDoc,
makeStdTx,
OfflineSigner,
Secp256k1HdWallet,
setupAuthExtension,
SigningCosmosClient,
StdFee,
} from "@cosmjs/launchpad";
import { assert } from "@cosmjs/utils";
import {
isMsgInstantiateContract,
isMsgStoreCode,
MsgExecuteContract,
MsgInstantiateContract,
MsgStoreCode,
} from "../msgs";
import {
alice,
base64Matcher,
bech32AddressMatcher,
ContractUploadInstructions,
deployedHackatom,
fromOneElementArray,
getHackatom,
launchpad,
launchpadEnabled,
makeRandomAddress,
pendingWithoutLaunchpad,
} from "../testutils.spec";
import { setupWasmExtension, WasmExtension } from "./wasm";
type WasmClient = LcdClient & AuthExtension & WasmExtension;
function makeWasmClient(apiUrl: string): WasmClient {
return LcdClient.withExtensions({ apiUrl }, setupAuthExtension, setupWasmExtension);
}
async function uploadContract(
signer: OfflineSigner,
contract: ContractUploadInstructions,
): Promise<BroadcastTxResult> {
const memo = "My first contract on chain";
const theMsg: MsgStoreCode = {
type: "wasm/MsgStoreCode",
value: {
sender: alice.address0,
wasm_byte_code: toBase64(contract.data),
source: contract.source || "",
builder: contract.builder || "",
},
};
const fee: StdFee = {
amount: coins(5000000, "ucosm"),
gas: "89000000",
};
const firstAddress = (await signer.getAccounts())[0].address;
const client = new SigningCosmosClient(launchpad.endpoint, firstAddress, signer);
return client.signAndBroadcast([theMsg], fee, memo);
}
async function instantiateContract(
signer: OfflineSigner,
codeId: number,
beneficiaryAddress: string,
funds?: readonly Coin[],
): Promise<BroadcastTxResult> {
const memo = "Create an escrow instance";
const theMsg: MsgInstantiateContract = {
type: "wasm/MsgInstantiateContract",
value: {
sender: alice.address0,
code_id: codeId.toString(),
label: "my escrow",
init_msg: {
verifier: alice.address0,
beneficiary: beneficiaryAddress,
},
init_funds: funds || [],
},
};
const fee: StdFee = {
amount: coins(5000000, "ucosm"),
gas: "89000000",
};
const firstAddress = (await signer.getAccounts())[0].address;
const client = new SigningCosmosClient(launchpad.endpoint, firstAddress, signer);
return client.signAndBroadcast([theMsg], fee, memo);
}
async function executeContract(
client: WasmClient,
signer: OfflineSigner,
contractAddress: string,
msg: Record<string, unknown>,
): Promise<BroadcastTxsResponse> {
const memo = "Time for action";
const theMsg: MsgExecuteContract = {
type: "wasm/MsgExecuteContract",
value: {
sender: alice.address0,
contract: contractAddress,
msg: msg,
sent_funds: [],
},
};
const fee: StdFee = {
amount: coins(5000000, "ucosm"),
gas: "89000000",
};
const { account_number, sequence } = (await client.auth.account(alice.address0)).result.value;
const signDoc = makeSignDoc([theMsg], fee, launchpad.chainId, memo, account_number, sequence);
const { signed, signature } = await signer.signAmino(alice.address0, signDoc);
const signedTx = makeStdTx(signed, signature);
return client.broadcastTx(signedTx);
}
describe("WasmExtension", () => {
const hackatom = getHackatom();
const hackatomConfigKey = toAscii("config");
let hackatomCodeId: number | undefined;
let hackatomContractAddress: string | undefined;
beforeAll(async () => {
if (launchpadEnabled()) {
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const result = await uploadContract(wallet, hackatom);
assertIsBroadcastTxSuccess(result);
const parsedLogs = logs.parseLogs(result.logs);
const codeIdAttr = logs.findAttribute(parsedLogs, "message", "code_id");
hackatomCodeId = Number.parseInt(codeIdAttr.value, 10);
const instantiateResult = await instantiateContract(wallet, hackatomCodeId, makeRandomAddress());
assertIsBroadcastTxSuccess(instantiateResult);
const instantiateLogs = logs.parseLogs(instantiateResult.logs);
const contractAddressAttr = logs.findAttribute(instantiateLogs, "message", "contract_address");
hackatomContractAddress = contractAddressAttr.value;
}
});
describe("listCodeInfo", () => {
it("has recently uploaded contract as last entry", async () => {
pendingWithoutLaunchpad();
assert(hackatomCodeId);
const client = makeWasmClient(launchpad.endpoint);
const codesList = await client.wasm.listCodeInfo();
const lastCode = codesList[codesList.length - 1];
expect(lastCode.id).toEqual(hackatomCodeId);
expect(lastCode.creator).toEqual(alice.address0);
expect(lastCode.source).toEqual(hackatom.source);
expect(lastCode.builder).toEqual(hackatom.builder);
expect(lastCode.data_hash.toLowerCase()).toEqual(toHex(sha256(hackatom.data)));
});
});
describe("getCode", () => {
it("contains fill code information", async () => {
pendingWithoutLaunchpad();
assert(hackatomCodeId);
const client = makeWasmClient(launchpad.endpoint);
const code = await client.wasm.getCode(hackatomCodeId);
expect(code.id).toEqual(hackatomCodeId);
expect(code.creator).toEqual(alice.address0);
expect(code.source).toEqual(hackatom.source);
expect(code.builder).toEqual(hackatom.builder);
expect(code.data_hash.toLowerCase()).toEqual(toHex(sha256(hackatom.data)));
expect(code.data).toEqual(toBase64(hackatom.data));
});
});
// TODO: move listContractsByCodeId tests out of here
describe("getContractInfo", () => {
it("works", async () => {
pendingWithoutLaunchpad();
assert(hackatomCodeId);
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = makeWasmClient(launchpad.endpoint);
// create new instance and compare before and after
const existingContractsByCode = await client.wasm.listContractsByCodeId(hackatomCodeId);
for (const contract of existingContractsByCode) {
expect(contract.address).toMatch(bech32AddressMatcher);
expect(contract.code_id).toEqual(hackatomCodeId);
expect(contract.creator).toMatch(bech32AddressMatcher);
expect(contract.label).toMatch(/^.+$/);
}
const beneficiaryAddress = makeRandomAddress();
const funds = coins(707707, "ucosm");
const result = await instantiateContract(wallet, hackatomCodeId, beneficiaryAddress, funds);
assertIsBroadcastTxSuccess(result);
const parsedLogs = logs.parseLogs(result.logs);
const contractAddressAttr = logs.findAttribute(parsedLogs, "message", "contract_address");
const myAddress = contractAddressAttr.value;
const newContractsByCode = await client.wasm.listContractsByCodeId(hackatomCodeId);
expect(newContractsByCode.length).toEqual(existingContractsByCode.length + 1);
const newContract = newContractsByCode[newContractsByCode.length - 1];
expect(newContract).toEqual(
jasmine.objectContaining({
code_id: hackatomCodeId,
creator: alice.address0,
label: "my escrow",
}),
);
const info = await client.wasm.getContractInfo(myAddress);
assert(info);
expect(info).toEqual(
jasmine.objectContaining({
code_id: hackatomCodeId,
creator: alice.address0,
label: "my escrow",
}),
);
expect(info.admin).toBeUndefined();
});
it("returns null for non-existent address", async () => {
pendingWithoutLaunchpad();
assert(hackatomCodeId);
const client = makeWasmClient(launchpad.endpoint);
const nonExistentAddress = makeRandomAddress();
const info = await client.wasm.getContractInfo(nonExistentAddress);
expect(info).toBeNull();
});
});
describe("getContractCodeHistory", () => {
it("can list contract history", async () => {
pendingWithoutLaunchpad();
assert(hackatomCodeId);
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = makeWasmClient(launchpad.endpoint);
// create new instance and compare before and after
const beneficiaryAddress = makeRandomAddress();
const funds = coins(707707, "ucosm");
const result = await instantiateContract(wallet, hackatomCodeId, beneficiaryAddress, funds);
assertIsBroadcastTxSuccess(result);
const parsedLogs = logs.parseLogs(result.logs);
const contractAddressAttr = logs.findAttribute(parsedLogs, "message", "contract_address");
const myAddress = contractAddressAttr.value;
const history = await client.wasm.getContractCodeHistory(myAddress);
assert(history);
expect(history).toContain({
code_id: hackatomCodeId,
operation: "Init",
msg: {
verifier: alice.address0,
beneficiary: beneficiaryAddress,
},
});
});
it("returns null for non-existent address", async () => {
pendingWithoutLaunchpad();
assert(hackatomCodeId);
const client = makeWasmClient(launchpad.endpoint);
const nonExistentAddress = makeRandomAddress();
const history = await client.wasm.getContractCodeHistory(nonExistentAddress);
expect(history).toBeNull();
});
});
describe("getAllContractState", () => {
it("can get all state", async () => {
pendingWithoutLaunchpad();
assert(hackatomContractAddress);
const client = makeWasmClient(launchpad.endpoint);
const state = await client.wasm.getAllContractState(hackatomContractAddress);
expect(state.length).toEqual(1);
const data = state[0];
expect(data.key).toEqual(hackatomConfigKey);
const value = JSON.parse(fromUtf8(data.val));
expect(value.verifier).toMatch(base64Matcher);
expect(value.beneficiary).toMatch(base64Matcher);
});
it("is empty for non-existent address", async () => {
pendingWithoutLaunchpad();
const client = makeWasmClient(launchpad.endpoint);
const nonExistentAddress = makeRandomAddress();
const state = await client.wasm.getAllContractState(nonExistentAddress);
expect(state).toEqual([]);
});
});
describe("queryContractRaw", () => {
it("can query by key", async () => {
pendingWithoutLaunchpad();
assert(hackatomContractAddress);
const client = makeWasmClient(launchpad.endpoint);
const raw = await client.wasm.queryContractRaw(hackatomContractAddress, hackatomConfigKey);
assert(raw, "must get result");
const model = JSON.parse(fromAscii(raw));
expect(model.verifier).toMatch(base64Matcher);
expect(model.beneficiary).toMatch(base64Matcher);
});
it("returns null for missing key", async () => {
pendingWithoutLaunchpad();
assert(hackatomContractAddress);
const client = makeWasmClient(launchpad.endpoint);
const info = await client.wasm.queryContractRaw(hackatomContractAddress, fromHex("cafe0dad"));
expect(info).toBeNull();
});
it("returns null for non-existent address", async () => {
pendingWithoutLaunchpad();
const client = makeWasmClient(launchpad.endpoint);
const nonExistentAddress = makeRandomAddress();
const info = await client.wasm.queryContractRaw(nonExistentAddress, hackatomConfigKey);
expect(info).toBeNull();
});
});
describe("queryContractSmart", () => {
it("can make smart queries", async () => {
pendingWithoutLaunchpad();
assert(hackatomContractAddress);
const client = makeWasmClient(launchpad.endpoint);
const request = { verifier: {} };
const response = await client.wasm.queryContractSmart(hackatomContractAddress, request);
expect(response).toEqual({ verifier: alice.address0 });
});
it("throws for invalid query requests", async () => {
pendingWithoutLaunchpad();
assert(hackatomContractAddress);
const client = makeWasmClient(launchpad.endpoint);
const request = { nosuchkey: {} };
await client.wasm.queryContractSmart(hackatomContractAddress, request).then(
() => fail("shouldn't succeed"),
(error) =>
expect(error).toMatch(
/query wasm contract failed: Error parsing into type hackatom::contract::QueryMsg: unknown variant/,
),
);
});
it("throws for non-existent address", async () => {
pendingWithoutLaunchpad();
const client = makeWasmClient(launchpad.endpoint);
const nonExistentAddress = makeRandomAddress();
const request = { verifier: {} };
await client.wasm.queryContractSmart(nonExistentAddress, request).then(
() => fail("shouldn't succeed"),
(error) => expect(error).toMatch("not found"),
);
});
});
describe("txsQuery", () => {
it("can query by tags (module + code_id)", async () => {
pendingWithoutLaunchpad();
const client = makeWasmClient(launchpad.endpoint);
const result = await client.txsQuery(`message.module=wasm&message.code_id=${deployedHackatom.codeId}`);
expect(parseInt(result.count, 10)).toBeGreaterThanOrEqual(4);
// Check first 4 results
const [store, zero, one, two] = result.txs.map((tx) => fromOneElementArray(tx.tx.value.msg));
assert(isMsgStoreCode(store));
assert(isMsgInstantiateContract(zero));
assert(isMsgInstantiateContract(one));
assert(isMsgInstantiateContract(two));
expect(store.value).toEqual(
jasmine.objectContaining({
sender: alice.address0,
source: deployedHackatom.source,
builder: deployedHackatom.builder,
}),
);
expect(zero.value).toEqual({
code_id: deployedHackatom.codeId.toString(),
init_funds: [],
init_msg: jasmine.objectContaining({
beneficiary: deployedHackatom.instances[0].beneficiary,
}),
label: deployedHackatom.instances[0].label,
sender: alice.address0,
});
expect(one.value).toEqual({
code_id: deployedHackatom.codeId.toString(),
init_funds: [],
init_msg: jasmine.objectContaining({
beneficiary: deployedHackatom.instances[1].beneficiary,
}),
label: deployedHackatom.instances[1].label,
sender: alice.address0,
});
expect(two.value).toEqual({
code_id: deployedHackatom.codeId.toString(),
init_funds: [],
init_msg: jasmine.objectContaining({
beneficiary: deployedHackatom.instances[2].beneficiary,
}),
label: deployedHackatom.instances[2].label,
sender: alice.address0,
admin: alice.address1,
});
});
// Like previous test but filtered by message.action=store-code and message.action=instantiate
it("can query by tags (module + code_id + action)", async () => {
pendingWithoutLaunchpad();
const client = makeWasmClient(launchpad.endpoint);
{
const uploads = await client.txsQuery(
`message.module=wasm&message.code_id=${deployedHackatom.codeId}&message.action=store-code`,
);
expect(parseInt(uploads.count, 10)).toEqual(1);
const store = fromOneElementArray(uploads.txs[0].tx.value.msg);
assert(isMsgStoreCode(store));
expect(store.value).toEqual(
jasmine.objectContaining({
sender: alice.address0,
source: deployedHackatom.source,
builder: deployedHackatom.builder,
}),
);
}
{
const instantiations = await client.txsQuery(
`message.module=wasm&message.code_id=${deployedHackatom.codeId}&message.action=instantiate`,
);
expect(parseInt(instantiations.count, 10)).toBeGreaterThanOrEqual(3);
const [zero, one, two] = instantiations.txs.map((tx) => fromOneElementArray(tx.tx.value.msg));
assert(isMsgInstantiateContract(zero));
assert(isMsgInstantiateContract(one));
assert(isMsgInstantiateContract(two));
expect(zero.value).toEqual({
code_id: deployedHackatom.codeId.toString(),
init_funds: [],
init_msg: jasmine.objectContaining({
beneficiary: deployedHackatom.instances[0].beneficiary,
}),
label: deployedHackatom.instances[0].label,
sender: alice.address0,
});
expect(one.value).toEqual({
code_id: deployedHackatom.codeId.toString(),
init_funds: [],
init_msg: jasmine.objectContaining({
beneficiary: deployedHackatom.instances[1].beneficiary,
}),
label: deployedHackatom.instances[1].label,
sender: alice.address0,
});
expect(two.value).toEqual({
code_id: deployedHackatom.codeId.toString(),
init_funds: [],
init_msg: jasmine.objectContaining({
beneficiary: deployedHackatom.instances[2].beneficiary,
}),
label: deployedHackatom.instances[2].label,
sender: alice.address0,
admin: alice.address1,
});
}
});
});
describe("broadcastTx", () => {
it("can upload, instantiate and execute wasm", async () => {
pendingWithoutLaunchpad();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = makeWasmClient(launchpad.endpoint);
let codeId: number;
// upload
{
// console.log("Raw log:", result.raw_log);
const result = await uploadContract(wallet, getHackatom());
assertIsBroadcastTxSuccess(result);
const parsedLogs = logs.parseLogs(result.logs);
const codeIdAttr = logs.findAttribute(parsedLogs, "message", "code_id");
codeId = Number.parseInt(codeIdAttr.value, 10);
expect(codeId).toBeGreaterThanOrEqual(1);
expect(codeId).toBeLessThanOrEqual(200);
expect(result.data).toEqual(toAscii(`${codeId}`));
}
const funds = [coin(1234, "ucosm"), coin(321, "ustake")];
const beneficiaryAddress = makeRandomAddress();
let contractAddress: string;
// instantiate
{
const result = await instantiateContract(wallet, codeId, beneficiaryAddress, funds);
assertIsBroadcastTxSuccess(result);
// console.log("Raw log:", result.raw_log);
const parsedLogs = logs.parseLogs(result.logs);
const contractAddressAttr = logs.findAttribute(parsedLogs, "message", "contract_address");
contractAddress = contractAddressAttr.value;
const amountAttr = logs.findAttribute(parsedLogs, "transfer", "amount");
expect(amountAttr.value).toEqual("1234ucosm,321ustake");
expect(result.data).toEqual(Bech32.decode(contractAddress).data);
const balance = (await client.auth.account(contractAddress)).result.value.coins;
expect(balance).toEqual(funds);
}
// execute
{
const result = await executeContract(client, wallet, contractAddress, { release: {} });
assert(!result.code);
expect(result.data).toEqual("F00BAA");
// console.log("Raw log:", result.logs);
const parsedLogs = logs.parseLogs(result.logs);
const wasmEvent = parsedLogs.find(() => true)?.events.find((e) => e.type === "wasm");
assert(wasmEvent, "Event of type wasm expected");
expect(wasmEvent.attributes).toContain({ key: "action", value: "release" });
expect(wasmEvent.attributes).toContain({
key: "destination",
value: beneficiaryAddress,
});
// Verify token transfer from contract to beneficiary
const beneficiaryBalance = (await client.auth.account(beneficiaryAddress)).result.value.coins;
expect(beneficiaryBalance).toEqual(funds);
const contractBalance = (await client.auth.account(contractAddress)).result.value.coins;
expect(contractBalance).toEqual([]);
}
});
});
});

View File

@ -1,181 +0,0 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { fromBase64, fromUtf8, toHex, toUtf8 } from "@cosmjs/encoding";
import { LcdApiArray, LcdClient, normalizeLcdApiArray } from "@cosmjs/launchpad";
import { JsonObject, Model, parseWasmData, WasmData } from "../types";
type WasmResponse<T> = WasmSuccess<T> | WasmError;
interface WasmSuccess<T> {
readonly height: string;
readonly result: T;
}
interface WasmError {
readonly error: string;
}
export interface CodeInfo {
readonly id: number;
/** Bech32 account address */
readonly creator: string;
/** Hex-encoded sha256 hash of the code stored here */
readonly data_hash: string;
/**
* An URL to a .tar.gz archive of the source code of the contract, which can be used to reproducibly build the Wasm bytecode.
*
* @see https://github.com/CosmWasm/cosmwasm-verify
*/
readonly source?: string;
/**
* A docker image (including version) to reproducibly build the Wasm bytecode from the source code.
*
* @example ```cosmwasm/rust-optimizer:0.8.0```
* @see https://github.com/CosmWasm/cosmwasm-verify
*/
readonly builder?: string;
}
export interface CodeDetails extends CodeInfo {
/** Base64 encoded raw wasm data */
readonly data: string;
}
// This is list view, without contract info
export interface ContractInfo {
readonly address: string;
readonly code_id: number;
/** Bech32 account address */
readonly creator: string;
/** Bech32-encoded admin address */
readonly admin?: string;
readonly label: string;
}
// An entry in the contracts code/ migration history
export interface ContractCodeHistoryEntry {
/** The source of this history entry */
readonly operation: "Genesis" | "Init" | "Migrate";
readonly code_id: number;
readonly msg: Record<string, unknown>;
}
interface SmartQueryResponse {
// base64 encoded response
readonly smart: string;
}
function isWasmError<T>(resp: WasmResponse<T>): resp is WasmError {
return (resp as WasmError).error !== undefined;
}
function unwrapWasmResponse<T>(response: WasmResponse<T>): T {
if (isWasmError(response)) {
throw new Error(response.error);
}
return response.result;
}
/**
* @see https://github.com/cosmwasm/wasmd/blob/master/x/wasm/client/rest/query.go#L19-L27
*/
export interface WasmExtension {
readonly wasm: {
readonly listCodeInfo: () => Promise<readonly CodeInfo[]>;
/**
* Downloads the original wasm bytecode by code ID.
*
* Throws an error if no code with this id
*/
readonly getCode: (id: number) => Promise<CodeDetails>;
readonly listContractsByCodeId: (id: number) => Promise<readonly ContractInfo[]>;
/**
* Returns null when contract was not found at this address.
*/
readonly getContractInfo: (address: string) => Promise<ContractInfo | null>;
/**
* Returns null when contract history was not found for this address.
*/
readonly getContractCodeHistory: (address: string) => Promise<ContractCodeHistoryEntry[] | null>;
/**
* Returns all contract state.
* This is an empty array if no such contract, or contract has no data.
*/
readonly getAllContractState: (address: string) => Promise<readonly Model[]>;
/**
* Returns the data at the key if present (unknown decoded json),
* or null if no data at this (contract address, key) pair
*/
readonly queryContractRaw: (address: string, key: Uint8Array) => Promise<Uint8Array | null>;
/**
* Makes a smart query on the contract and parses the response as JSON.
* Throws error if no such contract exists, the query format is invalid or the response is invalid.
*/
readonly queryContractSmart: (address: string, query: Record<string, unknown>) => Promise<JsonObject>;
};
}
export function setupWasmExtension(base: LcdClient): WasmExtension {
return {
wasm: {
listCodeInfo: async () => {
const path = `/wasm/code`;
const responseData = (await base.get(path)) as WasmResponse<LcdApiArray<CodeInfo>>;
return normalizeLcdApiArray(unwrapWasmResponse(responseData));
},
getCode: async (id: number) => {
const path = `/wasm/code/${id}`;
const responseData = (await base.get(path)) as WasmResponse<CodeDetails>;
return unwrapWasmResponse(responseData);
},
listContractsByCodeId: async (id: number) => {
const path = `/wasm/code/${id}/contracts`;
const responseData = (await base.get(path)) as WasmResponse<LcdApiArray<ContractInfo>>;
return normalizeLcdApiArray(unwrapWasmResponse(responseData));
},
getContractInfo: async (address: string) => {
const path = `/wasm/contract/${address}`;
const response = (await base.get(path)) as WasmResponse<ContractInfo | null>;
return unwrapWasmResponse(response);
},
getContractCodeHistory: async (address: string) => {
const path = `/wasm/contract/${address}/history`;
const response = (await base.get(path)) as WasmResponse<ContractCodeHistoryEntry[] | null>;
return unwrapWasmResponse(response);
},
getAllContractState: async (address: string) => {
const path = `/wasm/contract/${address}/state`;
const responseData = (await base.get(path)) as WasmResponse<LcdApiArray<WasmData>>;
return normalizeLcdApiArray(unwrapWasmResponse(responseData)).map(parseWasmData);
},
queryContractRaw: async (address: string, key: Uint8Array) => {
const hexKey = toHex(key);
const path = `/wasm/contract/${address}/raw/${hexKey}?encoding=hex`;
const responseData = (await base.get(path)) as WasmResponse<WasmData[] | null | string>;
const data = unwrapWasmResponse(responseData);
if (Array.isArray(data)) {
// The CosmWasm 0.10 interface
return data.length === 0 ? null : fromBase64(data[0].val);
} else {
// The CosmWasm 0.11 interface
return !data ? null : fromBase64(data); // Yes, we cannot differentiate empty fields from non-existent fields :(
}
},
queryContractSmart: async (address: string, query: Record<string, unknown>) => {
const encoded = toHex(toUtf8(JSON.stringify(query)));
const path = `/wasm/contract/${address}/smart/${encoded}?encoding=hex`;
const responseData = (await base.get(path)) as WasmResponse<SmartQueryResponse>;
const result = unwrapWasmResponse(responseData);
// By convention, smart queries must return a valid JSON document (see https://github.com/CosmWasm/cosmwasm/issues/144)
return JSON.parse(fromUtf8(fromBase64(result.smart)));
},
},
};
}

View File

@ -1,146 +0,0 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { Coin, Msg } from "@cosmjs/launchpad";
// TODO: implement
/**
* @see https://github.com/CosmWasm/wasmd/blob/v0.10.0-alpha/x/wasm/internal/types/params.go#L68-L71
*/
export type AccessConfig = never;
/**
* Uploads Wasm code to the chain.
* A numeric, auto-incrementing code ID will be generated as a result of the execution of this message.
*
* @see https://github.com/CosmWasm/wasmd/blob/v0.10.0-alpha/x/wasm/internal/types/msg.go#L10-L20
*/
export interface MsgStoreCode extends Msg {
readonly type: "wasm/MsgStoreCode";
readonly value: {
/** Bech32 account address */
readonly sender: string;
/** Base64 encoded Wasm */
readonly wasm_byte_code: string;
/** A valid URI reference to the contract's source code. Can be empty. */
readonly source: string;
/** A docker tag. Can be empty. */
readonly builder: string;
readonly instantiate_permission?: AccessConfig;
};
}
export function isMsgStoreCode(msg: Msg): msg is MsgStoreCode {
return (msg as MsgStoreCode).type === "wasm/MsgStoreCode";
}
/**
* Creates an instance of contract that was uploaded before.
* This will trigger a call to the "init" export.
*
* @see https://github.com/CosmWasm/wasmd/blob/v0.9.0-alpha4/x/wasm/internal/types/msg.go#L104
*/
export interface MsgInstantiateContract extends Msg {
readonly type: "wasm/MsgInstantiateContract";
readonly value: {
/** Bech32 account address */
readonly sender: string;
/** ID of the Wasm code that was uploaded before */
readonly code_id: string;
/** Human-readable label for this contract */
readonly label: string;
/** Init message as JavaScript object */
readonly init_msg: any;
readonly init_funds: readonly Coin[];
/** Bech32-encoded admin address */
readonly admin?: string;
};
}
export function isMsgInstantiateContract(msg: Msg): msg is MsgInstantiateContract {
return (msg as MsgInstantiateContract).type === "wasm/MsgInstantiateContract";
}
/**
* Update the admin of a contract
*
* @see https://github.com/CosmWasm/wasmd/blob/v0.9.0-beta/x/wasm/internal/types/msg.go#L231
*/
export interface MsgUpdateAdmin extends Msg {
readonly type: "wasm/MsgUpdateAdmin";
readonly value: {
/** Bech32-encoded sender address. This must be the old admin. */
readonly sender: string;
/** Bech32-encoded contract address to be updated */
readonly contract: string;
/** Bech32-encoded address of the new admin */
readonly new_admin: string;
};
}
export function isMsgUpdateAdmin(msg: Msg): msg is MsgUpdateAdmin {
return (msg as MsgUpdateAdmin).type === "wasm/MsgUpdateAdmin";
}
/**
* Clears the admin of a contract, making it immutable.
*
* @see https://github.com/CosmWasm/wasmd/blob/v0.9.0-beta/x/wasm/internal/types/msg.go#L269
*/
export interface MsgClearAdmin extends Msg {
readonly type: "wasm/MsgClearAdmin";
readonly value: {
/** Bech32-encoded sender address. This must be the old admin. */
readonly sender: string;
/** Bech32-encoded contract address to be updated */
readonly contract: string;
};
}
export function isMsgClearAdmin(msg: Msg): msg is MsgClearAdmin {
return (msg as MsgClearAdmin).type === "wasm/MsgClearAdmin";
}
/**
* Execute a smart contract.
* This will trigger a call to the "handle" export.
*
* @see https://github.com/CosmWasm/wasmd/blob/v0.9.0-alpha4/x/wasm/internal/types/msg.go#L158
*/
export interface MsgExecuteContract extends Msg {
readonly type: "wasm/MsgExecuteContract";
readonly value: {
/** Bech32 account address */
readonly sender: string;
/** Bech32 account address */
readonly contract: string;
/** Handle message as JavaScript object */
readonly msg: any;
readonly sent_funds: readonly Coin[];
};
}
export function isMsgExecuteContract(msg: Msg): msg is MsgExecuteContract {
return (msg as MsgExecuteContract).type === "wasm/MsgExecuteContract";
}
/**
* Migrates a contract to a new Wasm code.
*
* @see https://github.com/CosmWasm/wasmd/blob/v0.9.0-alpha4/x/wasm/internal/types/msg.go#L195
*/
export interface MsgMigrateContract extends Msg {
readonly type: "wasm/MsgMigrateContract";
readonly value: {
/** Bech32 account address */
readonly sender: string;
/** Bech32 account address */
readonly contract: string;
/** The new code */
readonly code_id: string;
/** Migrate message as JavaScript object */
readonly msg: any;
};
}
export function isMsgMigrateContract(msg: Msg): msg is MsgMigrateContract {
return (msg as MsgMigrateContract).type === "wasm/MsgMigrateContract";
}

View File

@ -1,565 +0,0 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { sha256 } from "@cosmjs/crypto";
import { toHex } from "@cosmjs/encoding";
import {
assertIsBroadcastTxSuccess,
AuthExtension,
coin,
coins,
GasPrice,
LcdClient,
MsgDelegate,
Secp256k1HdWallet,
setupAuthExtension,
} from "@cosmjs/launchpad";
import { assert } from "@cosmjs/utils";
import { PrivateCosmWasmClient } from "./cosmwasmclient";
import { setupWasmExtension, WasmExtension } from "./lcdapi/wasm";
import { SigningCosmWasmClient, UploadMeta } from "./signingcosmwasmclient";
import {
alice,
getHackatom,
launchpad,
makeRandomAddress,
pendingWithoutLaunchpad,
unused,
} from "./testutils.spec";
function makeWasmClient(apiUrl: string): LcdClient & AuthExtension & WasmExtension {
return LcdClient.withExtensions({ apiUrl }, setupAuthExtension, setupWasmExtension);
}
describe("SigningCosmWasmClient", () => {
describe("makeReadOnly", () => {
it("can be constructed", async () => {
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new SigningCosmWasmClient(launchpad.endpoint, alice.address0, wallet);
expect(client).toBeTruthy();
});
it("can be constructed with custom gas price", async () => {
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const gasPrice = GasPrice.fromString("3.14utest");
const client = new SigningCosmWasmClient(launchpad.endpoint, alice.address0, wallet, gasPrice);
expect(client.fees).toEqual({
upload: {
amount: [
{
amount: "4710000",
denom: "utest",
},
],
gas: "1500000",
},
init: {
amount: [
{
amount: "1570000",
denom: "utest",
},
],
gas: "500000",
},
migrate: {
amount: [
{
amount: "628000",
denom: "utest",
},
],
gas: "200000",
},
exec: {
amount: [
{
amount: "628000",
denom: "utest",
},
],
gas: "200000",
},
send: {
amount: [
{
amount: "251200",
denom: "utest",
},
],
gas: "80000",
},
changeAdmin: {
amount: [
{
amount: "251200",
denom: "utest",
},
],
gas: "80000",
},
});
});
it("can be constructed with custom gas limits", async () => {
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const gasLimits = {
send: 160000,
};
const client = new SigningCosmWasmClient(
launchpad.endpoint,
alice.address0,
wallet,
undefined,
gasLimits,
);
expect(client.fees).toEqual({
upload: {
amount: [
{
amount: "37500",
denom: "ucosm",
},
],
gas: "1500000",
},
init: {
amount: [
{
amount: "12500",
denom: "ucosm",
},
],
gas: "500000",
},
migrate: {
amount: [
{
amount: "5000",
denom: "ucosm",
},
],
gas: "200000",
},
exec: {
amount: [
{
amount: "5000",
denom: "ucosm",
},
],
gas: "200000",
},
send: {
amount: [
{
amount: "4000",
denom: "ucosm",
},
],
gas: "160000",
},
changeAdmin: {
amount: [
{
amount: "2000",
denom: "ucosm",
},
],
gas: "80000",
},
});
});
it("can be constructed with custom gas price and gas limits", async () => {
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const gasPrice = GasPrice.fromString("3.14utest");
const gasLimits = {
send: 160000,
};
const client = new SigningCosmWasmClient(
launchpad.endpoint,
alice.address0,
wallet,
gasPrice,
gasLimits,
);
expect(client.fees).toEqual({
upload: {
amount: [
{
amount: "4710000",
denom: "utest",
},
],
gas: "1500000",
},
init: {
amount: [
{
amount: "1570000",
denom: "utest",
},
],
gas: "500000",
},
migrate: {
amount: [
{
amount: "628000",
denom: "utest",
},
],
gas: "200000",
},
exec: {
amount: [
{
amount: "628000",
denom: "utest",
},
],
gas: "200000",
},
send: {
amount: [
{
amount: "502400",
denom: "utest",
},
],
gas: "160000",
},
changeAdmin: {
amount: [
{
amount: "251200",
denom: "utest",
},
],
gas: "80000",
},
});
});
});
describe("getHeight", () => {
it("always uses authAccount implementation", async () => {
pendingWithoutLaunchpad();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new SigningCosmWasmClient(launchpad.endpoint, alice.address0, wallet);
const openedClient = client as unknown as PrivateCosmWasmClient;
const blockLatestSpy = spyOn(openedClient.lcdClient, "blocksLatest").and.callThrough();
const authAccountsSpy = spyOn(openedClient.lcdClient.auth, "account").and.callThrough();
const height = await client.getHeight();
expect(height).toBeGreaterThan(0);
expect(blockLatestSpy).toHaveBeenCalledTimes(0);
expect(authAccountsSpy).toHaveBeenCalledTimes(1);
});
});
describe("upload", () => {
it("works", async () => {
pendingWithoutLaunchpad();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new SigningCosmWasmClient(launchpad.endpoint, alice.address0, wallet);
const wasm = getHackatom().data;
const { codeId, originalChecksum, originalSize, compressedChecksum, compressedSize } =
await client.upload(wasm);
expect(originalChecksum).toEqual(toHex(sha256(wasm)));
expect(originalSize).toEqual(wasm.length);
expect(compressedChecksum).toMatch(/^[0-9a-f]{64}$/);
expect(compressedSize).toBeLessThan(wasm.length * 0.5);
expect(codeId).toBeGreaterThanOrEqual(1);
});
it("can set builder and source", async () => {
pendingWithoutLaunchpad();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new SigningCosmWasmClient(launchpad.endpoint, alice.address0, wallet);
const hackatom = getHackatom();
const meta: UploadMeta = {
source: "https://crates.io/api/v1/crates/cw-nameservice/0.1.0/download",
builder: "confio/cosmwasm-opt:0.6.2",
};
const { codeId } = await client.upload(hackatom.data, meta);
const codeDetails = await client.getCodeDetails(codeId);
expect(codeDetails.source).toEqual(meta.source);
expect(codeDetails.builder).toEqual(meta.builder);
});
});
describe("instantiate", () => {
it("works with transfer amount", async () => {
pendingWithoutLaunchpad();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new SigningCosmWasmClient(launchpad.endpoint, alice.address0, wallet);
const { codeId } = await client.upload(getHackatom().data);
const funds = [coin(1234, "ucosm"), coin(321, "ustake")];
const beneficiaryAddress = makeRandomAddress();
const { contractAddress } = await client.instantiate(
codeId,
{
verifier: alice.address0,
beneficiary: beneficiaryAddress,
},
"My cool label",
{
memo: "Let's see if the memo is used",
funds: funds,
},
);
const lcdClient = makeWasmClient(launchpad.endpoint);
const balance = (await lcdClient.auth.account(contractAddress)).result.value.coins;
expect(balance).toEqual(funds);
});
it("works with admin", async () => {
pendingWithoutLaunchpad();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new SigningCosmWasmClient(launchpad.endpoint, alice.address0, wallet);
const { codeId } = await client.upload(getHackatom().data);
const beneficiaryAddress = makeRandomAddress();
const { contractAddress } = await client.instantiate(
codeId,
{
verifier: alice.address0,
beneficiary: beneficiaryAddress,
},
"My cool label",
{ admin: unused.address },
);
const lcdClient = makeWasmClient(launchpad.endpoint);
const contract = await lcdClient.wasm.getContractInfo(contractAddress);
assert(contract);
expect(contract.admin).toEqual(unused.address);
});
it("can instantiate one code multiple times", async () => {
pendingWithoutLaunchpad();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new SigningCosmWasmClient(launchpad.endpoint, alice.address0, wallet);
const { codeId } = await client.upload(getHackatom().data);
const contractAddress1 = await client.instantiate(
codeId,
{
verifier: alice.address0,
beneficiary: makeRandomAddress(),
},
"contract 1",
);
const contractAddress2 = await client.instantiate(
codeId,
{
verifier: alice.address0,
beneficiary: makeRandomAddress(),
},
"contract 2",
);
expect(contractAddress1).not.toEqual(contractAddress2);
});
});
describe("updateAdmin", () => {
it("can update an admin", async () => {
pendingWithoutLaunchpad();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new SigningCosmWasmClient(launchpad.endpoint, alice.address0, wallet);
const { codeId } = await client.upload(getHackatom().data);
const beneficiaryAddress = makeRandomAddress();
const { contractAddress } = await client.instantiate(
codeId,
{
verifier: alice.address0,
beneficiary: beneficiaryAddress,
},
"My cool label",
{
admin: alice.address0,
},
);
const lcdClient = makeWasmClient(launchpad.endpoint);
const state1 = await lcdClient.wasm.getContractInfo(contractAddress);
assert(state1);
expect(state1.admin).toEqual(alice.address0);
await client.updateAdmin(contractAddress, unused.address);
const state2 = await lcdClient.wasm.getContractInfo(contractAddress);
assert(state2);
expect(state2.admin).toEqual(unused.address);
});
});
describe("clearAdmin", () => {
it("can clear an admin", async () => {
pendingWithoutLaunchpad();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new SigningCosmWasmClient(launchpad.endpoint, alice.address0, wallet);
const { codeId } = await client.upload(getHackatom().data);
const beneficiaryAddress = makeRandomAddress();
const { contractAddress } = await client.instantiate(
codeId,
{
verifier: alice.address0,
beneficiary: beneficiaryAddress,
},
"My cool label",
{
admin: alice.address0,
},
);
const lcdClient = makeWasmClient(launchpad.endpoint);
const state1 = await lcdClient.wasm.getContractInfo(contractAddress);
assert(state1);
expect(state1.admin).toEqual(alice.address0);
await client.clearAdmin(contractAddress);
const state2 = await lcdClient.wasm.getContractInfo(contractAddress);
assert(state2);
expect(state2.admin).toBeUndefined();
});
});
describe("migrate", () => {
it("can can migrate from one code ID to another", async () => {
pendingWithoutLaunchpad();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new SigningCosmWasmClient(launchpad.endpoint, alice.address0, wallet);
const { codeId: codeId1 } = await client.upload(getHackatom().data);
const { codeId: codeId2 } = await client.upload(getHackatom().data);
const beneficiaryAddress = makeRandomAddress();
const { contractAddress } = await client.instantiate(
codeId1,
{
verifier: alice.address0,
beneficiary: beneficiaryAddress,
},
"My cool label",
{
admin: alice.address0,
},
);
const lcdClient = makeWasmClient(launchpad.endpoint);
const state1 = await lcdClient.wasm.getContractInfo(contractAddress);
assert(state1);
expect(state1.admin).toEqual(alice.address0);
const newVerifier = makeRandomAddress();
await client.migrate(contractAddress, codeId2, { verifier: newVerifier });
const state2 = await lcdClient.wasm.getContractInfo(contractAddress);
assert(state2);
expect(state2).toEqual({
...state1,
code_id: codeId2,
});
});
});
describe("execute", () => {
it("works", async () => {
pendingWithoutLaunchpad();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new SigningCosmWasmClient(launchpad.endpoint, alice.address0, wallet);
const { codeId } = await client.upload(getHackatom().data);
// instantiate
const funds = [coin(233444, "ucosm"), coin(5454, "ustake")];
const beneficiaryAddress = makeRandomAddress();
const { contractAddress } = await client.instantiate(
codeId,
{
verifier: alice.address0,
beneficiary: beneficiaryAddress,
},
"amazing random contract",
{
funds: funds,
},
);
// execute
const result = await client.execute(contractAddress, { release: {} }, undefined);
const wasmEvent = result.logs.find(() => true)?.events.find((e) => e.type === "wasm");
assert(wasmEvent, "Event of type wasm expected");
expect(wasmEvent.attributes).toContain({ key: "action", value: "release" });
expect(wasmEvent.attributes).toContain({
key: "destination",
value: beneficiaryAddress,
});
// Verify token transfer from contract to beneficiary
const lcdClient = makeWasmClient(launchpad.endpoint);
const beneficiaryBalance = (await lcdClient.auth.account(beneficiaryAddress)).result.value.coins;
expect(beneficiaryBalance).toEqual(funds);
const contractBalance = (await lcdClient.auth.account(contractAddress)).result.value.coins;
expect(contractBalance).toEqual([]);
});
});
describe("sendTokens", () => {
it("works", async () => {
pendingWithoutLaunchpad();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new SigningCosmWasmClient(launchpad.endpoint, alice.address0, wallet);
const amount = coins(7890, "ucosm");
const beneficiaryAddress = makeRandomAddress();
// no tokens here
const before = await client.getAccount(beneficiaryAddress);
expect(before).toBeUndefined();
// send
const result = await client.sendTokens(beneficiaryAddress, amount, "for dinner");
assertIsBroadcastTxSuccess(result);
const [firstLog] = result.logs;
expect(firstLog).toBeTruthy();
// got tokens
const after = await client.getAccount(beneficiaryAddress);
assert(after);
expect(after.balance).toEqual(amount);
});
});
describe("signAndBroadcast", () => {
it("works", async () => {
pendingWithoutLaunchpad();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
const client = new SigningCosmWasmClient(launchpad.endpoint, alice.address0, wallet);
const msg: MsgDelegate = {
type: "cosmos-sdk/MsgDelegate",
value: {
delegator_address: alice.address0,
validator_address: launchpad.validator.address,
amount: coin(1234, "ustake"),
},
};
const fee = {
amount: coins(2000, "ucosm"),
gas: "180000", // 180k
};
const result = await client.signAndBroadcast([msg], fee, "Use your power wisely");
assertIsBroadcastTxSuccess(result);
});
});
});

View File

@ -1,370 +0,0 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { sha256 } from "@cosmjs/crypto";
import { toBase64, toHex } from "@cosmjs/encoding";
import {
BroadcastMode,
BroadcastTxFailure,
BroadcastTxResult,
buildFeeTable,
Coin,
CosmosFeeTable,
GasLimits,
GasPrice,
isBroadcastTxFailure,
logs,
makeSignDoc,
makeStdTx,
Msg,
MsgSend,
OfflineSigner,
StdFee,
} from "@cosmjs/launchpad";
import { Uint53 } from "@cosmjs/math";
import pako from "pako";
import { isValidBuilder } from "./builder";
import { Account, CosmWasmClient, GetSequenceResult } from "./cosmwasmclient";
import {
MsgClearAdmin,
MsgExecuteContract,
MsgInstantiateContract,
MsgMigrateContract,
MsgStoreCode,
MsgUpdateAdmin,
} from "./msgs";
/**
* These fees are used by the higher level methods of SigningCosmWasmClient
*/
export interface CosmWasmFeeTable extends CosmosFeeTable {
readonly upload: StdFee;
readonly init: StdFee;
readonly exec: StdFee;
readonly migrate: StdFee;
/** Paid when setting the contract admin to a new address or unsetting it */
readonly changeAdmin: StdFee;
}
function prepareBuilder(builder: string | undefined): string {
if (builder === undefined) {
return ""; // normalization needed by backend
} else {
if (!isValidBuilder(builder)) throw new Error("The builder (Docker Hub image with tag) is not valid");
return builder;
}
}
const defaultGasPrice = GasPrice.fromString("0.025ucosm");
const defaultGasLimits: GasLimits<CosmWasmFeeTable> = {
upload: 1_500_000,
init: 500_000,
migrate: 200_000,
exec: 200_000,
send: 80_000,
changeAdmin: 80_000,
};
export interface UploadMeta {
/**
* An URL to a .tar.gz archive of the source code of the contract, which can be used to reproducibly build the Wasm bytecode.
*
* @see https://github.com/CosmWasm/cosmwasm-verify
*/
readonly source?: string;
/**
* A docker image (including version) to reproducibly build the Wasm bytecode from the source code.
*
* @example ```cosmwasm/rust-optimizer:0.8.0```
* @see https://github.com/CosmWasm/cosmwasm-verify
*/
readonly builder?: string;
}
export interface UploadResult {
/** Size of the original wasm code in bytes */
readonly originalSize: number;
/** A hex encoded sha256 checksum of the original wasm code (that is stored on chain) */
readonly originalChecksum: string;
/** Size of the compressed wasm code in bytes */
readonly compressedSize: number;
/** A hex encoded sha256 checksum of the compressed wasm code (that stored in the transaction) */
readonly compressedChecksum: string;
/** The ID of the code asigned by the chain */
readonly codeId: number;
readonly logs: readonly logs.Log[];
/** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */
readonly transactionHash: string;
}
/**
* The options of an .instantiate() call.
* All properties are optional.
*/
export interface InstantiateOptions {
readonly memo?: string;
/**
* The funds that are transferred from the sender to the newly created contract.
* The funds are transferred as part of the message execution after the contract address is
* created and before the instantiation message is executed by the contract.
*
* Only native tokens are supported.
*/
readonly funds?: readonly Coin[];
/**
* A bech32 encoded address of an admin account.
* Caution: an admin has the privilege to upgrade a contract. If this is not desired, do not set this value.
*/
readonly admin?: string;
}
export interface InstantiateResult {
/** The address of the newly instantiated contract */
readonly contractAddress: string;
readonly logs: readonly logs.Log[];
/** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */
readonly transactionHash: string;
}
/**
* Result type of updateAdmin and clearAdmin
*/
export interface ChangeAdminResult {
readonly logs: readonly logs.Log[];
/** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */
readonly transactionHash: string;
}
export interface MigrateResult {
readonly logs: readonly logs.Log[];
/** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */
readonly transactionHash: string;
}
export interface ExecuteResult {
readonly logs: readonly logs.Log[];
/** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */
readonly transactionHash: string;
}
function createBroadcastTxErrorMessage(result: BroadcastTxFailure): string {
return `Error when broadcasting tx ${result.transactionHash} at height ${result.height}. Code: ${result.code}; Raw log: ${result.rawLog}`;
}
export class SigningCosmWasmClient extends CosmWasmClient {
public readonly fees: CosmWasmFeeTable;
public readonly signerAddress: string;
private readonly signer: OfflineSigner;
/**
* Creates a new client with signing capability to interact with a CosmWasm blockchain. This is the bigger brother of CosmWasmClient.
*
* This instance does a lot of caching. In order to benefit from that you should try to use one instance
* for the lifetime of your application. When switching backends, a new instance must be created.
*
* @param apiUrl The URL of a Cosmos SDK light client daemon API (sometimes called REST server or REST API)
* @param signerAddress The address that will sign transactions using this instance. The `signer` must be able to sign with this address.
* @param signer An implementation of OfflineSigner which can provide signatures for transactions, potentially requiring user input.
* @param gasPrice The price paid per unit of gas
* @param gasLimits Custom overrides for gas limits related to specific transaction types
* @param broadcastMode Defines at which point of the transaction processing the broadcastTx method returns
*/
public constructor(
apiUrl: string,
signerAddress: string,
signer: OfflineSigner,
gasPrice: GasPrice = defaultGasPrice,
gasLimits: Partial<GasLimits<CosmWasmFeeTable>> = {},
broadcastMode = BroadcastMode.Block,
) {
super(apiUrl, broadcastMode);
this.anyValidAddress = signerAddress;
this.signerAddress = signerAddress;
this.signer = signer;
this.fees = buildFeeTable<CosmWasmFeeTable>(gasPrice, defaultGasLimits, gasLimits);
}
public override async getSequence(address?: string): Promise<GetSequenceResult> {
return super.getSequence(address || this.signerAddress);
}
public override async getAccount(address?: string): Promise<Account | undefined> {
return super.getAccount(address || this.signerAddress);
}
/** Uploads code and returns a receipt, including the code ID */
public async upload(wasmCode: Uint8Array, meta: UploadMeta = {}, memo = ""): Promise<UploadResult> {
const source = meta.source || "";
const builder = prepareBuilder(meta.builder);
const compressed = pako.gzip(wasmCode, { level: 9 });
const storeCodeMsg: MsgStoreCode = {
type: "wasm/MsgStoreCode",
value: {
sender: this.signerAddress,
wasm_byte_code: toBase64(compressed),
source: source,
builder: builder,
},
};
const result = await this.signAndBroadcast([storeCodeMsg], this.fees.upload, memo);
if (isBroadcastTxFailure(result)) {
throw new Error(createBroadcastTxErrorMessage(result));
}
const codeIdAttr = logs.findAttribute(result.logs, "message", "code_id");
return {
originalSize: wasmCode.length,
originalChecksum: toHex(sha256(wasmCode)),
compressedSize: compressed.length,
compressedChecksum: toHex(sha256(compressed)),
codeId: Number.parseInt(codeIdAttr.value, 10),
logs: result.logs,
transactionHash: result.transactionHash,
};
}
public async instantiate(
codeId: number,
msg: Record<string, unknown>,
label: string,
options: InstantiateOptions = {},
): Promise<InstantiateResult> {
const instantiateMsg: MsgInstantiateContract = {
type: "wasm/MsgInstantiateContract",
value: {
sender: this.signerAddress,
code_id: new Uint53(codeId).toString(),
label: label,
init_msg: msg,
init_funds: options.funds || [],
admin: options.admin,
},
};
const result = await this.signAndBroadcast([instantiateMsg], this.fees.init, options.memo);
if (isBroadcastTxFailure(result)) {
throw new Error(createBroadcastTxErrorMessage(result));
}
const contractAddressAttr = logs.findAttribute(result.logs, "message", "contract_address");
return {
contractAddress: contractAddressAttr.value,
logs: result.logs,
transactionHash: result.transactionHash,
};
}
public async updateAdmin(contractAddress: string, newAdmin: string, memo = ""): Promise<ChangeAdminResult> {
const updateAdminMsg: MsgUpdateAdmin = {
type: "wasm/MsgUpdateAdmin",
value: {
sender: this.signerAddress,
contract: contractAddress,
new_admin: newAdmin,
},
};
const result = await this.signAndBroadcast([updateAdminMsg], this.fees.changeAdmin, memo);
if (isBroadcastTxFailure(result)) {
throw new Error(createBroadcastTxErrorMessage(result));
}
return {
logs: result.logs,
transactionHash: result.transactionHash,
};
}
public async clearAdmin(contractAddress: string, memo = ""): Promise<ChangeAdminResult> {
const clearAdminMsg: MsgClearAdmin = {
type: "wasm/MsgClearAdmin",
value: {
sender: this.signerAddress,
contract: contractAddress,
},
};
const result = await this.signAndBroadcast([clearAdminMsg], this.fees.changeAdmin, memo);
if (isBroadcastTxFailure(result)) {
throw new Error(createBroadcastTxErrorMessage(result));
}
return {
logs: result.logs,
transactionHash: result.transactionHash,
};
}
public async migrate(
contractAddress: string,
codeId: number,
migrateMsg: Record<string, unknown>,
memo = "",
): Promise<MigrateResult> {
const msg: MsgMigrateContract = {
type: "wasm/MsgMigrateContract",
value: {
sender: this.signerAddress,
contract: contractAddress,
code_id: new Uint53(codeId).toString(),
msg: migrateMsg,
},
};
const result = await this.signAndBroadcast([msg], this.fees.migrate, memo);
if (isBroadcastTxFailure(result)) {
throw new Error(createBroadcastTxErrorMessage(result));
}
return {
logs: result.logs,
transactionHash: result.transactionHash,
};
}
public async execute(
contractAddress: string,
msg: Record<string, unknown>,
memo = "",
funds?: readonly Coin[],
): Promise<ExecuteResult> {
const executeMsg: MsgExecuteContract = {
type: "wasm/MsgExecuteContract",
value: {
sender: this.signerAddress,
contract: contractAddress,
msg: msg,
sent_funds: funds || [],
},
};
const result = await this.signAndBroadcast([executeMsg], this.fees.exec, memo);
if (isBroadcastTxFailure(result)) {
throw new Error(createBroadcastTxErrorMessage(result));
}
return {
logs: result.logs,
transactionHash: result.transactionHash,
};
}
public async sendTokens(
recipientAddress: string,
amount: readonly Coin[],
memo = "",
): Promise<BroadcastTxResult> {
const sendMsg: MsgSend = {
type: "cosmos-sdk/MsgSend",
value: {
from_address: this.signerAddress,
to_address: recipientAddress,
amount: amount,
},
};
return this.signAndBroadcast([sendMsg], this.fees.send, memo);
}
/**
* Gets account number and sequence from the API, creates a sign doc,
* creates a single signature, assembles the signed transaction and broadcasts it.
*/
public async signAndBroadcast(msgs: readonly Msg[], fee: StdFee, memo = ""): Promise<BroadcastTxResult> {
const { accountNumber, sequence } = await this.getSequence();
const chainId = await this.getChainId();
const signDoc = makeSignDoc(msgs, fee, chainId, memo, accountNumber, sequence);
const { signed, signature } = await this.signer.signAmino(this.signerAddress, signDoc);
const signedTx = makeStdTx(signed, signature);
return this.broadcastTx(signedTx);
}
}

File diff suppressed because one or more lines are too long

View File

@ -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"
}

View File

@ -1,167 +0,0 @@
import { Random } from "@cosmjs/crypto";
import { Bech32, fromBase64 } from "@cosmjs/encoding";
import hackatom from "./testdata/contract.json";
/** An internal testing type. SigningCosmWasmClient has a similar but different interface */
export interface ContractUploadInstructions {
/** The wasm bytecode */
readonly data: Uint8Array;
readonly source?: string;
readonly builder?: string;
}
export function getHackatom(): ContractUploadInstructions {
return {
data: fromBase64(hackatom.data),
source: "https://some.registry.nice/project/raw/0.7/lib/vm/testdata/contract_0.6.wasm.blub.tar.gz",
builder: "confio/cosmwasm-opt:12.34.56",
};
}
export function makeRandomAddress(): string {
return Bech32.encode("cosmos", Random.getBytes(20));
}
export const tendermintIdMatcher = /^[0-9A-F]{64}$/;
/** @see https://rgxdb.com/r/1NUN74O6 */
export const base64Matcher =
/^(?:[a-zA-Z0-9+/]{4})*(?:|(?:[a-zA-Z0-9+/]{3}=)|(?:[a-zA-Z0-9+/]{2}==)|(?:[a-zA-Z0-9+/]{1}===))$/;
// https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32
export const bech32AddressMatcher = /^[\x21-\x7e]{1,83}1[02-9ac-hj-np-z]{38}$/;
export const alice = {
mnemonic: "enlist hip relief stomach skate base shallow young switch frequent cry park",
pubkey0: {
type: "tendermint/PubKeySecp256k1",
value: "A9cXhWb8ZpqCzkA8dQCPV29KdeRLV3rUYxrkHudLbQtS",
},
address0: "cosmos14qemq0vw6y3gc3u3e0aty2e764u4gs5le3hada",
address1: "cosmos1hhg2rlu9jscacku2wwckws7932qqqu8x3gfgw0",
address2: "cosmos1xv9tklw7d82sezh9haa573wufgy59vmwe6xxe5",
address3: "cosmos17yg9mssjenmc3jkqth6ulcwj9cxujrxxzezwta",
address4: "cosmos1f7j7ryulwjfe9ljplvhtcaxa6wqgula3etktce",
};
/** Unused account */
export const unused = {
pubkey: {
type: "tendermint/PubKeySecp256k1",
value: "ArkCaFUJ/IH+vKBmNRCdUVl3mCAhbopk9jjW4Ko4OfRQ",
},
address: "cosmos1cjsxept9rkggzxztslae9ndgpdyt2408lk850u",
accountNumber: 19,
sequence: 0,
};
/** Deployed as part of scripts/launchpad/init.sh */
export const deployedHackatom = {
codeId: 1,
source: "https://crates.io/api/v1/crates/hackatom/not-yet-released/download",
builder: "cosmwasm/rust-optimizer:0.9.1",
checksum: "3defc33a41f58c71d38b176d521c411d8e74d26403fde7660486930c7579a016",
instances: [
{
beneficiary: alice.address0,
address: "cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5",
label: "From deploy_hackatom.js (0)",
},
{
beneficiary: alice.address1,
address: "cosmos1hqrdl6wstt8qzshwc6mrumpjk9338k0lr4dqxd",
label: "From deploy_hackatom.js (1)",
},
{
beneficiary: alice.address2,
address: "cosmos18r5szma8hm93pvx6lwpjwyxruw27e0k5uw835c",
label: "From deploy_hackatom.js (2)",
},
],
};
/** Deployed as part of scripts/launchpad/init.sh */
export const deployedErc20 = {
codeId: 2,
source: "https://crates.io/api/v1/crates/cw-erc20/0.7.0/download",
builder: "cosmwasm/rust-optimizer:0.10.4",
checksum: "d04368320ad55089384adb171aaea39e43d710d7608829adba0300ed30aa2988",
instances: [
"cosmos1vjecguu37pmd577339wrdp208ddzymkudc46zj", // HASH
"cosmos1ym5m5dw7pttft5w430nxx6uat8f84ck4algmhg", // ISA
"cosmos1gv07846a3867ezn3uqkk082c5ftke7hpllcu8q", // JADE
],
};
/** Deployed as part of scripts/launchpad/init.sh */
export const deployedCw3 = {
codeId: 3,
source: "https://crates.io/api/v1/crates/cw3-fixed-multisig/0.3.1/download",
builder: "cosmwasm/rust-optimizer:0.10.4",
instances: [
"cosmos1xqeym28j9xgv0p93pwwt6qcxf9tdvf9zddufdw", // Multisig (1/3)
"cosmos1jka38ckju8cpjap00jf9xdvdyttz9caujtd6t5", // Multisig (2/3)
"cosmos12dnl585uxzddjw9hw4ca694f054shgpgr4zg80", // Multisig (uneven weights)
],
};
/** Deployed as part of scripts/launchpad/init.sh */
export const deployedCw1 = {
codeId: 4,
source: "https://crates.io/api/v1/crates/cw1-subkeys/0.3.1/download",
builder: "cosmwasm/rust-optimizer:0.10.4",
instances: ["cosmos1vs2vuks65rq7xj78mwtvn7vvnm2gn7ad5me0d2"],
};
export const launchpad = {
endpoint: "http://localhost:1317",
chainId: "testing",
validator: {
address: "cosmosvaloper1yfkkk04ve8a0sugj4fe6q6zxuvmvza8r3arurr",
},
};
export function launchpadEnabled(): boolean {
return !!process.env.LAUNCHPAD_ENABLED;
}
export function pendingWithoutLaunchpad(): void {
if (!launchpadEnabled()) {
return pending("Set LAUNCHPAD_ENABLED to enable Launchpad-based tests");
}
}
export function erc20Enabled(): boolean {
return !!process.env.ERC20_ENABLED;
}
export function pendingWithoutErc20(): void {
if (!erc20Enabled()) {
return pending("Set ERC20_ENABLED to enable ERC20-based tests");
}
}
export function cw3Enabled(): boolean {
return !!process.env.CW3_ENABLED;
}
export function pendingWithoutCw3(): void {
if (!cw3Enabled()) {
return pending("Set CW3_ENABLED to enable CW3-based tests");
}
}
export function cw1Enabled(): boolean {
return !!process.env.CW1_ENABLED;
}
export function pendingWithoutCw1(): void {
if (!cw1Enabled()) {
return pending("Set CW1_ENABLED to enable CW1-based tests");
}
}
/** Returns first element. Throws if array has a different length than 1. */
export function fromOneElementArray<T>(elements: ArrayLike<T>): T {
if (elements.length !== 1) throw new Error(`Expected exactly one element but got ${elements.length}`);
return elements[0];
}

View File

@ -1,27 +0,0 @@
import { fromBase64, fromHex } from "@cosmjs/encoding";
export interface WasmData {
// key is hex-encoded
readonly key: string;
// value is base64 encoded
readonly val: string;
}
// Model is a parsed WasmData object
export interface Model {
readonly key: Uint8Array;
readonly val: Uint8Array;
}
export function parseWasmData({ key, val }: WasmData): Model {
return {
key: fromHex(key),
val: fromBase64(val),
};
}
/**
* An object containing a parsed JSON document. The result of JSON.parse().
* This doesn't provide any type safety over `any` but expresses intent in the code.
*/
export type JsonObject = any;

View File

@ -1,9 +0,0 @@
{
// extend your base config so you don't have to redefine your compilerOptions
"extends": "./tsconfig.json",
"include": [
"src/**/*",
"*.js",
".eslintrc.js"
]
}

View File

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

View File

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

View File

@ -1,40 +0,0 @@
/* eslint-disable @typescript-eslint/naming-convention */
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({
LAUNCHPAD_ENABLED: "",
ERC20_ENABLED: "",
CW3_ENABLED: "",
CW1_ENABLED: "",
}),
new webpack.ProvidePlugin({
Buffer: ["buffer", "Buffer"],
}),
],
resolve: {
fallback: {
buffer: false,
crypto: false,
events: false,
path: false,
stream: require.resolve("stream-browserify"),
string_decoder: false,
},
},
},
];

View File

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

View File

@ -1,92 +0,0 @@
module.exports = {
env: {
es6: true,
jasmine: true,
node: true,
worker: true,
},
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: 2018,
project: "./tsconfig.eslint.json",
tsconfigRootDir: __dirname,
},
plugins: ["@typescript-eslint", "prettier", "simple-import-sort", "import"],
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"prettier",
"plugin:prettier/recommended",
"plugin:import/typescript",
],
rules: {
curly: ["warn", "multi-line", "consistent"],
"no-bitwise": "warn",
"no-console": ["warn", { allow: ["error", "info", "table", "warn"] }],
"no-param-reassign": "warn",
"no-shadow": "off", // disabled in favour of @typescript-eslint/no-shadow, see https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-shadow.md
"no-unused-vars": "off", // disabled in favour of @typescript-eslint/no-unused-vars, see https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unused-vars.md
"prefer-const": "warn",
radix: ["warn", "always"],
"spaced-comment": ["warn", "always", { line: { markers: ["/ <reference"] } }],
"import/no-cycle": "warn",
"simple-import-sort/imports": "warn",
"@typescript-eslint/array-type": ["warn", { default: "array-simple" }],
"@typescript-eslint/await-thenable": "warn",
"@typescript-eslint/ban-types": "warn",
"@typescript-eslint/explicit-function-return-type": ["warn", { allowExpressions: true }],
"@typescript-eslint/explicit-member-accessibility": "warn",
"@typescript-eslint/naming-convention": [
"warn",
{
selector: "default",
format: ["strictCamelCase"],
},
{
selector: "typeLike",
format: ["StrictPascalCase"],
},
{
selector: "enumMember",
format: ["StrictPascalCase"],
},
{
selector: "variable",
format: ["strictCamelCase"],
leadingUnderscore: "allow",
},
{
selector: "parameter",
format: ["strictCamelCase"],
leadingUnderscore: "allow",
},
],
"@typescript-eslint/no-dynamic-delete": "warn",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-empty-interface": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-floating-promises": "warn",
"@typescript-eslint/no-parameter-properties": "warn",
"@typescript-eslint/no-shadow": "warn",
"@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_", varsIgnorePattern: "^_" }],
"@typescript-eslint/no-unnecessary-type-assertion": "warn",
"@typescript-eslint/no-use-before-define": "warn",
"@typescript-eslint/prefer-readonly": "warn",
},
overrides: [
{
files: "**/*.js",
rules: {
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/explicit-member-accessibility": "off",
},
},
{
files: "**/*.spec.ts",
rules: {
"@typescript-eslint/no-non-null-assertion": "off",
},
},
],
};

View File

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

View File

@ -1,5 +0,0 @@
# @cosmjs/cosmwasm
This package is deprecated and simply wraps `@cosmjs/cosmwasm-launchpad`, which
should be used for Launchpad support. At some point in the future this package
name will be used for a Stargate-compatible CosmWasm package.

Some files were not shown because too many files have changed in this diff Show More