Giter VIP home page Giter VIP logo

cw-asset's Introduction

cw-asset's People

Contributors

apollo-sturdy avatar cyberhoward avatar dancreee avatar javiersuweijie avatar larry0x avatar piobab avatar rhaki avatar y-pakorn avatar

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

Watchers

 avatar  avatar

cw-asset's Issues

Implement `PrimaryKey` on `AssetInfo` directly

I suggest to implement the cw-storage-plus PrimaryKey trait on AssetInfo directly instead of using an intermediary type AssetInfoKey. This allows the type to be easily used in maps and specifically multi-index maps.

Support CW1155

Other than native and cw20. It would be good to support CW1155 multi-token contracts.

A CW1155 tokens consists of a contract_addr: Addr and a token_id: String

It could look something like:

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum AssetInfoBase<T> {
    Cw20(T),
    Cw1155(T, String),
    Native(String),
}

Bump CosmWasm to v2.0

Cosmwasm 2.0 is out for a while, getting cosmwasm packages updated is a requirement for any project that depends on cw-asset to upgrade.

String comparison issue related to CW20 addresses

Currently, AssetInfo derives its PartialEq trait, meaning that comparing two AssetInfo::Cw20 instances will be a simple comparison of their contract addresses. This implies that two AssetInfo instances of the same CW20 token, but one with the address in lower case and the other in upper case, will be considered different:

let token1 = AssetInfo::cw20(api.addr_validate("terra1234abcd")?);
let token2 = AssetInfo::cw20(api.addr_validate("TERRA1234ABCD")?);
token1 == token2 // false

This could be a security vulnerability in some cases. Consider this situation: a contract holds some tokens. The contract owner implements a function to allow these tokens to be transferred out, but wants to withhold one from being transferred. A straightforward implementation would be:

const DISALLOWED_TOKEN: &str = "terra1234abcd";

fn execute_transfer(token_to_transfer: &Asset, recipient: &Addr) -> StdResult<CosmosMsg> {
    let disallowed_token_info = AssetInfo::cw20(api.addr_validate(DISALLOWED_TOKEN)?);
    if token_to_transfer.info == disallowed_token_info {
        return Err(StdError::generic_err("transfer of this token is not allowed"));
    }
    token_to_transfer.transfer_msg(recipient)
}

Since DISALLOWED_TOKEN is defined in lower case here, an exploiter can bypass the check by simply providing the token address in upper case.

Solution: When checking an AssetInfo instance, automatically converts all addresses to lower case.

Implement a method to deserialize SDK coins

Cosmos SDK stringifies native coins in a different format as cw-asset does. Whereas cw_asset::Asset strinfigifies to:

cw20:{address}:{amount}
native:{denom}:{amount}

SDK stringifies coins to:

{amount}{denom}

There should be a method AssetUnchecked::from_sdk_str to construct an AssetUnchecked::Native instance from the such strings.

Implement `FromStr` for the unchecked types

We should be able to so this:

let info_unchecked = AssetInfoUnchecked::from_str("native:uatom")?;
let info = info_unchecked.check(api, None)?;

let asset_unchecked = AssetUnchecked::from_str("cw20:terra1a7zxk56c72elupp7p44hn4k94fsvavnhylhr6h:12345")?;
let asset = asset_unchecked.check(api, None)?;

let list_unchecked = AssetListUnchecked::from_str("native:uatom:12345,native:uluna:69420")?;
let list = list.unchecked.check(api, None)?;

suggestion: `transfer_from` should take `MessageInfo` as an argument and work for native denominations

Feel free to close this if you think this is a silly idea. I think we can implement transfer_from for native tokens easily enough by having it take a MessageInfo struct and then doing may_pay on it and returning no messages to be executed.

It's a bit of a break from the normal interface of this package, but I think semantically those are the same thing. For example:

let maybe_message = asset.transfer_from("ekez", info)?;

If ekez is the sender and the funds are included in the funds field it feels to me that the cw20 and native versions are the same here.

Legacy example doesn't work

Based on the example at https://docs.rs/cw-asset/0.3.4/cw_asset/#legacy-feature, get error:

the trait bound Asset: From<AssetBase<cosmwasm_std::addresses::Addr>> is not satisfied
required because of the requirements on the impl of Into<Asset> for AssetBase<cosmwasm_std::addresses::Addr>

Cargo.toml

[package]
name = "test-assetinfo"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
cw-asset = { version = "0.3.3", features = ["legacy"] }
astroport = "1.0.1"

main.rs

fn main() {
    let a = cw_asset::Asset::native("uusd", 1u128);
    let b: astroport::asset::Asset = a.into();
}

Validate native denoms

I was recently looking into native denom validation, and it turns out there are actually some reasonably strict rules in the SDK as to what strings may be denominations. We should be able to perform that validation in a contract reasonably enough. From dao-contracts:

/// Follows cosmos SDK validation logic. Specifically, the regex
/// string `[a-zA-Z][a-zA-Z0-9/:._-]{2,127}`.
///
/// <https://github.com/cosmos/cosmos-sdk/blob/7728516abfab950dc7a9120caad4870f1f962df5/types/coin.go#L865-L867>
pub fn validate_native_denom(denom: String) -> Result<String, DenomError> {
    if denom.len() < 3 || denom.len() > 128 {
        return Err(DenomError::NativeDenomLength { len: denom.len() });
    }
    let mut chars = denom.chars();
    // Really this means that a non utf-8 character is in here, but
    // non-ascii is also correct.
    let first = chars.next().ok_or(DenomError::NonAlphabeticAscii)?;
    if !first.is_ascii_alphabetic() {
        return Err(DenomError::NonAlphabeticAscii);
    }

    for c in chars {
        if !(c.is_ascii_alphanumeric() || c == '/' || c == ':' || c == '.' || c == '_' || c == '-')
        {
            return Err(DenomError::InvalidCharacter { c });
        }
    }

    Ok(denom)
}

Use `AssetInfo` or `AssetInfoUnchecked` as `KeyDeserialize::Output` for `AssetInfoKey`

We can use AssetInfo or AssetInfoUnchecked as KeyDeserialize::Output for AssetInfoKey here to avoid unnecessary casting step.

impl KeyDeserialize for AssetInfoKey {
    type Output = Self;

    #[inline(always)]
    fn from_vec(value: Vec<u8>) -> StdResult<Self::Output> {
        Ok(Self(value))
    }
}
impl KeyDeserialize for AssetInfoKey {
    type Output = AssetInfoUnchecked;

    #[inline(always)]
    fn from_vec(value: Vec<u8>) -> StdResult<Self::Output> {
        Self::Output::try_from(Self(value))
    }
}

`AssetInfoBase<T>` should be non-exhaustive

Since the addition of Cw1155 variants of AssetInfoBase, we should consider adding the #[non_exhaustive] macro tag to prevent breaking change of pattern matching when adding new enum variants.

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.