diff --git a/.cargo/config b/.cargo/config new file mode 100644 index 0000000..af5698e --- /dev/null +++ b/.cargo/config @@ -0,0 +1,4 @@ +[alias] +wasm = "build --release --lib --target wasm32-unknown-unknown" +unit-test = "test --lib" +schema = "run --bin schema" diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..9b07669 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,61 @@ +version: 2.1 + +executors: + builder: + docker: + - image: buildpack-deps:trusty + +jobs: + docker-image: + executor: builder + steps: + - checkout + - setup_remote_docker + docker_layer_caching: true + - run: + name: Build Docker artifact + command: docker build --pull -t "cosmwasm/cw-gitpod-base:${CIRCLE_SHA1}" . + - run: + name: Push application Docker image to docker hub + command: | + if [ "${CIRCLE_BRANCH}" = "master" ]; then + docker tag "cosmwasm/cw-gitpod-base:${CIRCLE_SHA1}" cosmwasm/cw-gitpod-base:latest + docker login --password-stdin -u "$DOCKER_USER" \<<<"$DOCKER_PASS" + docker push cosmwasm/cw-gitpod-base:latest + docker logout + fi + + docker-tagged: + executor: builder + steps: + - checkout + - setup_remote_docker + docker_layer_caching: true + - run: + name: Push application Docker image to docker hub + command: | + docker tag "cosmwasm/cw-gitpod-base:${CIRCLE_SHA1}" "cosmwasm/cw-gitpod-base:${CIRCLE_TAG}" + docker login --password-stdin -u "$DOCKER_USER" \<<<"$DOCKER_PASS" + docker push + docker logout + +workflows: + version: 2 + test-suite: + jobs: + # this is now a slow process... let's only run on master + - docker-image: + filters: + branches: + only: + - master + - docker-tagged: + filters: + tags: + only: + - /^v.*/ + branches: + ignore: + - /.*/ + requires: + - docker-image diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..3d36f20 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.rs] +indent_size = 4 diff --git a/.github/workflows/Basic.yml b/.github/workflows/Basic.yml new file mode 100644 index 0000000..3890a07 --- /dev/null +++ b/.github/workflows/Basic.yml @@ -0,0 +1,75 @@ +# Based on https://github.com/actions-rs/example/blob/master/.github/workflows/quickstart.yml + +on: [push, pull_request] + +name: Basic + +jobs: + + test: + name: Test Suite + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + - name: Install stable toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: 1.60.0 + target: wasm32-unknown-unknown + override: true + + - name: Run unit tests + uses: actions-rs/cargo@v1 + with: + command: unit-test + args: --locked + env: + RUST_BACKTRACE: 1 + + - name: Compile WASM contract + uses: actions-rs/cargo@v1 + with: + command: wasm + args: --locked + env: + RUSTFLAGS: "-C link-arg=-s" + + lints: + name: Lints + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + - name: Install stable toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: 1.60.0 + override: true + components: rustfmt, clippy + + - name: Run cargo fmt + uses: actions-rs/cargo@v1 + with: + command: fmt + args: --all -- --check + + - name: Run cargo clippy + uses: actions-rs/cargo@v1 + with: + command: clippy + args: -- -D warnings + + - name: Generate Schema + uses: actions-rs/cargo@v1 + with: + command: schema + args: --locked + + - name: Schema Changes + # fails if any changes not committed + run: git diff --exit-code schema diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml new file mode 100644 index 0000000..a9d5979 --- /dev/null +++ b/.github/workflows/Release.yml @@ -0,0 +1,35 @@ +name: release wasm + +on: + release: + types: [created] + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v2 + - name: Install cargo-run-script + uses: actions-rs/cargo@v1 + with: + command: install + args: cargo-run-script + - name: Run cargo optimize + uses: actions-rs/cargo@v1 + with: + command: run-script + args: optimize + - name: Get release ID + id: get_release + uses: bruceadams/get-release@v1.2.3 + env: + GITHUB_TOKEN: ${{ github.token }} + - name: Upload optimized wasm + uses: svenstaro/upload-release-action@v2 + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + file: ./artifacts/*.wasm + tag: ${{ github.ref }} + overwrite: true + file_glob: true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9095dea --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +# Build results +/target +/schema + +# Cargo+Git helper file (https://github.com/rust-lang/cargo/blob/0.44.1/src/cargo/sources/git/utils.rs#L320-L327) +.cargo-ok + +# Text file backups +**/*.rs.bk + +# macOS +.DS_Store + +# IDEs +*.iml +.idea diff --git a/.gitpod.Dockerfile b/.gitpod.Dockerfile new file mode 100644 index 0000000..bff8bc5 --- /dev/null +++ b/.gitpod.Dockerfile @@ -0,0 +1,17 @@ +### wasmd ### +FROM cosmwasm/wasmd:v0.18.0 as wasmd + +### rust-optimizer ### +FROM cosmwasm/rust-optimizer:0.11.5 as rust-optimizer + +FROM gitpod/workspace-full:latest + +COPY --from=wasmd /usr/bin/wasmd /usr/local/bin/wasmd +COPY --from=wasmd /opt/* /opt/ + +RUN sudo apt-get update \ + && sudo apt-get install -y jq \ + && sudo rm -rf /var/lib/apt/lists/* + +RUN rustup update stable \ + && rustup target add wasm32-unknown-unknown diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 0000000..d03610c --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,10 @@ +image: cosmwasm/cw-gitpod-base:v0.16 + +vscode: + extensions: + - rust-lang.rust + +tasks: + - name: Dependencies & Build + init: | + cargo build diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..364c3dc --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,873 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "anyhow" +version = "1.0.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" + +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "const-oid" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" + +[[package]] +name = "cosmo-aggr" +version = "0.1.0" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cosmwasm-storage", + "cw-multi-test", + "cw-storage-plus", + "cw2", + "osmosis-std", + "schemars", + "serde", + "thiserror", +] + +[[package]] +name = "cosmwasm-crypto" +version = "1.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b76d2207945b8aa3ce0735da53ab9a74f75fe3e7794754c216a9edfa04e1e627" +dependencies = [ + "digest 0.10.6", + "ed25519-zebra", + "k256", + "rand_core 0.6.4", + "thiserror", +] + +[[package]] +name = "cosmwasm-derive" +version = "1.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd07af7736164d2d8126dc67fdb33b1b5c54fb5a3190395c47f46d24fc6d592" +dependencies = [ + "syn 1.0.109", +] + +[[package]] +name = "cosmwasm-schema" +version = "1.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e9e92cdce475a91659d0dc4d17836a484fc534e80e787281aa4adde4cb1798b" +dependencies = [ + "cosmwasm-schema-derive", + "schemars", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cosmwasm-schema-derive" +version = "1.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69681bac3dbeb0b00990279e3ed39e3d4406b29f538b16b712f6771322a45048" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "cosmwasm-std" +version = "1.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d39f20967baeb94709123f7bba13a25ae2fa166bc5e7813f734914df3f8f6a1" +dependencies = [ + "base64", + "cosmwasm-crypto", + "cosmwasm-derive", + "derivative", + "forward_ref", + "hex", + "schemars", + "serde", + "serde-json-wasm", + "sha2 0.10.6", + "thiserror", + "uint", +] + +[[package]] +name = "cosmwasm-storage" +version = "1.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88f7944b5204c3a998f73248925a097ace887bdf01c2f70de00d8b92cd69e807" +dependencies = [ + "cosmwasm-std", + "serde", +] + +[[package]] +name = "cpufeatures" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" +dependencies = [ + "libc", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "cw-multi-test" +version = "0.16.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a18afd2e201221c6d72a57f0886ef2a22151bbc9e6db7af276fde8a91081042" +dependencies = [ + "anyhow", + "cosmwasm-std", + "cw-storage-plus", + "cw-utils", + "derivative", + "itertools", + "k256", + "prost 0.9.0", + "schemars", + "serde", + "thiserror", +] + +[[package]] +name = "cw-storage-plus" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053a5083c258acd68386734f428a5a171b29f7d733151ae83090c6fcc9417ffa" +dependencies = [ + "cosmwasm-std", + "schemars", + "serde", +] + +[[package]] +name = "cw-utils" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c80e93d1deccb8588db03945016a292c3c631e6325d349ebb35d2db6f4f946f7" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw2", + "schemars", + "semver", + "serde", + "thiserror", +] + +[[package]] +name = "cw2" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fb70cee2cf0b4a8ff7253e6bc6647107905e8eb37208f87d54f67810faa62f8" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus", + "schemars", + "serde", +] + +[[package]] +name = "der" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", + "subtle", +] + +[[package]] +name = "dyn-clone" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30" + +[[package]] +name = "ecdsa" +version = "0.14.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" +dependencies = [ + "der", + "elliptic-curve", + "rfc6979", + "signature", +] + +[[package]] +name = "ed25519-zebra" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" +dependencies = [ + "curve25519-dalek", + "hashbrown", + "hex", + "rand_core 0.6.4", + "serde", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "elliptic-curve" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" +dependencies = [ + "base16ct", + "crypto-bigint", + "der", + "digest 0.10.6", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "ff" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "forward_ref" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8cbd1169bd7b4a0a20d92b9af7a7e0422888bd38a6f5ec29c1fd8c1558a272e" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "group" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.6", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + +[[package]] +name = "k256" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "sha2 0.10.6", +] + +[[package]] +name = "libc" +version = "0.2.142" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" + +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "osmosis-std" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50fb348fd7aefc37038ba8125e18b360af5bd44c6e007d2b10346777995857e3" +dependencies = [ + "cosmwasm-std", + "osmosis-std-derive", + "prost 0.11.9", + "prost-types", + "schemars", + "serde", +] + +[[package]] +name = "osmosis-std-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743ed6a9bb8d2c210a8c184a874244dbf56ebb2f6062c3848300b7ea9817ca50" +dependencies = [ + "itertools", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "pkcs8" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "proc-macro2" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prost" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" +dependencies = [ + "bytes", + "prost-derive 0.9.0", +] + +[[package]] +name = "prost" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +dependencies = [ + "bytes", + "prost-derive 0.11.9", +] + +[[package]] +name = "prost-derive" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "prost-derive" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "prost-types" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" +dependencies = [ + "prost 0.11.9", +] + +[[package]] +name = "quote" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rfc6979" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" +dependencies = [ + "crypto-bigint", + "hmac", + "zeroize", +] + +[[package]] +name = "ryu" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + +[[package]] +name = "schemars" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 1.0.109", +] + +[[package]] +name = "sec1" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "semver" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" + +[[package]] +name = "serde" +version = "1.0.160" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-json-wasm" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16a62a1fad1e1828b24acac8f2b468971dade7b8c3c2e672bcadefefb1f8c137" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.160" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] + +[[package]] +name = "serde_derive_internals" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "serde_json" +version = "1.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.6", +] + +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +dependencies = [ + "digest 0.10.6", + "rand_core 0.6.4", +] + +[[package]] +name = "spki" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "zeroize" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..1f34fda --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,54 @@ +[package] +name = "cosmo-aggr" +version = "0.1.0" +authors = ["fuzious"] +edition = "2021" + +exclude = [ + # Those files are rust-optimizer artifacts. You might want to commit them for convenience but they should not be part of the source code publication. + "contract.wasm", + "hash.txt", +] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +crate-type = ["cdylib", "rlib"] + +[profile.release] +opt-level = 3 +debug = false +rpath = false +lto = true +debug-assertions = false +codegen-units = 1 +panic = 'abort' +incremental = false +overflow-checks = true + +[features] +# for more explicit tests, cargo test --features=backtraces +backtraces = ["cosmwasm-std/backtraces"] +# use library feature to disable all instantiate/execute/query exports +library = [] + +[package.metadata.scripts] +optimize = """docker run --rm -v "$(pwd)":/code \ + --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ + --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ + cosmwasm/rust-optimizer:0.12.10 +""" + +[dependencies] +cosmwasm-schema = "1.1.3" +cosmwasm-std = "1.1.3" +cosmwasm-storage = "1.1.3" +cw-storage-plus = "1.0.1" +cw2 = "1.0.1" +osmosis-std = "0.1.4" +schemars = "0.8.10" +serde = { version = "1.0.145", default-features = false, features = ["derive"] } +thiserror = { version = "1.0.31" } + +[dev-dependencies] +cw-multi-test = "0.16.2" diff --git a/Developing.md b/Developing.md new file mode 100644 index 0000000..77e66ac --- /dev/null +++ b/Developing.md @@ -0,0 +1,104 @@ +# Developing + +If you have recently created a contract with this template, you probably could use some +help on how to build and test the contract, as well as prepare it for production. This +file attempts to provide a brief overview, assuming you have installed a recent +version of Rust already (eg. 1.58.1+). + +## Prerequisites + +Before starting, make sure you have [rustup](https://rustup.rs/) along with a +recent `rustc` and `cargo` version installed. Currently, we are testing on 1.58.1+. + +And you need to have the `wasm32-unknown-unknown` target installed as well. + +You can check that via: + +```sh +rustc --version +cargo --version +rustup target list --installed +# if wasm32 is not listed above, run this +rustup target add wasm32-unknown-unknown +``` + +## Compiling and running tests + +Now that you created your custom contract, make sure you can compile and run it before +making any changes. Go into the repository and do: + +```sh +# this will produce a wasm build in ./target/wasm32-unknown-unknown/release/YOUR_NAME_HERE.wasm +cargo wasm + +# this runs unit tests with helpful backtraces +RUST_BACKTRACE=1 cargo unit-test + +# auto-generate json schema +cargo schema +``` + +### Understanding the tests + +The main code is in `src/contract.rs` and the unit tests there run in pure rust, +which makes them very quick to execute and give nice output on failures, especially +if you do `RUST_BACKTRACE=1 cargo unit-test`. + +We consider testing critical for anything on a blockchain, and recommend to always keep +the tests up to date. + +## Generating JSON Schema + +While the Wasm calls (`instantiate`, `execute`, `query`) accept JSON, this is not enough +information to use it. We need to expose the schema for the expected messages to the +clients. You can generate this schema by calling `cargo schema`, which will output +4 files in `./schema`, corresponding to the 3 message types the contract accepts, +as well as the internal `State`. + +These files are in standard json-schema format, which should be usable by various +client side tools, either to auto-generate codecs, or just to validate incoming +json wrt. the defined schema. + +## Preparing the Wasm bytecode for production + +Before we upload it to a chain, we need to ensure the smallest output size possible, +as this will be included in the body of a transaction. We also want to have a +reproducible build process, so third parties can verify that the uploaded Wasm +code did indeed come from the claimed rust code. + +To solve both these issues, we have produced `rust-optimizer`, a docker image to +produce an extremely small build output in a consistent manner. The suggest way +to run it is this: + +```sh +docker run --rm -v "$(pwd)":/code \ + --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ + --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ + cosmwasm/rust-optimizer:0.12.11 +``` + +Or, If you're on an arm64 machine, you should use a docker image built with arm64. +```sh +docker run --rm -v "$(pwd)":/code \ + --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ + --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ + cosmwasm/rust-optimizer-arm64:0.12.11 +``` + +We must mount the contract code to `/code`. You can use a absolute path instead +of `$(pwd)` if you don't want to `cd` to the directory first. The other two +volumes are nice for speedup. Mounting `/code/target` in particular is useful +to avoid docker overwriting your local dev files with root permissions. +Note the `/code/target` cache is unique for each contract being compiled to limit +interference, while the registry cache is global. + +This is rather slow compared to local compilations, especially the first compile +of a given contract. The use of the two volume caches is very useful to speed up +following compiles of the same contract. + +This produces an `artifacts` directory with a `PROJECT_NAME.wasm`, as well as +`checksums.txt`, containing the Sha256 hash of the wasm file. +The wasm file is compiled deterministically (anyone else running the same +docker on the same git commit should get the identical file with the same Sha256 hash). +It is also stripped and minimized for upload to a blockchain (we will also +gzip it in the uploading process to make it even smaller). diff --git a/Importing.md b/Importing.md new file mode 100644 index 0000000..7dcec4f --- /dev/null +++ b/Importing.md @@ -0,0 +1,62 @@ +# Importing + +In [Publishing](./Publishing.md), we discussed how you can publish your contract to the world. +This looks at the flip-side, how can you use someone else's contract (which is the same +question as how they will use your contract). Let's go through the various stages. + +## Verifying Artifacts + +Before using remote code, you most certainly want to verify it is honest. + +The simplest audit of the repo is to simply check that the artifacts in the repo +are correct. This involves recompiling the claimed source with the claimed builder +and validating that the locally compiled code (hash) matches the code hash that was +uploaded. This will verify that the source code is the correct preimage. Which allows +one to audit the original (Rust) source code, rather than looking at wasm bytecode. + +We have a script to do this automatic verification steps that can +easily be run by many individuals. Please check out +[`cosmwasm-verify`](https://github.com/CosmWasm/cosmwasm-verify/blob/master/README.md) +to see a simple shell script that does all these steps and easily allows you to verify +any uploaded contract. + +## Reviewing + +Once you have done the quick programatic checks, it is good to give at least a quick +look through the code. A glance at `examples/schema.rs` to make sure it is outputing +all relevant structs from `contract.rs`, and also ensure `src/lib.rs` is just the +default wrapper (nothing funny going on there). After this point, we can dive into +the contract code itself. Check the flows for the execute methods, any invariants and +permission checks that should be there, and a reasonable data storage format. + +You can dig into the contract as far as you want, but it is important to make sure there +are no obvious backdoors at least. + +## Decentralized Verification + +It's not very practical to do a deep code review on every dependency you want to use, +which is a big reason for the popularity of code audits in the blockchain world. We trust +some experts review in lieu of doing the work ourselves. But wouldn't it be nice to do this +in a decentralized manner and peer-review each other's contracts? Bringing in deeper domain +knowledge and saving fees. + +Luckily, there is an amazing project called [crev](https://github.com/crev-dev/cargo-crev/blob/master/cargo-crev/README.md) +that provides `A cryptographically verifiable code review system for the cargo (Rust) package manager`. + +I highly recommend that CosmWasm contract developers get set up with this. At minimum, we +can all add a review on a package that programmatically checked out that the json schemas +and wasm bytecode do match the code, and publish our claim, so we don't all rely on some +central server to say it validated this. As we go on, we can add deeper reviews on standard +packages. + +If you want to use `cargo-crev`, please follow their +[getting started guide](https://github.com/crev-dev/cargo-crev/blob/master/cargo-crev/src/doc/getting_started.md) +and once you have made your own *proof repository* with at least one *trust proof*, +please make a PR to the [`cawesome-wasm`]() repo with a link to your repo and +some public name or pseudonym that people know you by. This allows people who trust you +to also reuse your proofs. + +There is a [standard list of proof repos](https://github.com/crev-dev/cargo-crev/wiki/List-of-Proof-Repositories) +with some strong rust developers in there. This may cover dependencies like `serde` and `snafu` +but will not hit any CosmWasm-related modules, so we look to bootstrap a very focused +review community. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..15ad7a5 --- /dev/null +++ b/NOTICE @@ -0,0 +1,13 @@ +Copyright 2023 fuzious + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/Publishing.md b/Publishing.md new file mode 100644 index 0000000..c94f867 --- /dev/null +++ b/Publishing.md @@ -0,0 +1,115 @@ +# Publishing Contracts + +This is an overview of how to publish the contract's source code in this repo. +We use Cargo's default registry [crates.io](https://crates.io/) for publishing contracts written in Rust. + +## Preparation + +Ensure the `Cargo.toml` file in the repo is properly configured. In particular, you want to +choose a name starting with `cw-`, which will help a lot finding CosmWasm contracts when +searching on crates.io. For the first publication, you will probably want version `0.1.0`. +If you have tested this on a public net already and/or had an audit on the code, +you can start with `1.0.0`, but that should imply some level of stability and confidence. +You will want entries like the following in `Cargo.toml`: + +```toml +name = "cw-escrow" +version = "0.1.0" +description = "Simple CosmWasm contract for an escrow with arbiter and timeout" +repository = "https://github.com/confio/cosmwasm-examples" +``` + +You will also want to add a valid [SPDX license statement](https://spdx.org/licenses/), +so others know the rules for using this crate. You can use any license you wish, +even a commercial license, but we recommend choosing one of the following, unless you have +specific requirements. + +* Permissive: [`Apache-2.0`](https://spdx.org/licenses/Apache-2.0.html#licenseText) or [`MIT`](https://spdx.org/licenses/MIT.html#licenseText) +* Copyleft: [`GPL-3.0-or-later`](https://spdx.org/licenses/GPL-3.0-or-later.html#licenseText) or [`AGPL-3.0-or-later`](https://spdx.org/licenses/AGPL-3.0-or-later.html#licenseText) +* Commercial license: `Commercial` (not sure if this works, I cannot find examples) + +It is also helpful to download the LICENSE text (linked to above) and store this +in a LICENSE file in your repo. Now, you have properly configured your crate for use +in a larger ecosystem. + +### Updating schema + +To allow easy use of the contract, we can publish the schema (`schema/*.json`) together +with the source code. + +```sh +cargo schema +``` + +Ensure you check in all the schema files, and make a git commit with the final state. +This commit will be published and should be tagged. Generally, you will want to +tag with the version (eg. `v0.1.0`), but in the `cosmwasm-examples` repo, we have +multiple contracts and label it like `escrow-0.1.0`. Don't forget a +`git push && git push --tags` + +### Note on build results + +Build results like Wasm bytecode or expected hash don't need to be updated since +they don't belong to the source publication. However, they are excluded from packaging +in `Cargo.toml` which allows you to commit them to your git repository if you like. + +```toml +exclude = ["artifacts"] +``` + +A single source code can be built with multiple different optimizers, so +we should not make any strict assumptions on the tooling that will be used. + +## Publishing + +Now that your package is properly configured and all artifacts are committed, it +is time to share it with the world. +Please refer to the [complete instructions for any questions](https://rurust.github.io/cargo-docs-ru/crates-io.html), +but I will try to give a quick overview of the happy path here. + +### Registry + +You will need an account on [crates.io](https://crates.io) to publish a rust crate. +If you don't have one already, just click on "Log in with GitHub" in the top-right +to quickly set up a free account. Once inside, click on your username (top-right), +then "Account Settings". On the bottom, there is a section called "API Access". +If you don't have this set up already, create a new token and use `cargo login` +to set it up. This will now authenticate you with the `cargo` cli tool and allow +you to publish. + +### Uploading + +Once this is set up, make sure you commit the current state you want to publish. +Then try `cargo publish --dry-run`. If that works well, review the files that +will be published via `cargo package --list`. If you are satisfied, you can now +officially publish it via `cargo publish`. + +Congratulations, your package is public to the world. + +### Sharing + +Once you have published your package, people can now find it by +[searching for "cw-" on crates.io](https://crates.io/search?q=cw). +But that isn't exactly the simplest way. To make things easier and help +keep the ecosystem together, we suggest making a PR to add your package +to the [`cawesome-wasm`](https://github.com/cosmwasm/cawesome-wasm) list. + +### Organizations + +Many times you are writing a contract not as a solo developer, but rather as +part of an organization. You will want to allow colleagues to upload new +versions of the contract to crates.io when you are on holiday. +[These instructions show how]() you can set up your crate to allow multiple maintainers. + +You can add another owner to the crate by specifying their github user. Note, you will +now both have complete control of the crate, and they can remove you: + +`cargo owner --add ethanfrey` + +You can also add an existing github team inside your organization: + +`cargo owner --add github:confio:developers` + +The team will allow anyone who is currently in the team to publish new versions of the crate. +And this is automatically updated when you make changes on github. However, it will not allow +anyone in the team to add or remove other owners. diff --git a/README.md b/README.md new file mode 100644 index 0000000..054ea48 --- /dev/null +++ b/README.md @@ -0,0 +1,99 @@ +# CosmWasm Starter Pack + +This is a template to build smart contracts in Rust to run inside a +[Cosmos SDK](https://github.com/cosmos/cosmos-sdk) module on all chains that enable it. +To understand the framework better, please read the overview in the +[cosmwasm repo](https://github.com/CosmWasm/cosmwasm/blob/master/README.md), +and dig into the [cosmwasm docs](https://www.cosmwasm.com). +This assumes you understand the theory and just want to get coding. + +## Creating a new repo from template + +Assuming you have a recent version of Rust and Cargo installed +(via [rustup](https://rustup.rs/)), +then the following should get you a new repo to start a contract: + +Install [cargo-generate](https://github.com/ashleygwilliams/cargo-generate) and cargo-run-script. +Unless you did that before, run this line now: + +```sh +cargo install cargo-generate --features vendored-openssl +cargo install cargo-run-script +``` + +Now, use it to create your new contract. +Go to the folder in which you want to place it and run: + +**Latest** + +```sh +cargo generate --git https://github.com/CosmWasm/cw-template.git --name PROJECT_NAME +``` + +For cloning minimal code repo: + +```sh +cargo generate --git https://github.com/CosmWasm/cw-template.git --name PROJECT_NAME -d minimal=true +``` + +**Older Version** + +Pass version as branch flag: + +```sh +cargo generate --git https://github.com/CosmWasm/cw-template.git --branch --name PROJECT_NAME +``` + +Example: + +```sh +cargo generate --git https://github.com/CosmWasm/cw-template.git --branch 0.16 --name PROJECT_NAME +``` + +You will now have a new folder called `PROJECT_NAME` (I hope you changed that to something else) +containing a simple working contract and build system that you can customize. + +## Create a Repo + +After generating, you have a initialized local git repo, but no commits, and no remote. +Go to a server (eg. github) and create a new upstream repo (called `YOUR-GIT-URL` below). +Then run the following: + +```sh +# this is needed to create a valid Cargo.lock file (see below) +cargo check +git branch -M main +git add . +git commit -m 'Initial Commit' +git remote add origin YOUR-GIT-URL +git push -u origin main +``` + +## CI Support + +We have template configurations for both [GitHub Actions](.github/workflows/Basic.yml) +and [Circle CI](.circleci/config.yml) in the generated project, so you can +get up and running with CI right away. + +One note is that the CI runs all `cargo` commands +with `--locked` to ensure it uses the exact same versions as you have locally. This also means +you must have an up-to-date `Cargo.lock` file, which is not auto-generated. +The first time you set up the project (or after adding any dep), you should ensure the +`Cargo.lock` file is updated, so the CI will test properly. This can be done simply by +running `cargo check` or `cargo unit-test`. + +## Using your project + +Once you have your custom repo, you should check out [Developing](./Developing.md) to explain +more on how to run tests and develop code. Or go through the +[online tutorial](https://docs.cosmwasm.com/) to get a better feel +of how to develop. + +[Publishing](./Publishing.md) contains useful information on how to publish your contract +to the world, once you are ready to deploy it on a running blockchain. And +[Importing](./Importing.md) contains information about pulling in other contracts or crates +that have been published. + +Please replace this README file with information about your specific project. You can keep +the `Developing.md` and `Publishing.md` files as useful referenced, but please set some +proper description in the README. diff --git a/src/bin/schema.rs b/src/bin/schema.rs new file mode 100644 index 0000000..db8e23e --- /dev/null +++ b/src/bin/schema.rs @@ -0,0 +1,11 @@ +use cosmwasm_schema::write_api; + +use cosmo_aggr::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; + +fn main() { + write_api! { + instantiate: InstantiateMsg, + execute: ExecuteMsg, + query: QueryMsg, + } +} diff --git a/src/contract.rs b/src/contract.rs new file mode 100644 index 0000000..b80e473 --- /dev/null +++ b/src/contract.rs @@ -0,0 +1,126 @@ +#[cfg(not(feature = "library"))] +use cosmwasm_std::entry_point; +use cosmwasm_std::{Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult }; +use cw2::set_contract_version; + +use crate::error::ContractError; +use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; +use crate::state::{State, STATE}; + +// version info for migration info +const CONTRACT_NAME: &str = "crates.io:cosmo-aggr"; +const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn instantiate( + deps: DepsMut, + _env: Env, + info: MessageInfo, + msg: InstantiateMsg, +) -> Result { + let state = State { + }; + set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + STATE.save(deps.storage, &state)?; + + Ok(Response::new() + .add_attribute("method", "instantiate") + ) +} + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn execute( + deps: DepsMut, + _env: Env, + info: MessageInfo, + msg: ExecuteMsg, +) -> Result { + match msg { + ExecuteMsg::SwapExactIn { call, token_in, min_token_out } => execute::swapExactIn(deps, info, call, token_in, min_token_out ) + } +} + +pub mod execute { + // use std::mem::swap; + // use std::str::FromStr; + use cosmwasm_std::{Coin, CosmosMsg, from_slice, StdError, Uint128}; + use osmosis_std::types::osmosis::gamm::v1beta1::MsgSwapExactAmountIn; + use crate::ContractError::Std; + use super::*; + + pub fn swapExactIn(deps: DepsMut, info: MessageInfo, call: Binary, tokenIn: Coin, min_token_out: Coin) -> Result { + let msg_swap = build_exact_in_validate(call)?; + let cosmos_msg_swap: CosmosMsg = msg_swap.clone().into(); + check_sufficient_funds(&info, tokenIn)?; + let minimum_token_out = msg_swap.token_out_min_amount; // when IBC implemented after swap this amount will be sent back to M1 src chain + Ok(Response::new() + .add_message(cosmos_msg_swap)) + } + + fn check_sufficient_funds(info: &MessageInfo, token_in: Coin) -> Result<(), ContractError> { + for coin in info.funds.iter() { + if coin.denom == token_in.denom && coin.amount >= token_in.amount { + return Ok(()); + } + } + Err(Std(StdError::generic_err("Insufficient funds"))) + } + + pub fn build_exact_in_validate(call: Binary) -> Result { + let msg_swap_in: MsgSwapExactAmountIn = from_slice(&call).map_err(|_| Std(StdError::generic_err("Invalid Decoding")))?; + Ok(msg_swap_in) + } + +} + +#[cfg(test)] +mod tests { + use super::*; + use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; + use cosmwasm_std::{coins, from_binary, Uint128, to_binary, Uint64, Addr}; + use osmosis_std::types::cosmos::base::v1beta1::Coin; + use osmosis_std::types::osmosis::gamm::v1beta1::{MsgSwapExactAmountIn, SwapAmountInRoute}; + use schemars::_serde_json::json; + + #[test] + fn test_swap_exact_in_success() { + let mut deps = mock_dependencies(); + let env = mock_env(); + let msg = InstantiateMsg {}; + let info = mock_info("owner", &[]); + instantiate(deps.as_mut(), env.clone(), info.clone(), msg).unwrap(); + let call = create_call_data(&env.contract.address); + let token_in = cosmwasm_std::Coin { denom: "uosmo".to_string(), amount: Uint128::from(100000u128) }; + let min_token_out = cosmwasm_std::Coin { denom: "ibc-token".to_string(), amount: Uint128::from(500u128) }; + let info = mock_info("sender", &coins(100000, "uosmo")); + let msg = ExecuteMsg::SwapExactIn { call: call.clone(), token_in: token_in.clone(), min_token_out: min_token_out.clone() }; + let res = execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap(); + + // Check if the swap message was created correctly + assert_eq!(res.messages.len(), 1); + // Add more assertions to verify the created message + + } + + fn create_call_data(contract_addr: &Addr) -> Binary { + let sender = contract_addr.to_string(); + let routes = vec![SwapAmountInRoute { + pool_id: 1u64, + token_out_denom: "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2".to_string(), + }]; + let token_in = Some(Coin { + denom: "uosmo".to_string(), + amount: "100000".to_string(), + }); + let token_out_min_amount = "77961000".to_string(); + + let msg_swap_in = MsgSwapExactAmountIn { + sender, + routes, + token_in, + token_out_min_amount, + }; + to_binary(&msg_swap_in).unwrap() + } + +} diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..4a69d8f --- /dev/null +++ b/src/error.rs @@ -0,0 +1,13 @@ +use cosmwasm_std::StdError; +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum ContractError { + #[error("{0}")] + Std(#[from] StdError), + + #[error("Unauthorized")] + Unauthorized {}, + // Add any other custom errors you like here. + // Look at https://docs.rs/thiserror/1.0.21/thiserror/ for details. +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..dfedc9d --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,6 @@ +pub mod contract; +mod error; +pub mod msg; +pub mod state; + +pub use crate::error::ContractError; diff --git a/src/msg.rs b/src/msg.rs new file mode 100644 index 0000000..8f3f06a --- /dev/null +++ b/src/msg.rs @@ -0,0 +1,25 @@ +use cosmwasm_schema::{cw_serde, QueryResponses}; +use cosmwasm_std::{Binary, Coin}; + +#[cw_serde] +pub struct InstantiateMsg { +} + +#[cw_serde] +pub enum ExecuteMsg { + SwapExactIn { call: Binary, token_in: Coin, min_token_out: Coin } +} + +#[cw_serde] +#[derive(QueryResponses)] +pub enum QueryMsg { + // GetCount returns the current count as a json-encoded number + // #[returns(GetCountResponse)] + // GetCount {}, +} + +// We define a custom struct for each query response +#[cw_serde] +pub struct GetCountResponse { + pub count: i32, +} diff --git a/src/state.rs b/src/state.rs new file mode 100644 index 0000000..2551f22 --- /dev/null +++ b/src/state.rs @@ -0,0 +1,12 @@ +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +use cosmwasm_std::Addr; +use cw_storage_plus::Item; + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +pub struct State { + +} + +pub const STATE: Item = Item::new("state");