Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow the contract UpdateMappingPair #33

Merged
merged 7 commits into from
Nov 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions contracts/cw-ics20-latest/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "cw-ics20-latest"
version = "1.0.8"
version = "1.0.9"
authors = ["Ethan Frey <[email protected]>, Oraichain Labs"]
edition = "2021"
description = "IBC Enabled contracts that receives CW20 tokens and sends them over ICS20 to a remote chain"
Expand Down Expand Up @@ -32,7 +32,8 @@ sha256 = "=1.1.0"
skip = { workspace = true }
tokenfactory = { workspace = true }
token-bindings = { workspace = true }

bs58 = "0.5.1"
hex = "0.4.3"
[dev-dependencies]
cosmwasm-vm = { workspace = true }
# osmosis-test-tube = { workspace = true }
Expand Down
10 changes: 7 additions & 3 deletions contracts/cw-ics20-latest/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use cw2::set_contract_version;
use cw20::{Cw20ExecuteMsg, Cw20ReceiveMsg};
use cw20_ics20_msg::converter::ConverterController;
use cw20_ics20_msg::helper::parse_ibc_wasm_port_id;
use cw_controllers::AdminError;
use cw_storage_plus::Bound;
use oraiswap::asset::AssetInfo;
use oraiswap::router::RouterController;
Expand Down Expand Up @@ -165,7 +166,7 @@ pub fn execute(
orai_receiver,
args,
} => ibc_hooks_receive(deps, env, info, func, orai_receiver, args),
ExecuteMsg::RegisterDenom(msg) => register_denom(deps, info, msg),
ExecuteMsg::RegisterDenom(msg) => register_denom(deps, env, info, msg),
ExecuteMsg::WithdrawAsset { coin, receiver } => {
execute_withdraw_asset(deps, info, coin, receiver)
}
Expand Down Expand Up @@ -201,10 +202,13 @@ fn execute_withdraw_asset(

pub fn register_denom(
deps: DepsMut,
env: Env,
info: MessageInfo,
msg: RegisterDenomMsg,
) -> Result<Response, ContractError> {
ADMIN.assert_admin(deps.as_ref(), &info.sender)?;
if !ADMIN.is_admin(deps.as_ref(), &info.sender)? && info.sender != env.contract.address {
return Err(ContractError::Admin(AdminError::NotAdmin {}));
};

let config = CONFIG.load(deps.storage)?;

Expand Down Expand Up @@ -840,7 +844,7 @@ pub fn execute_delete_mapping_pair(
}

#[entry_point]
pub fn migrate(deps: DepsMut, _env: Env, msg: MigrateMsg) -> Result<Response, ContractError> {
pub fn migrate(deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
// we don't need to save anything if migrating from the same version
set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;

Expand Down
65 changes: 52 additions & 13 deletions contracts/cw-ics20-latest/src/ibc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,33 @@ use std::ops::Mul;

use cosmwasm_schema::cw_serde;
use cosmwasm_std::{
attr, entry_point, from_json, to_json_binary, wasm_execute, Api, Binary, CosmosMsg, Decimal,
Deps, DepsMut, Env, Ibc3ChannelOpenResponse, IbcBasicResponse, IbcChannel, IbcChannelCloseMsg,
IbcChannelConnectMsg, IbcChannelOpenMsg, IbcEndpoint, IbcMsg, IbcOrder, IbcPacket,
IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, IbcTimeout,
Order, QuerierWrapper, Reply, Response, StdError, StdResult, Storage, SubMsg, SubMsgResult,
Uint128,
attr, entry_point, from_json, to_json_binary, wasm_execute, Api, Binary, Coin, CosmosMsg,
Decimal, Deps, DepsMut, Env, Ibc3ChannelOpenResponse, IbcBasicResponse, IbcChannel,
IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, IbcEndpoint, IbcMsg, IbcOrder,
IbcPacket, IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse,
IbcTimeout, Order, QuerierWrapper, Reply, Response, StdError, StdResult, Storage, SubMsg,
SubMsgResult, Uint128,
};

use cw20_ics20_msg::helper::{
denom_to_asset_info, get_prefix_decode_bech32, parse_asset_info_denom,
denom_to_asset_info, get_full_denom, get_prefix_decode_bech32, parse_asset_info_denom,
};
use cw_storage_plus::Map;
use oraiswap::asset::AssetInfo;
use oraiswap::router::{RouterController, SwapOperation};
use skip::entry_point::ExecuteMsg as EntryPointExecuteMsg;
use token_bindings::Metadata;

use crate::contract::build_mint_mapping_msg;
use crate::error::{ContractError, Never};
use crate::msg::ExecuteMsg;
use crate::msg::{ExecuteMsg, RegisterDenomMsg};
use crate::state::{
get_key_ics20_ibc_denom, ics20_denoms, undo_reduce_channel_balance, ALLOW_LIST, CHANNEL_INFO,
CONFIG, RELAYER_FEE, TOKEN_FEE,
};
use cw20_ics20_msg::amount::{convert_remote_to_local, Amount};
use cw20_ics20_msg::msg::FeeData;
use cw20_ics20_msg::state::{ChannelInfo, Ratio};
use cw20_ics20_msg::state::{ChannelInfo, MappingMetadata, Ratio};

pub const ICS20_VERSION: &str = "ics20-1";
pub const ICS20_ORDERING: IbcOrder = IbcOrder::Unordered;
Expand Down Expand Up @@ -329,7 +330,7 @@ fn handle_ibc_packet_receive_native_remote_chain(
let config = CONFIG.load(storage)?;
let mut cosmos_msgs: Vec<CosmosMsg> = vec![];
let ibc_packet_amount = msg.amount.to_string();
let attributes = vec![
let attributes: Vec<(&str, &str)> = vec![
("action", "receive_native"),
("sender", &msg.sender),
("receiver", &msg.receiver),
Expand All @@ -341,9 +342,47 @@ fn handle_ibc_packet_receive_native_remote_chain(

// key in form transfer/channel-0/foo
let ibc_denom = get_key_ics20_ibc_denom(&packet.dest.port_id, &packet.dest.channel_id, denom);
let pair_mapping = ics20_denoms()
.load(storage, &ibc_denom)
.map_err(|_| ContractError::NotOnMappingList {})?;
let pair_mapping = match ics20_denoms().load(storage, &ibc_denom) {
Ok(pair_mapping) => pair_mapping,
Err(_) => {
let (prefix, denom) =
denom
.split_once("0x")
.ok_or(ContractError::Std(StdError::GenericErr {
msg: String::from("Cannot parse denom"),
}))?;

let bytes_address = hex::decode(denom).map_err(|_| {
ContractError::Std(StdError::GenericErr {
msg: String::from("Invalid hex address"),
})
})?;
let base58_address = bs58::encode(bytes_address).into_string();
let base58_denom = format!("{}0x{}", prefix, base58_address);
// push a register denom msg to the contract
cosmos_msgs.push(
wasm_execute(
env.contract.address.to_string(),
&ExecuteMsg::RegisterDenom(RegisterDenomMsg {
subdenom: base58_denom.clone(),
metadata: None,
}),
vec![Coin::new(1, "orai")],
)?
.into(),
);
let new_metadata = MappingMetadata {
asset_info: AssetInfo::NativeToken {
denom: get_full_denom(config.token_factory_addr.to_string(), base58_denom),
},
remote_decimals: 1, // Since we don't know metadata of remote_chain token, we set it to 1 in both decimals
asset_info_decimals: 1,
is_mint_burn: true, // Always mint burn if we don't know the metadata
};
ics20_denoms().save(storage, &ibc_denom, &new_metadata)?;
new_metadata
}
};
let initial_receive_asset_info = pair_mapping.asset_info;
let to_send = Amount::from_parts(
parse_asset_info_denom(&initial_receive_asset_info),
Expand Down
68 changes: 56 additions & 12 deletions contracts/cw-ics20-latest/src/testing/ibc_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ use cosmwasm_std::{
use cosmwasm_testing_util::mock::MockContract;
use cosmwasm_vm::testing::MockInstanceOptions;
use cw20_ics20_msg::converter::ConverterController;
use cw20_ics20_msg::helper::get_full_denom;
use cw_controllers::AdminError;
use oraiswap::asset::AssetInfo;
use oraiswap::router::RouterController;
use token_bindings::Metadata;

use crate::ibc::{
convert_remote_denom_to_evm_prefix, deduct_fee, deduct_relayer_fee, deduct_token_fee,
Expand All @@ -28,8 +30,8 @@ use cosmwasm_std::{

use crate::error::ContractError;
use crate::state::{
get_key_ics20_ibc_denom, increase_channel_balance, reduce_channel_balance, Config, ADMIN,
CHANNEL_REVERSE_STATE, CONFIG, RELAYER_FEE, REPLY_ARGS, TOKEN_FEE,
get_key_ics20_ibc_denom, ics20_denoms, increase_channel_balance, reduce_channel_balance,
Config, ADMIN, CHANNEL_REVERSE_STATE, CONFIG, RELAYER_FEE, REPLY_ARGS, TOKEN_FEE,
};
use cw20::{Cw20CoinVerified, Cw20ExecuteMsg, Cw20ReceiveMsg};
use cw20_ics20_msg::amount::{convert_remote_to_local, Amount};
Expand All @@ -41,7 +43,7 @@ use crate::contract::{
};
use crate::msg::{
AllowMsg, ChannelResponse, ConfigResponse, ExecuteMsg, InitMsg, ListChannelsResponse,
ListMappingResponse, PairQuery, QueryMsg,
ListMappingResponse, PairQuery, QueryMsg, RegisterDenomMsg,
};
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
use cosmwasm_std::{coins, to_json_vec};
Expand Down Expand Up @@ -230,28 +232,70 @@ fn send_native_from_remote_mapping_not_found() {
let send_channel = "channel-9";
let cw20_addr = "token-addr";
let custom_addr = "custom-addr";
let cw20_denom = "cw20:token-addr";
let cw20_denom = "oraib0x10407cEa4B614AB11bd05B326193d84ec20851f6";
let gas_limit = 1234567;
let mut deps = setup(
&["channel-1", "channel-7", send_channel],
&[(cw20_addr, gas_limit)],
);

let config = CONFIG.load(deps.as_ref().storage).unwrap();
// prepare some mock packets
let recv_packet =
mock_receive_packet_remote_to_local(send_channel, 876543210, cw20_denom, custom_addr, None);

let (prefix, denom) = cw20_denom.split_once("0x").unwrap();
let bytes_address = hex::decode(denom)
.map_err(|_| {
ContractError::Std(StdError::GenericErr {
msg: String::from("Invalid hex address"),
})
})
.unwrap();
let base58_address = bs58::encode(bytes_address).into_string();
let base58_denom = format!("{}0x{}", prefix, base58_address);
// we can receive this denom, channel balance should increase
let msg = IbcPacketReceiveMsg::new(recv_packet.clone(), relayer);
let res = ibc_packet_receive(deps.as_mut(), mock_env(), msg).unwrap();
// assert_eq!(res, StdError)

assert_eq!(
res.attributes
.into_iter()
.find(|attr| attr.key.eq("error"))
.unwrap()
.value,
"You can only send native tokens that has a map to the corresponding asset info"
res.messages[0].msg,
wasm_execute(
"cosmos2contract",
&ExecuteMsg::RegisterDenom(RegisterDenomMsg {
subdenom: String::from(base58_denom.clone()),
metadata: None
}),
vec![Coin::new(1u128.into(), "orai")]
)
.unwrap()
.into()
);
execute(
deps.as_mut(),
mock_env(),
mock_info("cosmos2contract", &[]),
ExecuteMsg::RegisterDenom(RegisterDenomMsg {
subdenom: String::from(denom),
metadata: None,
}),
)
.unwrap();
let pair_mapping = ics20_denoms()
.load(
deps.as_ref().storage,
"wasm.cosmos2contract/channel-9/oraib0x10407cEa4B614AB11bd05B326193d84ec20851f6",
)
.unwrap();
assert_eq!(
pair_mapping,
MappingMetadata {
asset_info: AssetInfo::NativeToken {
denom: get_full_denom(config.token_factory_addr.to_string(), base58_denom),
},
remote_decimals: 1,
asset_info_decimals: 1,
is_mint_burn: true
}
);
}

Expand Down
4 changes: 4 additions & 0 deletions packages/cw20-ics20-msg/src/helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ pub fn to_orai_bridge_address(address: &str) -> StdResult<String> {
})
}

pub fn get_full_denom(factory_contract: String, subdenom: String) -> String {
format!("factory/{}/{}", factory_contract, subdenom)
}

#[cfg(test)]
mod tests {
use crate::helper::{get_prefix_decode_bech32, to_orai_bridge_address};
Expand Down
Loading