From a272a3c2af5f073e12277c524f3b0e2ce8fcf5d9 Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Mon, 10 Jul 2023 18:40:19 +0200 Subject: [PATCH 01/44] Add missing dep --- package-lock.json | 291 +++++++++++++++++++++++++++------------------- package.json | 1 + 2 files changed, 170 insertions(+), 122 deletions(-) diff --git a/package-lock.json b/package-lock.json index 94a082a..7dac6e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,7 @@ "name": "create-next-example-app", "dependencies": { "@cosmjs/amino": "^0.31.0-alpha.2", + "@cosmjs/cosmwasm-stargate": "^0.31.0-alpha.2", "@cosmjs/crypto": "^0.31.0-alpha.2", "@cosmjs/encoding": "^0.31.0-alpha.2", "@cosmjs/ledger-amino": "^0.31.0-alpha.2", @@ -650,24 +651,42 @@ } }, "node_modules/@cosmjs/amino": { - "version": "0.31.0-alpha.2", - "resolved": "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.31.0-alpha.2.tgz", - "integrity": "sha512-6ybNyy82Ij5uyImmQjslaKxAecKM3F+4Z3xmEWeHtB39sToNnTzuKCc5qfSJH9v/sMlawJhkslllJaEjvowN2w==", + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.31.0.tgz", + "integrity": "sha512-xJ5CCEK7H79FTpOuEmlpSzVI+ZeYESTVvO3wHDgbnceIyAne3C68SvyaKqLUR4uJB0Z4q4+DZHbqW6itUiv4lA==", "dependencies": { - "@cosmjs/crypto": "^0.31.0-alpha.2", - "@cosmjs/encoding": "^0.31.0-alpha.2", - "@cosmjs/math": "^0.31.0-alpha.2", - "@cosmjs/utils": "^0.31.0-alpha.2" + "@cosmjs/crypto": "^0.31.0", + "@cosmjs/encoding": "^0.31.0", + "@cosmjs/math": "^0.31.0", + "@cosmjs/utils": "^0.31.0" + } + }, + "node_modules/@cosmjs/cosmwasm-stargate": { + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/cosmwasm-stargate/-/cosmwasm-stargate-0.31.0.tgz", + "integrity": "sha512-l6aX++3LhaAGZO46qIgrrNF40lYhOrdPfl35Z32ks6Wf3mwgbQEZwaxnoGzwUePY7/yaIiEFJ1JO6MlVPZVuag==", + "dependencies": { + "@cosmjs/amino": "^0.31.0", + "@cosmjs/crypto": "^0.31.0", + "@cosmjs/encoding": "^0.31.0", + "@cosmjs/math": "^0.31.0", + "@cosmjs/proto-signing": "^0.31.0", + "@cosmjs/stargate": "^0.31.0", + "@cosmjs/tendermint-rpc": "^0.31.0", + "@cosmjs/utils": "^0.31.0", + "cosmjs-types": "^0.8.0", + "long": "^4.0.0", + "pako": "^2.0.2" } }, "node_modules/@cosmjs/crypto": { - "version": "0.31.0-alpha.2", - "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.31.0-alpha.2.tgz", - "integrity": "sha512-2JKXtHP7kYjzCyLnbBTLyDVpMPXbjorkOjkm4fVV1C6hlgJAUrj6eNs0NWJtQypzSEpzASWtkV7XGAbKZhlrqQ==", + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.31.0.tgz", + "integrity": "sha512-UaqCe6Tgh0pe1QlZ66E13t6FlIF86QrnBXXq+EN7Xe1Rouza3fJ1ojGlPleJZkBoq3tAyYVIOOqdZIxtVj/sIQ==", "dependencies": { - "@cosmjs/encoding": "^0.31.0-alpha.2", - "@cosmjs/math": "^0.31.0-alpha.2", - "@cosmjs/utils": "^0.31.0-alpha.2", + "@cosmjs/encoding": "^0.31.0", + "@cosmjs/math": "^0.31.0", + "@cosmjs/utils": "^0.31.0", "@noble/hashes": "^1", "bn.js": "^5.2.0", "elliptic": "^6.5.4", @@ -675,9 +694,9 @@ } }, "node_modules/@cosmjs/encoding": { - "version": "0.31.0-alpha.2", - "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.31.0-alpha.2.tgz", - "integrity": "sha512-GcJ/mhWQBf0Mb7suCuboRO0I+wjS9zZ1Zuj5CplhMhZ6NjvDhXWxEM0Fgtt1IAbm/0/2CV4DnG2Av51LOfkq/g==", + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.31.0.tgz", + "integrity": "sha512-NYGQDRxT7MIRSlcbAezwxK0FqnaSPKCH7O32cmfpHNWorFxhy9lwmBoCvoe59Kd0HmArI4h+NGzLEfX3OLnA4Q==", "dependencies": { "base64-js": "^1.3.0", "bech32": "^1.1.4", @@ -685,11 +704,11 @@ } }, "node_modules/@cosmjs/json-rpc": { - "version": "0.31.0-alpha.2", - "resolved": "https://registry.npmjs.org/@cosmjs/json-rpc/-/json-rpc-0.31.0-alpha.2.tgz", - "integrity": "sha512-MW5ZLiEXmDCKTesTdiM1Ji5Z2aryUHnp+sSwMgT5IjKsHAhYvSrDLHB524xSO9NC25ihNpnYZ2TypUczik0rCg==", + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/json-rpc/-/json-rpc-0.31.0.tgz", + "integrity": "sha512-Ix2Cil2qysiLNrX+E0w3vtwCrqxGVq8jklpLA7B2vtMrw7tru/rS65fdFSy8ep0wUNLL6Ud32VXa5K0YObDOMA==", "dependencies": { - "@cosmjs/stream": "^0.31.0-alpha.2", + "@cosmjs/stream": "^0.31.0", "xstream": "^11.14.0" } }, @@ -722,51 +741,51 @@ } }, "node_modules/@cosmjs/math": { - "version": "0.31.0-alpha.2", - "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.31.0-alpha.2.tgz", - "integrity": "sha512-nQFLkbjZFa+2/FgNh/OuyNsp0k/UgNSLQt9r32Psw/bmTJcw5O21p30f8cK9OC522n0C15GhSD7o7WPQoLhMVg==", + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.31.0.tgz", + "integrity": "sha512-Sb/8Ry/+gKJaYiV6X8q45kxXC9FoV98XCY1WXtu0JQwOi61VCG2VXsURQnVvZ/EhR/CuT/swOlNKrqEs3da0fw==", "dependencies": { "bn.js": "^5.2.0" } }, "node_modules/@cosmjs/proto-signing": { - "version": "0.31.0-alpha.2", - "resolved": "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.31.0-alpha.2.tgz", - "integrity": "sha512-modSeaW3+v43thLteMVuUDhD3q2pXdKnNQQ6sQB6NpCuaNoR2ZC1smuLi8KNQbjZKlRUIAdpwzSNM58yf4C3qA==", + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.31.0.tgz", + "integrity": "sha512-JNlyOJRkn8EKB9mCthkjr6lVX6eyVQ09PFdmB4/DR874E62dFTvQ+YvyKMAgN7K7Dcjj26dVlAD3f6Xs7YOGDg==", "dependencies": { - "@cosmjs/amino": "^0.31.0-alpha.2", - "@cosmjs/crypto": "^0.31.0-alpha.2", - "@cosmjs/encoding": "^0.31.0-alpha.2", - "@cosmjs/math": "^0.31.0-alpha.2", - "@cosmjs/utils": "^0.31.0-alpha.2", + "@cosmjs/amino": "^0.31.0", + "@cosmjs/crypto": "^0.31.0", + "@cosmjs/encoding": "^0.31.0", + "@cosmjs/math": "^0.31.0", + "@cosmjs/utils": "^0.31.0", "cosmjs-types": "^0.8.0", "long": "^4.0.0" } }, "node_modules/@cosmjs/socket": { - "version": "0.31.0-alpha.2", - "resolved": "https://registry.npmjs.org/@cosmjs/socket/-/socket-0.31.0-alpha.2.tgz", - "integrity": "sha512-3YmrFvvM0q3vlMDwE8lFuHwnlWYJz8Mon1oos/MoF2a3fkX24+l7yJBRLGUL0oq5sss5v2rsuHojG48q7FdIKA==", + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/socket/-/socket-0.31.0.tgz", + "integrity": "sha512-WDh9gTyiP3OCXvSAJJn33+Ef3XqMWag+bpR1TdMBxTmlTxuvU+kPy4cf6P2OF+jkkUBEA5Se2EAju0eFbJMT+w==", "dependencies": { - "@cosmjs/stream": "^0.31.0-alpha.2", + "@cosmjs/stream": "^0.31.0", "isomorphic-ws": "^4.0.1", "ws": "^7", "xstream": "^11.14.0" } }, "node_modules/@cosmjs/stargate": { - "version": "0.31.0-alpha.2", - "resolved": "https://registry.npmjs.org/@cosmjs/stargate/-/stargate-0.31.0-alpha.2.tgz", - "integrity": "sha512-xQNHdAStrxesYFrq8d3IQEi61TVCPWbNfDd7cwr3l/UhjCgqQMlps+hLLUle/I46X2Q2OtHjM7wCC9bEDYTFsg==", + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/stargate/-/stargate-0.31.0.tgz", + "integrity": "sha512-GYhk9lzZPj/QmYHC0VV/4AMoRzVcOP+EnB1YZCoWlBdLuVmpBYKRagJqWIrIwdk1E0gF2ZoESd2TYfdh1fqIpg==", "dependencies": { "@confio/ics23": "^0.6.8", - "@cosmjs/amino": "^0.31.0-alpha.2", - "@cosmjs/encoding": "^0.31.0-alpha.2", - "@cosmjs/math": "^0.31.0-alpha.2", - "@cosmjs/proto-signing": "^0.31.0-alpha.2", - "@cosmjs/stream": "^0.31.0-alpha.2", - "@cosmjs/tendermint-rpc": "^0.31.0-alpha.2", - "@cosmjs/utils": "^0.31.0-alpha.2", + "@cosmjs/amino": "^0.31.0", + "@cosmjs/encoding": "^0.31.0", + "@cosmjs/math": "^0.31.0", + "@cosmjs/proto-signing": "^0.31.0", + "@cosmjs/stream": "^0.31.0", + "@cosmjs/tendermint-rpc": "^0.31.0", + "@cosmjs/utils": "^0.31.0", "cosmjs-types": "^0.8.0", "long": "^4.0.0", "protobufjs": "~6.11.3", @@ -774,25 +793,25 @@ } }, "node_modules/@cosmjs/stream": { - "version": "0.31.0-alpha.2", - "resolved": "https://registry.npmjs.org/@cosmjs/stream/-/stream-0.31.0-alpha.2.tgz", - "integrity": "sha512-yWxRm7BQbKZvoBR35MG3neILPq18B3Yd7M35MV56F2AvUBn9dQuugwNRt2HSNFEDsvCabzmErr2qaDHI8LLlpA==", + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/stream/-/stream-0.31.0.tgz", + "integrity": "sha512-Y+aSHwhHkLGIaQOdqRob+yga2zr9ifl9gZDKD+B7+R5pdWN5f2TTDhYWxA6YZcZ6xRmfr7u8a7tDh7iYLC/zKA==", "dependencies": { "xstream": "^11.14.0" } }, "node_modules/@cosmjs/tendermint-rpc": { - "version": "0.31.0-alpha.2", - "resolved": "https://registry.npmjs.org/@cosmjs/tendermint-rpc/-/tendermint-rpc-0.31.0-alpha.2.tgz", - "integrity": "sha512-BrRKiR9+LXwN9z+4oqUJJScjxQU0ciSoNjz7y6l5MaBceUDvdd8h/GpwDhrxmJ/0cAAaL5conIT5OpNeDcLoQw==", + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/tendermint-rpc/-/tendermint-rpc-0.31.0.tgz", + "integrity": "sha512-yo9xbeuI6UoEKIhFZ9g0dvUKLqnBzwdpEc/uldQygQc51j38gQVwFko+6sjmhieJqRYYvrYumcbJMiV6GFM9aA==", "dependencies": { - "@cosmjs/crypto": "^0.31.0-alpha.2", - "@cosmjs/encoding": "^0.31.0-alpha.2", - "@cosmjs/json-rpc": "^0.31.0-alpha.2", - "@cosmjs/math": "^0.31.0-alpha.2", - "@cosmjs/socket": "^0.31.0-alpha.2", - "@cosmjs/stream": "^0.31.0-alpha.2", - "@cosmjs/utils": "^0.31.0-alpha.2", + "@cosmjs/crypto": "^0.31.0", + "@cosmjs/encoding": "^0.31.0", + "@cosmjs/json-rpc": "^0.31.0", + "@cosmjs/math": "^0.31.0", + "@cosmjs/socket": "^0.31.0", + "@cosmjs/stream": "^0.31.0", + "@cosmjs/utils": "^0.31.0", "axios": "^0.21.2", "readonly-date": "^1.0.0", "xstream": "^11.14.0" @@ -807,9 +826,9 @@ } }, "node_modules/@cosmjs/utils": { - "version": "0.31.0-alpha.2", - "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.31.0-alpha.2.tgz", - "integrity": "sha512-SRHjcfmh/kGvjoV/BfouGTDpB3yVLloyEs6yEJakSWCWQF2Df7oTPpJhuquSTWuDDPK8FFg++iGaF9qeP41ggA==" + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.31.0.tgz", + "integrity": "sha512-nNcycZWUYLNJlrIXgpcgVRqdl6BXjF4YlXdxobQWpW9Tikk61bEGeAFhDYtC0PwHlokCNw0KxWiHGJL4nL7Q5A==" }, "node_modules/@emotion/babel-plugin": { "version": "11.10.6", @@ -7373,6 +7392,11 @@ "node": ">=6" } }, + "node_modules/pako": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -9441,24 +9465,42 @@ } }, "@cosmjs/amino": { - "version": "0.31.0-alpha.2", - "resolved": "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.31.0-alpha.2.tgz", - "integrity": "sha512-6ybNyy82Ij5uyImmQjslaKxAecKM3F+4Z3xmEWeHtB39sToNnTzuKCc5qfSJH9v/sMlawJhkslllJaEjvowN2w==", + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.31.0.tgz", + "integrity": "sha512-xJ5CCEK7H79FTpOuEmlpSzVI+ZeYESTVvO3wHDgbnceIyAne3C68SvyaKqLUR4uJB0Z4q4+DZHbqW6itUiv4lA==", "requires": { - "@cosmjs/crypto": "^0.31.0-alpha.2", - "@cosmjs/encoding": "^0.31.0-alpha.2", - "@cosmjs/math": "^0.31.0-alpha.2", - "@cosmjs/utils": "^0.31.0-alpha.2" + "@cosmjs/crypto": "^0.31.0", + "@cosmjs/encoding": "^0.31.0", + "@cosmjs/math": "^0.31.0", + "@cosmjs/utils": "^0.31.0" + } + }, + "@cosmjs/cosmwasm-stargate": { + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/cosmwasm-stargate/-/cosmwasm-stargate-0.31.0.tgz", + "integrity": "sha512-l6aX++3LhaAGZO46qIgrrNF40lYhOrdPfl35Z32ks6Wf3mwgbQEZwaxnoGzwUePY7/yaIiEFJ1JO6MlVPZVuag==", + "requires": { + "@cosmjs/amino": "^0.31.0", + "@cosmjs/crypto": "^0.31.0", + "@cosmjs/encoding": "^0.31.0", + "@cosmjs/math": "^0.31.0", + "@cosmjs/proto-signing": "^0.31.0", + "@cosmjs/stargate": "^0.31.0", + "@cosmjs/tendermint-rpc": "^0.31.0", + "@cosmjs/utils": "^0.31.0", + "cosmjs-types": "^0.8.0", + "long": "^4.0.0", + "pako": "^2.0.2" } }, "@cosmjs/crypto": { - "version": "0.31.0-alpha.2", - "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.31.0-alpha.2.tgz", - "integrity": "sha512-2JKXtHP7kYjzCyLnbBTLyDVpMPXbjorkOjkm4fVV1C6hlgJAUrj6eNs0NWJtQypzSEpzASWtkV7XGAbKZhlrqQ==", + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.31.0.tgz", + "integrity": "sha512-UaqCe6Tgh0pe1QlZ66E13t6FlIF86QrnBXXq+EN7Xe1Rouza3fJ1ojGlPleJZkBoq3tAyYVIOOqdZIxtVj/sIQ==", "requires": { - "@cosmjs/encoding": "^0.31.0-alpha.2", - "@cosmjs/math": "^0.31.0-alpha.2", - "@cosmjs/utils": "^0.31.0-alpha.2", + "@cosmjs/encoding": "^0.31.0", + "@cosmjs/math": "^0.31.0", + "@cosmjs/utils": "^0.31.0", "@noble/hashes": "^1", "bn.js": "^5.2.0", "elliptic": "^6.5.4", @@ -9466,9 +9508,9 @@ } }, "@cosmjs/encoding": { - "version": "0.31.0-alpha.2", - "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.31.0-alpha.2.tgz", - "integrity": "sha512-GcJ/mhWQBf0Mb7suCuboRO0I+wjS9zZ1Zuj5CplhMhZ6NjvDhXWxEM0Fgtt1IAbm/0/2CV4DnG2Av51LOfkq/g==", + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.31.0.tgz", + "integrity": "sha512-NYGQDRxT7MIRSlcbAezwxK0FqnaSPKCH7O32cmfpHNWorFxhy9lwmBoCvoe59Kd0HmArI4h+NGzLEfX3OLnA4Q==", "requires": { "base64-js": "^1.3.0", "bech32": "^1.1.4", @@ -9476,11 +9518,11 @@ } }, "@cosmjs/json-rpc": { - "version": "0.31.0-alpha.2", - "resolved": "https://registry.npmjs.org/@cosmjs/json-rpc/-/json-rpc-0.31.0-alpha.2.tgz", - "integrity": "sha512-MW5ZLiEXmDCKTesTdiM1Ji5Z2aryUHnp+sSwMgT5IjKsHAhYvSrDLHB524xSO9NC25ihNpnYZ2TypUczik0rCg==", + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/json-rpc/-/json-rpc-0.31.0.tgz", + "integrity": "sha512-Ix2Cil2qysiLNrX+E0w3vtwCrqxGVq8jklpLA7B2vtMrw7tru/rS65fdFSy8ep0wUNLL6Ud32VXa5K0YObDOMA==", "requires": { - "@cosmjs/stream": "^0.31.0-alpha.2", + "@cosmjs/stream": "^0.31.0", "xstream": "^11.14.0" } }, @@ -9509,51 +9551,51 @@ } }, "@cosmjs/math": { - "version": "0.31.0-alpha.2", - "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.31.0-alpha.2.tgz", - "integrity": "sha512-nQFLkbjZFa+2/FgNh/OuyNsp0k/UgNSLQt9r32Psw/bmTJcw5O21p30f8cK9OC522n0C15GhSD7o7WPQoLhMVg==", + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.31.0.tgz", + "integrity": "sha512-Sb/8Ry/+gKJaYiV6X8q45kxXC9FoV98XCY1WXtu0JQwOi61VCG2VXsURQnVvZ/EhR/CuT/swOlNKrqEs3da0fw==", "requires": { "bn.js": "^5.2.0" } }, "@cosmjs/proto-signing": { - "version": "0.31.0-alpha.2", - "resolved": "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.31.0-alpha.2.tgz", - "integrity": "sha512-modSeaW3+v43thLteMVuUDhD3q2pXdKnNQQ6sQB6NpCuaNoR2ZC1smuLi8KNQbjZKlRUIAdpwzSNM58yf4C3qA==", + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.31.0.tgz", + "integrity": "sha512-JNlyOJRkn8EKB9mCthkjr6lVX6eyVQ09PFdmB4/DR874E62dFTvQ+YvyKMAgN7K7Dcjj26dVlAD3f6Xs7YOGDg==", "requires": { - "@cosmjs/amino": "^0.31.0-alpha.2", - "@cosmjs/crypto": "^0.31.0-alpha.2", - "@cosmjs/encoding": "^0.31.0-alpha.2", - "@cosmjs/math": "^0.31.0-alpha.2", - "@cosmjs/utils": "^0.31.0-alpha.2", + "@cosmjs/amino": "^0.31.0", + "@cosmjs/crypto": "^0.31.0", + "@cosmjs/encoding": "^0.31.0", + "@cosmjs/math": "^0.31.0", + "@cosmjs/utils": "^0.31.0", "cosmjs-types": "^0.8.0", "long": "^4.0.0" } }, "@cosmjs/socket": { - "version": "0.31.0-alpha.2", - "resolved": "https://registry.npmjs.org/@cosmjs/socket/-/socket-0.31.0-alpha.2.tgz", - "integrity": "sha512-3YmrFvvM0q3vlMDwE8lFuHwnlWYJz8Mon1oos/MoF2a3fkX24+l7yJBRLGUL0oq5sss5v2rsuHojG48q7FdIKA==", + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/socket/-/socket-0.31.0.tgz", + "integrity": "sha512-WDh9gTyiP3OCXvSAJJn33+Ef3XqMWag+bpR1TdMBxTmlTxuvU+kPy4cf6P2OF+jkkUBEA5Se2EAju0eFbJMT+w==", "requires": { - "@cosmjs/stream": "^0.31.0-alpha.2", + "@cosmjs/stream": "^0.31.0", "isomorphic-ws": "^4.0.1", "ws": "^7", "xstream": "^11.14.0" } }, "@cosmjs/stargate": { - "version": "0.31.0-alpha.2", - "resolved": "https://registry.npmjs.org/@cosmjs/stargate/-/stargate-0.31.0-alpha.2.tgz", - "integrity": "sha512-xQNHdAStrxesYFrq8d3IQEi61TVCPWbNfDd7cwr3l/UhjCgqQMlps+hLLUle/I46X2Q2OtHjM7wCC9bEDYTFsg==", + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/stargate/-/stargate-0.31.0.tgz", + "integrity": "sha512-GYhk9lzZPj/QmYHC0VV/4AMoRzVcOP+EnB1YZCoWlBdLuVmpBYKRagJqWIrIwdk1E0gF2ZoESd2TYfdh1fqIpg==", "requires": { "@confio/ics23": "^0.6.8", - "@cosmjs/amino": "^0.31.0-alpha.2", - "@cosmjs/encoding": "^0.31.0-alpha.2", - "@cosmjs/math": "^0.31.0-alpha.2", - "@cosmjs/proto-signing": "^0.31.0-alpha.2", - "@cosmjs/stream": "^0.31.0-alpha.2", - "@cosmjs/tendermint-rpc": "^0.31.0-alpha.2", - "@cosmjs/utils": "^0.31.0-alpha.2", + "@cosmjs/amino": "^0.31.0", + "@cosmjs/encoding": "^0.31.0", + "@cosmjs/math": "^0.31.0", + "@cosmjs/proto-signing": "^0.31.0", + "@cosmjs/stream": "^0.31.0", + "@cosmjs/tendermint-rpc": "^0.31.0", + "@cosmjs/utils": "^0.31.0", "cosmjs-types": "^0.8.0", "long": "^4.0.0", "protobufjs": "~6.11.3", @@ -9561,25 +9603,25 @@ } }, "@cosmjs/stream": { - "version": "0.31.0-alpha.2", - "resolved": "https://registry.npmjs.org/@cosmjs/stream/-/stream-0.31.0-alpha.2.tgz", - "integrity": "sha512-yWxRm7BQbKZvoBR35MG3neILPq18B3Yd7M35MV56F2AvUBn9dQuugwNRt2HSNFEDsvCabzmErr2qaDHI8LLlpA==", + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/stream/-/stream-0.31.0.tgz", + "integrity": "sha512-Y+aSHwhHkLGIaQOdqRob+yga2zr9ifl9gZDKD+B7+R5pdWN5f2TTDhYWxA6YZcZ6xRmfr7u8a7tDh7iYLC/zKA==", "requires": { "xstream": "^11.14.0" } }, "@cosmjs/tendermint-rpc": { - "version": "0.31.0-alpha.2", - "resolved": "https://registry.npmjs.org/@cosmjs/tendermint-rpc/-/tendermint-rpc-0.31.0-alpha.2.tgz", - "integrity": "sha512-BrRKiR9+LXwN9z+4oqUJJScjxQU0ciSoNjz7y6l5MaBceUDvdd8h/GpwDhrxmJ/0cAAaL5conIT5OpNeDcLoQw==", + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/tendermint-rpc/-/tendermint-rpc-0.31.0.tgz", + "integrity": "sha512-yo9xbeuI6UoEKIhFZ9g0dvUKLqnBzwdpEc/uldQygQc51j38gQVwFko+6sjmhieJqRYYvrYumcbJMiV6GFM9aA==", "requires": { - "@cosmjs/crypto": "^0.31.0-alpha.2", - "@cosmjs/encoding": "^0.31.0-alpha.2", - "@cosmjs/json-rpc": "^0.31.0-alpha.2", - "@cosmjs/math": "^0.31.0-alpha.2", - "@cosmjs/socket": "^0.31.0-alpha.2", - "@cosmjs/stream": "^0.31.0-alpha.2", - "@cosmjs/utils": "^0.31.0-alpha.2", + "@cosmjs/crypto": "^0.31.0", + "@cosmjs/encoding": "^0.31.0", + "@cosmjs/json-rpc": "^0.31.0", + "@cosmjs/math": "^0.31.0", + "@cosmjs/socket": "^0.31.0", + "@cosmjs/stream": "^0.31.0", + "@cosmjs/utils": "^0.31.0", "axios": "^0.21.2", "readonly-date": "^1.0.0", "xstream": "^11.14.0" @@ -9596,9 +9638,9 @@ } }, "@cosmjs/utils": { - "version": "0.31.0-alpha.2", - "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.31.0-alpha.2.tgz", - "integrity": "sha512-SRHjcfmh/kGvjoV/BfouGTDpB3yVLloyEs6yEJakSWCWQF2Df7oTPpJhuquSTWuDDPK8FFg++iGaF9qeP41ggA==" + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.31.0.tgz", + "integrity": "sha512-nNcycZWUYLNJlrIXgpcgVRqdl6BXjF4YlXdxobQWpW9Tikk61bEGeAFhDYtC0PwHlokCNw0KxWiHGJL4nL7Q5A==" }, "@emotion/babel-plugin": { "version": "11.10.6", @@ -14540,6 +14582,11 @@ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, + "pako": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==" + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", diff --git a/package.json b/package.json index 4995aae..d134d52 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "@cosmjs/amino": "^0.31.0-alpha.2", + "@cosmjs/cosmwasm-stargate": "^0.31.0-alpha.2", "@cosmjs/crypto": "^0.31.0-alpha.2", "@cosmjs/encoding": "^0.31.0-alpha.2", "@cosmjs/ledger-amino": "^0.31.0-alpha.2", From 02b4f749149d87fde288781b48adf79ad9068586 Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Mon, 10 Jul 2023 18:40:48 +0200 Subject: [PATCH 02/44] Add new types --- lib/txMsgHelpers.ts | 6 ++++++ types/txMsg.ts | 11 +++++++++++ 2 files changed, 17 insertions(+) diff --git a/lib/txMsgHelpers.ts b/lib/txMsgHelpers.ts index 0654314..9e2f0b9 100644 --- a/lib/txMsgHelpers.ts +++ b/lib/txMsgHelpers.ts @@ -20,6 +20,12 @@ const gasOfMsg = (msgType: MsgTypeUrl): number => { return 100_000; case MsgTypeUrls.Transfer: return 180_000; + case MsgTypeUrls.Execute: + return 150_000; + case MsgTypeUrls.Instantiate: + return 150_000; + case MsgTypeUrls.Instantiate2: + return 150_000; default: throw new Error("Unknown msg type"); } diff --git a/types/txMsg.ts b/types/txMsg.ts index 3c7afc9..0c6db2c 100644 --- a/types/txMsg.ts +++ b/types/txMsg.ts @@ -9,6 +9,11 @@ import { MsgUndelegate, } from "cosmjs-types/cosmos/staking/v1beta1/tx"; import { MsgCreateVestingAccount } from "cosmjs-types/cosmos/vesting/v1beta1/tx"; +import { + MsgExecuteContract, + MsgInstantiateContract, + MsgInstantiateContract2, +} from "cosmjs-types/cosmwasm/wasm/v1/tx"; import { MsgTransfer } from "cosmjs-types/ibc/applications/transfer/v1/tx"; export const MsgTypeUrls = { @@ -20,6 +25,9 @@ export const MsgTypeUrls = { Undelegate: "/cosmos.staking.v1beta1.MsgUndelegate", CreateVestingAccount: "/cosmos.vesting.v1beta1.MsgCreateVestingAccount", Transfer: "/ibc.applications.transfer.v1.MsgTransfer", + Execute: "/cosmwasm.wasm.v1.MsgExecuteContract", + Instantiate: "/cosmwasm.wasm.v1.MsgInstantiateContract", + Instantiate2: "/cosmwasm.wasm.v1.MsgInstantiateContract2", } as const; export type MsgTypeUrl = (typeof MsgTypeUrls)[keyof typeof MsgTypeUrls]; @@ -33,4 +41,7 @@ export const MsgCodecs = { [MsgTypeUrls.Undelegate]: MsgUndelegate, [MsgTypeUrls.CreateVestingAccount]: MsgCreateVestingAccount, [MsgTypeUrls.Transfer]: MsgTransfer, + [MsgTypeUrls.Execute]: MsgExecuteContract, + [MsgTypeUrls.Instantiate]: MsgInstantiateContract, + [MsgTypeUrls.Instantiate2]: MsgInstantiateContract2, }; From 0327a3655ccfcfe9fa5b448e8c162587061249b7 Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Mon, 10 Jul 2023 18:41:14 +0200 Subject: [PATCH 03/44] Add execute details --- .../TxMsgExecuteContractDetails.tsx | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 components/dataViews/TransactionInfo/TxMsgExecuteContractDetails.tsx diff --git a/components/dataViews/TransactionInfo/TxMsgExecuteContractDetails.tsx b/components/dataViews/TransactionInfo/TxMsgExecuteContractDetails.tsx new file mode 100644 index 0000000..45a070f --- /dev/null +++ b/components/dataViews/TransactionInfo/TxMsgExecuteContractDetails.tsx @@ -0,0 +1,62 @@ +import { fromUtf8 } from "@cosmjs/encoding"; +import { MsgExecuteContract } from "cosmjs-types/cosmwasm/wasm/v1/tx"; +import { useAppContext } from "../../../context/AppContext"; +import { printableCoins } from "../../../lib/displayHelpers"; +import HashView from "../HashView"; + +interface TxMsgExecuteContractDetailsProps { + readonly msgValue: MsgExecuteContract; +} + +const TxMsgExecuteContractDetails = ({ msgValue }: TxMsgExecuteContractDetailsProps) => { + const { state } = useAppContext(); + + return ( + <> +
  • +

    MsgExecuteContract

    +
  • +
  • + +
    + +
    +
  • +
  • + +
    {printableCoins(msgValue.funds, state.chain)}
    +
  • +
  • + +
    {fromUtf8(msgValue.msg)}
    +
  • + + + ); +}; + +export default TxMsgExecuteContractDetails; From 630156c1dfbec51e6c7123b3c5155a4dc7930683 Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Mon, 10 Jul 2023 18:41:41 +0200 Subject: [PATCH 04/44] Add execute form --- .../MsgForm/MsgExecuteContractForm.tsx | 235 ++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 components/forms/CreateTxForm/MsgForm/MsgExecuteContractForm.tsx diff --git a/components/forms/CreateTxForm/MsgForm/MsgExecuteContractForm.tsx b/components/forms/CreateTxForm/MsgForm/MsgExecuteContractForm.tsx new file mode 100644 index 0000000..b9df274 --- /dev/null +++ b/components/forms/CreateTxForm/MsgForm/MsgExecuteContractForm.tsx @@ -0,0 +1,235 @@ +import { MsgExecuteContractEncodeObject } from "@cosmjs/cosmwasm-stargate"; +import { toUtf8 } from "@cosmjs/encoding"; +import { Decimal } from "@cosmjs/math"; +import { assert } from "@cosmjs/utils"; +import { useEffect, useState } from "react"; +import { MsgGetter } from ".."; +import { useAppContext } from "../../../../context/AppContext"; +import { checkAddress, exampleAddress } from "../../../../lib/displayHelpers"; +import { ChainInfo } from "../../../../types"; +import { MsgCodecs, MsgTypeUrls } from "../../../../types/txMsg"; +import Input from "../../../inputs/Input"; +import Select from "../../../inputs/Select"; +import StackableContainer from "../../../layout/StackableContainer"; + +const customDenomOption = { label: "Custom (enter denom below)", value: "custom" } as const; + +const getDenomOptions = (assets: ChainInfo["assets"]) => { + if (!assets?.length) { + return [customDenomOption]; + } + + return [...assets.map((asset) => ({ label: asset.symbol, value: asset })), customDenomOption]; +}; + +interface MsgExecuteContractFormProps { + readonly fromAddress: string; + readonly setMsgGetter: (msgGetter: MsgGetter) => void; + readonly deleteMsg: () => void; +} + +const MsgExecuteContractForm = ({ + fromAddress, + setMsgGetter, + deleteMsg, +}: MsgExecuteContractFormProps) => { + const { state } = useAppContext(); + assert(state.chain.addressPrefix, "addressPrefix missing"); + + const denomOptions = getDenomOptions(state.chain.assets); + + const [contractAddress, setContractAddress] = useState(""); + const [msgContent, setMsgContent] = useState("{}"); + const [selectedDenom, setSelectedDenom] = useState(denomOptions[0]); + const [customDenom, setCustomDenom] = useState(""); + const [amount, setAmount] = useState("0"); + + const [contractAddressError, setContractAddressError] = useState(""); + const [msgContentError, setMsgContentError] = useState(""); + const [customDenomError, setCustomDenomError] = useState(""); + const [amountError, setAmountError] = useState(""); + + useEffect(() => { + assert(state.chain.denom, "denom missing"); + + setContractAddressError(""); + setMsgContentError(""); + setCustomDenomError(""); + setAmountError(""); + + const isMsgValid = (): boolean => { + assert(state.chain.addressPrefix, "addressPrefix missing"); + + const addressErrorMsg = checkAddress(contractAddress, state.chain.addressPrefix); + if (addressErrorMsg) { + setContractAddressError( + `Invalid address for network ${state.chain.chainId}: ${addressErrorMsg}`, + ); + return false; + } + + try { + JSON.parse(msgContent); + } catch { + setMsgContentError("Msg must be valid JSON"); + return false; + } + + if (selectedDenom.value === customDenomOption.value && !customDenom) { + setCustomDenomError("Custom denom must be set because of selection above"); + return false; + } + + if (!amount || Number(amount) <= 0) { + setAmountError("Amount must be greater than 0"); + return false; + } + + if (selectedDenom.value === customDenomOption.value && !Number.isInteger(Number(amount))) { + setAmountError("Amount cannot be decimal for custom denom"); + return false; + } + + return true; + }; + + const denom = + selectedDenom.value === customDenomOption.value ? customDenom : selectedDenom.value.symbol; + + const amountInAtomics = (() => { + try { + if (selectedDenom.value === customDenomOption.value) { + return Decimal.fromUserInput(amount, 0).atomics; + } + + const foundAsset = state.chain.assets?.find((asset) => asset.symbol === denom); + const exponent = + foundAsset?.denom_units.find((unit) => unit.denom === foundAsset.symbol.toLowerCase()) + ?.exponent ?? 0; + + return Decimal.fromUserInput(amount, exponent).atomics; + } catch { + return "0"; + } + })(); + + const msgValue = MsgCodecs[MsgTypeUrls.Execute].fromPartial({ + sender: fromAddress, + contract: contractAddress, + msg: toUtf8(msgContent), + funds: [{ denom, amount: amountInAtomics }], + }); + + const msg: MsgExecuteContractEncodeObject = { typeUrl: MsgTypeUrls.Execute, value: msgValue }; + + setMsgGetter({ isMsgValid, msg }); + }, [ + amount, + contractAddress, + customDenom, + fromAddress, + msgContent, + selectedDenom.value, + setMsgGetter, + state.chain.addressPrefix, + state.chain.assets, + state.chain.chainId, + state.chain.denom, + ]); + + return ( + + +

    MsgSend

    +
    + setContractAddress(target.value)} + error={contractAddressError} + placeholder={`E.g. ${exampleAddress(0, state.chain.addressPrefix)}`} + /> +
    +
    + setMsgContent(target.value)} + error={msgContentError} + placeholder={"Enter msg JSON"} + /> +
    +
    + + setCustomDenom(target.value)} + placeholder={ + selectedDenom.value === customDenomOption.value + ? "Enter custom denom" + : "Select Custom denom above" + } + disabled={selectedDenom.value !== customDenomOption.value} + error={customDenomError} + /> +
    +
    + setAmount(target.value)} + error={amountError} + /> +
    + +
    + ); +}; + +export default MsgExecuteContractForm; From 910726f95fb877a9a071daf4c80059246c87b491 Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Mon, 10 Jul 2023 18:42:03 +0200 Subject: [PATCH 05/44] Add instantiate details --- .../TxMsgInstantiateContractDetails.tsx | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 components/dataViews/TransactionInfo/TxMsgInstantiateContractDetails.tsx diff --git a/components/dataViews/TransactionInfo/TxMsgInstantiateContractDetails.tsx b/components/dataViews/TransactionInfo/TxMsgInstantiateContractDetails.tsx new file mode 100644 index 0000000..839e513 --- /dev/null +++ b/components/dataViews/TransactionInfo/TxMsgInstantiateContractDetails.tsx @@ -0,0 +1,74 @@ +import { fromUtf8 } from "@cosmjs/encoding"; +import { MsgInstantiateContract } from "cosmjs-types/cosmwasm/wasm/v1/tx"; +import { useAppContext } from "../../../context/AppContext"; +import { printableCoins } from "../../../lib/displayHelpers"; +import HashView from "../HashView"; + +interface TxMsgInstantiateContractDetailsProps { + readonly msgValue: MsgInstantiateContract; +} + +const TxMsgInstantiateContractDetails = ({ msgValue }: TxMsgInstantiateContractDetailsProps) => { + const { state } = useAppContext(); + + return ( + <> +
  • +

    MsgInstantiateContract

    +
  • +
  • + +
    {msgValue.codeId.toString()}
    +
  • +
  • + +
    {msgValue.label || "None"}
    +
  • +
  • + + {msgValue.admin ? ( +
    + +
    + ) : ( +
    None
    + )} +
  • +
  • + +
    {printableCoins(msgValue.funds, state.chain)}
    +
  • +
  • + +
    {fromUtf8(msgValue.msg)}
    +
  • + + + ); +}; + +export default TxMsgInstantiateContractDetails; From 19ad69ef04729e1e1e74563104194d406f67b714 Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Mon, 10 Jul 2023 18:42:16 +0200 Subject: [PATCH 06/44] Add instantiate form --- .../MsgForm/MsgInstantiateContractForm.tsx | 267 ++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 components/forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx diff --git a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx new file mode 100644 index 0000000..a40abbe --- /dev/null +++ b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx @@ -0,0 +1,267 @@ +import { MsgInstantiateContractEncodeObject } from "@cosmjs/cosmwasm-stargate"; +import { toUtf8 } from "@cosmjs/encoding"; +import { Decimal } from "@cosmjs/math"; +import { assert } from "@cosmjs/utils"; +import { useEffect, useState } from "react"; +import { MsgGetter } from ".."; +import { useAppContext } from "../../../../context/AppContext"; +import { checkAddress, exampleAddress } from "../../../../lib/displayHelpers"; +import { ChainInfo } from "../../../../types"; +import { MsgCodecs, MsgTypeUrls } from "../../../../types/txMsg"; +import Input from "../../../inputs/Input"; +import Select from "../../../inputs/Select"; +import StackableContainer from "../../../layout/StackableContainer"; + +const customDenomOption = { label: "Custom (enter denom below)", value: "custom" } as const; + +const getDenomOptions = (assets: ChainInfo["assets"]) => { + if (!assets?.length) { + return [customDenomOption]; + } + + return [...assets.map((asset) => ({ label: asset.symbol, value: asset })), customDenomOption]; +}; + +interface MsgInstantiateContractFormProps { + readonly fromAddress: string; + readonly setMsgGetter: (msgGetter: MsgGetter) => void; + readonly deleteMsg: () => void; +} + +const MsgInstantiateContractForm = ({ + fromAddress, + setMsgGetter, + deleteMsg, +}: MsgInstantiateContractFormProps) => { + const { state } = useAppContext(); + assert(state.chain.addressPrefix, "addressPrefix missing"); + + const denomOptions = getDenomOptions(state.chain.assets); + + const [codeId, setCodeId] = useState(""); + const [label, setLabel] = useState(""); + const [adminAddress, setAdminAddress] = useState(""); + const [msgContent, setMsgContent] = useState("{}"); + const [selectedDenom, setSelectedDenom] = useState(denomOptions[0]); + const [customDenom, setCustomDenom] = useState(""); + const [amount, setAmount] = useState("0"); + + const [codeIdError, setCodeIdError] = useState(""); + const [adminAddressError, setAdminAddressError] = useState(""); + const [msgContentError, setMsgContentError] = useState(""); + const [customDenomError, setCustomDenomError] = useState(""); + const [amountError, setAmountError] = useState(""); + + useEffect(() => { + assert(state.chain.denom, "denom missing"); + + setAdminAddressError(""); + setMsgContentError(""); + setCustomDenomError(""); + setAmountError(""); + + const isMsgValid = (): boolean => { + assert(state.chain.addressPrefix, "addressPrefix missing"); + + if (!codeId || !Number.isSafeInteger(Number(codeId)) || Number(codeId) <= 0) { + setCodeIdError("Code ID must be a positive integer"); + return false; + } + + const addressErrorMsg = checkAddress(adminAddress, state.chain.addressPrefix); + if (adminAddress && addressErrorMsg) { + setAdminAddressError( + `Invalid address for network ${state.chain.chainId}: ${addressErrorMsg}`, + ); + return false; + } + + try { + JSON.parse(msgContent); + } catch { + setMsgContentError("Msg must be valid JSON"); + return false; + } + + if (selectedDenom.value === customDenomOption.value && !customDenom) { + setCustomDenomError("Custom denom must be set because of selection above"); + return false; + } + + if (!amount || Number(amount) <= 0) { + setAmountError("Amount must be greater than 0"); + return false; + } + + if (selectedDenom.value === customDenomOption.value && !Number.isInteger(Number(amount))) { + setAmountError("Amount cannot be decimal for custom denom"); + return false; + } + + return true; + }; + + const denom = + selectedDenom.value === customDenomOption.value ? customDenom : selectedDenom.value.symbol; + + const amountInAtomics = (() => { + try { + if (selectedDenom.value === customDenomOption.value) { + return Decimal.fromUserInput(amount, 0).atomics; + } + + const foundAsset = state.chain.assets?.find((asset) => asset.symbol === denom); + const exponent = + foundAsset?.denom_units.find((unit) => unit.denom === foundAsset.symbol.toLowerCase()) + ?.exponent ?? 0; + + return Decimal.fromUserInput(amount, exponent).atomics; + } catch { + return "0"; + } + })(); + + const msgValue = MsgCodecs[MsgTypeUrls.Instantiate].fromPartial({ + sender: fromAddress, + codeId, + label, + admin: adminAddress, + msg: toUtf8(msgContent), + funds: [{ denom, amount: amountInAtomics }], + }); + + const msg: MsgInstantiateContractEncodeObject = { + typeUrl: MsgTypeUrls.Instantiate, + value: msgValue, + }; + + setMsgGetter({ isMsgValid, msg }); + }, [ + adminAddress, + amount, + codeId, + customDenom, + fromAddress, + label, + msgContent, + selectedDenom.value, + setMsgGetter, + state.chain.addressPrefix, + state.chain.assets, + state.chain.chainId, + state.chain.denom, + ]); + + return ( + + +

    MsgInstantiateContract

    +
    + setCodeId(target.value)} + error={codeIdError} + /> +
    +
    + setLabel(target.value)} + /> +
    +
    + setAdminAddress(target.value)} + error={adminAddressError} + placeholder={`E.g. ${exampleAddress(0, state.chain.addressPrefix)}`} + /> +
    +
    + setMsgContent(target.value)} + error={msgContentError} + placeholder={"Enter msg JSON"} + /> +
    +
    + + setCustomDenom(target.value)} + placeholder={ + selectedDenom.value === customDenomOption.value + ? "Enter custom denom" + : "Select Custom denom above" + } + disabled={selectedDenom.value !== customDenomOption.value} + error={customDenomError} + /> +
    +
    + setAmount(target.value)} + error={amountError} + /> +
    + +
    + ); +}; + +export default MsgInstantiateContractForm; From 8e8cb7191bdc177ac5202766803dec2f19b84acf Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Mon, 10 Jul 2023 18:42:48 +0200 Subject: [PATCH 07/44] Add instantiate2 details --- .../TxMsgInstantiateContract2Details.tsx | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 components/dataViews/TransactionInfo/TxMsgInstantiateContract2Details.tsx diff --git a/components/dataViews/TransactionInfo/TxMsgInstantiateContract2Details.tsx b/components/dataViews/TransactionInfo/TxMsgInstantiateContract2Details.tsx new file mode 100644 index 0000000..2107ead --- /dev/null +++ b/components/dataViews/TransactionInfo/TxMsgInstantiateContract2Details.tsx @@ -0,0 +1,82 @@ +import { fromUtf8 } from "@cosmjs/encoding"; +import { MsgInstantiateContract2 } from "cosmjs-types/cosmwasm/wasm/v1/tx"; +import { useAppContext } from "../../../context/AppContext"; +import { printableCoins } from "../../../lib/displayHelpers"; +import HashView from "../HashView"; + +interface TxMsgInstantiateContract2DetailsProps { + readonly msgValue: MsgInstantiateContract2; +} + +const TxMsgInstantiateContract2Details = ({ msgValue }: TxMsgInstantiateContract2DetailsProps) => { + const { state } = useAppContext(); + + return ( + <> +
  • +

    MsgInstantiateContract

    +
  • +
  • + +
    {msgValue.codeId.toString()}
    +
  • +
  • + +
    {msgValue.label || "None"}
    +
  • +
  • + + {msgValue.admin ? ( +
    + +
    + ) : ( +
    None
    + )} +
  • +
  • + +
    {msgValue.fixMsg ? "Yes" : "No"}
    +
  • +
  • + +
    {fromUtf8(msgValue.salt)}
    +
  • +
  • + +
    {printableCoins(msgValue.funds, state.chain)}
    +
  • +
  • + +
    {fromUtf8(msgValue.msg)}
    +
  • + + + ); +}; + +export default TxMsgInstantiateContract2Details; From b3076b69212dfab692458a9ab26ed45b33608540 Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Mon, 10 Jul 2023 18:42:53 +0200 Subject: [PATCH 08/44] Add instantiate2 form --- .../MsgForm/MsgInstantiateContract2Form.tsx | 291 ++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx diff --git a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx new file mode 100644 index 0000000..1a177a3 --- /dev/null +++ b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx @@ -0,0 +1,291 @@ +import { MsgInstantiateContract2EncodeObject } from "@cosmjs/cosmwasm-stargate"; +import { toUtf8 } from "@cosmjs/encoding"; +import { Decimal } from "@cosmjs/math"; +import { assert } from "@cosmjs/utils"; +import { useEffect, useState } from "react"; +import { MsgGetter } from ".."; +import { useAppContext } from "../../../../context/AppContext"; +import { checkAddress, exampleAddress } from "../../../../lib/displayHelpers"; +import { ChainInfo } from "../../../../types"; +import { MsgCodecs, MsgTypeUrls } from "../../../../types/txMsg"; +import Input from "../../../inputs/Input"; +import Select from "../../../inputs/Select"; +import StackableContainer from "../../../layout/StackableContainer"; + +const customDenomOption = { label: "Custom (enter denom below)", value: "custom" } as const; + +const getDenomOptions = (assets: ChainInfo["assets"]) => { + if (!assets?.length) { + return [customDenomOption]; + } + + return [...assets.map((asset) => ({ label: asset.symbol, value: asset })), customDenomOption]; +}; + +interface MsgInstantiateContract2FormProps { + readonly fromAddress: string; + readonly setMsgGetter: (msgGetter: MsgGetter) => void; + readonly deleteMsg: () => void; +} + +const MsgInstantiateContract2Form = ({ + fromAddress, + setMsgGetter, + deleteMsg, +}: MsgInstantiateContract2FormProps) => { + const { state } = useAppContext(); + assert(state.chain.addressPrefix, "addressPrefix missing"); + + const denomOptions = getDenomOptions(state.chain.assets); + + const [codeId, setCodeId] = useState(""); + const [label, setLabel] = useState(""); + const [adminAddress, setAdminAddress] = useState(""); + const [fixMsg, setFixMsg] = useState(false); + const [salt, setSalt] = useState(""); + const [msgContent, setMsgContent] = useState("{}"); + const [selectedDenom, setSelectedDenom] = useState(denomOptions[0]); + const [customDenom, setCustomDenom] = useState(""); + const [amount, setAmount] = useState("0"); + + const [codeIdError, setCodeIdError] = useState(""); + const [adminAddressError, setAdminAddressError] = useState(""); + const [msgContentError, setMsgContentError] = useState(""); + const [customDenomError, setCustomDenomError] = useState(""); + const [amountError, setAmountError] = useState(""); + + useEffect(() => { + assert(state.chain.denom, "denom missing"); + + setAdminAddressError(""); + setMsgContentError(""); + setCustomDenomError(""); + setAmountError(""); + + const isMsgValid = (): boolean => { + assert(state.chain.addressPrefix, "addressPrefix missing"); + + if (!codeId || !Number.isSafeInteger(Number(codeId)) || Number(codeId) <= 0) { + setCodeIdError("Code ID must be a positive integer"); + return false; + } + + const addressErrorMsg = checkAddress(adminAddress, state.chain.addressPrefix); + if (adminAddress && addressErrorMsg) { + setAdminAddressError( + `Invalid address for network ${state.chain.chainId}: ${addressErrorMsg}`, + ); + return false; + } + + try { + JSON.parse(msgContent); + } catch { + setMsgContentError("Msg must be valid JSON"); + return false; + } + + if (selectedDenom.value === customDenomOption.value && !customDenom) { + setCustomDenomError("Custom denom must be set because of selection above"); + return false; + } + + if (!amount || Number(amount) <= 0) { + setAmountError("Amount must be greater than 0"); + return false; + } + + if (selectedDenom.value === customDenomOption.value && !Number.isInteger(Number(amount))) { + setAmountError("Amount cannot be decimal for custom denom"); + return false; + } + + return true; + }; + + const denom = + selectedDenom.value === customDenomOption.value ? customDenom : selectedDenom.value.symbol; + + const amountInAtomics = (() => { + try { + if (selectedDenom.value === customDenomOption.value) { + return Decimal.fromUserInput(amount, 0).atomics; + } + + const foundAsset = state.chain.assets?.find((asset) => asset.symbol === denom); + const exponent = + foundAsset?.denom_units.find((unit) => unit.denom === foundAsset.symbol.toLowerCase()) + ?.exponent ?? 0; + + return Decimal.fromUserInput(amount, exponent).atomics; + } catch { + return "0"; + } + })(); + + const msgValue = MsgCodecs[MsgTypeUrls.Instantiate2].fromPartial({ + sender: fromAddress, + codeId, + label, + admin: adminAddress, + fixMsg, + salt: toUtf8(salt), + msg: toUtf8(msgContent), + funds: [{ denom, amount: amountInAtomics }], + }); + + const msg: MsgInstantiateContract2EncodeObject = { + typeUrl: MsgTypeUrls.Instantiate2, + value: msgValue, + }; + + setMsgGetter({ isMsgValid, msg }); + }, [ + adminAddress, + amount, + codeId, + customDenom, + fixMsg, + fromAddress, + label, + msgContent, + salt, + selectedDenom.value, + setMsgGetter, + state.chain.addressPrefix, + state.chain.assets, + state.chain.chainId, + state.chain.denom, + ]); + + return ( + + +

    MsgInstantiateContract

    +
    + setCodeId(target.value)} + error={codeIdError} + /> +
    +
    + setLabel(target.value)} + /> +
    +
    + setAdminAddress(target.value)} + error={adminAddressError} + placeholder={`E.g. ${exampleAddress(0, state.chain.addressPrefix)}`} + /> +
    +
    + setFixMsg(target.checked)} + /> +
    +
    + setSalt(target.value)} + /> +
    +
    + setMsgContent(target.value)} + error={msgContentError} + placeholder={"Enter msg JSON"} + /> +
    +
    + + setCustomDenom(target.value)} + placeholder={ + selectedDenom.value === customDenomOption.value + ? "Enter custom denom" + : "Select Custom denom above" + } + disabled={selectedDenom.value !== customDenomOption.value} + error={customDenomError} + /> +
    +
    + setAmount(target.value)} + error={amountError} + /> +
    + +
    + ); +}; + +export default MsgInstantiateContract2Form; From 8ffb2a725a1f334ff6c6686fb1d272cfb14c1973 Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Mon, 10 Jul 2023 18:43:44 +0200 Subject: [PATCH 09/44] Switch new forms and details --- components/dataViews/TransactionInfo/index.tsx | 9 +++++++++ components/forms/CreateTxForm/MsgForm/index.tsx | 9 +++++++++ components/forms/CreateTxForm/index.tsx | 9 +++++++++ 3 files changed, 27 insertions(+) diff --git a/components/dataViews/TransactionInfo/index.tsx b/components/dataViews/TransactionInfo/index.tsx index 5986a8e..0b11c6c 100644 --- a/components/dataViews/TransactionInfo/index.tsx +++ b/components/dataViews/TransactionInfo/index.tsx @@ -7,6 +7,9 @@ import StackableContainer from "../../layout/StackableContainer"; import TxMsgClaimRewardsDetails from "./TxMsgClaimRewardsDetails"; import TxMsgCreateVestingAccountDetails from "./TxMsgCreateVestingAccountDetails"; import TxMsgDelegateDetails from "./TxMsgDelegateDetails"; +import TxMsgExecuteContractDetails from "./TxMsgExecuteContractDetails"; +import TxMsgInstantiateContract2Details from "./TxMsgInstantiateContract2Details"; +import TxMsgInstantiateContractDetails from "./TxMsgInstantiateContractDetails"; import TxMsgRedelegateDetails from "./TxMsgRedelegateDetails"; import TxMsgSendDetails from "./TxMsgSendDetails"; import TxMsgSetWithdrawAddressDetails from "./TxMsgSetWithdrawAddressDetails"; @@ -31,6 +34,12 @@ const TxMsgDetails = ({ typeUrl, value: msgValue }: EncodeObject) => { return ; case MsgTypeUrls.Transfer: return ; + case MsgTypeUrls.Execute: + return ; + case MsgTypeUrls.Instantiate: + return ; + case MsgTypeUrls.Instantiate2: + return ; default: return null; } diff --git a/components/forms/CreateTxForm/MsgForm/index.tsx b/components/forms/CreateTxForm/MsgForm/index.tsx index bcd9027..c47864c 100644 --- a/components/forms/CreateTxForm/MsgForm/index.tsx +++ b/components/forms/CreateTxForm/MsgForm/index.tsx @@ -3,6 +3,9 @@ import { MsgTypeUrl, MsgTypeUrls } from "../../../../types/txMsg"; import MsgClaimRewardsForm from "./MsgClaimRewardsForm"; import MsgCreateVestingAccountForm from "./MsgCreateVestingAccountForm"; import MsgDelegateForm from "./MsgDelegateForm"; +import MsgExecuteContractForm from "./MsgExecuteContractForm"; +import MsgInstantiateContract2Form from "./MsgInstantiateContract2Form"; +import MsgInstantiateContractForm from "./MsgInstantiateContractForm"; import MsgRedelegateForm from "./MsgRedelegateForm"; import MsgSendForm from "./MsgSendForm"; import MsgSetWithdrawAddressForm from "./MsgSetWithdrawAddressForm"; @@ -34,6 +37,12 @@ const MsgForm = ({ msgType, senderAddress, ...restProps }: MsgFormProps) => { return ; case MsgTypeUrls.Transfer: return ; + case MsgTypeUrls.Execute: + return ; + case MsgTypeUrls.Instantiate: + return ; + case MsgTypeUrls.Instantiate2: + return ; default: return null; } diff --git a/components/forms/CreateTxForm/index.tsx b/components/forms/CreateTxForm/index.tsx index 63eff73..9385e9c 100644 --- a/components/forms/CreateTxForm/index.tsx +++ b/components/forms/CreateTxForm/index.tsx @@ -179,6 +179,15 @@ const CreateTxForm = ({ router, senderAddress, accountOnChain }: CreateTxFormPro onClick={() => addMsgType(MsgTypeUrls.CreateVestingAccount)} /> -

    MsgSend

    +

    MsgExecuteContract

    deleteMsg()}> ✕ -

    MsgInstantiateContract

    +

    MsgInstantiateContract2

    Date: Mon, 10 Jul 2023 19:11:16 +0200 Subject: [PATCH 11/44] Fix remove error --- .../forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx | 1 + .../forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx index bcc66ab..ed6474f 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx @@ -57,6 +57,7 @@ const MsgInstantiateContract2Form = ({ useEffect(() => { assert(state.chain.denom, "denom missing"); + setCodeIdError(""); setAdminAddressError(""); setMsgContentError(""); setCustomDenomError(""); diff --git a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx index a40abbe..cc1ff7f 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx @@ -55,6 +55,7 @@ const MsgInstantiateContractForm = ({ useEffect(() => { assert(state.chain.denom, "denom missing"); + setCodeIdError(""); setAdminAddressError(""); setMsgContentError(""); setCustomDenomError(""); From 7ebb8f3389ada1c3f09d7a87311f703f4a158403 Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Mon, 10 Jul 2023 19:18:02 +0200 Subject: [PATCH 12/44] Add migrate types --- lib/txMsgHelpers.ts | 2 ++ types/txMsg.ts | 3 +++ 2 files changed, 5 insertions(+) diff --git a/lib/txMsgHelpers.ts b/lib/txMsgHelpers.ts index 9e2f0b9..f5cb6b8 100644 --- a/lib/txMsgHelpers.ts +++ b/lib/txMsgHelpers.ts @@ -26,6 +26,8 @@ const gasOfMsg = (msgType: MsgTypeUrl): number => { return 150_000; case MsgTypeUrls.Instantiate2: return 150_000; + case MsgTypeUrls.Migrate: + return 150_000; default: throw new Error("Unknown msg type"); } diff --git a/types/txMsg.ts b/types/txMsg.ts index 0c6db2c..6a1ccb2 100644 --- a/types/txMsg.ts +++ b/types/txMsg.ts @@ -13,6 +13,7 @@ import { MsgExecuteContract, MsgInstantiateContract, MsgInstantiateContract2, + MsgMigrateContract, } from "cosmjs-types/cosmwasm/wasm/v1/tx"; import { MsgTransfer } from "cosmjs-types/ibc/applications/transfer/v1/tx"; @@ -28,6 +29,7 @@ export const MsgTypeUrls = { Execute: "/cosmwasm.wasm.v1.MsgExecuteContract", Instantiate: "/cosmwasm.wasm.v1.MsgInstantiateContract", Instantiate2: "/cosmwasm.wasm.v1.MsgInstantiateContract2", + Migrate: "/cosmwasm.wasm.v1.MsgMigrateContract", } as const; export type MsgTypeUrl = (typeof MsgTypeUrls)[keyof typeof MsgTypeUrls]; @@ -44,4 +46,5 @@ export const MsgCodecs = { [MsgTypeUrls.Execute]: MsgExecuteContract, [MsgTypeUrls.Instantiate]: MsgInstantiateContract, [MsgTypeUrls.Instantiate2]: MsgInstantiateContract2, + [MsgTypeUrls.Migrate]: MsgMigrateContract, }; From 3d4f9dea893d4e7e04cb70bc64f5cbb25a3f52ae Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Mon, 10 Jul 2023 19:18:13 +0200 Subject: [PATCH 13/44] Add migrate details --- .../TxMsgMigrateContractDetails.tsx | 56 +++++++++++++++++++ .../dataViews/TransactionInfo/index.tsx | 3 + 2 files changed, 59 insertions(+) create mode 100644 components/dataViews/TransactionInfo/TxMsgMigrateContractDetails.tsx diff --git a/components/dataViews/TransactionInfo/TxMsgMigrateContractDetails.tsx b/components/dataViews/TransactionInfo/TxMsgMigrateContractDetails.tsx new file mode 100644 index 0000000..8e095a1 --- /dev/null +++ b/components/dataViews/TransactionInfo/TxMsgMigrateContractDetails.tsx @@ -0,0 +1,56 @@ +import { fromUtf8 } from "@cosmjs/encoding"; +import { MsgMigrateContract } from "cosmjs-types/cosmwasm/wasm/v1/tx"; +import HashView from "../HashView"; + +interface TxMsgMigrateContractDetailsProps { + readonly msgValue: MsgMigrateContract; +} + +const TxMsgMigrateContractDetails = ({ msgValue }: TxMsgMigrateContractDetailsProps) => ( + <> +
  • +

    MsgMigrateContract

    +
  • +
  • + +
    + +
    +
  • +
  • + +
    {msgValue.codeId.toString()}
    +
  • +
  • + +
    {fromUtf8(msgValue.msg)}
    +
  • + + +); + +export default TxMsgMigrateContractDetails; diff --git a/components/dataViews/TransactionInfo/index.tsx b/components/dataViews/TransactionInfo/index.tsx index 0b11c6c..c6f5c12 100644 --- a/components/dataViews/TransactionInfo/index.tsx +++ b/components/dataViews/TransactionInfo/index.tsx @@ -10,6 +10,7 @@ import TxMsgDelegateDetails from "./TxMsgDelegateDetails"; import TxMsgExecuteContractDetails from "./TxMsgExecuteContractDetails"; import TxMsgInstantiateContract2Details from "./TxMsgInstantiateContract2Details"; import TxMsgInstantiateContractDetails from "./TxMsgInstantiateContractDetails"; +import TxMsgMigrateContractDetails from "./TxMsgMigrateContractDetails"; import TxMsgRedelegateDetails from "./TxMsgRedelegateDetails"; import TxMsgSendDetails from "./TxMsgSendDetails"; import TxMsgSetWithdrawAddressDetails from "./TxMsgSetWithdrawAddressDetails"; @@ -40,6 +41,8 @@ const TxMsgDetails = ({ typeUrl, value: msgValue }: EncodeObject) => { return ; case MsgTypeUrls.Instantiate2: return ; + case MsgTypeUrls.Migrate: + return ; default: return null; } From fad870cc471890da25194a42f55ddf9ca0b3572c Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Mon, 10 Jul 2023 19:18:49 +0200 Subject: [PATCH 14/44] Add migrate form --- .../MsgForm/MsgMigrateContractForm.tsx | 152 ++++++++++++++++++ .../forms/CreateTxForm/MsgForm/index.tsx | 3 + components/forms/CreateTxForm/index.tsx | 1 + 3 files changed, 156 insertions(+) create mode 100644 components/forms/CreateTxForm/MsgForm/MsgMigrateContractForm.tsx diff --git a/components/forms/CreateTxForm/MsgForm/MsgMigrateContractForm.tsx b/components/forms/CreateTxForm/MsgForm/MsgMigrateContractForm.tsx new file mode 100644 index 0000000..71dc473 --- /dev/null +++ b/components/forms/CreateTxForm/MsgForm/MsgMigrateContractForm.tsx @@ -0,0 +1,152 @@ +import { MsgMigrateContractEncodeObject } from "@cosmjs/cosmwasm-stargate"; +import { toUtf8 } from "@cosmjs/encoding"; +import { assert } from "@cosmjs/utils"; +import { useEffect, useState } from "react"; +import { MsgGetter } from ".."; +import { useAppContext } from "../../../../context/AppContext"; +import { checkAddress, exampleAddress } from "../../../../lib/displayHelpers"; +import { MsgCodecs, MsgTypeUrls } from "../../../../types/txMsg"; +import Input from "../../../inputs/Input"; +import StackableContainer from "../../../layout/StackableContainer"; + +interface MsgMigrateContractFormProps { + readonly fromAddress: string; + readonly setMsgGetter: (msgGetter: MsgGetter) => void; + readonly deleteMsg: () => void; +} + +const MsgMigrateContractForm = ({ + fromAddress, + setMsgGetter, + deleteMsg, +}: MsgMigrateContractFormProps) => { + const { state } = useAppContext(); + assert(state.chain.addressPrefix, "addressPrefix missing"); + + const [codeId, setCodeId] = useState(""); + const [contractAddress, setContractAddress] = useState(""); + const [msgContent, setMsgContent] = useState("{}"); + + const [codeIdError, setCodeIdError] = useState(""); + const [contractAddressError, setContractAddressError] = useState(""); + const [msgContentError, setMsgContentError] = useState(""); + + useEffect(() => { + assert(state.chain.denom, "denom missing"); + + setCodeIdError(""); + setContractAddressError(""); + setMsgContentError(""); + + const isMsgValid = (): boolean => { + assert(state.chain.addressPrefix, "addressPrefix missing"); + + if (!codeId || !Number.isSafeInteger(Number(codeId)) || Number(codeId) <= 0) { + setCodeIdError("Code ID must be a positive integer"); + return false; + } + + const addressErrorMsg = checkAddress(contractAddress, state.chain.addressPrefix); + if (addressErrorMsg) { + setContractAddressError( + `Invalid address for network ${state.chain.chainId}: ${addressErrorMsg}`, + ); + return false; + } + + try { + JSON.parse(msgContent); + } catch { + setMsgContentError("Msg must be valid JSON"); + return false; + } + + return true; + }; + + const msgValue = MsgCodecs[MsgTypeUrls.Migrate].fromPartial({ + sender: fromAddress, + contract: contractAddress, + codeId, + msg: toUtf8(msgContent), + }); + + const msg: MsgMigrateContractEncodeObject = { typeUrl: MsgTypeUrls.Migrate, value: msgValue }; + + setMsgGetter({ isMsgValid, msg }); + }, [ + codeId, + contractAddress, + fromAddress, + msgContent, + setMsgGetter, + state.chain.addressPrefix, + state.chain.chainId, + state.chain.denom, + ]); + + return ( + + +

    MsgMigrateContract

    +
    + setCodeId(target.value)} + error={codeIdError} + /> +
    +
    + setContractAddress(target.value)} + error={contractAddressError} + placeholder={`E.g. ${exampleAddress(0, state.chain.addressPrefix)}`} + /> +
    +
    + setMsgContent(target.value)} + error={msgContentError} + placeholder={"Enter msg JSON"} + /> +
    + +
    + ); +}; + +export default MsgMigrateContractForm; diff --git a/components/forms/CreateTxForm/MsgForm/index.tsx b/components/forms/CreateTxForm/MsgForm/index.tsx index c47864c..21f048f 100644 --- a/components/forms/CreateTxForm/MsgForm/index.tsx +++ b/components/forms/CreateTxForm/MsgForm/index.tsx @@ -6,6 +6,7 @@ import MsgDelegateForm from "./MsgDelegateForm"; import MsgExecuteContractForm from "./MsgExecuteContractForm"; import MsgInstantiateContract2Form from "./MsgInstantiateContract2Form"; import MsgInstantiateContractForm from "./MsgInstantiateContractForm"; +import MsgMigrateContractForm from "./MsgMigrateContractForm"; import MsgRedelegateForm from "./MsgRedelegateForm"; import MsgSendForm from "./MsgSendForm"; import MsgSetWithdrawAddressForm from "./MsgSetWithdrawAddressForm"; @@ -43,6 +44,8 @@ const MsgForm = ({ msgType, senderAddress, ...restProps }: MsgFormProps) => { return ; case MsgTypeUrls.Instantiate2: return ; + case MsgTypeUrls.Migrate: + return ; default: return null; } diff --git a/components/forms/CreateTxForm/index.tsx b/components/forms/CreateTxForm/index.tsx index 9385e9c..df7624a 100644 --- a/components/forms/CreateTxForm/index.tsx +++ b/components/forms/CreateTxForm/index.tsx @@ -188,6 +188,7 @@ const CreateTxForm = ({ router, senderAddress, accountOnChain }: CreateTxFormPro label="Add MsgInstantiateContract2" onClick={() => addMsgType(MsgTypeUrls.Instantiate2)} /> +
    diff --git a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx index ed6474f..46584fa 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx @@ -1,12 +1,11 @@ import { MsgInstantiateContract2EncodeObject } from "@cosmjs/cosmwasm-stargate"; import { toUtf8 } from "@cosmjs/encoding"; import { Decimal } from "@cosmjs/math"; -import { assert } from "@cosmjs/utils"; import { useEffect, useState } from "react"; import { MsgGetter } from ".."; -import { useAppContext } from "../../../../context/AppContext"; +import { useChains } from "../../../../context/ChainsContext"; +import { ChainInfo } from "../../../../context/ChainsContext/types"; import { checkAddress, exampleAddress } from "../../../../lib/displayHelpers"; -import { ChainInfo } from "../../../../types"; import { MsgCodecs, MsgTypeUrls } from "../../../../types/txMsg"; import Input from "../../../inputs/Input"; import Select from "../../../inputs/Select"; @@ -33,10 +32,9 @@ const MsgInstantiateContract2Form = ({ setMsgGetter, deleteMsg, }: MsgInstantiateContract2FormProps) => { - const { state } = useAppContext(); - assert(state.chain.addressPrefix, "addressPrefix missing"); + const { chain } = useChains(); - const denomOptions = getDenomOptions(state.chain.assets); + const denomOptions = getDenomOptions(chain.assets); const [codeId, setCodeId] = useState(""); const [label, setLabel] = useState(""); @@ -55,8 +53,6 @@ const MsgInstantiateContract2Form = ({ const [amountError, setAmountError] = useState(""); useEffect(() => { - assert(state.chain.denom, "denom missing"); - setCodeIdError(""); setAdminAddressError(""); setMsgContentError(""); @@ -64,18 +60,14 @@ const MsgInstantiateContract2Form = ({ setAmountError(""); const isMsgValid = (): boolean => { - assert(state.chain.addressPrefix, "addressPrefix missing"); - if (!codeId || !Number.isSafeInteger(Number(codeId)) || Number(codeId) <= 0) { setCodeIdError("Code ID must be a positive integer"); return false; } - const addressErrorMsg = checkAddress(adminAddress, state.chain.addressPrefix); + const addressErrorMsg = checkAddress(adminAddress, chain.addressPrefix); if (adminAddress && addressErrorMsg) { - setAdminAddressError( - `Invalid address for network ${state.chain.chainId}: ${addressErrorMsg}`, - ); + setAdminAddressError(`Invalid address for network ${chain.chainId}: ${addressErrorMsg}`); return false; } @@ -113,7 +105,7 @@ const MsgInstantiateContract2Form = ({ return Decimal.fromUserInput(amount, 0).atomics; } - const foundAsset = state.chain.assets?.find((asset) => asset.symbol === denom); + const foundAsset = chain.assets?.find((asset) => asset.symbol === denom); const exponent = foundAsset?.denom_units.find((unit) => unit.denom === foundAsset.symbol.toLowerCase()) ?.exponent ?? 0; @@ -144,6 +136,10 @@ const MsgInstantiateContract2Form = ({ }, [ adminAddress, amount, + chain.addressPrefix, + chain.assets, + chain.chainId, + chain.denom, codeId, customDenom, fixMsg, @@ -153,10 +149,6 @@ const MsgInstantiateContract2Form = ({ salt, selectedDenom.value, setMsgGetter, - state.chain.addressPrefix, - state.chain.assets, - state.chain.chainId, - state.chain.denom, ]); return ( @@ -189,7 +181,7 @@ const MsgInstantiateContract2Form = ({ value={adminAddress} onChange={({ target }) => setAdminAddress(target.value)} error={adminAddressError} - placeholder={`E.g. ${exampleAddress(0, state.chain.addressPrefix)}`} + placeholder={`E.g. ${exampleAddress(0, chain.addressPrefix)}`} />
    diff --git a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx index cc1ff7f..3e5b668 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx @@ -1,12 +1,11 @@ import { MsgInstantiateContractEncodeObject } from "@cosmjs/cosmwasm-stargate"; import { toUtf8 } from "@cosmjs/encoding"; import { Decimal } from "@cosmjs/math"; -import { assert } from "@cosmjs/utils"; import { useEffect, useState } from "react"; import { MsgGetter } from ".."; -import { useAppContext } from "../../../../context/AppContext"; +import { useChains } from "../../../../context/ChainsContext"; +import { ChainInfo } from "../../../../context/ChainsContext/types"; import { checkAddress, exampleAddress } from "../../../../lib/displayHelpers"; -import { ChainInfo } from "../../../../types"; import { MsgCodecs, MsgTypeUrls } from "../../../../types/txMsg"; import Input from "../../../inputs/Input"; import Select from "../../../inputs/Select"; @@ -33,10 +32,9 @@ const MsgInstantiateContractForm = ({ setMsgGetter, deleteMsg, }: MsgInstantiateContractFormProps) => { - const { state } = useAppContext(); - assert(state.chain.addressPrefix, "addressPrefix missing"); + const { chain } = useChains(); - const denomOptions = getDenomOptions(state.chain.assets); + const denomOptions = getDenomOptions(chain.assets); const [codeId, setCodeId] = useState(""); const [label, setLabel] = useState(""); @@ -53,8 +51,6 @@ const MsgInstantiateContractForm = ({ const [amountError, setAmountError] = useState(""); useEffect(() => { - assert(state.chain.denom, "denom missing"); - setCodeIdError(""); setAdminAddressError(""); setMsgContentError(""); @@ -62,18 +58,14 @@ const MsgInstantiateContractForm = ({ setAmountError(""); const isMsgValid = (): boolean => { - assert(state.chain.addressPrefix, "addressPrefix missing"); - if (!codeId || !Number.isSafeInteger(Number(codeId)) || Number(codeId) <= 0) { setCodeIdError("Code ID must be a positive integer"); return false; } - const addressErrorMsg = checkAddress(adminAddress, state.chain.addressPrefix); + const addressErrorMsg = checkAddress(adminAddress, chain.addressPrefix); if (adminAddress && addressErrorMsg) { - setAdminAddressError( - `Invalid address for network ${state.chain.chainId}: ${addressErrorMsg}`, - ); + setAdminAddressError(`Invalid address for network ${chain.chainId}: ${addressErrorMsg}`); return false; } @@ -111,7 +103,7 @@ const MsgInstantiateContractForm = ({ return Decimal.fromUserInput(amount, 0).atomics; } - const foundAsset = state.chain.assets?.find((asset) => asset.symbol === denom); + const foundAsset = chain.assets?.find((asset) => asset.symbol === denom); const exponent = foundAsset?.denom_units.find((unit) => unit.denom === foundAsset.symbol.toLowerCase()) ?.exponent ?? 0; @@ -140,6 +132,9 @@ const MsgInstantiateContractForm = ({ }, [ adminAddress, amount, + chain.addressPrefix, + chain.assets, + chain.chainId, codeId, customDenom, fromAddress, @@ -147,10 +142,6 @@ const MsgInstantiateContractForm = ({ msgContent, selectedDenom.value, setMsgGetter, - state.chain.addressPrefix, - state.chain.assets, - state.chain.chainId, - state.chain.denom, ]); return ( @@ -183,7 +174,7 @@ const MsgInstantiateContractForm = ({ value={adminAddress} onChange={({ target }) => setAdminAddress(target.value)} error={adminAddressError} - placeholder={`E.g. ${exampleAddress(0, state.chain.addressPrefix)}`} + placeholder={`E.g. ${exampleAddress(0, chain.addressPrefix)}`} />
    diff --git a/components/forms/CreateTxForm/MsgForm/MsgMigrateContractForm.tsx b/components/forms/CreateTxForm/MsgForm/MsgMigrateContractForm.tsx index 71dc473..8d42e3f 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgMigrateContractForm.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgMigrateContractForm.tsx @@ -1,9 +1,8 @@ import { MsgMigrateContractEncodeObject } from "@cosmjs/cosmwasm-stargate"; import { toUtf8 } from "@cosmjs/encoding"; -import { assert } from "@cosmjs/utils"; import { useEffect, useState } from "react"; import { MsgGetter } from ".."; -import { useAppContext } from "../../../../context/AppContext"; +import { useChains } from "../../../../context/ChainsContext"; import { checkAddress, exampleAddress } from "../../../../lib/displayHelpers"; import { MsgCodecs, MsgTypeUrls } from "../../../../types/txMsg"; import Input from "../../../inputs/Input"; @@ -20,8 +19,7 @@ const MsgMigrateContractForm = ({ setMsgGetter, deleteMsg, }: MsgMigrateContractFormProps) => { - const { state } = useAppContext(); - assert(state.chain.addressPrefix, "addressPrefix missing"); + const { chain } = useChains(); const [codeId, setCodeId] = useState(""); const [contractAddress, setContractAddress] = useState(""); @@ -32,25 +30,19 @@ const MsgMigrateContractForm = ({ const [msgContentError, setMsgContentError] = useState(""); useEffect(() => { - assert(state.chain.denom, "denom missing"); - setCodeIdError(""); setContractAddressError(""); setMsgContentError(""); const isMsgValid = (): boolean => { - assert(state.chain.addressPrefix, "addressPrefix missing"); - if (!codeId || !Number.isSafeInteger(Number(codeId)) || Number(codeId) <= 0) { setCodeIdError("Code ID must be a positive integer"); return false; } - const addressErrorMsg = checkAddress(contractAddress, state.chain.addressPrefix); + const addressErrorMsg = checkAddress(contractAddress, chain.addressPrefix); if (addressErrorMsg) { - setContractAddressError( - `Invalid address for network ${state.chain.chainId}: ${addressErrorMsg}`, - ); + setContractAddressError(`Invalid address for network ${chain.chainId}: ${addressErrorMsg}`); return false; } @@ -80,9 +72,9 @@ const MsgMigrateContractForm = ({ fromAddress, msgContent, setMsgGetter, - state.chain.addressPrefix, - state.chain.chainId, - state.chain.denom, + chain.addressPrefix, + chain.chainId, + chain.denom, ]); return ( @@ -107,7 +99,7 @@ const MsgMigrateContractForm = ({ value={contractAddress} onChange={({ target }) => setContractAddress(target.value)} error={contractAddressError} - placeholder={`E.g. ${exampleAddress(0, state.chain.addressPrefix)}`} + placeholder={`E.g. ${exampleAddress(0, chain.addressPrefix)}`} />
    From 726bde774c377f285cd210ec8f741e9b57dcaba9 Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Thu, 13 Jul 2023 18:22:31 +0200 Subject: [PATCH 16/44] Add jsoneditor dep --- package-lock.json | 13 ++++++++++++- package.json | 3 ++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7dac6e3..850f6e6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,8 @@ "next": "^13.3.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-select": "^5.7.2" + "react-select": "^5.7.2", + "vanilla-jsoneditor": "^0.17.8" }, "devDependencies": { "@testing-library/jest-dom": "^5.16.5", @@ -8719,6 +8720,11 @@ "node": ">=10.12.0" } }, + "node_modules/vanilla-jsoneditor": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/vanilla-jsoneditor/-/vanilla-jsoneditor-0.17.8.tgz", + "integrity": "sha512-DP9GP/IBQjYOnC820CYoFuXs3vgrL+zdGGp1X83qFirSkRWPeP+6zB/14a0LYhvomQNNezes5Gwel89MKc4Qbg==" + }, "node_modules/w3c-xmlserializer": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", @@ -15537,6 +15543,11 @@ "convert-source-map": "^1.6.0" } }, + "vanilla-jsoneditor": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/vanilla-jsoneditor/-/vanilla-jsoneditor-0.17.8.tgz", + "integrity": "sha512-DP9GP/IBQjYOnC820CYoFuXs3vgrL+zdGGp1X83qFirSkRWPeP+6zB/14a0LYhvomQNNezes5Gwel89MKc4Qbg==" + }, "w3c-xmlserializer": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", diff --git a/package.json b/package.json index d134d52..bb14c36 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,8 @@ "next": "^13.3.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-select": "^5.7.2" + "react-select": "^5.7.2", + "vanilla-jsoneditor": "^0.17.8" }, "devDependencies": { "@testing-library/jest-dom": "^5.16.5", From a8acfa4fb167ce3ef3ed2546d1ecbdedd7b3654a Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Thu, 13 Jul 2023 18:22:39 +0200 Subject: [PATCH 17/44] Add JsonEditor component --- components/inputs/JsonEditor.tsx | 65 ++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 components/inputs/JsonEditor.tsx diff --git a/components/inputs/JsonEditor.tsx b/components/inputs/JsonEditor.tsx new file mode 100644 index 0000000..a171671 --- /dev/null +++ b/components/inputs/JsonEditor.tsx @@ -0,0 +1,65 @@ +import { CSSProperties, useEffect, useRef } from "react"; +import { JSONEditorPropsOptional, JSONEditor as VanillaJsonEditor } from "vanilla-jsoneditor"; + +const editorStyle: { [key: string]: string } & CSSProperties = { + "--jse-a-color": "white", + "--jse-delimiter-color": "white", + "--jse-key-color": "white", + "--jse-text-color": "white", + "--jse-value-color": "white", + "--jse-value-color-boolean": "white", + "--jse-value-color-null": "white", + "--jse-value-color-number": "white", + "--jse-value-color-string": "white", + "--jse-value-color-url": "white", + "--jse-background-color": "transparent", + "--jse-panel-background": "transparent", + "--jse-selection-background-color": "rgba(255, 255, 255, 0.5)", + "--jse-main-border": "2px solid rgba(255, 255, 255, 0.5)", + "--jse-panel-border": "2px solid rgba(255, 255, 255, 0.5)", +}; + +interface JsonEditorProps extends JSONEditorPropsOptional { + readonly label?: string; +} + +export default function JsonEditor({ label, ...editorProps }: JsonEditorProps) { + const refContainer = useRef(null); + const refEditor = useRef(null); + + useEffect(() => { + if (!refContainer.current) return; + + refEditor.current = new VanillaJsonEditor({ target: refContainer.current, props: {} }); + + return () => { + if (refEditor.current) { + refEditor.current.destroy(); + refEditor.current = null; + } + }; + }, []); + + useEffect(() => { + if (refEditor.current) { + refEditor.current.updateProps({ mode: "text", mainMenuBar: false, ...editorProps }); + } + }, [editorProps]); + + return ( +
    + {label ? : null} + +
    + ); +} From 089383a401eff280e1d9905f778337d781f6a181 Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Thu, 13 Jul 2023 18:23:02 +0200 Subject: [PATCH 18/44] Use JsonEditor in MsgExecuteContractForm --- .../MsgForm/MsgExecuteContractForm.tsx | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/components/forms/CreateTxForm/MsgForm/MsgExecuteContractForm.tsx b/components/forms/CreateTxForm/MsgForm/MsgExecuteContractForm.tsx index 3f136eb..6c6e59c 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgExecuteContractForm.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgExecuteContractForm.tsx @@ -1,6 +1,7 @@ import { MsgExecuteContractEncodeObject } from "@cosmjs/cosmwasm-stargate"; import { toUtf8 } from "@cosmjs/encoding"; import { Decimal } from "@cosmjs/math"; +import dynamic from "next/dynamic"; import { useEffect, useState } from "react"; import { MsgGetter } from ".."; import { useChains } from "../../../../context/ChainsContext"; @@ -11,6 +12,8 @@ import Input from "../../../inputs/Input"; import Select from "../../../inputs/Select"; import StackableContainer from "../../../layout/StackableContainer"; +const JsonEditor = dynamic(() => import("../../../inputs/JsonEditor"), { ssr: false }); + const customDenomOption = { label: "Custom (enter denom below)", value: "custom" } as const; const getDenomOptions = (assets: ChainInfo["assets"]) => { @@ -43,13 +46,11 @@ const MsgExecuteContractForm = ({ const [amount, setAmount] = useState("0"); const [contractAddressError, setContractAddressError] = useState(""); - const [msgContentError, setMsgContentError] = useState(""); const [customDenomError, setCustomDenomError] = useState(""); const [amountError, setAmountError] = useState(""); useEffect(() => { setContractAddressError(""); - setMsgContentError(""); setCustomDenomError(""); setAmountError(""); @@ -60,13 +61,6 @@ const MsgExecuteContractForm = ({ return false; } - try { - JSON.parse(msgContent); - } catch { - setMsgContentError("Msg must be valid JSON"); - return false; - } - if (selectedDenom.value === customDenomOption.value && !customDenom) { setCustomDenomError("Custom denom must be set because of selection above"); return false; @@ -145,13 +139,12 @@ const MsgExecuteContractForm = ({ />
    - setMsgContent(target.value)} - error={msgContentError} - placeholder={"Enter msg JSON"} + + setMsgContent("text" in newMsgContent ? newMsgContent.text ?? "{}" : "{}") + } />
    From edc1c61b8d6ce56ca605ced6b85d4dd7f0bc9d49 Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Thu, 13 Jul 2023 18:23:16 +0200 Subject: [PATCH 19/44] Use JsonEditor in MsgInstantiateContractForm --- .../MsgForm/MsgInstantiateContractForm.tsx | 27 +++++++------------ 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx index 3e5b668..5cb44ab 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx @@ -1,6 +1,7 @@ import { MsgInstantiateContractEncodeObject } from "@cosmjs/cosmwasm-stargate"; import { toUtf8 } from "@cosmjs/encoding"; import { Decimal } from "@cosmjs/math"; +import dynamic from "next/dynamic"; import { useEffect, useState } from "react"; import { MsgGetter } from ".."; import { useChains } from "../../../../context/ChainsContext"; @@ -11,6 +12,8 @@ import Input from "../../../inputs/Input"; import Select from "../../../inputs/Select"; import StackableContainer from "../../../layout/StackableContainer"; +const JsonEditor = dynamic(() => import("../../../inputs/JsonEditor"), { ssr: false }); + const customDenomOption = { label: "Custom (enter denom below)", value: "custom" } as const; const getDenomOptions = (assets: ChainInfo["assets"]) => { @@ -46,14 +49,12 @@ const MsgInstantiateContractForm = ({ const [codeIdError, setCodeIdError] = useState(""); const [adminAddressError, setAdminAddressError] = useState(""); - const [msgContentError, setMsgContentError] = useState(""); const [customDenomError, setCustomDenomError] = useState(""); const [amountError, setAmountError] = useState(""); useEffect(() => { setCodeIdError(""); setAdminAddressError(""); - setMsgContentError(""); setCustomDenomError(""); setAmountError(""); @@ -69,13 +70,6 @@ const MsgInstantiateContractForm = ({ return false; } - try { - JSON.parse(msgContent); - } catch { - setMsgContentError("Msg must be valid JSON"); - return false; - } - if (selectedDenom.value === customDenomOption.value && !customDenom) { setCustomDenomError("Custom denom must be set because of selection above"); return false; @@ -116,7 +110,7 @@ const MsgInstantiateContractForm = ({ const msgValue = MsgCodecs[MsgTypeUrls.Instantiate].fromPartial({ sender: fromAddress, - codeId, + codeId: codeId || 1, label, admin: adminAddress, msg: toUtf8(msgContent), @@ -178,13 +172,12 @@ const MsgInstantiateContractForm = ({ />
    - setMsgContent(target.value)} - error={msgContentError} - placeholder={"Enter msg JSON"} + + setMsgContent("text" in newMsgContent ? newMsgContent.text ?? "{}" : "{}") + } />
    From 11858574804477fe116e0e14cd255bb0e413e4a2 Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Thu, 13 Jul 2023 18:23:26 +0200 Subject: [PATCH 20/44] Use JsonEditor in MsgInstantiateContract2Form --- .../MsgForm/MsgInstantiateContract2Form.tsx | 27 +++++++------------ 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx index 46584fa..05fea76 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx @@ -1,6 +1,7 @@ import { MsgInstantiateContract2EncodeObject } from "@cosmjs/cosmwasm-stargate"; import { toUtf8 } from "@cosmjs/encoding"; import { Decimal } from "@cosmjs/math"; +import dynamic from "next/dynamic"; import { useEffect, useState } from "react"; import { MsgGetter } from ".."; import { useChains } from "../../../../context/ChainsContext"; @@ -11,6 +12,8 @@ import Input from "../../../inputs/Input"; import Select from "../../../inputs/Select"; import StackableContainer from "../../../layout/StackableContainer"; +const JsonEditor = dynamic(() => import("../../../inputs/JsonEditor"), { ssr: false }); + const customDenomOption = { label: "Custom (enter denom below)", value: "custom" } as const; const getDenomOptions = (assets: ChainInfo["assets"]) => { @@ -48,14 +51,12 @@ const MsgInstantiateContract2Form = ({ const [codeIdError, setCodeIdError] = useState(""); const [adminAddressError, setAdminAddressError] = useState(""); - const [msgContentError, setMsgContentError] = useState(""); const [customDenomError, setCustomDenomError] = useState(""); const [amountError, setAmountError] = useState(""); useEffect(() => { setCodeIdError(""); setAdminAddressError(""); - setMsgContentError(""); setCustomDenomError(""); setAmountError(""); @@ -71,13 +72,6 @@ const MsgInstantiateContract2Form = ({ return false; } - try { - JSON.parse(msgContent); - } catch { - setMsgContentError("Msg must be valid JSON"); - return false; - } - if (selectedDenom.value === customDenomOption.value && !customDenom) { setCustomDenomError("Custom denom must be set because of selection above"); return false; @@ -118,7 +112,7 @@ const MsgInstantiateContract2Form = ({ const msgValue = MsgCodecs[MsgTypeUrls.Instantiate2].fromPartial({ sender: fromAddress, - codeId, + codeId: codeId || 1, label, admin: adminAddress, fixMsg, @@ -203,13 +197,12 @@ const MsgInstantiateContract2Form = ({ />
    - setMsgContent(target.value)} - error={msgContentError} - placeholder={"Enter msg JSON"} + + setMsgContent("text" in newMsgContent ? newMsgContent.text ?? "{}" : "{}") + } />
    From fd60bd5e421d076a858dd8d02bf66e5135fd0a90 Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Thu, 13 Jul 2023 18:45:03 +0200 Subject: [PATCH 21/44] Remove unneded dep from useEffect --- .../forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx index 05fea76..b95d28e 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx @@ -133,7 +133,6 @@ const MsgInstantiateContract2Form = ({ chain.addressPrefix, chain.assets, chain.chainId, - chain.denom, codeId, customDenom, fixMsg, From 5cc4d506e9445a48fba4003346bac96da6c28ebe Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Thu, 13 Jul 2023 18:45:20 +0200 Subject: [PATCH 22/44] Use JsonEditor in MsgMigrateContractForm --- .../MsgForm/MsgMigrateContractForm.tsx | 32 +++++++------------ 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/components/forms/CreateTxForm/MsgForm/MsgMigrateContractForm.tsx b/components/forms/CreateTxForm/MsgForm/MsgMigrateContractForm.tsx index 8d42e3f..09f6dc6 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgMigrateContractForm.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgMigrateContractForm.tsx @@ -1,5 +1,6 @@ import { MsgMigrateContractEncodeObject } from "@cosmjs/cosmwasm-stargate"; import { toUtf8 } from "@cosmjs/encoding"; +import dynamic from "next/dynamic"; import { useEffect, useState } from "react"; import { MsgGetter } from ".."; import { useChains } from "../../../../context/ChainsContext"; @@ -8,6 +9,8 @@ import { MsgCodecs, MsgTypeUrls } from "../../../../types/txMsg"; import Input from "../../../inputs/Input"; import StackableContainer from "../../../layout/StackableContainer"; +const JsonEditor = dynamic(() => import("../../../inputs/JsonEditor"), { ssr: false }); + interface MsgMigrateContractFormProps { readonly fromAddress: string; readonly setMsgGetter: (msgGetter: MsgGetter) => void; @@ -27,12 +30,10 @@ const MsgMigrateContractForm = ({ const [codeIdError, setCodeIdError] = useState(""); const [contractAddressError, setContractAddressError] = useState(""); - const [msgContentError, setMsgContentError] = useState(""); useEffect(() => { setCodeIdError(""); setContractAddressError(""); - setMsgContentError(""); const isMsgValid = (): boolean => { if (!codeId || !Number.isSafeInteger(Number(codeId)) || Number(codeId) <= 0) { @@ -46,20 +47,13 @@ const MsgMigrateContractForm = ({ return false; } - try { - JSON.parse(msgContent); - } catch { - setMsgContentError("Msg must be valid JSON"); - return false; - } - return true; }; const msgValue = MsgCodecs[MsgTypeUrls.Migrate].fromPartial({ sender: fromAddress, contract: contractAddress, - codeId, + codeId: codeId || 1, msg: toUtf8(msgContent), }); @@ -67,14 +61,13 @@ const MsgMigrateContractForm = ({ setMsgGetter({ isMsgValid, msg }); }, [ + chain.addressPrefix, + chain.chainId, codeId, contractAddress, fromAddress, msgContent, setMsgGetter, - chain.addressPrefix, - chain.chainId, - chain.denom, ]); return ( @@ -103,13 +96,12 @@ const MsgMigrateContractForm = ({ />
    - setMsgContent(target.value)} - error={msgContentError} - placeholder={"Enter msg JSON"} + + setMsgContent("text" in newMsgContent ? newMsgContent.text ?? "{}" : "{}") + } />
    ); diff --git a/components/dataViews/TransactionInfo/TxMsgInstantiateContract2Details.tsx b/components/dataViews/TransactionInfo/TxMsgInstantiateContract2Details.tsx index 00cefe9..c390a8d 100644 --- a/components/dataViews/TransactionInfo/TxMsgInstantiateContract2Details.tsx +++ b/components/dataViews/TransactionInfo/TxMsgInstantiateContract2Details.tsx @@ -1,6 +1,8 @@ -import { fromUtf8 } from "@cosmjs/encoding"; +import { fromUtf8, toHex } from "@cosmjs/encoding"; import { MsgInstantiateContract2 } from "cosmjs-types/cosmwasm/wasm/v1/tx"; import dynamic from "next/dynamic"; +import { useState } from "react"; +import { JSONValue } from "vanilla-jsoneditor"; import { useChains } from "../../../context/ChainsContext"; import { printableCoins } from "../../../lib/displayHelpers"; import HashView from "../HashView"; @@ -13,6 +15,20 @@ interface TxMsgInstantiateContract2DetailsProps { const TxMsgInstantiateContract2Details = ({ msgValue }: TxMsgInstantiateContract2DetailsProps) => { const { chain } = useChains(); + const [parseError, setParseError] = useState(""); + + const json: JSONValue = (() => { + if (parseError) { + return {}; + } + + try { + return JSON.parse(fromUtf8(msgValue.msg)); + } catch (e) { + setParseError(e instanceof Error ? e.message : "Failed to decode UTF-8 msg"); + return {}; + } + })(); return ( <> @@ -45,9 +61,15 @@ const TxMsgInstantiateContract2Details = ({ msgValue }: TxMsgInstantiateContract
    {printableCoins(msgValue.funds, chain)}
    -
  • - -
  • + {parseError ? ( +
  • +

    {parseError}

    +
  • + ) : ( +
  • + +
  • + )} ); diff --git a/components/dataViews/TransactionInfo/TxMsgInstantiateContractDetails.tsx b/components/dataViews/TransactionInfo/TxMsgInstantiateContractDetails.tsx index c50db10..fe6513a 100644 --- a/components/dataViews/TransactionInfo/TxMsgInstantiateContractDetails.tsx +++ b/components/dataViews/TransactionInfo/TxMsgInstantiateContractDetails.tsx @@ -1,6 +1,8 @@ import { fromUtf8 } from "@cosmjs/encoding"; import { MsgInstantiateContract } from "cosmjs-types/cosmwasm/wasm/v1/tx"; import dynamic from "next/dynamic"; +import { useState } from "react"; +import { JSONValue } from "vanilla-jsoneditor"; import { useChains } from "../../../context/ChainsContext"; import { printableCoins } from "../../../lib/displayHelpers"; import HashView from "../HashView"; @@ -13,6 +15,20 @@ interface TxMsgInstantiateContractDetailsProps { const TxMsgInstantiateContractDetails = ({ msgValue }: TxMsgInstantiateContractDetailsProps) => { const { chain } = useChains(); + const [parseError, setParseError] = useState(""); + + const json: JSONValue = (() => { + if (parseError) { + return {}; + } + + try { + return JSON.parse(fromUtf8(msgValue.msg)); + } catch (e) { + setParseError(e instanceof Error ? e.message : "Failed to decode UTF-8 msg"); + return {}; + } + })(); return ( <> @@ -41,9 +57,15 @@ const TxMsgInstantiateContractDetails = ({ msgValue }: TxMsgInstantiateContractD
    {printableCoins(msgValue.funds, chain)}
    -
  • - -
  • + {parseError ? ( +
  • +

    {parseError}

    +
  • + ) : ( +
  • + +
  • + )} ); diff --git a/components/dataViews/TransactionInfo/TxMsgMigrateContractDetails.tsx b/components/dataViews/TransactionInfo/TxMsgMigrateContractDetails.tsx index 09be796..086222e 100644 --- a/components/dataViews/TransactionInfo/TxMsgMigrateContractDetails.tsx +++ b/components/dataViews/TransactionInfo/TxMsgMigrateContractDetails.tsx @@ -1,6 +1,8 @@ import { fromUtf8 } from "@cosmjs/encoding"; import { MsgMigrateContract } from "cosmjs-types/cosmwasm/wasm/v1/tx"; import dynamic from "next/dynamic"; +import { useState } from "react"; +import { JSONValue } from "vanilla-jsoneditor"; import HashView from "../HashView"; const JsonEditor = dynamic(() => import("../../inputs/JsonEditor"), { ssr: false }); @@ -9,50 +11,79 @@ interface TxMsgMigrateContractDetailsProps { readonly msgValue: MsgMigrateContract; } -const TxMsgMigrateContractDetails = ({ msgValue }: TxMsgMigrateContractDetailsProps) => ( - <> -
  • -

    MsgMigrateContract

    -
  • -
  • - -
    - -
    -
  • -
  • - -
    {msgValue.codeId.toString()}
    -
  • -
  • - -
  • - - -); +const TxMsgMigrateContractDetails = ({ msgValue }: TxMsgMigrateContractDetailsProps) => { + const [parseError, setParseError] = useState(""); + + const json: JSONValue = (() => { + if (parseError) { + return {}; + } + + try { + return JSON.parse(fromUtf8(msgValue.msg)); + } catch (e) { + setParseError(e instanceof Error ? e.message : "Failed to decode UTF-8 msg"); + return {}; + } + })(); + + return ( + <> +
  • +

    MsgMigrateContract

    +
  • +
  • + +
    + +
    +
  • +
  • + +
    {msgValue.codeId.toString()}
    +
  • + {parseError ? ( +
  • +

    {parseError}

    +
  • + ) : ( +
  • + +
  • + )} + + + ); +}; export default TxMsgMigrateContractDetails; From f62fa054755a9e354244f78448152bc8d05f5d08 Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Wed, 26 Jul 2023 17:44:45 +0200 Subject: [PATCH 41/44] Return undefined msgContentUtf8Array --- .../forms/CreateTxForm/MsgForm/MsgExecuteContractForm.tsx | 2 +- .../forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx | 2 +- .../forms/CreateTxForm/MsgForm/MsgMigrateContractForm.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/forms/CreateTxForm/MsgForm/MsgExecuteContractForm.tsx b/components/forms/CreateTxForm/MsgForm/MsgExecuteContractForm.tsx index 93d7fad..3340c5c 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgExecuteContractForm.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgExecuteContractForm.tsx @@ -95,7 +95,7 @@ const MsgExecuteContractForm = ({ // The JsonEditor does not escape \n or remove whitespaces, so we need to parse + stringify return toUtf8(JSON.stringify(JSON.parse(msgContent))); } catch { - return Uint8Array.from([]); + return undefined; } })(); diff --git a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx index 07bac73..8039b8a 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx @@ -111,7 +111,7 @@ const MsgInstantiateContractForm = ({ // The JsonEditor does not escape \n or remove whitespaces, so we need to parse + stringify return toUtf8(JSON.stringify(JSON.parse(msgContent))); } catch { - return Uint8Array.from([]); + return undefined; } })(); diff --git a/components/forms/CreateTxForm/MsgForm/MsgMigrateContractForm.tsx b/components/forms/CreateTxForm/MsgForm/MsgMigrateContractForm.tsx index d89f48b..59c1880 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgMigrateContractForm.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgMigrateContractForm.tsx @@ -55,7 +55,7 @@ const MsgMigrateContractForm = ({ // The JsonEditor does not escape \n or remove whitespaces, so we need to parse + stringify return toUtf8(JSON.stringify(JSON.parse(msgContent))); } catch { - return Uint8Array.from([]); + return undefined; } })(); From d6c1686dd734e65c5beaf640150c9fbcf72d2582 Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Wed, 26 Jul 2023 17:45:38 +0200 Subject: [PATCH 42/44] Remove fix msg. Use hex salt --- .../MsgForm/MsgInstantiateContract2Form.tsx | 41 +++++++++++-------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx index d3ebba6..56951e8 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx @@ -1,5 +1,5 @@ import { MsgInstantiateContract2EncodeObject } from "@cosmjs/cosmwasm-stargate"; -import { toUtf8 } from "@cosmjs/encoding"; +import { fromHex, toUtf8 } from "@cosmjs/encoding"; import dynamic from "next/dynamic"; import { useEffect, useState } from "react"; import { MsgGetter } from ".."; @@ -42,7 +42,6 @@ const MsgInstantiateContract2Form = ({ const [codeId, setCodeId] = useState(""); const [label, setLabel] = useState(""); const [adminAddress, setAdminAddress] = useState(""); - const [fixMsg, setFixMsg] = useState(false); const [salt, setSalt] = useState(""); const [msgContent, setMsgContent] = useState("{}"); const [selectedDenom, setSelectedDenom] = useState(denomOptions[0]); @@ -52,6 +51,7 @@ const MsgInstantiateContract2Form = ({ const [codeIdError, setCodeIdError] = useState(""); const [labelError, setLabelError] = useState(""); const [adminAddressError, setAdminAddressError] = useState(""); + const [saltError, setSaltError] = useState(""); const [customDenomError, setCustomDenomError] = useState(""); const [amountError, setAmountError] = useState(""); @@ -59,6 +59,7 @@ const MsgInstantiateContract2Form = ({ setCodeIdError(""); setLabelError(""); setAdminAddressError(""); + setSaltError(""); setCustomDenomError(""); setAmountError(""); @@ -79,6 +80,13 @@ const MsgInstantiateContract2Form = ({ return false; } + try { + fromHex(salt); + } catch (e) { + setSaltError(e instanceof Error ? e.message : "Salt needs to be an hexadecimal string"); + return false; + } + if (selectedDenom.value === customDenomOption.value && !customDenom) { setCustomDenomError("Custom denom must be set because of selection above"); return false; @@ -108,12 +116,20 @@ const MsgInstantiateContract2Form = ({ } })(); + const hexSalt = (() => { + try { + return fromHex(salt); + } catch { + return undefined; + } + })(); + const msgContentUtf8Array = (() => { try { // The JsonEditor does not escape \n or remove whitespaces, so we need to parse + stringify return toUtf8(JSON.stringify(JSON.parse(msgContent))); } catch { - return Uint8Array.from([]); + return undefined; } })(); @@ -122,8 +138,8 @@ const MsgInstantiateContract2Form = ({ codeId: codeId || 0, label, admin: adminAddress, - fixMsg, - salt: toUtf8(salt), + fixMsg: false, + salt: hexSalt, msg: msgContentUtf8Array, funds: [microCoin], }); @@ -142,7 +158,6 @@ const MsgInstantiateContract2Form = ({ chain.chainId, codeId, customDenom, - fixMsg, fromAddress, label, msgContent, @@ -187,20 +202,12 @@ const MsgInstantiateContract2Form = ({
    setFixMsg(target.checked)} - /> -
    -
    - setSalt(target.value)} + error={saltError} />
    From d49baa25fabf7ed26cb78011e68fab96a1e3de2f Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Wed, 26 Jul 2023 17:50:02 +0200 Subject: [PATCH 43/44] Check empty salt --- .../CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx index 56951e8..900dc58 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx @@ -81,6 +81,10 @@ const MsgInstantiateContract2Form = ({ } try { + if (!salt) { + throw new Error("Salt is required"); + } + fromHex(salt); } catch (e) { setSaltError(e instanceof Error ? e.message : "Salt needs to be an hexadecimal string"); From 62be9d6b5a0eac931da4144fea4b64eada39f855 Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Thu, 27 Jul 2023 09:39:08 +0200 Subject: [PATCH 44/44] Avoid sending form with JSON errors --- .../MsgForm/MsgExecuteContractForm.tsx | 14 ++++++++++---- .../MsgForm/MsgInstantiateContract2Form.tsx | 14 ++++++++++---- .../MsgForm/MsgInstantiateContractForm.tsx | 14 ++++++++++---- .../MsgForm/MsgMigrateContractForm.tsx | 14 ++++++++++---- 4 files changed, 40 insertions(+), 16 deletions(-) diff --git a/components/forms/CreateTxForm/MsgForm/MsgExecuteContractForm.tsx b/components/forms/CreateTxForm/MsgForm/MsgExecuteContractForm.tsx index 3340c5c..a335b98 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgExecuteContractForm.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgExecuteContractForm.tsx @@ -1,7 +1,7 @@ import { MsgExecuteContractEncodeObject } from "@cosmjs/cosmwasm-stargate"; import { toUtf8 } from "@cosmjs/encoding"; import dynamic from "next/dynamic"; -import { useEffect, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { MsgGetter } from ".."; import { useChains } from "../../../../context/ChainsContext"; import { ChainInfo } from "../../../../context/ChainsContext/types"; @@ -45,6 +45,7 @@ const MsgExecuteContractForm = ({ const [customDenom, setCustomDenom] = useState(""); const [amount, setAmount] = useState("0"); + const jsonError = useRef(false); const [contractAddressError, setContractAddressError] = useState(""); const [customDenomError, setCustomDenomError] = useState(""); const [amountError, setAmountError] = useState(""); @@ -55,6 +56,10 @@ const MsgExecuteContractForm = ({ setAmountError(""); const isMsgValid = (): boolean => { + if (jsonError.current) { + return false; + } + const addressErrorMsg = checkAddress(contractAddress, chain.addressPrefix); if (addressErrorMsg) { setContractAddressError(`Invalid address for network ${chain.chainId}: ${addressErrorMsg}`); @@ -142,9 +147,10 @@ const MsgExecuteContractForm = ({ - setMsgContent("text" in newMsgContent ? newMsgContent.text ?? "{}" : "{}") - } + onChange={(newMsgContent, _, { contentErrors }) => { + setMsgContent("text" in newMsgContent ? newMsgContent.text ?? "{}" : "{}"); + jsonError.current = !!contentErrors; + }} />
    diff --git a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx index 900dc58..64b8a16 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContract2Form.tsx @@ -1,7 +1,7 @@ import { MsgInstantiateContract2EncodeObject } from "@cosmjs/cosmwasm-stargate"; import { fromHex, toUtf8 } from "@cosmjs/encoding"; import dynamic from "next/dynamic"; -import { useEffect, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { MsgGetter } from ".."; import { useChains } from "../../../../context/ChainsContext"; import { ChainInfo } from "../../../../context/ChainsContext/types"; @@ -48,6 +48,7 @@ const MsgInstantiateContract2Form = ({ const [customDenom, setCustomDenom] = useState(""); const [amount, setAmount] = useState("0"); + const jsonError = useRef(false); const [codeIdError, setCodeIdError] = useState(""); const [labelError, setLabelError] = useState(""); const [adminAddressError, setAdminAddressError] = useState(""); @@ -64,6 +65,10 @@ const MsgInstantiateContract2Form = ({ setAmountError(""); const isMsgValid = (): boolean => { + if (jsonError.current) { + return false; + } + if (!codeId || !Number.isSafeInteger(Number(codeId)) || Number(codeId) <= 0) { setCodeIdError("Code ID must be a positive integer"); return false; @@ -218,9 +223,10 @@ const MsgInstantiateContract2Form = ({ - setMsgContent("text" in newMsgContent ? newMsgContent.text ?? "{}" : "{}") - } + onChange={(newMsgContent, _, { contentErrors }) => { + setMsgContent("text" in newMsgContent ? newMsgContent.text ?? "{}" : "{}"); + jsonError.current = !!contentErrors; + }} />
    diff --git a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx index 8039b8a..77d1f18 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgInstantiateContractForm.tsx @@ -1,7 +1,7 @@ import { MsgInstantiateContractEncodeObject } from "@cosmjs/cosmwasm-stargate"; import { toUtf8 } from "@cosmjs/encoding"; import dynamic from "next/dynamic"; -import { useEffect, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { MsgGetter } from ".."; import { useChains } from "../../../../context/ChainsContext"; import { ChainInfo } from "../../../../context/ChainsContext/types"; @@ -47,6 +47,7 @@ const MsgInstantiateContractForm = ({ const [customDenom, setCustomDenom] = useState(""); const [amount, setAmount] = useState("0"); + const jsonError = useRef(false); const [codeIdError, setCodeIdError] = useState(""); const [labelError, setLabelError] = useState(""); const [adminAddressError, setAdminAddressError] = useState(""); @@ -61,6 +62,10 @@ const MsgInstantiateContractForm = ({ setAmountError(""); const isMsgValid = (): boolean => { + if (jsonError.current) { + return false; + } + if (!codeId || !Number.isSafeInteger(Number(codeId)) || Number(codeId) <= 0) { setCodeIdError("Code ID must be a positive integer"); return false; @@ -183,9 +188,10 @@ const MsgInstantiateContractForm = ({ - setMsgContent("text" in newMsgContent ? newMsgContent.text ?? "{}" : "{}") - } + onChange={(newMsgContent, _, { contentErrors }) => { + setMsgContent("text" in newMsgContent ? newMsgContent.text ?? "{}" : "{}"); + jsonError.current = !!contentErrors; + }} />
    diff --git a/components/forms/CreateTxForm/MsgForm/MsgMigrateContractForm.tsx b/components/forms/CreateTxForm/MsgForm/MsgMigrateContractForm.tsx index 59c1880..c1f4dae 100644 --- a/components/forms/CreateTxForm/MsgForm/MsgMigrateContractForm.tsx +++ b/components/forms/CreateTxForm/MsgForm/MsgMigrateContractForm.tsx @@ -1,7 +1,7 @@ import { MsgMigrateContractEncodeObject } from "@cosmjs/cosmwasm-stargate"; import { toUtf8 } from "@cosmjs/encoding"; import dynamic from "next/dynamic"; -import { useEffect, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { MsgGetter } from ".."; import { useChains } from "../../../../context/ChainsContext"; import { checkAddress, exampleAddress } from "../../../../lib/displayHelpers"; @@ -28,6 +28,7 @@ const MsgMigrateContractForm = ({ const [codeId, setCodeId] = useState(""); const [msgContent, setMsgContent] = useState("{}"); + const jsonError = useRef(false); const [contractAddressError, setContractAddressError] = useState(""); const [codeIdError, setCodeIdError] = useState(""); @@ -36,6 +37,10 @@ const MsgMigrateContractForm = ({ setContractAddressError(""); const isMsgValid = (): boolean => { + if (jsonError.current) { + return false; + } + const addressErrorMsg = checkAddress(contractAddress, chain.addressPrefix); if (addressErrorMsg) { setContractAddressError(`Invalid address for network ${chain.chainId}: ${addressErrorMsg}`); @@ -108,9 +113,10 @@ const MsgMigrateContractForm = ({ - setMsgContent("text" in newMsgContent ? newMsgContent.text ?? "{}" : "{}") - } + onChange={(newMsgContent, _, { contentErrors }) => { + setMsgContent("text" in newMsgContent ? newMsgContent.text ?? "{}" : "{}"); + jsonError.current = !!contentErrors; + }} />