Skip to content

Commit f587f19

Browse files
authored
Merge pull request #10 from oraichain/feat/relayer-fee
Feat/relayer fee
2 parents f791558 + bdb7848 commit f587f19

File tree

5 files changed

+183
-136
lines changed

5 files changed

+183
-136
lines changed

contracts/cw-ics20-latest/src/contract.rs

Lines changed: 85 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
use cosmwasm_std::entry_point;
33
use cosmwasm_std::{
44
from_binary, to_binary, Addr, Binary, Deps, DepsMut, Empty, Env, IbcEndpoint, IbcMsg, IbcQuery,
5-
MessageInfo, Order, PortIdResponse, Response, StdError, StdResult,
5+
MessageInfo, Order, PortIdResponse, Response, StdResult,
66
};
77
use cw2::set_contract_version;
88
use cw20::{Cw20Coin, Cw20ReceiveMsg};
@@ -21,8 +21,8 @@ use crate::msg::{
2121
};
2222
use crate::state::{
2323
get_key_ics20_ibc_denom, ics20_denoms, increase_channel_balance, reduce_channel_balance,
24-
AllowInfo, Config, MappingMetadata, RelayerFee, ADMIN, ALLOW_LIST, CHANNEL_FORWARD_STATE,
25-
CHANNEL_INFO, CHANNEL_REVERSE_STATE, CONFIG, RELAYER_FEE,
24+
AllowInfo, Config, MappingMetadata, TokenFee, ADMIN, ALLOW_LIST, CHANNEL_FORWARD_STATE,
25+
CHANNEL_INFO, CHANNEL_REVERSE_STATE, CONFIG, TOKEN_FEE,
2626
};
2727
use cw20_ics20_msg::amount::{convert_local_to_remote, Amount};
2828
use cw_utils::{maybe_addr, nonpayable, one_coin};
@@ -39,17 +39,17 @@ pub fn instantiate(
3939
msg: InitMsg,
4040
) -> Result<Response, ContractError> {
4141
set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
42+
let admin = deps.api.addr_validate(&msg.gov_contract)?;
43+
ADMIN.set(deps.branch(), Some(admin.clone()))?;
4244
let cfg = Config {
4345
default_timeout: msg.default_timeout,
4446
default_gas_limit: msg.default_gas_limit,
4547
fee_denom: "orai".to_string(),
4648
swap_router_contract: msg.swap_router_contract,
49+
fee_receiver: admin,
4750
};
4851
CONFIG.save(deps.storage, &cfg)?;
4952

50-
let admin = deps.api.addr_validate(&msg.gov_contract)?;
51-
ADMIN.set(deps.branch(), Some(admin))?;
52-
5353
// add all allows
5454
for allowed in msg.allowlist {
5555
let contract = deps.api.addr_validate(&allowed.contract)?;
@@ -88,7 +88,8 @@ pub fn execute(
8888
fee_denom,
8989
swap_router_contract,
9090
admin,
91-
relayer_fee,
91+
token_fee,
92+
fee_receiver,
9293
} => update_config(
9394
deps,
9495
info,
@@ -97,7 +98,8 @@ pub fn execute(
9798
fee_denom,
9899
swap_router_contract,
99100
admin,
100-
relayer_fee,
101+
token_fee,
102+
fee_receiver,
101103
),
102104
}
103105
}
@@ -110,11 +112,14 @@ pub fn update_config(
110112
fee_denom: Option<String>,
111113
swap_router_contract: Option<String>,
112114
admin: Option<String>,
113-
relayer_fee: Option<RelayerFee>,
115+
token_fee: Option<Vec<TokenFee>>,
116+
fee_receiver: Option<String>,
114117
) -> Result<Response, ContractError> {
115118
ADMIN.assert_admin(deps.as_ref(), &info.sender)?;
116-
if let Some(relayer_fee) = relayer_fee {
117-
RELAYER_FEE.save(deps.storage, &relayer_fee.chain, &relayer_fee.ratio)?;
119+
if let Some(token_fee) = token_fee {
120+
for fee in token_fee {
121+
TOKEN_FEE.save(deps.storage, &fee.token_denom, &fee.ratio)?;
122+
}
118123
}
119124
CONFIG.update(deps.storage, |mut config| -> StdResult<Config> {
120125
if let Some(default_timeout) = default_timeout {
@@ -126,6 +131,9 @@ pub fn update_config(
126131
if let Some(swap_router_contract) = swap_router_contract {
127132
config.swap_router_contract = swap_router_contract;
128133
}
134+
if let Some(fee_receiver) = fee_receiver {
135+
config.fee_receiver = deps.api.addr_validate(&fee_receiver)?;
136+
}
129137
config.default_gas_limit = default_gas_limit;
130138
Ok(config)
131139
})?;
@@ -270,28 +278,27 @@ pub fn execute_transfer_back_to_remote_chain(
270278
)?;
271279

272280
// parse denom & compare with user input. Should not use string.includes() because hacker can fake a port that has the same remote denom to return true
273-
let mapping_search_result = mappings.into_iter().find(|pair| -> bool {
274-
let (denom, is_native) = parse_voucher_denom(
275-
pair.key.as_str(),
276-
&IbcEndpoint {
277-
port_id: parse_ibc_wasm_port_id(env.contract.address.clone().into_string()),
278-
channel_id: msg.local_channel_id.clone(), // also verify local channel id
279-
},
280-
)
281-
.unwrap_or_else(|_| ("", true)); // if there's an error, change is_native to true so it automatically returns false
282-
if is_native {
281+
let mapping = mappings
282+
.into_iter()
283+
.find(|pair| -> bool {
284+
let (denom, is_native) = parse_voucher_denom(
285+
pair.key.as_str(),
286+
&IbcEndpoint {
287+
port_id: parse_ibc_wasm_port_id(env.contract.address.clone().into_string()),
288+
channel_id: msg.local_channel_id.clone(), // also verify local channel id
289+
},
290+
)
291+
.unwrap_or_else(|_| ("", true)); // if there's an error, change is_native to true so it automatically returns false
292+
if is_native {
293+
return false;
294+
}
295+
if denom.eq(&msg.remote_denom) {
296+
return true;
297+
}
283298
return false;
284-
}
285-
if denom.eq(&msg.remote_denom) {
286-
return true;
287-
}
288-
return false;
289-
});
290-
if mapping_search_result.is_none() {
291-
return Err(ContractError::MappingPairNotFound {});
292-
}
299+
})
300+
.ok_or(ContractError::MappingPairNotFound {})?;
293301

294-
let mapping = mapping_search_result.unwrap();
295302
let ibc_denom = mapping.key;
296303
// ensure the requested channel is registered
297304
if !CHANNEL_INFO.has(deps.storage, &msg.local_channel_id) {
@@ -341,13 +348,8 @@ pub fn execute_transfer_back_to_remote_chain(
341348
timeout: timeout.into(),
342349
};
343350

344-
let mut cosmos_msgs = collect_transfer_fee_msgs(
345-
ADMIN
346-
.get(deps.as_ref())?
347-
.ok_or(StdError::generic_err("Cannot find contract admin"))?
348-
.into_string(),
349-
deps.storage,
350-
)?;
351+
let mut cosmos_msgs =
352+
collect_transfer_fee_msgs(config.fee_receiver.into_string(), deps.storage)?;
351353
cosmos_msgs.push(msg.into());
352354

353355
// send response
@@ -475,6 +477,7 @@ pub fn migrate(deps: DepsMut, _env: Env, msg: MigrateMsg) -> Result<Response, Co
475477
default_gas_limit: msg.default_gas_limit,
476478
fee_denom: config.fee_denom,
477479
swap_router_contract: config.swap_router_contract,
480+
fee_receiver: deps.api.addr_validate(&msg.fee_receiver)?,
478481
},
479482
)?;
480483
set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
@@ -504,8 +507,8 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
504507
to_binary(&get_mappings_from_asset_info(deps, asset_info)?)
505508
}
506509
QueryMsg::Admin {} => to_binary(&ADMIN.query_admin(deps)?),
507-
QueryMsg::GetTransferFee { evm_prefix } => {
508-
to_binary(&RELAYER_FEE.load(deps.storage, &evm_prefix)?)
510+
QueryMsg::GetTransferTokenFee { remote_token_denom } => {
511+
to_binary(&TOKEN_FEE.load(deps.storage, &remote_token_denom)?)
509512
}
510513
}
511514
}
@@ -680,8 +683,8 @@ mod test {
680683
use std::ops::Sub;
681684

682685
use super::*;
683-
use crate::ibc::{ibc_packet_receive, parse_asset_info_denom};
684-
use crate::state::{Ratio, RELAYER_FEE_ACCUMULATOR};
686+
use crate::ibc::ibc_packet_receive;
687+
use crate::state::Ratio;
685688
use crate::test_helpers::*;
686689

687690
use cosmwasm_std::testing::{mock_env, mock_info};
@@ -1121,6 +1124,7 @@ mod test {
11211124
mock_env(),
11221125
MigrateMsg {
11231126
default_gas_limit: Some(123456),
1127+
fee_receiver: "receiver".to_string(),
11241128
// default_timeout: 100u64,
11251129
// fee_denom: "orai".to_string(),
11261130
// swap_router_contract: "foobar".to_string(),
@@ -1184,16 +1188,8 @@ mod test {
11841188
let fee_amount =
11851189
Uint128::from(amount) * Decimal::from_ratio(ratio.nominator, ratio.denominator);
11861190
let mut deps = setup(&[remote_channel, local_channel], &[]);
1187-
RELAYER_FEE
1188-
.save(deps.as_mut().storage, "uatom", &ratio)
1189-
.unwrap();
1190-
// reset fee so that other tests wont get affected
1191-
RELAYER_FEE_ACCUMULATOR
1192-
.save(
1193-
deps.as_mut().storage,
1194-
&parse_asset_info_denom(asset_info.clone()),
1195-
&Uint128::zero(),
1196-
)
1191+
TOKEN_FEE
1192+
.save(deps.as_mut().storage, denom, &ratio)
11971193
.unwrap();
11981194

11991195
let pair = UpdatePairMsg {
@@ -1360,7 +1356,23 @@ mod test {
13601356
default_gas_limit: None,
13611357
fee_denom: Some("hehe".to_string()),
13621358
swap_router_contract: Some("new_router".to_string()),
1363-
relayer_fee: None,
1359+
token_fee: Some(vec![
1360+
TokenFee {
1361+
token_denom: "orai".to_string(),
1362+
ratio: Ratio {
1363+
nominator: 1,
1364+
denominator: 10,
1365+
},
1366+
},
1367+
TokenFee {
1368+
token_denom: "atom".to_string(),
1369+
ratio: Ratio {
1370+
nominator: 1,
1371+
denominator: 5,
1372+
},
1373+
},
1374+
]),
1375+
fee_receiver: None,
13641376
};
13651377
// unauthorized case
13661378
let unauthorized_info = mock_info(&String::from("somebody"), &[]);
@@ -1381,6 +1393,26 @@ mod test {
13811393
assert_eq!(config.default_timeout, 1);
13821394
assert_eq!(config.fee_denom, "hehe".to_string());
13831395
assert_eq!(config.swap_router_contract, "new_router".to_string());
1396+
assert_eq!(
1397+
TOKEN_FEE
1398+
.range(deps.as_ref().storage, None, None, Order::Ascending)
1399+
.count(),
1400+
2usize
1401+
);
1402+
assert_eq!(
1403+
TOKEN_FEE
1404+
.load(deps.as_ref().storage, "orai")
1405+
.unwrap()
1406+
.denominator,
1407+
10
1408+
);
1409+
assert_eq!(
1410+
TOKEN_FEE
1411+
.load(deps.as_ref().storage, "atom")
1412+
.unwrap()
1413+
.denominator,
1414+
5
1415+
)
13841416
}
13851417

13861418
#[test]

0 commit comments

Comments
 (0)