diff --git a/contracts/cw1155-base/src/contract.rs b/contracts/cw1155-base/src/contract.rs index a441ac577..5efc844cc 100644 --- a/contracts/cw1155-base/src/contract.rs +++ b/contracts/cw1155-base/src/contract.rs @@ -1,6 +1,6 @@ use cosmwasm_std::{ - to_binary, Api, Binary, Deps, DepsMut, Env, HumanAddr, MessageInfo, Order, Response, StdResult, - Uint128, KV, + to_binary, Api, Binary, Deps, DepsMut, Env, HumanAddr, MessageInfo, Order, Response, StdError, + StdResult, Uint128, KV, }; use cw_storage_plus::Bound; @@ -83,6 +83,13 @@ pub fn execute( } } +fn checked_add(a: Uint128, b: Uint128) -> StdResult { + a.u128() + .checked_add(b.u128()) + .map(Uint128) + .ok_or_else(|| StdError::underflow(a, b)) // FIXME add Overflow error branch in StdError +} + /// When from is None: mint new coins /// When to is None: burn coins /// When both are None: not token balance is changed, meaningless but valid @@ -107,7 +114,9 @@ fn execute_transfer_inner<'a>( BALANCES.update( deps.storage, (canonical_to.as_slice(), token_id), - |balance: Option| -> StdResult<_> { Ok(balance.unwrap_or_default() + amount) }, + |balance: Option| -> StdResult<_> { + checked_add(balance.unwrap_or_default(), amount) + }, )?; } @@ -1178,6 +1187,83 @@ mod tests { #[test] fn balance_overflow() { - // TODO + let mut deps = mock_dependencies(&[]); + let token1 = "token1".to_owned(); + let minter: HumanAddr = "minter".into(); + let user1: HumanAddr = "user1".into(); + let user2: HumanAddr = "user2".into(); + + let env = { + let mut env = mock_env(); + env.block.height = 1; + env + }; + + let msg = InitMsg { + minter: minter.clone(), + }; + let res = instantiate(deps.as_mut(), env.clone(), mock_info("operator", &[]), msg).unwrap(); + assert_eq!(0, res.messages.len()); + + execute( + deps.as_mut(), + env.clone(), + mock_info(minter.clone(), &[]), + Cw1155HandleMsg::Mint { + to: user1.clone(), + token_id: token1.clone(), + value: u128::MAX.into(), + msg: None, + }, + ) + .unwrap(); + + // overflow + assert!(matches!( + execute( + deps.as_mut(), + env.clone(), + mock_info(minter.clone(), &[]), + Cw1155HandleMsg::Mint { + to: user1.clone(), + token_id: token1.clone(), + value: 1u64.into(), + msg: None, + }, + ), + Err(_) + )); + + assert!(matches!( + execute( + deps.as_mut(), + env.clone(), + mock_info(minter.clone(), &[]), + Cw1155HandleMsg::Mint { + to: user2.clone(), + token_id: token1.clone(), + value: 1u64.into(), + msg: None, + }, + ), + Ok(_) + )); + + // overflow + assert!(matches!( + execute( + deps.as_mut(), + env.clone(), + mock_info(user2.clone(), &[]), + Cw1155HandleMsg::SendFrom { + from: user2.clone(), + to: user1.clone(), + token_id: token1.clone(), + value: 1u64.into(), + msg: None, + }, + ), + Err(_) + )); } }