Giter Site home page Giter Site logo

cw-plus's Introduction

CosmWasm Plus

CircleCI

Specification Crates.io Docs Coverage
cw1 cw1 on crates.io Docs codecov
cw3 cw3 on crates.io Docs codecov
cw4 cw4 on crates.io Docs codecov
cw20 cw20 on crates.io Docs codecov
Contracts Download Docs Coverage
cw1-subkeys Release v0.13.4 Docs codecov
cw1-whitelist Release v0.13.4 Docs codecov
cw3-fixed-multisig Release v0.13.4 Docs codecov
cw3-flex-multisig Release v0.13.4 Docs codecov
cw4-group Release v0.13.4 Docs codecov
cw4-stake Release v0.13.4 Docs codecov
cw20-base Release v0.13.4 Docs codecov
cw20-ics20 Release v0.13.4 Docs codecov

Note: cw2 and controllers have been moved to the cw-minus repo and can be followed there.

Note: cw721 and cw721-base have moved to the new cw-nfts repo and can be followed there.

Note: most of the cw20-* contracts besides cw20-base have moved to the new cw-tokens repo and can be followed there.

This is a collection of specification and contracts designed for use on real networks. They are designed not just as examples, but to solve real-world use cases, and to provide a reusable basis to build many custom contracts.

If you don't know what CosmWasm is, please check out our homepage and our documentation to get more background. We are running public testnets you can use to test out any contracts.

Warning None of these contracts have been audited and no liability is assumed for the use of this code. They are provided to turbo-start your projects.

Specifications

The most reusable components are the various cwXYZ specifications under packages. Each one defines a standard interface for different domains, e.g. cw20 for fungible tokens, cw721 for non-fungible tokens, cw1 for "proxy contracts", etc. The interface comes with a human description in the READMEs, as well as Rust types that can be imported.

They contain no logic, but specify an interface. It shows what you need to implement to create a compatible contracts, as well as what interface we guarantee to any consumer of such contracts. This is the real bonus of specifications, we can create an escrow contract that can handle many different fungible tokens, as long as they all adhere to the cw20 specification.

If you have ideas for new specifications , please raise an issue or create a pull request on this repo.

Contracts

We provide sample contracts that either implement or consume these specifications to both provide examples, and provide a basis for code you can extend for more custom contacts, without worrying about reinventing the wheel each time. For example cw20-base is a basic implementation of a cw20 compatible contract that can be imported in any custom contract you want to build on it.

CW1 Proxy Contracts:

  • cw1-whitelist a minimal implementation of cw1 mainly designed for reference.
  • cw1-subkeys a simple, but useful implementation, which lets us use a proxy contract to provide "allowances" for native tokens without modifying the bank module.

CW3 Multisig:

  • cw3-fixed-multisig a simple implementation of the cw3 spec. It is a multisig with a fixed set of addresses, created upon initialization. Each address may have the same weight (K of N), or some may have extra voting power. This works much like the native Cosmos SDK multisig, except that rather than aggregating the signatures off chain and submitting the final result, we aggregate the approvals on-chain.
  • cw3-flex-multisig builds on cw3-fixed-multisig, with a more powerful implementation of the cw3 spec. It's a multisig contract backed by a cw4 (group) contract, which independently maintains the voter set.

CW4 Group:

  • cw4-group a basic implementation of the cw4 spec. It handles elected membership, by admin or multisig. It fulfills all elements of the spec, including raw query lookups, and is designed to be used as a backing storage for cw3 compliant contracts.
  • cw4-stake a second implementation of the cw4 spec. It fulfills all elements of the spec, including raw query lookups, and is designed to be used as a backing storage for cw3 compliant contracts. It provides a similar API to [cw4-group], but rather than appointing members, their membership and weight are based on the number of staked tokens they have.

CW20 Fungible Tokens:

  • cw20-base a straightforward, but complete implementation of the cw20 spec along with all extensions. Can be deployed as-is, or imported by other contracts.

Compiling

To compile all the contracts, run the following in the repo root:

docker run --rm -v "$(pwd)":/code \
  --mount type=volume,source="$(basename "$(pwd)")_cache",target=/target \
  --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \
  cosmwasm/optimizer:0.16.0

This will compile all packages in the contracts directory and output the stripped and optimized wasm code under the artifacts directory as output, along with a checksums.txt file.

If you hit any issues there and want to debug, you can try to run the following in each contract dir: RUSTFLAGS="-C link-arg=-s" cargo build --release --target=wasm32-unknown-unknown --locked

Quality Control

One of the basic metrics of assurance over code quality is how much is covered by unit tests. There are several tools available for Rust to do such analysis and we will describe one below. This should be used as a baseline metric to give some confidence in the code.

Beyond code coverage metrics, just having a robust PR review process with a few more trained eyes looking for bugs is very helpful in detecting paths the original coder was not aware of. This is more subjective, but looking at the relevant PRs and depth of discussion can give an idea how much review was present.

After that, fuzzing it (ideally with an intelligent fuzzer that understands the domain) can be valuable. And beyond that formal verification can provide even more assurance (but is very time-consuming and expensive).

Code Coverage

I recommend the use of tarpaulin: cargo install cargo-tarpaulin

To get some nice interactive charts, you can go to the root directory and run:

cargo tarpaulin -o html and then xdg-open tarpaulin-report.html (or just open on MacOS).

Once you find a package that you want to improve, you can do the following to just analyze this package, which gives much faster turn-around:

cargo tarpaulin -o html --packages cw3-fixed-multisig

Note that it will produce a code coverage report for the entire project, but only the coverage in that package is the real value. If does give quick feedback for you if you unit test writing was successful.

Contributing

See our Contributing Guidelines.

Generating changelog

To generate a changelog we decided to use github-changelog-generator.

To install tool you need Ruby's gem package manager.

$ gem --user install github_changelog_generator

And put $HOME/.gem/ruby/*/bin/ into your PATH.

Generating changelog file first time:

$ github_changelog_generator -u CosmWasm -p cw-plus

Appending next releases could be done adding --base flag:

$ github_changelog_generator -u CosmWasm -p cw-plus --base CHANGELOG.md

If you hit GitHub's 50 requests/hour limit, please follow this guide to create a token key which you can pass using --token flag.

There's also a convenience scripts/update_changelog.sh, which can take a --since-tag parameter (to avoid processing the entire history). It can also auto-detect the latest version tag for you, with --latest-tag.

License

This repo is licensed under Apache 2.0.

cw-plus's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cw-plus's Issues

Fix Claims handling in cw20-staking

Part of #59 - pulled out for needed UI

Note: should be done on the v0.2.x branch and released as v0.2.3, before merging into master.

We currently just store how many tokens the person has unbonded and allow anyone with claims to grab the money. This is unfair as if I start unbonding 3 weeks ago and forget to check right at time, you may have unbonded yesterday and snap up the claims as soon as my unbonding made it to the contract account, making me wait 3 more weeks for your period.

The solution here is to store information on the native staking unbonding period inside the contract as a Duration - this contact value should equal the actual unbonding period of the chain for best effect.

Further Claims are no longer Uint128, but rather Vec<Claim>

pub struct Claim {
  pub mature Expiration,
  pub amount Uint128
}

These should be stored as one Vec per client. And sorted from first expiration to last expiration. This info must be displayed on a query.

On a handling a claim msg, we remove all mature claims from the list, and take the sum of their totals, releasing these native tokens to the claimee.

Implement base NFT contract

Builds on #43

Implement a simple contract that implements the NFT spec (like cw20-base does). This is means to be used stand-alone or further customized.

Not not implement enumeration, or at least enumeration by owner, as that requires secondary indexes to do cleanly: CosmWasm/cosmwasm#468

Add "ListAccounts" to cw20-base

Allow a way to show all accounts. We can do that with the iterator, but it may use tons of gas if there is lots.

Maybe add some pagination here, like:

struct ListAllAccounts {
  // start from beginning if None, or right after this if set (use last address from previous result) 
  after: Option<HumanAddress>,
  // require some limit to how many on a page. Gas limits will cap it, we can enforce no more than 100 
  limit: u32,
}

Define Spec of NFTs

Write a CW721 spec package defining how they work. Look at ERC721 and ERC1155 for inspiration. Also others?

Add README in project root

There is only the description in "About" which is not very prominent. I would love some:

  • High level description what this repo is about
  • Infos about the license model: there are currently AGPL and Apache license files in the repo
  • Links to other resources/ repos if possible for a bigger context

Migration to 0.11: errors of shared functions accross contracts

Facing the following error migrating errors to the new format (i.e. to 0.11):

53 | |         HandleMsg::Freeze {} => handle_freeze(deps, env),
   | |                                 ^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `error::ContractError`, found enum `cw1_whitelist::error::ContractError`

This is because handle_freeze() is being imported from cw1-whitelist, which has its own ContractError.

Opening this issue so we can document / discuss solutions to this.

Test harness for testing composition

This implements what was described in CosmWasm/cosmwasm#90 and CosmWasm/cosmwasm#101.

Basically a minimal runtime in rust that can execute multiple contracts. Ideally allowing unit-tests to call other modules and mocks for native modules. This needs a bank contract for basic functionality as well as a way to dynamically dispatch to arbitrary contracts.

Implement Copy for Coin / Vec<Coin>

Currently when coins are sent in a message's sent_funds, they need to be cloned in order to be used independently of the containing struct (env / env.message). This makes some code constructs unnatural (or imply extra cloning of the whole structure).

See by example the discussion in #72 (comment) .

Rust errors E0382 / E0505 suggest as an alternative implementing the Copy trait, for the members that need to be accessed independently.

Implement atomic swap contract with native tokens

This should be a basic contract that implements one half of the IOV atomic swap spec. There is also a Solidity implementation of atomic swap as well as one that supports ERC20 tokens, so creating such a contract allows any CosmWasm-based chain to swap tokens with an Ethereum-based chain, possibly on some off-chain DEX or just "over the counter".

Create one contract that can handle and track many atomic swaps. Each swap has a unique ID and can store some tokens when it is created. Its balance cannot be adjusted after that fact, until it is either claimed or aborted (when the swap is closed and the funds go to a recipient).

For the first step, this should just handle native tokens that are sent along with the "create swap" message (see env.msg.sent_funds), and these can be distributed with BankMsg::Send.

You can start with with cosmwasm-template, but as the various contracts in this package are rather customized, it might make sense to copy eg. cw20-escrow as a start and then modify it heavily.

Please cover it with reasonable unit tests. You can look at this integration test to get an idea of a successful end-to-end flow. For this contract, it would be nice to break it up into smaller pieces. Note it should be able to create both sides of the swap on the same contract and resolve them.

Define CW20-base

This is a simple implementation of cw20 functionality, which is meant to be imported piece by piece as well as used in a contract. Make sure all wasm compile code is optional (behind feature flag)

Implement mintable for cw20-base contract

Implement mintable on cw20-base.

Allow this to be imported piecemeal, such that another contract may just use the base components without minting.

Add minter on init and leave it static (unless someone extends it in a custom contract)

Improve cw20-staking contract

Builds on #58

Some things to improve:

  • Track unbonding period for claims - you cannot get payment before all the other claims ahead of you (#110)
  • Handle case the validator unbonded and all your delegations auto-unbonded (contract cannot detect and stuck currently)
  • Figure out if we need get_bonded and assert_bonded or a better solution - these are debug sanity checks but expensive code

Check for / reject zero amount tokens

Add a check for considering zero amounts as missing.

For native coins, filter out zeros, and then ensure then remaining balance has length > 0. Only save the filtered list.

For cw20 coins, reject zero amounts directly. Add a check to also reject such sends in cw20-base.

Unify handling of native and cw20 coins in contracts

Refactor cw20-enabled contracts to use the same pattern introduced in cw0-atomic-swap, of using the same function to handle both native and cw20 coins.

The main candidate for implementing this is cw20-escrow.

Also, document the pattern in the cosmwasm / cosmwasm-plus wiki docs.

Add @cosmjs/cli helpers for each contract

Add some helper code that will allow simple query/execute of a given contract on the client side.

The basic idea is similar to web3x-codegen, but hand-coded for now. Wrapping a CosmWasmSigningClient and providing methods for each HandleMsg and QueryMsg, possibly init and upload methods.

In a future version, when we like the API, we can see how to auto-generate this from the JSON Schema

Related to cosmos/cosmjs#385

Cw20Coin duplication

When I was looking into how to implement cw20 compatible atomic swaps in noticed the contract needs to define a construct for Cw20 tokens. I checked other contracts and saw Cw20Token is defined in cw20-escrow contract. We need to define this struct either in cw20-base or cw20 to prevent duplication in contracts that use cw20

Look at serde(flatten) to simplify return value composition

https://serde.rs/attr-flatten.html

When we try to "extend" structs, especially those we serialize but don't deserialize (query responses), rather than copy the definition and add more fields, we could embed it.

Here is an example to explain what I mean. AllowanceResponse is extended to AllowanceInfo. Currently that looks like:

#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug, Default)]
pub struct AllowanceResponse {
    pub allowance: Uint128,
    pub expires: Expiration,
}

#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug, Default)]
pub struct AllowanceInfo {
    pub spender: HumanAddr,
    pub allowance: Uint128,
    pub expires: Expiration,
}

Maybe it would be possible to do:

#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug, Default)]
pub struct AllowanceInfo {
    #[serde(flatten)]
    pub base: AllowanceResponse,
    pub expires: Expiration,
}

This PR should not only worry about the code compiling and working in Rust, but also check the JSON schema we expose externally. This can be demo-ed on a few values like above and then we can see if this works at all, and if it works, if it simplifies or complicates things.

Note: This may not work with the custom serde-json-wasm library we use. If flatten is not supported, or raises errors, then please raise an issue on that repo (our custom json lib) and close this issue. (We are unlikely to implement it)

Deliverables:

  • Update AllowanceInfo as defined
  • Update all contracts to use it properly
  • Check generated json schema (should be the same) and manually print out an example of serializing it
  • Test serializing/deserializing with this struct

In addition, please provide a short response if this seems to make the coding simpler (extending single query to enumerable) and if you feel it improves code quality, a list of other structs to consider in future issues. (This may just add confusion, and we may not make this change, but I wanted to try it out before building too many List queries)

Define cw3 spec for multisigs

This should define pubic operations like create_proposal, vote, and execute. The flow should be similar to cw1 (proposal can contain any number of CosmosMsg but they must be proposed and voted on in various steps before they can be executed. Each successful proposal can be executed exactly once.

The multisig contains a group and one set of criteria for successful proposals (how many votes needed, voting duration)

Avoid linking contract into contract

On current master I tried:

docker run --rm -v "$(pwd)":/code \
  --mount type=volume,source="cosmwasm_plus_cache",target=/code/target \
  --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \
  cosmwasm/rust-optimizer:0.9.0 ./contracts/cw1-subkeys

which fails at link time with

   Building contract in /code/contracts/cw1-subkeys
    Updating crates.io index
  Downloading crates ...
  Downloaded ryu v1.0.5
  Downloaded serde_derive v1.0.114
  Downloaded serde_json v1.0.57
   [...]
   Compiling serde-json-wasm v0.2.1
   Compiling cosmwasm-std v0.10.0
   Compiling cosmwasm-storage v0.10.0
   Compiling cw20 v0.1.0 (/code/packages/cw20)
   Compiling cw1-whitelist v0.1.0 (/code/contracts/cw1-whitelist)
   Compiling cw1-subkeys v0.1.0 (/code/contracts/cw1-subkeys)
error: linking with `rust-lld` failed: exit code: 1
  |
  = note: "rust-lld" "-flavor" "wasm" "--no-threads" "-z" "stack-size=1048576" "--stack-first" "--allow-undefined" "--fatal-warnings" "--no-demangle" "--export-dynamic" "--no-entry" "-L" "/usr/local/rustup/toolchains/1.45.0-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-unknown/lib" "/code/target/wasm32-unknown-unknown/release/deps/cw1_subkeys.cw1_subkeys.edpvpi68-cgu.0.rcgu.o" "/code/target/wasm32-unknown-unknown/release/deps/cw1_subkeys.cw1_subkeys.edpvpi68-cgu.1.rcgu.o" "/code/target/wasm32-unknown-unknown/release/deps/cw1_subkeys.cw1_subkeys.edpvpi68-cgu.10.rcgu.o" "/code/target/wasm32-unknown-unknown/release/deps/cw1_subkeys.cw1_subkeys.edpvpi68-cgu.11.rcgu.o" "/code/target/wasm32-unknown-unknown/release/deps/cw1_subkeys.cw1_subkeys.edpvpi68-cgu.12.rcgu.o" "/code/target/wasm32-unknown-unknown/release/deps/cw1_subkeys.cw1_subkeys.edpvpi68-cgu.13.rcgu.o" "/code/target/wasm32-unknown-unknown/release/deps/cw1_subkeys.cw1_subkeys.edpvpi68-cgu.14.rcgu.o" "/code/target/wasm32-unknown-unknown/release/deps/cw1_subkeys.cw1_subkeys.edpvpi68-cgu.15.rcgu.o" "/code/target/wasm32-unknown-unknown/release/deps/cw1_subkeys.cw1_subkeys.edpvpi68-cgu.2.rcgu.o" "/code/target/wasm32-unknown-unknown/release/deps/cw1_subkeys.cw1_subkeys.edpvpi68-cgu.3.rcgu.o" "/code/target/wasm32-unknown-unknown/release/deps/cw1_subkeys.cw1_subkeys.edpvpi68-cgu.4.rcgu.o" "/code/target/wasm32-unknown-unknown/release/deps/cw1_subkeys.cw1_subkeys.edpvpi68-cgu.5.rcgu.o" "/code/target/wasm32-unknown-unknown/release/deps/cw1_subkeys.cw1_subkeys.edpvpi68-cgu.6.rcgu.o" "/code/target/wasm32-unknown-unknown/release/deps/cw1_subkeys.cw1_subkeys.edpvpi68-cgu.7.rcgu.o" "/code/target/wasm32-unknown-unknown/release/deps/cw1_subkeys.cw1_subkeys.edpvpi68-cgu.8.rcgu.o" "/code/target/wasm32-unknown-unknown/release/deps/cw1_subkeys.cw1_subkeys.edpvpi68-cgu.9.rcgu.o" "-o" "/code/target/wasm32-unknown-unknown/release/deps/cw1_subkeys.wasm" "--export" "handle" "--export" "init" "--export" "query" "--export" "allocate" "--export" "cosmwasm_vm_version_3" "--export" "deallocate" "--export" "handle" "--export" "init" "--export" "query" "--export=__heap_base" "--export=__data_end" "/code/target/wasm32-unknown-unknown/release/deps/cw1_subkeys.3ud1cdnswvb0gv8q.rcgu.o" "--gc-sections" "--no-entry" "-O3" "-L" "/code/target/wasm32-unknown-unknown/release/deps" "-L" "/code/target/release/deps" "-L" "/usr/local/rustup/toolchains/1.45.0-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-unknown/lib" "/code/target/wasm32-unknown-unknown/release/deps/libcw20-b055068809359fb5.rlib" "/code/target/wasm32-unknown-unknown/release/deps/libcw1_whitelist.rlib" "/code/target/wasm32-unknown-unknown/release/deps/libcosmwasm_storage-2f977327130675bf.rlib" "/code/target/wasm32-unknown-unknown/release/deps/libcosmwasm_std-46f86e334b1f2699.rlib" "/code/target/wasm32-unknown-unknown/release/deps/libserde_json_wasm-fd625dbf49c6983b.rlib" "/code/target/wasm32-unknown-unknown/release/deps/libbase64-4599cac9ef208a35.rlib" "/code/target/wasm32-unknown-unknown/release/deps/libsnafu-2851ee6f4901727d.rlib" "/code/target/wasm32-unknown-unknown/release/deps/libdoc_comment-bac7a973323b8efe.rlib" "/code/target/wasm32-unknown-unknown/release/deps/libschemars-fa286a1f9b77bc1c.rlib" "/code/target/wasm32-unknown-unknown/release/deps/libserde_json-64a983c58636b2c0.rlib" "/code/target/wasm32-unknown-unknown/release/deps/libryu-4c2166b6a7371059.rlib" "/code/target/wasm32-unknown-unknown/release/deps/libitoa-3b5317f8135b4fc6.rlib" "/code/target/wasm32-unknown-unknown/release/deps/libserde-0655f9d4f93fcc00.rlib" "/usr/local/rustup/toolchains/1.45.0-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-unknown/lib/libstd-0e15d81285ef9c5e.rlib" "/usr/local/rustup/toolchains/1.45.0-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-unknown/lib/libpanic_abort-34947b3cc643563f.rlib" "/usr/local/rustup/toolchains/1.45.0-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-unknown/lib/libdlmalloc-6b294adc19156ae8.rlib" "/usr/local/rustup/toolchains/1.45.0-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-unknown/lib/libhashbrown-58d23605d0d5de33.rlib" "/usr/local/rustup/toolchains/1.45.0-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-unknown/lib/librustc_std_workspace_alloc-0fe91d8ec108e6e2.rlib" "/usr/local/rustup/toolchains/1.45.0-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-unknown/lib/libbacktrace-372a268696b9cc5b.rlib" "/usr/local/rustup/toolchains/1.45.0-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-unknown/lib/librustc_demangle-a22152a68a4c1806.rlib" "/usr/local/rustup/toolchains/1.45.0-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-unknown/lib/libunwind-a7a6ecf939ca4bfa.rlib" "/usr/local/rustup/toolchains/1.45.0-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-unknown/lib/libcfg_if-97056b9676d330ba.rlib" "/usr/local/rustup/toolchains/1.45.0-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-unknown/lib/liblibc-db3306f467412913.rlib" "/usr/local/rustup/toolchains/1.45.0-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-unknown/lib/liballoc-29d36a52659bbac5.rlib" "/usr/local/rustup/toolchains/1.45.0-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-unknown/lib/librustc_std_workspace_core-b50ae3e1cc06c201.rlib" "/usr/local/rustup/toolchains/1.45.0-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-unknown/lib/libcore-56084c30744b3d96.rlib" "/usr/local/rustup/toolchains/1.45.0-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-unknown/lib/libcompiler_builtins-618bea36272ab7ec.rlib" "-s"
  = note: rust-lld: error: duplicate symbol: init
          >>> defined in /code/target/wasm32-unknown-unknown/release/deps/cw1_subkeys.cw1_subkeys.edpvpi68-cgu.14.rcgu.o
          >>> defined in /code/target/wasm32-unknown-unknown/release/deps/libcw1_whitelist.rlib(cw1_whitelist.cw1_whitelist.crnxeiab-cgu.12.rcgu.o)
          
          rust-lld: error: duplicate symbol: handle
          >>> defined in /code/target/wasm32-unknown-unknown/release/deps/cw1_subkeys.cw1_subkeys.edpvpi68-cgu.14.rcgu.o
          >>> defined in /code/target/wasm32-unknown-unknown/release/deps/libcw1_whitelist.rlib(cw1_whitelist.cw1_whitelist.crnxeiab-cgu.12.rcgu.o)
          
          rust-lld: error: duplicate symbol: query
          >>> defined in /code/target/wasm32-unknown-unknown/release/deps/cw1_subkeys.cw1_subkeys.edpvpi68-cgu.14.rcgu.o
          >>> defined in /code/target/wasm32-unknown-unknown/release/deps/libcw1_whitelist.rlib(cw1_whitelist.cw1_whitelist.crnxeiab-cgu.12.rcgu.o)

This makes sense, because as soon as you use cw1_whitelist::, you export it's C exports. I don't think it is possible to link a contract as a dependency of a contract.

Build bonding curve with cw20-base

Has a function that takes native tokens to cw20 token at a variable exchange rate. Import basic cw20 functionality from base, just implement the bonding curve logic

Fix DoS attack on cw20-escrow

I wrote a simple, straight-forward escrow contract to demo and also propose as a bug hunting challenge for the online workshop. Here is the issue with the original implementation.

We allow anyone to "top up" the contract, which is fine with native tokens. However, it opens up a DoS attack surface. If I Receive(ReceiveMsg::TopUp{}) from a public key address (or any contract that doesn't implement Cw20HandleMsg::Transfer, then when I approve or refund the escrow and try to release funds, this message will return an error and thus abort the entire contract (other funds also remain locked). Since anyone can do this, it allows people to freeze funds in an escrow, even if they cannot steal them.

One approach would be to check if this address is a valid contract, but that is quite hard. It could be a slightly modified cw20 token contract that works perfectly, except on Transfer is the sender == escrow_contract && height > xyz (where xyz is a block or 2 ahead of the top-up call). Thus, there is no way to programatically ensure that arbitrary tokens are valid.

We could also permission top up, so only the original sender could add tokens. But this then gives them a revenge chance, of locking up the escrow before it was released to the proper recipient. They don't get the funds, but they can prevent the recipient from getting them too.

The only clean design I can think of is providing a whitelist of valid cw20 token contracts on Create. This is by default empty if creating with native tokens, or just the one cw20 token send on create if creating with cw20. You can also add an additional whitelist explicitly. The arbiter and recipient can review the list of tokens in the whitelist before accepting the escrow as valid payment, and if these are all valid addresses, TopUp can remain permissionless, while not allowing any more DoS vectors.

This issue and related PR should be references to this attack vector and a solution to it.

Add cw20 support to atomic swap contract

Builds on #26

Just like cw20-escrow supports both native tokens and cw20 tokens (via Receive), the atomic swap contract should be extended with this. We do not want a TopUp like cw20-escrow, but the creation via direct function call or via the cw20::Receive entry point serve as a useful model on how to implement this.

To test it, try swaping a native token vs a cw20 token using the same CosmWasm contract for both sides.

Once completed we can swap any native or cw20 token against eth or any erc20 token. Well.. we would need a UI for that, but the contracts are ready.

Fix compiler warning (const_item_mutation)

This comes up when compiling with a newer compiler (cosmwasm/workspace-optimizer:0.10.3 -> cosmwasm/workspace-optimizer:0.10.4)

   Compiling cw3-fixed-multisig v0.3.0 (/code/contracts/cw3-fixed-multisig)
warning: taking a mutable reference to a `const` item
   --> contracts/cw3-fixed-multisig/src/contract.rs:169:5
    |
169 |     BALLOTS.update(
    |     ^^^^^^^
    |
    = note: `#[warn(const_item_mutation)]` on by default
    = note: each usage of a `const` item creates a new temporary
    = note: the mutable reference will refer to this temporary, not the original `const` item
note: `const` item defined here
   --> contracts/cw3-fixed-multisig/src/state.rs:63:1
    |
63  | pub const BALLOTS: Map<(U64Key, &[u8]), Ballot> = Map::new(b"votes");
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

warning: 1 warning emitted

Build cw20-escrow contract

Similar to cosmwasm-examples escrow but accepts cw20 tokens instead of (or as well as) native tokens, using the Sender/Receiver interfaces.

This is meant as a demo of the interfaces. Better ideas that also demo the interfaces are welcome

Brainstorm: cw-storage-plus support when key can be derived from stored object

Based on a PR comment: #109 (comment)

If we think in typical DBs, the primary key is part of the object being saved. We don't think of these separately. If we define objects like this, then we don't have to pass in the key in save, but can derive it from the saved object.

Thinking more, it is just that one method - load, may_load, update and remove all require the full key in any case.

@maurolacy if you still like this idea, can you develop it more. Once I started to flesh it out, I think it doesn't really have much use.

Building contracts failed

On current master branch I tried to build with

sudo 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/workspace-optimizer:0.10.3

and got

error[E0593]: function is expected to take 3 arguments, but it takes 2 arguments
   --> contracts/cw1-whitelist/src/lib.rs:9:1
    |
9   |   cosmwasm_std::create_entry_points!(contract);
    |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected function that takes 3 arguments
    | 
   ::: contracts/cw1-whitelist/src/contract.rs:125:1
    |
125 | / pub fn query<S: Storage, A: Api, Q: Querier>(
126 | |     deps: &Extern<S, A, Q>,
127 | |     msg: QueryMsg,
128 | | ) -> StdResult<Binary> {
...   |
132 | |     }
133 | | }
    | |_- takes 2 arguments
    |
    = note: required for the cast to the object type `dyn for<'r> std::ops::Fn(&'r cosmwasm_std::Extern<cosmwasm_std::ExternalStorage, cosmwasm_std::ExternalApi, cosmwasm_std::ExternalQuerier>, cosmwasm_std::Env, _) -> std::result::Result<cosmwasm_std::Binary, _>`
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
For more information about this error, try `rustc --explain E0593`.
error: could not compile `cw1-whitelist`.
To learn more, run the command again with --verbose.
Traceback (most recent call last):
  File "/usr/local/bin/optimize_workspace.py", line 45, in <module>
    subprocess.check_call(cmd, cwd=contract)
  File "/usr/lib/python3.7/subprocess.py", line 347, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['cargo', '-Z=unstable-options', 'build', '--release', '--target=wasm32-unknown-unknown', '--locked', '--out-dir=/tmp/contracts/cw1-whitelist']' returned non-zero exit status 101.

My versions

> rustc --version
rustc 1.48.0-nightly (5099914a1 2020-09-08)
> cargo --version
cargo 1.48.0-nightly (126907a7c 2020-08-31)

Fix docker run script in all contract README

We no longer need something like:

docker run --rm -v "$(pwd)":/code \
  --mount type=volume,source="cosmwasm_plus_cache",target=/code/target \
  --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \
  cosmwasm/rust-optimizer:0.9.0 ./contracts/cw20-atomic-swap

but rather:

docker run --rm -v "$(pwd)":/code \
  --mount type=volume,source="cosmwasm_plus_cache",target=/code/target \
  --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \
  cosmwasm/workspace-optimizer:0.10.2 

And the output is artifacts/cw20_staking.wasm

This should be updated in all contracts

Define CW20 spec

This file is meant to be imported and defines all public interfaces

Use more unique names for store/queries (not "Config" / "Meta")

We start having contracts importing code from other contracts (building on base code).
When multiple contracts use the same generic prefixes or data-types like "config", "meta", this can get confusing.

Use clearer names, like "AdminList" for cw1-whitelist and "TokenInfo" for cw20-base.

calc_range_start to cw0

We use this a lot of places. Often with HumanAddr. Sometimes with String or u64.

It would be nice to move the simple helpers for &[u8] like data (Vec<u8>, String, CanonicalAddr, HumanAddr) into cw0 so we don't cut and paste so much between contracts for the standard idiom.

I don't think let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize; would benefit from a function, as it could only obscure the logic, and possibly lead to DEFAULT / MAX mixups.

Basic multisig contract

Builds on #79

Define a basic, usable multisig

  • Define fixed participant set in the beginning
  • Each participant may have a different weight
  • "Pass" threshold defined on init
  • Proposal expiration defined on init
  • Any member may create a proposal (&[CosmosMsg]) with an expiration
  • Any member may vote once for a proposal.
  • If enough yes votes are applied, any member may execute the proposal
  • Implement all queries
  • Unit test coverage

In addition, specify a standard interface for the multisig, which can be used by more complex implementations.

Separate Groups from Multisigs

Builds on #8 and #79

Aim:

Often we will want to use one group of actors in two different multisigs. Some actions may need 50% (to send tokens), others may need 67% (to add new members). Rather than try to keep the groups of two different multisigs in sync, we can create a group contract that just maintains a set of voters and has one contract that can update it.

The multisig contracts can then query this group contract when they want to check if the person is eligible to vote and how many votes they have.


Details:

Create a new contract called cw3-flex-multisig. This works like cw3-fixed-multisig, except it does not store group membership inside. Instead it gets an address of a cw4-group contract (actually any cw4 compatible contract) on init. Upon starting a proposal, query the total weight from the group to properly initialize the proposal. And upon each vote, check membership via the cw4 contract. You can use cw4/helpers.rs to provide these calls.

You can no longer use the test cases as written in cw3-fixed-multisig as they require a mock querier to call into other contracts. Please use #137 as a reference how to write such tests and do feel free to simplify the API. In the end, you should be able to port over most of the cw3-fixed-multisig logic, so let's see how we can make multi-tests simple enough to set up - maybe best to just copy it and then start trimming it out.

Note: We assume the group is static - or at least does not change during an open proposal. That adds a lot of complexity and we will address that in a later issue

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.