From e9bd7cea87e18ad16c30d474ae724376942e3eb9 Mon Sep 17 00:00:00 2001 From: Ash Date: Wed, 7 Aug 2024 17:48:15 -0700 Subject: [PATCH 1/7] tf20 initial pass --- Cargo.toml | 4 +- contracts/tf20/src/contract.rs | 510 +++++++++++++++++++++++++++++++++ contracts/tf20/src/error.rs | 16 ++ contracts/tf20/src/lib.rs | 4 + contracts/tf20/src/msg.rs | 102 +++++++ contracts/tf20/src/state.rs | 13 + 6 files changed, 647 insertions(+), 2 deletions(-) create mode 100644 contracts/tf20/src/contract.rs create mode 100644 contracts/tf20/src/error.rs create mode 100644 contracts/tf20/src/lib.rs create mode 100644 contracts/tf20/src/msg.rs create mode 100644 contracts/tf20/src/state.rs diff --git a/Cargo.toml b/Cargo.toml index cef1a34..1525899 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ overflow-checks = true # Disable integer overflow checks. [workspace.dependencies] cosmwasm-schema = "2.1.1" -cosmwasm-std = { version = "2.1.1", features = ["stargate", "cosmwasm_2_0"] } +cosmwasm-std = { version = "2.1.1", features = ["cosmwasm_2_0"] } cw2 = "2.0.0" cw-storage-plus = "2.0.0" cw-utils = "2.0.0" @@ -29,6 +29,6 @@ rsa = { version = "0.9.2" } getrandom = { version = "0.2.10", features = ["custom"] } p256 = {version = "0.13.2", features = ["ecdsa-core", "arithmetic", "serde"]} prost = {version = "0.13.1", default-features = false, features = ["prost-derive"]} -cosmos-sdk-proto = {git = "https://github.com/burnt-labs/cosmos-rust.git", rev = "ba87a886e16f24056e5d2e0c2e07fc958f551a5e", default-features = false, features = ["std", "cosmwasm", "xion"]} +cosmos-sdk-proto = {git = "https://github.com/burnt-labs/cosmos-rust.git", rev = "53887487c978c5fef6aa064a36f81b23ddb4ee03", default-features = false, features = ["std", "cosmwasm", "xion", "tokenfactory"]} prost-types = "0.13.1" pbjson-types = "0.7.0" \ No newline at end of file diff --git a/contracts/tf20/src/contract.rs b/contracts/tf20/src/contract.rs new file mode 100644 index 0000000..519b058 --- /dev/null +++ b/contracts/tf20/src/contract.rs @@ -0,0 +1,510 @@ +use std::ptr::metadata; +use cosmos_sdk_proto::cosmos::bank::v1beta1::Metadata; +#[cfg(not(feature = "library"))] +use cosmwasm_std::entry_point; + +use cw2::set_contract_version; +use cosmwasm_std::{Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult, Uint128, CosmosMsg, AnyMsg, to_json_binary, BankMsg, DenomUnit, Addr}; +use cosmos_sdk_proto::cosmos::base::v1beta1::Coin; + +use cw20_base::allowances::{deduct_allowance, execute_decrease_allowance, execute_increase_allowance, query_allowance}; +use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; +use crate::error::{ContractError, ContractResult}; +use cosmos_sdk_proto::tokenfactory::v1beta1::{MsgBurn, MsgChangeAdmin, MsgForceTransfer, MsgMint, MsgSetDenomMetadata}; +use cw20::{BalanceResponse, Cw20ReceiveMsg, TokenInfoResponse}; +use crate::state::{TOKEN_INFO, TokenInfo}; + +// version info for migration info +const CONTRACT_NAME: &str = "crates.io:tf20"; +const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); + +pub fn denom(deps: Deps) -> StdResult { + let token_info = TOKEN_INFO.load(deps.storage)?; + Ok(format!("tokenfactory/{creator}/{subdenom}", creator = token_info.creator, subdenom = token_info.subdenom)) +} + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn instantiate( + deps: DepsMut, + _env: Env, + info: MessageInfo, + msg: InstantiateMsg, +) -> Result { + set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + + // todo who is minter, do we handle new and existing tokens + + // store token info using cw20-base format + let data = TokenInfo { + creator: msg.creator, + subdenom: msg.subdenom, + admin: Some(info.sender), + }; + TOKEN_INFO.save(deps.storage, &data)?; + + Ok(Response::default()) +} + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn execute( + deps: DepsMut, + env: Env, + info: MessageInfo, + msg: ExecuteMsg, +) -> Result { + match msg { + // admin functions for the contract to control the tokenfactory denom + ExecuteMsg::Mint { recipient, amount } => { + Ok(mint(deps, env, info, recipient, amount)?) + } + ExecuteMsg::ForceTransfer { owner, recipient, amount } => { + Ok(force_transfer(deps, env, info, owner, recipient, amount)?) + } + ExecuteMsg::ForceBurn { owner , amount } => { + Ok(force_burn(deps, env, info, owner, amount)?) + } + ExecuteMsg::ForceSend { owner, contract, amount, msg} => { + Ok(force_send(deps, env, info, owner, contract, amount, msg)?) + } + ExecuteMsg::UpdateContractAdmin { new_admin } => { + Ok(update_contract_admin(deps, env, info, new_admin)?) + } + ExecuteMsg::UpdateTokenFactoryAdmin { new_admin } => { + Ok(update_tokenfactory_admin(deps, env, info, new_admin)?) + } + ExecuteMsg::ModifyMetadata { metadata } => { + Ok(modify_metadata(deps, env, info, metadata)?) + } + + // these all come from cw20-base to implement the cw20 standard + ExecuteMsg::Transfer { recipient, amount } => { + Ok(transfer(deps, env, info, recipient, amount)?) + } + ExecuteMsg::Burn { amount } => Ok(burn(deps, env, info, amount)?), + ExecuteMsg::Send { + contract, + amount, + msg, + } => Ok(send(deps, env, info, contract, amount, msg)?), + ExecuteMsg::IncreaseAllowance { + spender, + amount, + expires, + } => Ok(execute_increase_allowance( + deps, env, info, spender, amount, expires, + )?), + ExecuteMsg::DecreaseAllowance { + spender, + amount, + expires, + } => Ok(execute_decrease_allowance( + deps, env, info, spender, amount, expires, + )?), + ExecuteMsg::TransferFrom { + owner, + recipient, + amount, + } => Ok(transfer_from( + deps, env, info, owner, recipient, amount, + )?), + ExecuteMsg::BurnFrom { owner, amount } => { + Ok(burn_from(deps, env, info, owner, amount)?) + } + ExecuteMsg::SendFrom { + owner, + contract, + amount, + msg, + } => Ok(send_from( + deps, env, info, owner, contract, amount, msg, + )?), + } +} + +pub fn assert_admin(deps: Deps, sender: Addr) -> ContractResult<()> { + let token_info = TOKEN_INFO.load(deps.storage)?; + match token_info.admin { + None => Err(ContractError::Unauthorized), + Some(admin) => { + if sender != admin { + return Err(ContractError::Unauthorized); + } + Ok(()) + } + } +} + +pub fn mint( + deps: DepsMut, + env: Env, + info: MessageInfo, + recipient: String, + amount: Uint128, +) -> Result { + assert_admin(deps.as_ref(), info.sender)?; + + deps.api.addr_validate(&recipient)?; + + let denom = denom(deps.as_ref())?; + let coin = Coin { denom, amount: amount.clone().to_string() }; + + let force_transfer_msg = MsgMint { + sender: env.contract.address.into_string(), + amount: Some(coin), + mint_to_address: recipient.clone(), + }; + let any_msg = AnyMsg { + type_url: String::from("/osmosis.tokenfactory.v1beta1.Msg/Mint"), + value: to_json_binary(&force_transfer_msg)?, + }; + + let res = Response::new() + .add_attribute("action", "mint") + .add_attribute("to", recipient) + .add_attribute("amount", amount) + .add_message(CosmosMsg::Any(any_msg)); + Ok(res) +} + +pub fn force_transfer( + deps: DepsMut, + env: Env, + info: MessageInfo, + owner: String, + recipient: String, + amount: Uint128, +) -> Result { + assert_admin(deps.as_ref(), info.sender)?; + + deps.api.addr_validate(&owner)?; + deps.api.addr_validate(&recipient)?; + + _transfer(deps, env, owner, recipient, amount) +} + +pub fn force_burn( + deps: DepsMut, + env: Env, + info: MessageInfo, + owner: String, + amount: Uint128, +) -> Result { + assert_admin(deps.as_ref(), info.sender)?; + + deps.api.addr_validate(&owner)?; + _burn(deps, env, owner, amount) +} + +pub fn force_send( + deps: DepsMut, + env: Env, + info: MessageInfo, + owner: String, + contract: String, + amount: Uint128, + msg: Binary, +) -> Result { + assert_admin(deps.as_ref(), info.sender)?; + + deps.api.addr_validate(&owner)?; + deps.api.addr_validate(&contract)?; + _send(deps, env, owner, contract, amount, msg) +} + +pub fn update_contract_admin( + deps: DepsMut, + _env: Env, + info: MessageInfo, + new_admin: String, +) -> Result { + assert_admin(deps.as_ref(), info.sender.clone())?; + let old_admin = info.sender.into_string(); + + let admin = match new_admin.is_empty() { + true => {None} + false => { + let addr = deps.api.addr_validate(&new_admin)?; + Some(addr) + } + }; + + + let mut token_info = TOKEN_INFO.load(deps.storage)?; + token_info.admin = admin; + TOKEN_INFO.save(deps.storage, &token_info)?; + Ok(Response::new() + .add_attribute("action", "update_contract_admin") + .add_attribute("old_admin", old_admin) + .add_attribute("new_admin", new_admin)) +} + +pub fn update_tokenfactory_admin( + deps: DepsMut, + _env: Env, + info: MessageInfo, + new_admin: String, +) -> Result { + assert_admin(deps.as_ref(), info.sender.clone())?; + let old_admin = info.sender.clone().into_string(); + + let denom = denom(deps.as_ref())?; + + let change_admin_msg = MsgChangeAdmin{ + sender: info.sender.into_string(), + denom, + new_admin: new_admin.clone(), + }; + + let any_msg = AnyMsg{ + type_url: String::from("/osmosis.tokenfactory.v1beta1.Msg/ChangeAdmin"), + value: to_json_binary(&change_admin_msg)?, + }; + + Ok(Response::new() + .add_attribute("action", "update_tokenfactory_admin") + .add_attribute("old_admin", old_admin) + .add_attribute("new_admin", new_admin) + .add_message(CosmosMsg::Any(any_msg))) +} + +pub fn modify_metadata( + deps: DepsMut, + _env: Env, + info: MessageInfo, + metadata: Metadata, +) -> Result { + assert_admin(deps.as_ref(), info.sender.clone())?; + + let change_admin_msg = MsgSetDenomMetadata{ + sender: info.sender.into_string(), + metadata: Some(metadata.clone()), + }; + + let any_msg = AnyMsg{ + type_url: String::from("/osmosis.tokenfactory.v1beta1.Msg/ChangeAdmin"), + value: to_json_binary(&change_admin_msg)?, + }; + + Ok(Response::new() + .add_attribute("action", "modify_metadata") + .add_attribute("metadata", metadata.to_string()) + .add_message(CosmosMsg::Any(any_msg))) +} + + +pub fn transfer( + deps: DepsMut, + env: Env, + info: MessageInfo, + recipient: String, + amount: Uint128, +) -> Result { + _transfer(deps, env, info.sender.into_string(), recipient, amount) +} + +pub fn transfer_from( + deps: DepsMut, + env: Env, + info: MessageInfo, + owner: String, + recipient: String, + amount: Uint128, +) -> Result { + deps.api.addr_validate(&recipient)?; + let owner_addr = deps.api.addr_validate(&owner)?; + + // deduct allowance before doing anything else have enough allowance + deduct_allowance(deps.storage, &owner_addr, &info.sender, &env.block, amount)?; + + _transfer(deps, env, owner, recipient, amount) +} + +pub fn _transfer( + deps: DepsMut, + env: Env, + sender: String, + recipient: String, + amount: Uint128) -> Result { + let denom = denom(deps.as_ref())?; + let coin = Coin { denom, amount: amount.clone().to_string() }; + + let force_transfer_msg = MsgForceTransfer { + sender: env.contract.address.into_string(), + amount: Some(coin), + transfer_from_address: sender.clone(), + transfer_to_address: recipient.clone(), + }; + let any_msg = AnyMsg { + type_url: String::from("/osmosis.tokenfactory.v1beta1.Msg/ForceTransfer"), + value: to_json_binary(&force_transfer_msg)?, + }; + + let res = Response::new() + .add_attribute("action", "transfer") + .add_attribute("from", sender) + .add_attribute("to", recipient) + .add_attribute("amount", amount) + .add_message(CosmosMsg::Any(any_msg)); + Ok(res) +} + +pub fn send( + deps: DepsMut, + env: Env, + info: MessageInfo, + contract: String, + amount: Uint128, + msg: Binary, +) -> Result { + deps.api.addr_validate(&contract)?; + _send(deps, env, info.sender.into_string(), contract, amount, msg) +} + +pub fn send_from( + deps: DepsMut, + env: Env, + info: MessageInfo, + owner: String, + contract: String, + amount: Uint128, + msg: Binary, +) -> Result { + deps.api.addr_validate(&contract)?; + let owner_addr = deps.api.addr_validate(&owner)?; + + // deduct allowance before doing anything else have enough allowance + deduct_allowance(deps.storage, &owner_addr, &info.sender, &env.block, amount)?; + + _send(deps, env, info.sender.into_string(), contract, amount, msg) +} + +pub fn _send( + deps: DepsMut, + env: Env, + sender: String, + contract: String, + amount: Uint128, + msg: Binary, +) -> Result { + deps.api.addr_validate(&contract)?; + + let token_info = TOKEN_INFO.load(deps.storage)?; + let denom = denom(deps.as_ref())?; + let coin = Coin { denom, amount: amount.clone().to_string() }; + + let force_transfer_msg = MsgForceTransfer { + sender: env.contract.address.into_string(), + amount: Some(coin), + transfer_from_address: sender.clone(), + transfer_to_address: contract.clone(), + }; + let any_msg = AnyMsg { + type_url: String::from("/osmosis.tokenfactory.v1beta1.Msg/ForceTransfer"), + value: to_json_binary(&force_transfer_msg)?, + }; + + let res = Response::new() + .add_attribute("action", "send") + .add_attribute("from", &sender) + .add_attribute("to", &contract) + .add_attribute("amount", amount) + .add_message( + Cw20ReceiveMsg { + sender, + amount, + msg, + } + .into_cosmos_msg(contract)?, + ) + .add_message(CosmosMsg::Any(any_msg)); + Ok(res) +} + + +pub fn burn( + deps: DepsMut, + env: Env, + info: MessageInfo, + amount: Uint128, +) -> Result { + _burn(deps, env, info.sender.into_string(), amount) +} + +pub fn burn_from( + deps: DepsMut, + env: Env, + info: MessageInfo, + owner: String, + amount: Uint128, +) -> Result { + let owner_addr = deps.api.addr_validate(&owner)?; + + // deduct allowance before doing anything else have enough allowance + deduct_allowance(deps.storage, &owner_addr, &info.sender, &env.block, amount)?; + + _burn(deps, env, owner, amount) +} + +pub fn _burn( + deps: DepsMut, + env: Env, + sender: String, + amount: Uint128, +) -> Result { + let denom = denom(deps.as_ref())?; + let coin = Coin { denom, amount: amount.clone().to_string() }; + + let burn_msg = MsgBurn { + sender: env.contract.address.into_string(), + amount: Some(coin), + burn_from_address: sender.clone(), + }; + let any_msg = AnyMsg { + type_url: String::from("/osmosis.tokenfactory.v1beta1.Msg/Burn"), + value: to_json_binary(&burn_msg)?, + }; + + let res = Response::new() + .add_attribute("action", "burn") + .add_attribute("from", sender) + .add_attribute("amount", amount) + .add_message(CosmosMsg::Any(any_msg)); + Ok(res) +} + + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { + match msg { + // inherited from cw20-base + QueryMsg::TokenInfo {} => to_json_binary(&query_token_info(deps)?), + QueryMsg::Balance { address } => to_json_binary(&query_balance(deps, address)?), + QueryMsg::Allowance { owner, spender } => { + to_json_binary(&query_allowance(deps, owner, spender)?) + } + } +} + +pub fn query_token_info(deps: Deps) -> StdResult { + let denom = denom(deps)?; + let metadata = deps.querier.query_denom_metadata(denom.clone())?; + let supply = deps.querier.query_supply(denom)?; + + let base_denom_unit = metadata.denom_units.iter().find(|&d| d.denom == metadata.base).unwrap_or_default(); + let res = TokenInfoResponse { + name: metadata.name, + symbol: metadata.symbol, + decimals: base_denom_unit.exponent as u8, + total_supply: supply.amount, + }; + Ok(res) +} + +pub fn query_balance(deps: Deps, address: String) -> StdResult { + deps.api.addr_validate(&address)?; + + let denom = denom(deps)?; + let coin = deps.querier.query_balance(address, denom)?; + + Ok(BalanceResponse { balance: coin.amount }) +} \ No newline at end of file diff --git a/contracts/tf20/src/error.rs b/contracts/tf20/src/error.rs new file mode 100644 index 0000000..efd6057 --- /dev/null +++ b/contracts/tf20/src/error.rs @@ -0,0 +1,16 @@ +use cosmwasm_std::{StdError, Uint128}; +use thiserror::Error; + +#[derive(Error, Debug, PartialEq)] +pub enum ContractError { + #[error("{0}")] + Std(#[from] StdError), + + #[error(transparent)] + CW20Base(#[from] cw20_base::ContractError), + + #[error("only the contract admin can call this method")] + Unauthorized, +} + +pub type ContractResult = Result; diff --git a/contracts/tf20/src/lib.rs b/contracts/tf20/src/lib.rs new file mode 100644 index 0000000..baac53f --- /dev/null +++ b/contracts/tf20/src/lib.rs @@ -0,0 +1,4 @@ +mod contract; +mod msg; +mod error; +mod state; \ No newline at end of file diff --git a/contracts/tf20/src/msg.rs b/contracts/tf20/src/msg.rs new file mode 100644 index 0000000..8b0f0b5 --- /dev/null +++ b/contracts/tf20/src/msg.rs @@ -0,0 +1,102 @@ +use cosmos_sdk_proto::cosmos::bank::v1beta1::Metadata; +use cosmwasm_schema::{cw_serde, QueryResponses}; + +use cosmwasm_std::{Binary, Coin, Decimal, Uint128}; +use cw20::Expiration; +use cw20::{AllowanceResponse, BalanceResponse, TokenInfoResponse}; +pub use cw_controllers::ClaimsResponse; + +#[cw_serde] +pub struct InstantiateMsg { + /// name of the derivative token + pub creator: String, + /// symbol / ticker of the derivative token + pub subdenom: String, +} + +#[cw_serde] +pub enum ExecuteMsg { + /// Admin functionality to mirror TokenFactory + /// Creates more tokens to the specified account + Mint { recipient: String, amount: Uint128 }, + + /// The following are admin overrides of their matching named commands + ForceTransfer { owner: String, recipient: String, amount: Uint128 }, + ForceBurn { owner: String, amount: Uint128 }, + ForceSend { + owner: String, + contract: String, + amount: Uint128, + msg: Binary, + }, + + /// Allows current admin of the contract to select a new admin for the contract, or set it to empty. + /// if the admin is set to empty, no admin commands can be called again + UpdateContractAdmin { new_admin: String }, + /// Allows the current admin to select a new admin of the TokenFactory denom, or set it to empty. + /// If a new admin is selected for the denom, this contract will no longer be a valid admin of the denom + /// and all allowances and cw20 utility will no longer be functional + UpdateTokenFactoryAdmin { new_admin: String }, + /// Allows the admin to modify the token denom metadata + ModifyMetadata { metadata: Metadata }, + + /// Implements CW20. Transfer is a base message to move tokens to another account without triggering actions + Transfer { recipient: String, amount: Uint128 }, + /// Implements CW20. Burn is a base message to destroy tokens forever + Burn { amount: Uint128 }, + /// Implements CW20. Send is a base message to transfer tokens to a contract and trigger an action + /// on the receiving contract. + Send { + contract: String, + amount: Uint128, + msg: Binary, + }, + /// Implements CW20 "approval" extension. Allows spender to access an additional amount tokens + /// from the owner's (env.sender) account. If expires is Some(), overwrites current allowance + /// expiration with this one. + IncreaseAllowance { + spender: String, + amount: Uint128, + expires: Option, + }, + /// Implements CW20 "approval" extension. Lowers the spender's access of tokens + /// from the owner's (env.sender) account by amount. If expires is Some(), overwrites current + /// allowance expiration with this one. + DecreaseAllowance { + spender: String, + amount: Uint128, + expires: Option, + }, + /// Implements CW20 "approval" extension. Transfers amount tokens from owner -> recipient + /// if `env.sender` has sufficient pre-approval. + TransferFrom { + owner: String, + recipient: String, + amount: Uint128, + }, + /// Implements CW20 "approval" extension. Sends amount tokens from owner -> contract + /// if `env.sender` has sufficient pre-approval. + SendFrom { + owner: String, + contract: String, + amount: Uint128, + msg: Binary, + }, + /// Implements CW20 "approval" extension. Destroys tokens forever + BurnFrom { owner: String, amount: Uint128 }, +} + +#[cw_serde] +#[derive(QueryResponses)] +pub enum QueryMsg { + /// Implements CW20. Returns the current balance of the given address, 0 if unset. + #[returns(BalanceResponse)] + Balance { address: String }, + /// Implements CW20. Returns metadata on the contract - name, decimals, supply, etc. + #[returns(TokenInfoResponse)] + TokenInfo {}, + /// Implements CW20 "allowance" extension. + /// Returns how much spender can use from owner account, 0 if unset. + #[returns(AllowanceResponse)] + Allowance { owner: String, spender: String }, +} \ No newline at end of file diff --git a/contracts/tf20/src/state.rs b/contracts/tf20/src/state.rs new file mode 100644 index 0000000..6e1fa64 --- /dev/null +++ b/contracts/tf20/src/state.rs @@ -0,0 +1,13 @@ +use cosmwasm_schema::cw_serde; +use cosmwasm_std::{Addr, Uint128}; +use cw20_base::state::MinterData; +use cw_storage_plus::Item; + +#[cw_serde] +pub struct TokenInfo { + pub creator: String, + pub subdenom: String, + pub admin: Option, +} + +pub const TOKEN_INFO: Item = Item::new("token_info"); From d170a38568ba5af8a6ccf53ad98ec8e88cccec28 Mon Sep 17 00:00:00 2001 From: Ash Date: Wed, 7 Aug 2024 17:48:31 -0700 Subject: [PATCH 2/7] cargo --- contracts/tf20/Cargo.toml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 contracts/tf20/Cargo.toml diff --git a/contracts/tf20/Cargo.toml b/contracts/tf20/Cargo.toml new file mode 100644 index 0000000..1daa0ea --- /dev/null +++ b/contracts/tf20/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "tf20" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +cosmwasm-schema = { workspace = true } +cosmwasm-std = { workspace = true } +cw2 = { workspace = true } +cw-storage-plus = { workspace = true } +cw-utils = { workspace = true} +cosmos-sdk-proto = {workspace = true} +cw20 = "2.0.0" +cw20-base = { version = "2.0.0", features = ["library"] } +cw-controllers = "2.0.0" +thiserror = { workspace = true } \ No newline at end of file From 443335eed28b0f291ac0e8a7d644003df58baada Mon Sep 17 00:00:00 2001 From: Ash Date: Wed, 7 Aug 2024 18:13:09 -0700 Subject: [PATCH 3/7] lint --- Cargo.toml | 2 +- contracts/account/src/auth/jwt.rs | 4 +- contracts/tf20/src/contract.rs | 148 ++++++++++++---------- contracts/tf20/src/error.rs | 2 +- contracts/tf20/src/lib.rs | 4 +- contracts/tf20/src/msg.rs | 50 ++++++-- contracts/tf20/src/state.rs | 3 +- contracts/treasury/src/grant/allowance.rs | 12 +- 8 files changed, 131 insertions(+), 94 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1525899..9ca54cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,6 @@ rsa = { version = "0.9.2" } getrandom = { version = "0.2.10", features = ["custom"] } p256 = {version = "0.13.2", features = ["ecdsa-core", "arithmetic", "serde"]} prost = {version = "0.13.1", default-features = false, features = ["prost-derive"]} -cosmos-sdk-proto = {git = "https://github.com/burnt-labs/cosmos-rust.git", rev = "53887487c978c5fef6aa064a36f81b23ddb4ee03", default-features = false, features = ["std", "cosmwasm", "xion", "tokenfactory"]} +cosmos-sdk-proto = {git = "https://github.com/burnt-labs/cosmos-rust.git", rev = "1dafd5eb36f3d3ee5100fb8f331c2640badc13f2", default-features = false, features = ["std", "cosmwasm", "xion", "tokenfactory"]} prost-types = "0.13.1" pbjson-types = "0.7.0" \ No newline at end of file diff --git a/contracts/account/src/auth/jwt.rs b/contracts/account/src/auth/jwt.rs index fbe0f06..6cb1a97 100644 --- a/contracts/account/src/auth/jwt.rs +++ b/contracts/account/src/auth/jwt.rs @@ -4,7 +4,7 @@ use base64::engine::general_purpose::URL_SAFE_NO_PAD; use base64::Engine as _; use cosmos_sdk_proto::xion::v1::jwk::QueryValidateJwtRequest; use cosmwasm_schema::cw_serde; -use cosmwasm_std::{Binary, Deps, to_json_binary}; +use cosmwasm_std::{to_json_binary, Binary, Deps}; use serde::{Deserialize, Serialize}; use std::str; @@ -43,7 +43,7 @@ pub fn verify( sig_bytes: String::from_utf8(sig_bytes.into())?, // tx_hash: challenge, }; - let grpc_query = cosmwasm_std::GrpcQuery{ + let grpc_query = cosmwasm_std::GrpcQuery { path: String::from("/xion.jwk.v1.Query/ValidateJWT"), data: to_json_binary(&query)?, }; diff --git a/contracts/tf20/src/contract.rs b/contracts/tf20/src/contract.rs index 519b058..0c6617d 100644 --- a/contracts/tf20/src/contract.rs +++ b/contracts/tf20/src/contract.rs @@ -1,18 +1,23 @@ -use std::ptr::metadata; -use cosmos_sdk_proto::cosmos::bank::v1beta1::Metadata; #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; -use cw2::set_contract_version; -use cosmwasm_std::{Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult, Uint128, CosmosMsg, AnyMsg, to_json_binary, BankMsg, DenomUnit, Addr}; use cosmos_sdk_proto::cosmos::base::v1beta1::Coin; +use cosmwasm_std::{ + from_json, to_json_binary, Addr, AnyMsg, Binary, CosmosMsg, Deps, DepsMut, Env, MessageInfo, + Response, StdResult, Uint128, +}; +use cw2::set_contract_version; -use cw20_base::allowances::{deduct_allowance, execute_decrease_allowance, execute_increase_allowance, query_allowance}; -use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; use crate::error::{ContractError, ContractResult}; -use cosmos_sdk_proto::tokenfactory::v1beta1::{MsgBurn, MsgChangeAdmin, MsgForceTransfer, MsgMint, MsgSetDenomMetadata}; +use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; +use crate::state::{TokenInfo, TOKEN_INFO}; +use cosmos_sdk_proto::osmosis::tokenfactory::v1beta1::{ + MsgBurn, MsgChangeAdmin, MsgForceTransfer, MsgMint, MsgSetDenomMetadata, +}; use cw20::{BalanceResponse, Cw20ReceiveMsg, TokenInfoResponse}; -use crate::state::{TOKEN_INFO, TokenInfo}; +use cw20_base::allowances::{ + deduct_allowance, execute_decrease_allowance, execute_increase_allowance, query_allowance, +}; // version info for migration info const CONTRACT_NAME: &str = "crates.io:tf20"; @@ -20,7 +25,11 @@ const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); pub fn denom(deps: Deps) -> StdResult { let token_info = TOKEN_INFO.load(deps.storage)?; - Ok(format!("tokenfactory/{creator}/{subdenom}", creator = token_info.creator, subdenom = token_info.subdenom)) + Ok(format!( + "tokenfactory/{creator}/{subdenom}", + creator = token_info.creator, + subdenom = token_info.subdenom + )) } #[cfg_attr(not(feature = "library"), entry_point)] @@ -54,27 +63,26 @@ pub fn execute( ) -> Result { match msg { // admin functions for the contract to control the tokenfactory denom - ExecuteMsg::Mint { recipient, amount } => { - Ok(mint(deps, env, info, recipient, amount)?) - } - ExecuteMsg::ForceTransfer { owner, recipient, amount } => { - Ok(force_transfer(deps, env, info, owner, recipient, amount)?) - } - ExecuteMsg::ForceBurn { owner , amount } => { - Ok(force_burn(deps, env, info, owner, amount)?) - } - ExecuteMsg::ForceSend { owner, contract, amount, msg} => { - Ok(force_send(deps, env, info, owner, contract, amount, msg)?) - } + ExecuteMsg::Mint { recipient, amount } => Ok(mint(deps, env, info, recipient, amount)?), + ExecuteMsg::ForceTransfer { + owner, + recipient, + amount, + } => Ok(force_transfer(deps, env, info, owner, recipient, amount)?), + ExecuteMsg::ForceBurn { owner, amount } => Ok(force_burn(deps, env, info, owner, amount)?), + ExecuteMsg::ForceSend { + owner, + contract, + amount, + msg, + } => Ok(force_send(deps, env, info, owner, contract, amount, msg)?), ExecuteMsg::UpdateContractAdmin { new_admin } => { Ok(update_contract_admin(deps, env, info, new_admin)?) } ExecuteMsg::UpdateTokenFactoryAdmin { new_admin } => { Ok(update_tokenfactory_admin(deps, env, info, new_admin)?) } - ExecuteMsg::ModifyMetadata { metadata } => { - Ok(modify_metadata(deps, env, info, metadata)?) - } + ExecuteMsg::ModifyMetadata { metadata } => Ok(modify_metadata(deps, env, info, metadata)?), // these all come from cw20-base to implement the cw20 standard ExecuteMsg::Transfer { recipient, amount } => { @@ -104,20 +112,14 @@ pub fn execute( owner, recipient, amount, - } => Ok(transfer_from( - deps, env, info, owner, recipient, amount, - )?), - ExecuteMsg::BurnFrom { owner, amount } => { - Ok(burn_from(deps, env, info, owner, amount)?) - } + } => Ok(transfer_from(deps, env, info, owner, recipient, amount)?), + ExecuteMsg::BurnFrom { owner, amount } => Ok(burn_from(deps, env, info, owner, amount)?), ExecuteMsg::SendFrom { owner, contract, amount, msg, - } => Ok(send_from( - deps, env, info, owner, contract, amount, msg, - )?), + } => Ok(send_from(deps, env, info, owner, contract, amount, msg)?), } } @@ -142,11 +144,14 @@ pub fn mint( amount: Uint128, ) -> Result { assert_admin(deps.as_ref(), info.sender)?; - + deps.api.addr_validate(&recipient)?; let denom = denom(deps.as_ref())?; - let coin = Coin { denom, amount: amount.clone().to_string() }; + let coin = Coin { + denom, + amount: amount.clone().to_string(), + }; let force_transfer_msg = MsgMint { sender: env.contract.address.into_string(), @@ -178,7 +183,7 @@ pub fn force_transfer( deps.api.addr_validate(&owner)?; deps.api.addr_validate(&recipient)?; - + _transfer(deps, env, owner, recipient, amount) } @@ -221,14 +226,13 @@ pub fn update_contract_admin( let old_admin = info.sender.into_string(); let admin = match new_admin.is_empty() { - true => {None} + true => None, false => { let addr = deps.api.addr_validate(&new_admin)?; Some(addr) } }; - - + let mut token_info = TOKEN_INFO.load(deps.storage)?; token_info.admin = admin; TOKEN_INFO.save(deps.storage, &token_info)?; @@ -246,20 +250,20 @@ pub fn update_tokenfactory_admin( ) -> Result { assert_admin(deps.as_ref(), info.sender.clone())?; let old_admin = info.sender.clone().into_string(); - + let denom = denom(deps.as_ref())?; - - let change_admin_msg = MsgChangeAdmin{ + + let change_admin_msg = MsgChangeAdmin { sender: info.sender.into_string(), denom, new_admin: new_admin.clone(), }; - - let any_msg = AnyMsg{ + + let any_msg = AnyMsg { type_url: String::from("/osmosis.tokenfactory.v1beta1.Msg/ChangeAdmin"), value: to_json_binary(&change_admin_msg)?, }; - + Ok(Response::new() .add_attribute("action", "update_tokenfactory_admin") .add_attribute("old_admin", old_admin) @@ -271,27 +275,27 @@ pub fn modify_metadata( deps: DepsMut, _env: Env, info: MessageInfo, - metadata: Metadata, + metadata: Binary, ) -> Result { assert_admin(deps.as_ref(), info.sender.clone())?; - - let change_admin_msg = MsgSetDenomMetadata{ + + let deserialized_metadata = from_json(metadata)?; + + let change_admin_msg = MsgSetDenomMetadata { sender: info.sender.into_string(), - metadata: Some(metadata.clone()), + metadata: Some(deserialized_metadata), }; - let any_msg = AnyMsg{ + let any_msg = AnyMsg { type_url: String::from("/osmosis.tokenfactory.v1beta1.Msg/ChangeAdmin"), value: to_json_binary(&change_admin_msg)?, }; Ok(Response::new() .add_attribute("action", "modify_metadata") - .add_attribute("metadata", metadata.to_string()) .add_message(CosmosMsg::Any(any_msg))) } - pub fn transfer( deps: DepsMut, env: Env, @@ -324,9 +328,13 @@ pub fn _transfer( env: Env, sender: String, recipient: String, - amount: Uint128) -> Result { + amount: Uint128, +) -> Result { let denom = denom(deps.as_ref())?; - let coin = Coin { denom, amount: amount.clone().to_string() }; + let coin = Coin { + denom, + amount: amount.clone().to_string(), + }; let force_transfer_msg = MsgForceTransfer { sender: env.contract.address.into_string(), @@ -388,9 +396,11 @@ pub fn _send( ) -> Result { deps.api.addr_validate(&contract)?; - let token_info = TOKEN_INFO.load(deps.storage)?; let denom = denom(deps.as_ref())?; - let coin = Coin { denom, amount: amount.clone().to_string() }; + let coin = Coin { + denom, + amount: amount.clone().to_string(), + }; let force_transfer_msg = MsgForceTransfer { sender: env.contract.address.into_string(), @@ -414,13 +424,12 @@ pub fn _send( amount, msg, } - .into_cosmos_msg(contract)?, + .into_cosmos_msg(contract)?, ) .add_message(CosmosMsg::Any(any_msg)); Ok(res) } - pub fn burn( deps: DepsMut, env: Env, @@ -452,7 +461,10 @@ pub fn _burn( amount: Uint128, ) -> Result { let denom = denom(deps.as_ref())?; - let coin = Coin { denom, amount: amount.clone().to_string() }; + let coin = Coin { + denom, + amount: amount.clone().to_string(), + }; let burn_msg = MsgBurn { sender: env.contract.address.into_string(), @@ -472,7 +484,6 @@ pub fn _burn( Ok(res) } - #[cfg_attr(not(feature = "library"), entry_point)] pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { match msg { @@ -490,11 +501,18 @@ pub fn query_token_info(deps: Deps) -> StdResult { let metadata = deps.querier.query_denom_metadata(denom.clone())?; let supply = deps.querier.query_supply(denom)?; - let base_denom_unit = metadata.denom_units.iter().find(|&d| d.denom == metadata.base).unwrap_or_default(); + let exponent = match metadata + .denom_units + .iter() + .find(|&d| d.denom == metadata.base) + { + None => 0, + Some(denom_unit) => denom_unit.exponent, + }; let res = TokenInfoResponse { name: metadata.name, symbol: metadata.symbol, - decimals: base_denom_unit.exponent as u8, + decimals: exponent as u8, total_supply: supply.amount, }; Ok(res) @@ -506,5 +524,7 @@ pub fn query_balance(deps: Deps, address: String) -> StdResult let denom = denom(deps)?; let coin = deps.querier.query_balance(address, denom)?; - Ok(BalanceResponse { balance: coin.amount }) -} \ No newline at end of file + Ok(BalanceResponse { + balance: coin.amount, + }) +} diff --git a/contracts/tf20/src/error.rs b/contracts/tf20/src/error.rs index efd6057..568b09b 100644 --- a/contracts/tf20/src/error.rs +++ b/contracts/tf20/src/error.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{StdError, Uint128}; +use cosmwasm_std::StdError; use thiserror::Error; #[derive(Error, Debug, PartialEq)] diff --git a/contracts/tf20/src/lib.rs b/contracts/tf20/src/lib.rs index baac53f..5871e0e 100644 --- a/contracts/tf20/src/lib.rs +++ b/contracts/tf20/src/lib.rs @@ -1,4 +1,4 @@ mod contract; -mod msg; mod error; -mod state; \ No newline at end of file +mod msg; +mod state; diff --git a/contracts/tf20/src/msg.rs b/contracts/tf20/src/msg.rs index 8b0f0b5..2359c7f 100644 --- a/contracts/tf20/src/msg.rs +++ b/contracts/tf20/src/msg.rs @@ -1,9 +1,7 @@ -use cosmos_sdk_proto::cosmos::bank::v1beta1::Metadata; use cosmwasm_schema::{cw_serde, QueryResponses}; -use cosmwasm_std::{Binary, Coin, Decimal, Uint128}; +use cosmwasm_std::{Binary, Uint128}; use cw20::Expiration; -use cw20::{AllowanceResponse, BalanceResponse, TokenInfoResponse}; pub use cw_controllers::ClaimsResponse; #[cw_serde] @@ -18,11 +16,21 @@ pub struct InstantiateMsg { pub enum ExecuteMsg { /// Admin functionality to mirror TokenFactory /// Creates more tokens to the specified account - Mint { recipient: String, amount: Uint128 }, - + Mint { + recipient: String, + amount: Uint128, + }, + /// The following are admin overrides of their matching named commands - ForceTransfer { owner: String, recipient: String, amount: Uint128 }, - ForceBurn { owner: String, amount: Uint128 }, + ForceTransfer { + owner: String, + recipient: String, + amount: Uint128, + }, + ForceBurn { + owner: String, + amount: Uint128, + }, ForceSend { owner: String, contract: String, @@ -32,18 +40,29 @@ pub enum ExecuteMsg { /// Allows current admin of the contract to select a new admin for the contract, or set it to empty. /// if the admin is set to empty, no admin commands can be called again - UpdateContractAdmin { new_admin: String }, + UpdateContractAdmin { + new_admin: String, + }, /// Allows the current admin to select a new admin of the TokenFactory denom, or set it to empty. /// If a new admin is selected for the denom, this contract will no longer be a valid admin of the denom /// and all allowances and cw20 utility will no longer be functional - UpdateTokenFactoryAdmin { new_admin: String }, + UpdateTokenFactoryAdmin { + new_admin: String, + }, /// Allows the admin to modify the token denom metadata - ModifyMetadata { metadata: Metadata }, + ModifyMetadata { + metadata: Binary, + }, /// Implements CW20. Transfer is a base message to move tokens to another account without triggering actions - Transfer { recipient: String, amount: Uint128 }, + Transfer { + recipient: String, + amount: Uint128, + }, /// Implements CW20. Burn is a base message to destroy tokens forever - Burn { amount: Uint128 }, + Burn { + amount: Uint128, + }, /// Implements CW20. Send is a base message to transfer tokens to a contract and trigger an action /// on the receiving contract. Send { @@ -83,7 +102,10 @@ pub enum ExecuteMsg { msg: Binary, }, /// Implements CW20 "approval" extension. Destroys tokens forever - BurnFrom { owner: String, amount: Uint128 }, + BurnFrom { + owner: String, + amount: Uint128, + }, } #[cw_serde] @@ -99,4 +121,4 @@ pub enum QueryMsg { /// Returns how much spender can use from owner account, 0 if unset. #[returns(AllowanceResponse)] Allowance { owner: String, spender: String }, -} \ No newline at end of file +} diff --git a/contracts/tf20/src/state.rs b/contracts/tf20/src/state.rs index 6e1fa64..a6209d2 100644 --- a/contracts/tf20/src/state.rs +++ b/contracts/tf20/src/state.rs @@ -1,6 +1,5 @@ use cosmwasm_schema::cw_serde; -use cosmwasm_std::{Addr, Uint128}; -use cw20_base::state::MinterData; +use cosmwasm_std::Addr; use cw_storage_plus::Item; #[cw_serde] diff --git a/contracts/treasury/src/grant/allowance.rs b/contracts/treasury/src/grant/allowance.rs index 1f5aaa2..fe877cd 100644 --- a/contracts/treasury/src/grant/allowance.rs +++ b/contracts/treasury/src/grant/allowance.rs @@ -20,8 +20,7 @@ pub fn format_allowance( "/cosmos.feegrant.v1beta1.BasicAllowance" => match expiration.clone() { None => allowance_any, Some(_) => { - let mut allowance = - BasicAllowance::decode(allowance_any.value.as_slice())?; + let mut allowance = BasicAllowance::decode(allowance_any.value.as_slice())?; allowance.expiration = expiration; let allowance_bz = allowance.to_bytes()?; Any { @@ -34,8 +33,7 @@ pub fn format_allowance( "/cosmos.feegrant.v1beta1.PeriodicAllowance" => match expiration.clone() { None => allowance_any, Some(_) => { - let mut allowance = - PeriodicAllowance::decode(allowance_any.value.as_slice())?; + let mut allowance = PeriodicAllowance::decode(allowance_any.value.as_slice())?; let mut inner_basic = allowance.basic.clone().ok_or(AllowanceUnset)?; inner_basic.expiration = expiration; allowance.basic = Some(inner_basic); @@ -48,8 +46,7 @@ pub fn format_allowance( }, "/cosmos.feegrant.v1beta1.AllowedMsgAllowance" => { - let mut allowance = - AllowedMsgAllowance::decode(allowance_any.value.as_slice())?; + let mut allowance = AllowedMsgAllowance::decode(allowance_any.value.as_slice())?; let inner_allowance = format_allowance( allowance.allowance.ok_or(AllowanceUnset)?.into(), _granter, @@ -85,8 +82,7 @@ pub fn format_allowance( } "/xion.v1.ContractsAllowance" => { - let mut allowance = - ContractsAllowance::decode(allowance_any.value.as_slice())?; + let mut allowance = ContractsAllowance::decode(allowance_any.value.as_slice())?; let inner_allowance = format_allowance( allowance.allowance.ok_or(AllowanceUnset)?.into(), _granter, From f9d2d98044113d55ec63d88586f370926812a064 Mon Sep 17 00:00:00 2001 From: Ash Date: Wed, 7 Aug 2024 18:20:57 -0700 Subject: [PATCH 4/7] query for admin --- contracts/tf20/src/contract.rs | 13 ++++++++++++- contracts/tf20/src/msg.rs | 11 +++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/contracts/tf20/src/contract.rs b/contracts/tf20/src/contract.rs index 0c6617d..af32155 100644 --- a/contracts/tf20/src/contract.rs +++ b/contracts/tf20/src/contract.rs @@ -9,7 +9,7 @@ use cosmwasm_std::{ use cw2::set_contract_version; use crate::error::{ContractError, ContractResult}; -use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; +use crate::msg::{AdminResponse, ExecuteMsg, InstantiateMsg, QueryMsg}; use crate::state::{TokenInfo, TOKEN_INFO}; use cosmos_sdk_proto::osmosis::tokenfactory::v1beta1::{ MsgBurn, MsgChangeAdmin, MsgForceTransfer, MsgMint, MsgSetDenomMetadata, @@ -493,6 +493,9 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { QueryMsg::Allowance { owner, spender } => { to_json_binary(&query_allowance(deps, owner, spender)?) } + QueryMsg::Admin {} => { + to_json_binary(&query_admin(deps)?) + } } } @@ -528,3 +531,11 @@ pub fn query_balance(deps: Deps, address: String) -> StdResult balance: coin.amount, }) } + +pub fn query_admin(deps: Deps) -> StdResult { + let token_info = TOKEN_INFO.load(deps.storage)?; + + Ok(AdminResponse { + admin: token_info.admin, + }) +} diff --git a/contracts/tf20/src/msg.rs b/contracts/tf20/src/msg.rs index 2359c7f..fa5f124 100644 --- a/contracts/tf20/src/msg.rs +++ b/contracts/tf20/src/msg.rs @@ -1,7 +1,7 @@ use cosmwasm_schema::{cw_serde, QueryResponses}; - -use cosmwasm_std::{Binary, Uint128}; +use cosmwasm_std::{Addr, Binary, Uint128}; use cw20::Expiration; +use cw20::{AllowanceResponse, BalanceResponse, TokenInfoResponse}; pub use cw_controllers::ClaimsResponse; #[cw_serde] @@ -121,4 +121,11 @@ pub enum QueryMsg { /// Returns how much spender can use from owner account, 0 if unset. #[returns(AllowanceResponse)] Allowance { owner: String, spender: String }, + #[returns(AdminResponse)] + Admin {}, } + +#[cw_serde] +pub struct AdminResponse { + pub admin: Option, +} \ No newline at end of file From 29b19975266b1b68444f70a6fefd29c0e52458f4 Mon Sep 17 00:00:00 2001 From: Ash Date: Thu, 8 Aug 2024 14:38:36 -0700 Subject: [PATCH 5/7] review notes --- contracts/tf20/src/contract.rs | 29 +++++++++++++++++++---------- contracts/tf20/src/msg.rs | 6 ++---- contracts/tf20/src/state.rs | 3 +-- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/contracts/tf20/src/contract.rs b/contracts/tf20/src/contract.rs index af32155..07e8c39 100644 --- a/contracts/tf20/src/contract.rs +++ b/contracts/tf20/src/contract.rs @@ -25,11 +25,7 @@ const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); pub fn denom(deps: Deps) -> StdResult { let token_info = TOKEN_INFO.load(deps.storage)?; - Ok(format!( - "tokenfactory/{creator}/{subdenom}", - creator = token_info.creator, - subdenom = token_info.subdenom - )) + Ok(token_info.denom) } #[cfg_attr(not(feature = "library"), entry_point)] @@ -41,12 +37,23 @@ pub fn instantiate( ) -> Result { set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; - // todo who is minter, do we handle new and existing tokens - + // This initializes a new contract which acts as a wrapper and admin of a + // token that has previously been created in x/tokenfactory + // The recommended flow is: + // 1. creator creates a new token in x/tokenfactory, setting themselves as the token admin + // 2. creator creates an instance of this contract with the relevant information set + // 3. creator transfers token admin control in x/tokenfactory from themselves, to this contract + + // because this contract needs to be the admin of the TF denom, it acts as a + // passthrough admin for the admin of the contract. The contract admin can + // do all the same things the TF admin can. + // Similar to TF denom admin, you can choose to remove the admin value and + // have the token be admin-free, which means that tokens can no longer be + // minted or "forced" via the admin commands. + // store token info using cw20-base format let data = TokenInfo { - creator: msg.creator, - subdenom: msg.subdenom, + denom: msg.denom, admin: Some(info.sender), }; TOKEN_INFO.save(deps.storage, &data)?; @@ -124,6 +131,8 @@ pub fn execute( } pub fn assert_admin(deps: Deps, sender: Addr) -> ContractResult<()> { + // asserts that the sender is the contract admin for this instance + // if an admin is not set, always fail let token_info = TOKEN_INFO.load(deps.storage)?; match token_info.admin { None => Err(ContractError::Unauthorized), @@ -287,7 +296,7 @@ pub fn modify_metadata( }; let any_msg = AnyMsg { - type_url: String::from("/osmosis.tokenfactory.v1beta1.Msg/ChangeAdmin"), + type_url: String::from("/osmosis.tokenfactory.v1beta1.Msg/SetDenomMetadata"), value: to_json_binary(&change_admin_msg)?, }; diff --git a/contracts/tf20/src/msg.rs b/contracts/tf20/src/msg.rs index fa5f124..8142b9b 100644 --- a/contracts/tf20/src/msg.rs +++ b/contracts/tf20/src/msg.rs @@ -6,10 +6,8 @@ pub use cw_controllers::ClaimsResponse; #[cw_serde] pub struct InstantiateMsg { - /// name of the derivative token - pub creator: String, - /// symbol / ticker of the derivative token - pub subdenom: String, + /// full string of the x/tokenfactory denom + pub denom: String, } #[cw_serde] diff --git a/contracts/tf20/src/state.rs b/contracts/tf20/src/state.rs index a6209d2..eab940d 100644 --- a/contracts/tf20/src/state.rs +++ b/contracts/tf20/src/state.rs @@ -4,8 +4,7 @@ use cw_storage_plus::Item; #[cw_serde] pub struct TokenInfo { - pub creator: String, - pub subdenom: String, + pub denom: String, pub admin: Option, } From f1cfd665ca26f181231dd8d87f4a8954f912a2b9 Mon Sep 17 00:00:00 2001 From: Ash Date: Mon, 12 Aug 2024 16:10:31 -0700 Subject: [PATCH 6/7] upgrade prost --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index df87704..323c031 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,6 @@ phf = { version = "0.11.2", features = ["macros"] } rsa = { version = "0.9.2" } getrandom = { version = "0.2.10", features = ["custom"] } p256 = {version = "0.13.2", features = ["ecdsa-core", "arithmetic", "serde"]} -prost = {version = "0.11.2", default-features = false, features = ["prost-derive"]} +prost = {version = "0.13.1", default-features = false, features = ["prost-derive"]} cosmos-sdk-proto = { git = "https://github.com/burnt-labs/cosmos-rust.git", rev = "75e72f446629f98330e209e2f6268250d325cccb", default-features = false, features = ["std", "cosmwasm", "xion", "tokenfactory", "serde"]} osmosis-std-derive = "0.13.2" From 62853cd822bd8fc86d8e2c19864fadcaa7085d55 Mon Sep 17 00:00:00 2001 From: Ash Date: Mon, 12 Aug 2024 16:26:29 -0700 Subject: [PATCH 7/7] remove unneeded conversion --- contracts/account/src/auth/jwt.rs | 2 +- contracts/tf20/Cargo.toml | 8 ++++++-- contracts/tf20/src/lib.rs | 6 +++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/contracts/account/src/auth/jwt.rs b/contracts/account/src/auth/jwt.rs index 84eb8ea..49595fc 100644 --- a/contracts/account/src/auth/jwt.rs +++ b/contracts/account/src/auth/jwt.rs @@ -47,7 +47,7 @@ pub fn verify( let query_bz = query.to_bytes()?; deps.querier.query_grpc( - String::from("/xion.jwk.v1.Query/ValidateJWT".to_string()), + String::from("/xion.jwk.v1.Query/ValidateJWT"), Binary::new(query_bz), )?; diff --git a/contracts/tf20/Cargo.toml b/contracts/tf20/Cargo.toml index 76a0f3e..fbe1f41 100644 --- a/contracts/tf20/Cargo.toml +++ b/contracts/tf20/Cargo.toml @@ -5,8 +5,11 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +crate-type = ["cdylib", "rlib"] + [features] -# enable feature if you want to disable entry points +# use library feature to disable all instantiate/execute/query exports library = [] [dependencies] @@ -19,4 +22,5 @@ cosmos-sdk-proto = {workspace = true} cw20 = "2.0.0" cw20-base = { version = "2.0.0", features = ["library"] } cw-controllers = "2.0.0" -thiserror = { workspace = true } \ No newline at end of file +thiserror = { workspace = true } +[dev-dependencies] \ No newline at end of file diff --git a/contracts/tf20/src/lib.rs b/contracts/tf20/src/lib.rs index 5871e0e..d78159f 100644 --- a/contracts/tf20/src/lib.rs +++ b/contracts/tf20/src/lib.rs @@ -1,4 +1,4 @@ -mod contract; +pub mod contract; mod error; -mod msg; -mod state; +pub mod msg; +pub mod state;