tx-test-tube 6.0.0

CosmWasm integration testing for TX
use crate::{fn_execute, fn_query};

use test_tube_tx::module::Module;
use test_tube_tx::runner::Runner;
use tx_wasm_sdk::types::cosmos::authz::v1beta1::{
    MsgExec, MsgExecResponse, MsgGrant, MsgGrantResponse, MsgRevoke, MsgRevokeResponse,
    QueryGranteeGrantsRequest, QueryGranteeGrantsResponse, QueryGranterGrantsRequest,
    QueryGranterGrantsResponse, QueryGrantsRequest, QueryGrantsResponse,
};

pub struct Authz<'a, R: Runner<'a>> {
    runner: &'a R,
}

impl<'a, R: Runner<'a>> Module<'a, R> for Authz<'a, R> {
    fn new(runner: &'a R) -> Self {
        Self { runner }
    }
}

impl<'a, R> Authz<'a, R>
where
    R: Runner<'a>,
{
    fn_execute! {
        pub grant: MsgGrant["/cosmos.authz.v1beta1.MsgGrant"] => MsgGrantResponse
    }

    fn_execute! {
        pub revoke: MsgRevoke["/cosmos.authz.v1beta1.MsgRevoke"] => MsgRevokeResponse
    }

    fn_execute! {
        pub exec: MsgExec["/cosmos.authz.v1beta1.MsgExec"] => MsgExecResponse
    }

    fn_query! {
        pub query_grants ["/cosmos.authz.v1beta1.Query/Grants"]: QueryGrantsRequest => QueryGrantsResponse
    }

    fn_query! {
        pub query_granter_grants ["/cosmos.authz.v1beta1.Query/GranterGrants"]: QueryGranterGrantsRequest => QueryGranterGrantsResponse
    }

    fn_query! {
        pub query_grantee_grants ["/cosmos.authz.v1beta1.Query/GranteeGrants"]: QueryGranteeGrantsRequest => QueryGranteeGrantsResponse
    }
}

#[cfg(test)]
mod tests {
    use cosmwasm_std::Coin;
    use tx_wasm_sdk::shim::Any;
    use tx_wasm_sdk::types::cosmos::authz::v1beta1::{
        Grant, MsgExec, MsgGrant, QueryGrantsRequest,
    };
    use tx_wasm_sdk::types::cosmos::nft::v1beta1::{MsgSend, QueryOwnerRequest};
    use tx_wasm_sdk::types::tx::asset::nft::v1::{
        MsgIssueClass, MsgMint, NftIdentifier, SendAuthorization,
    };

    use crate::runner::app::FEE_DENOM;
    use crate::{Account, AssetNFT, Authz, Module, TXTestApp, NFT};

    #[test]
    fn authz_integration() {
        let app = TXTestApp::new();
        let signer = app
            .init_account(&[Coin::new(100_000_000_000_000_000_000u128, FEE_DENOM)])
            .unwrap();
        let grantee = app
            .init_account(&[Coin::new(100_000_000_000_000_000_000u128, FEE_DENOM)])
            .unwrap();
        let authz = Authz::new(&app);
        let assetnft = AssetNFT::new(&app);
        let nft = NFT::new(&app);

        assetnft
            .issue(
                MsgIssueClass {
                    issuer: signer.address(),
                    symbol: "TEST".to_string(),
                    name: "TEST_NAME".to_string(),
                    description: "test_description".to_string(),
                    uri: "".to_string(),
                    uri_hash: "".to_string(),
                    data: None,
                    features: vec![],
                    royalty_rate: "0".to_string(),
                },
                &signer,
            )
            .unwrap();

        let class_id = format!("{}-{}", "TEST", signer.address()).to_lowercase();

        assetnft
            .mint(
                MsgMint {
                    sender: signer.address(),
                    class_id: class_id.clone(),
                    id: "test1".to_string(),
                    uri: "".to_string(),
                    uri_hash: "".to_string(),
                    data: None,
                    recipient: signer.address(),
                },
                &signer,
            )
            .unwrap();

        let owner_response = nft
            .query_owner(&QueryOwnerRequest {
                class_id: class_id.clone(),
                id: "test1".to_string(),
            })
            .unwrap();

        assert_eq!(owner_response.owner, signer.address());

        let send_authorization = SendAuthorization {
            nfts: vec![NftIdentifier {
                class_id: class_id.clone(),
                id: "test1".to_string(),
            }],
        }
        .to_any();

        authz
            .grant(
                MsgGrant {
                    granter: signer.address(),
                    grantee: grantee.address(),
                    grant: Some(Grant {
                        authorization: Some(Any {
                            type_url: send_authorization.type_url,
                            value: send_authorization.value.to_vec(),
                        }),
                        expiration: None,
                    }),
                },
                &signer,
            )
            .unwrap();

        let grants = authz
            .query_grants(&QueryGrantsRequest {
                msg_type_url: "".to_string(),
                pagination: None,
                granter: signer.address(),
                grantee: grantee.address(),
            })
            .unwrap();

        assert_eq!(grants.grants.len(), 1);

        let send_msg = MsgSend {
            class_id: class_id.clone(),
            id: "test1".to_string(),
            sender: signer.address(),
            receiver: grantee.address(),
        };

        authz
            .exec(
                MsgExec {
                    grantee: grantee.address(),
                    msgs: vec![Any {
                        type_url: send_msg.to_any().type_url,
                        value: send_msg.to_any().value.to_vec(),
                    }],
                },
                &grantee,
            )
            .unwrap();

        let owner_response = nft
            .query_owner(&QueryOwnerRequest {
                class_id,
                id: "test1".to_string(),
            })
            .unwrap();

        assert_eq!(owner_response.owner, grantee.address());
    }
}