Skip to content

Commit 9660afa

Browse files
authored
Merge pull request #31 from oraidex/feat/withdraw-stuck-tokens
feat: add withdraws func
2 parents 90511ad + ed60246 commit 9660afa

File tree

4 files changed

+77
-2
lines changed

4 files changed

+77
-2
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ tests/test-data.json
99
.env
1010

1111
.scannerwork/
12-
clippy-report.json
12+
clippy-report.json
13+
.DS_Store

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

+21
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ pub fn execute(
166166
args,
167167
} => ibc_hooks_receive(deps, env, info, func, orai_receiver, args),
168168
ExecuteMsg::RegisterDenom(msg) => register_denom(deps, info, msg),
169+
ExecuteMsg::WithdrawAsset { coin, receiver } => {
170+
execute_withdraw_asset(deps, info, coin, receiver)
171+
}
169172
}
170173
}
171174

@@ -178,6 +181,24 @@ pub fn is_caller_contract(caller: Addr, contract_addr: Addr) -> StdResult<()> {
178181
Ok(())
179182
}
180183

184+
// withdraw stuck coin and transfer back to user
185+
// only owner can execute
186+
fn execute_withdraw_asset(
187+
deps: DepsMut,
188+
info: MessageInfo,
189+
coin: Amount,
190+
receiver: Option<Addr>,
191+
) -> Result<Response, ContractError> {
192+
ADMIN.assert_admin(deps.as_ref(), &info.sender)?;
193+
let receiver = receiver.unwrap_or(info.sender);
194+
195+
let msg = coin.send_amount(receiver.to_string(), None);
196+
197+
Ok(Response::new()
198+
.add_attributes(vec![("action", "withdraw_asset")])
199+
.add_message(msg))
200+
}
201+
181202
pub fn register_denom(
182203
deps: DepsMut,
183204
info: MessageInfo,

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

+4
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ pub enum ExecuteMsg {
105105
args: Binary,
106106
},
107107
RegisterDenom(RegisterDenomMsg),
108+
WithdrawAsset {
109+
coin: Amount,
110+
receiver: Option<Addr>,
111+
},
108112
}
109113

110114
#[cw_serde]

contracts/cw-ics20-latest/src/testing/ibc_tests.rs

+50-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use cosmwasm_std::{
2828

2929
use crate::error::ContractError;
3030
use crate::state::{
31-
get_key_ics20_ibc_denom, increase_channel_balance, reduce_channel_balance, Config,
31+
get_key_ics20_ibc_denom, increase_channel_balance, reduce_channel_balance, Config, ADMIN,
3232
CHANNEL_REVERSE_STATE, CONFIG, RELAYER_FEE, REPLY_ARGS, TOKEN_FEE,
3333
};
3434
use cw20::{Cw20CoinVerified, Cw20ExecuteMsg, Cw20ReceiveMsg};
@@ -2487,3 +2487,52 @@ pub fn test_get_follow_up_msg() {
24872487
);
24882488
// case 4: call universal swap (todo)
24892489
}
2490+
2491+
#[test]
2492+
fn test_withdraw_stuck_asset() {
2493+
let mut deps = mock_dependencies();
2494+
ADMIN
2495+
.set(deps.as_mut(), Some(Addr::unchecked("admin")))
2496+
.unwrap();
2497+
2498+
// case 1: unauthorized
2499+
let err = execute(
2500+
deps.as_mut(),
2501+
mock_env(),
2502+
mock_info("addr000", &[]),
2503+
ExecuteMsg::WithdrawAsset {
2504+
coin: Amount::Native(Coin {
2505+
denom: "orai".to_string(),
2506+
amount: Uint128::new(1000000),
2507+
}),
2508+
receiver: Some(Addr::unchecked("receiver")),
2509+
},
2510+
)
2511+
.unwrap_err();
2512+
assert_eq!(err, ContractError::Admin(AdminError::NotAdmin {}));
2513+
2514+
// case 2: success
2515+
let res = execute(
2516+
deps.as_mut(),
2517+
mock_env(),
2518+
mock_info("admin", &[]),
2519+
ExecuteMsg::WithdrawAsset {
2520+
coin: Amount::Native(Coin {
2521+
denom: "orai".to_string(),
2522+
amount: Uint128::new(1000000),
2523+
}),
2524+
receiver: Some(Addr::unchecked("receiver")),
2525+
},
2526+
)
2527+
.unwrap();
2528+
assert_eq!(
2529+
res.messages,
2530+
vec![SubMsg::new(CosmosMsg::Bank(BankMsg::Send {
2531+
to_address: "receiver".to_string(),
2532+
amount: vec![Coin {
2533+
denom: "orai".to_string(),
2534+
amount: Uint128::new(1000000)
2535+
}]
2536+
}))]
2537+
);
2538+
}

0 commit comments

Comments
 (0)