def setUp(self): self.patcher = ScorePatcher(Converter) self.patcher.start() self.score_address = Address.from_string("cx" + os.urandom(20).hex()) self.score = Converter(create_db(self.score_address)) self.owner = Address.from_string("hx" + os.urandom(20).hex()) self.token = Address.from_string("cx" + os.urandom(20).hex()) registry = Address.from_string("cx" + os.urandom(20).hex()) max_conversion_fee = 1000000 self.initial_connector_token = Address.from_string( "cx" + os.urandom(20).hex()) self.initial_connector_weight = 500000 with patch_property(IconScoreBase, 'msg', Message(self.owner)): self.score.on_install(self.token, registry, max_conversion_fee, self.initial_connector_token, self.initial_connector_weight) FlexibleTokenController.on_install.assert_called_with( self.score, self.token) self.score._token.set(self.token) self.assertEqual(registry, self.score._registry.get()) self.assertEqual(registry, self.score._prev_registry.get()) self.assertEqual(max_conversion_fee, self.score._max_conversion_fee.get()) self.assertEqual( True, self.score._connectors[ self.initial_connector_token].is_set.get()) self.assertEqual( self.initial_connector_weight, self.score._connectors[ self.initial_connector_token].weight.get())
def setUp(self): self.patcher = ScorePatcher(TokenHolder) self.patcher.start() self.score_address = Address.from_string("cx" + "1" * 40) self.token_holder = TokenHolder(create_db(self.score_address)) self.token_owner = Address.from_string("hx" + "2" * 40) with patch_property(IconScoreBase, 'msg', Message(self.token_owner)): self.token_holder.on_install() Owned.on_install.assert_called_with(self.token_holder)
def setUp(self): self.patcher = ScorePatcher(Owned) self.patcher.start() score_address = Address.from_string("cx" + "1" * 40) self.score = Owned(create_db(score_address)) self.sender = Address.from_string("hx" + "2" * 40) with patch_property(IconScoreBase, 'msg', Message(self.sender)): self.score.on_install() self.assertEqual(self.sender, self.score._owner.get()) self.assertEqual(ZERO_SCORE_ADDRESS, self.score._new_owner.get())
def setUp(self): self.patcher = ScorePatcher(IcxToken) self.patcher.start() self.score_address = Address.from_string("cx" + "1" * 40) self.icx_token = IcxToken(create_db(self.score_address)) self.token_owner = Address.from_string("hx" + "2" * 40) with patch_property(IconScoreBase, 'msg', Message(self.token_owner)): self.icx_token.on_install() IRCToken.on_install.assert_called_with(self.icx_token, 'icx_token', 'ICX', 0, 18) TokenHolder.on_install.assert_called_with(self.icx_token)
def setUp(self): self.patcher = ScorePatcher(IcxToken) self.patcher.start() self.score_address = Address.from_string("cx" + "1" * 40) self.flexible_token_address = Address.from_string("cx" + "2" * 40) self.score = FlexibleTokenController(create_db(self.score_address)) self.owner = Address.from_string("hx" + "2" * 40) with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(self.owner)), patch('contracts.utility.flexible_token_controller.require_valid_address') ]) as mocks: self.score.on_install(self.flexible_token_address) TokenHolder.on_install.assert_called_with(self.score) mocks[1].assert_called()
def setUp(self): self.patcher = ScorePatcher(ScoreRegistry) self.patcher.start() self.score_address = Address.from_string("cx" + "1" * 40) self.registry_score = ScoreRegistry(create_db(self.score_address)) self.registry_owner = Address.from_string("hx" + "1" * 40) with patch_property(IconScoreBase, 'msg', Message(self.registry_owner)): self.registry_score.on_install() Owned.on_install.assert_called_with(self.registry_score) # success case: when deploy ScoreRegistry, score registry address should be registered by default self.assertEqual \ (self.score_address, self.registry_score._score_address[self.registry_score.SCORE_REGISTRY.encode()])
def setUp(self): self.patcher = ScorePatcher(Network) self.patcher.start() self.score_address = Address.from_string("cx" + "1" * 40) self.network_score = Network(create_db(self.score_address)) self.network_owner = Address.from_string("hx" + "1" * 40) self.flexible_token_address_list = [ Address.from_string("cx" + str(i) * 40) for i in range(0, 3) ] self.connector_token_list = [ Address.from_string("cx" + str(i) * 40) for i in range(3, 7) ] self.icx_token = Address.from_string("cx" + "7" * 40) with patch_property(IconScoreBase, 'msg', Message(self.network_owner)): self.network_score.on_install() TokenHolder.on_install.assert_called_with(self.network_score)
def setUp(self): self.patcher = ScorePatcher(IRCToken) self.patcher.start() self.score_address = Address.from_string("cx" + "1" * 40) self.irc_token = IRCToken(create_db(self.score_address)) token_name = "test_token" token_symbol = "TST" token_supply = 100 token_decimals = 18 self.token_owner = Address.from_string("hx" + "2" * 40) # failure case: total supply is under 0 with patch_property(IconScoreBase, 'msg', Message(self.token_owner)): invalid_token_supply = -1 self.assertRaises(RevertException, self.irc_token.on_install, token_name, token_symbol, invalid_token_supply, token_decimals) # failure case: decimal is under 0 with patch_property(IconScoreBase, 'msg', Message(self.token_owner)): invalid_token_decimals = -1 self.assertRaises(RevertException, self.irc_token.on_install, token_name, token_symbol, token_supply, invalid_token_decimals) # success case: deploy IRCToken with valid parameters with patch_property(IconScoreBase, 'msg', Message(self.token_owner)): self.irc_token.on_install(token_name, token_symbol, token_supply, token_decimals) self.assertEqual(token_name, self.irc_token._name.get()) self.assertEqual(token_symbol, self.irc_token._symbol.get()) self.assertEqual(token_decimals, self.irc_token._decimals.get()) self.assertEqual(token_supply * 10**token_decimals, self.irc_token._total_supply.get()) self.assertEqual(token_supply * 10**token_decimals, self.irc_token._balances[self.token_owner])
class TestOwned(unittest.TestCase): def setUp(self): self.patcher = ScorePatcher(Owned) self.patcher.start() score_address = Address.from_string("cx" + "1" * 40) self.score = Owned(create_db(score_address)) self.sender = Address.from_string("hx" + "2" * 40) with patch_property(IconScoreBase, 'msg', Message(self.sender)): self.score.on_install() self.assertEqual(self.sender, self.score._owner.get()) self.assertEqual(ZERO_SCORE_ADDRESS, self.score._new_owner.get()) def tearDown(self): self.patcher.stop() def test_getOwner(self): actual_owner = self.score.getOwner() self.assertEqual(self.score._owner.get(), actual_owner) def test_getNewOwner(self): actual_new_owner = self.score.getNewOwner() self.assertEqual(self.score._new_owner.get(), actual_new_owner) def test_transferOwnerShip(self): # failure case: non owner try to transfer ownership. non_owner = Address.from_string("hx" + "3" * 40) new_owner = Address.from_string("hx" + "4" * 40) with patch_property(IconScoreBase, 'msg', Message(non_owner)): self.assertRaises(RevertException, self.score.transferOwnerShip, new_owner) # failure case: set new owner as previous owner with patch_property(IconScoreBase, 'msg', Message(self.sender)): self.assertRaises(RevertException, self.score.transferOwnerShip, self.sender) # success case: transfer ownership to new_owner with patch_property(IconScoreBase, 'msg', Message(self.sender)): self.score.require_owner_only = Mock() self.score.transferOwnerShip(new_owner) self.score.require_owner_only.assert_called() self.assertEqual(self.sender, self.score._owner.get()) self.assertEqual(new_owner, self.score._new_owner.get()) def test_acceptOwnership(self): # ### initial setting for test start new_owner = Address.from_string("hx" + "4" * 40) with patch_property(IconScoreBase, 'msg', Message(self.sender)): self.score.transferOwnerShip(new_owner) # ### initial setting for test end # failure case: current owner try to accept ownership ( only new owner can accept ownership) with patch_property(IconScoreBase, 'msg', Message(self.sender)): self.assertRaises(RevertException, self.score.acceptOwnerShip) # failure case: another address try to accept ownership # ( only new owner can accept ownership) another_owner = Address.from_string("hx" + "5" * 40) with patch_property(IconScoreBase, 'msg', Message(another_owner)): self.assertRaises(RevertException, self.score.acceptOwnerShip) # success case: new owner accept ownership with patch_property(IconScoreBase, 'msg', Message(new_owner)): self.score.acceptOwnerShip() self.assertEqual(new_owner, self.score._owner.get()) self.assertEqual(ZERO_SCORE_ADDRESS, self.score._new_owner.get()) self.score.OwnerUpdate.assert_called_with(self.sender, new_owner)
class TestTokenHolder(unittest.TestCase): def setUp(self): self.patcher = ScorePatcher(TokenHolder) self.patcher.start() self.score_address = Address.from_string("cx" + "1" * 40) self.token_holder = TokenHolder(create_db(self.score_address)) self.token_owner = Address.from_string("hx" + "2" * 40) with patch_property(IconScoreBase, 'msg', Message(self.token_owner)): self.token_holder.on_install() Owned.on_install.assert_called_with(self.token_holder) def tearDown(self): self.patcher.stop() def test_withdrawTokens(self): token_address = Address.from_string("cx" + "2" * 40) token_receiver = Address.from_string("hx" + "3" * 40) irc_token_score_interface = \ self.token_holder.create_interface_score(token_address, ProxyScore(ABCIRCToken)) irc_token_score_interface.transfer = Mock() with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(self.token_owner)), patch.object(TokenHolder, 'create_interface_score', return_value=irc_token_score_interface) ]): amount = 10 # success case: withdraw 10 token self.token_holder.withdrawTokens(token_address, token_receiver, amount) self.token_holder.create_interface_score.assert_called_with( token_address, ProxyScore(ABCIRCToken)) irc_token_score_interface.transfer.assert_called_with( token_receiver, amount) self.token_holder.create_interface_score.reset_mock() irc_token_score_interface.transfer.reset_mock() # failure case: amount is under 0 invalid_amount = -1 self.assertRaises(RevertException, self.token_holder.withdrawTokens, token_address, token_receiver, invalid_amount) self.token_holder.create_interface_score.assert_not_called() irc_token_score_interface.transfer.assert_not_called() self.token_holder.create_interface_score.reset_mock() irc_token_score_interface.transfer.reset_mock() # failure case: 'to' address is this self.assertRaises(RevertException, self.token_holder.withdrawTokens, token_address, self.score_address, amount) self.token_holder.create_interface_score.assert_not_called() irc_token_score_interface.transfer.assert_not_called() self.token_holder.create_interface_score.reset_mock() irc_token_score_interface.transfer.reset_mock() # failure case: 'to' address is invalid address self.assertRaises(RevertException, self.token_holder.withdrawTokens, token_address, ZERO_SCORE_ADDRESS, amount) self.token_holder.create_interface_score.assert_not_called() irc_token_score_interface.transfer.assert_not_called() self.token_holder.create_interface_score.reset_mock() irc_token_score_interface.transfer.reset_mock()
class TestIRCToken(unittest.TestCase): def setUp(self): self.patcher = ScorePatcher(IRCToken) self.patcher.start() self.score_address = Address.from_string("cx" + "1" * 40) self.irc_token = IRCToken(create_db(self.score_address)) token_name = "test_token" token_symbol = "TST" token_supply = 100 token_decimals = 18 self.token_owner = Address.from_string("hx" + "2" * 40) # failure case: total supply is under 0 with patch_property(IconScoreBase, 'msg', Message(self.token_owner)): invalid_token_supply = -1 self.assertRaises(RevertException, self.irc_token.on_install, token_name, token_symbol, invalid_token_supply, token_decimals) # failure case: decimal is under 0 with patch_property(IconScoreBase, 'msg', Message(self.token_owner)): invalid_token_decimals = -1 self.assertRaises(RevertException, self.irc_token.on_install, token_name, token_symbol, token_supply, invalid_token_decimals) # success case: deploy IRCToken with valid parameters with patch_property(IconScoreBase, 'msg', Message(self.token_owner)): self.irc_token.on_install(token_name, token_symbol, token_supply, token_decimals) self.assertEqual(token_name, self.irc_token._name.get()) self.assertEqual(token_symbol, self.irc_token._symbol.get()) self.assertEqual(token_decimals, self.irc_token._decimals.get()) self.assertEqual(token_supply * 10**token_decimals, self.irc_token._total_supply.get()) self.assertEqual(token_supply * 10**token_decimals, self.irc_token._balances[self.token_owner]) def tearDown(self): self.patcher.stop() def test_external_transfer(self): token_receiver = Address.from_string("hx" + "3" * 40) with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(self.token_owner)), patch.object(IRCToken, '_transfer') ]): self.irc_token.transfer(token_receiver, 10) IRCToken._transfer.assert_called_with(self.token_owner, token_receiver, 10, b'None') self.irc_token.transfer(token_receiver, 10, b'test') IRCToken._transfer.assert_called_with(self.token_owner, token_receiver, 10, b'test') def test_transfer(self): eoa_token_receiver = Address.from_string("hx" + "3" * 40) score_token_receiver = Address.from_string("cx" + "3" * 40) with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(self.token_owner)), patch.object(TokenFallbackInterface, 'tokenFallback') ]): # failure case: value is under 0 invalid_value = -1 self.assertRaises(RevertException, self.irc_token._transfer, self.token_owner, eoa_token_receiver, invalid_value, b'None') # failure case: value is higher than senders' total balance value = self.irc_token._balances[self.token_owner] + 1 self.assertRaises(RevertException, self.irc_token._transfer, self.token_owner, eoa_token_receiver, value, b'None') # success cass: transfer 10 token to token_receiver (EOA) with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(self.token_owner)), patch.object(TokenFallbackInterface, 'tokenFallback') ]): value = 10 before_owner_balance = self.irc_token._balances[self.token_owner] before_eoa_receiver_balance = self.irc_token._balances[ eoa_token_receiver] self.irc_token._transfer(self.token_owner, eoa_token_receiver, value, b'None') self.assertEqual(before_owner_balance - value, self.irc_token._balances[self.token_owner]) self.assertEqual(before_eoa_receiver_balance + value, self.irc_token._balances[eoa_token_receiver]) TokenFallbackInterface.tokenFallback.assert_not_called() self.irc_token.Transfer.assert_called_with(self.token_owner, eoa_token_receiver, value, b'None') # success cass: transfer 10 token to token_receiver (SCORE) with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(self.token_owner)), patch.object(TokenFallbackInterface, 'tokenFallback') ]): value = 10 before_owner_balance = self.irc_token._balances[self.token_owner] before_score_receiver_balance = self.irc_token._balances[ score_token_receiver] self.irc_token._transfer(self.token_owner, score_token_receiver, value, b'None') self.assertEqual(before_owner_balance - value, self.irc_token._balances[self.token_owner]) self.assertEqual(before_score_receiver_balance + value, self.irc_token._balances[score_token_receiver]) TokenFallbackInterface.tokenFallback.assert_called_with( self.token_owner, value, b'None') self.irc_token.Transfer.assert_called_with(self.token_owner, score_token_receiver, value, b'None')
class TestScoreRegistry(unittest.TestCase): def setUp(self): self.patcher = ScorePatcher(ScoreRegistry) self.patcher.start() self.score_address = Address.from_string("cx" + "1" * 40) self.registry_score = ScoreRegistry(create_db(self.score_address)) self.registry_owner = Address.from_string("hx" + "1" * 40) with patch_property(IconScoreBase, 'msg', Message(self.registry_owner)): self.registry_score.on_install() Owned.on_install.assert_called_with(self.registry_score) # success case: when deploy ScoreRegistry, score registry address should be registered by default self.assertEqual \ (self.score_address, self.registry_score._score_address[self.registry_score.SCORE_REGISTRY.encode()]) def tearDown(self): self.patcher.stop() def test_getAddress(self): # success case: search the registered score address registered_score_name = self.registry_score.SCORE_REGISTRY actual_registered_address = self.registry_score.getAddress( registered_score_name) self.assertEqual(self.score_address, actual_registered_address) # success case: search the score address which has not been registered (should return zero score address) unregistered_score_name = self.registry_score.NETWORK actual_registered_address = self.registry_score.getAddress( unregistered_score_name) self.assertEqual(ZERO_SCORE_ADDRESS, actual_registered_address) def test_registerAddress(self): eoa_address = Address.from_string("hx" + "3" * 40) network_id = self.registry_score.NETWORK network_address = Address.from_string("cx" + "2" * 40) with patch_property(IconScoreBase, 'msg', Message(self.registry_owner)): # failure case: invalid register score address self.assertRaises(RevertException, self.registry_score.registerAddress, network_id, ZERO_SCORE_ADDRESS) # failure case: try to register eoa address self.assertRaises(RevertException, self.registry_score.registerAddress, network_id, eoa_address) # failure case: score name is not in the SCORE_KEYS non_listed_id = "NON_LISTED_SCORE_ID" self.assertRaises(RevertException, self.registry_score.registerAddress, non_listed_id, network_address) # success case: register network self.registry_score.registerAddress(network_id, network_address) self.assertEqual(network_address, self.registry_score._score_address[network_id]) self.registry_score.AddressUpdate.assert_called_with( network_id, network_address) def test_unregisterAddress(self): network_id = self.registry_score.NETWORK network_address = Address.from_string("cx" + "2" * 40) # register network self.registry_score._score_address[network_id] = network_address with patch_property(IconScoreBase, 'msg', Message(self.registry_owner)): # failure case: try to unregister not recorded score address non_registered_id = 'abc' self.assertRaises(RevertException, self.registry_score.unregisterAddress, non_registered_id) # success case: unregister score address which has been registered self.registry_score.unregisterAddress(network_id) self.assertEqual(None, self.registry_score._score_address[network_id]) self.registry_score.AddressUpdate.assert_called_with( network_id, ZERO_SCORE_ADDRESS)
class TestFlexibleTokenController(unittest.TestCase): def setUp(self): self.patcher = ScorePatcher(IcxToken) self.patcher.start() self.score_address = Address.from_string("cx" + "1" * 40) self.flexible_token_address = Address.from_string("cx" + "2" * 40) self.score = FlexibleTokenController(create_db(self.score_address)) self.owner = Address.from_string("hx" + "2" * 40) with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(self.owner)), patch('contracts.utility.flexible_token_controller.require_valid_address') ]) as mocks: self.score.on_install(self.flexible_token_address) TokenHolder.on_install.assert_called_with(self.score) mocks[1].assert_called() def tearDown(self): self.patcher.stop() def test_transferTokenOwnership(self): new_owner = Address.from_string("hx" + "3" * 40) with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(self.owner)), patch.object(InternalCall, 'other_external_call'), ]): self.score.transferTokenOwnership(new_owner) self.score.require_owner_only.assert_called() assert_inter_call( self, self.score.address, self.score._token.get(), 'transferOwnerShip', [new_owner]) def test_acceptTokenOwnership(self): with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(self.owner)), patch.object(InternalCall, 'other_external_call'), ]): self.score.acceptTokenOwnership() self.score.require_owner_only.assert_called() assert_inter_call( self, self.score.address, self.score._token.get(), 'acceptOwnerShip', [] ) def test_disableTokenTransfers(self): disable = True with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(self.owner)), patch.object(InternalCall, 'other_external_call'), ]): self.score.disableTokenTransfers(disable) self.score.require_owner_only.assert_called() assert_inter_call( self, self.score.address, self.score._token.get(), 'disableTransfer', [disable] ) def test_withdrawFromToken(self): token = Address.from_string("cx" + "3" * 40) to = Address.from_string("hx" + "3" * 40) amount = 100 with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(self.owner)), patch.object(InternalCall, 'other_external_call'), ]): self.score.withdrawFromToken(token, to, amount) self.score.require_owner_only.assert_called() assert_inter_call( self, self.score.address, self.score._token.get(), 'withdrawTokens', [token, to, amount] ) def test_isActive(self): with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(self.owner)), patch.object(InternalCall, 'other_external_call'), ]) as mocks: mocks[1].return_value = self.score.address is_active = self.score.isActive() self.assertEqual(True, is_active) with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(self.owner)), patch.object(InternalCall, 'other_external_call'), ]) as mocks: mocks[1].return_value = ZERO_SCORE_ADDRESS is_active = self.score.isActive() self.assertEqual(False, is_active) def test_getToken(self): with patch.object(IconScoreBase, 'msg', Message(self.owner)): token = self.score.getToken() self.assertEqual(self.score._token.get(), token)
class TestIcxToken(unittest.TestCase): def setUp(self): self.patcher = ScorePatcher(IcxToken) self.patcher.start() self.score_address = Address.from_string("cx" + "1" * 40) self.icx_token = IcxToken(create_db(self.score_address)) self.token_owner = Address.from_string("hx" + "2" * 40) with patch_property(IconScoreBase, 'msg', Message(self.token_owner)): self.icx_token.on_install() IRCToken.on_install.assert_called_with(self.icx_token, 'icx_token', 'ICX', 0, 18) TokenHolder.on_install.assert_called_with(self.icx_token) def tearDown(self): self.patcher.stop() def test_deposit(self): value = 10 with patch_property(IconScoreBase, 'msg', Message(self.token_owner, value=value)): before_balance = self.icx_token._balances[self.token_owner] before_total_supply = self.icx_token._total_supply.get() self.icx_token.deposit() self.assertEqual( value, self.icx_token._balances[self.token_owner] - before_balance) self.assertEqual( value, self.icx_token._total_supply.get() - before_total_supply) self.icx_token.Issuance.assert_called_with(value) self.icx_token.Transfer.assert_called_with(self.icx_token.address, self.token_owner, value, b'None') def test_withdrawTo(self): to = Address.from_string("hx" + "3" * 40) self.icx_token._balances[self.token_owner] = 10 self.icx_token._total_supply.set(10) with patch_property(IconScoreBase, 'msg', Message(self.token_owner)): # failure case: amount is under 0 self.assertRaises(RevertException, self.icx_token.withdrawTo, -1, to) # failure case: amount is higher than token holders' total balance self.assertRaises(RevertException, self.icx_token.withdrawTo, 20, to) # success case: withdraw 10 token to 'to' self.icx_token.withdrawTo(10, to) self.icx_token.icx.transfer.assert_called_with(to, 10) self.assertEqual(0, self.icx_token._balances[self.token_owner]) self.assertEqual(0, self.icx_token._total_supply.get()) self.icx_token.Destruction.assert_called_with(10) def test_transfer(self): # failure case: transfer token to this score (should raise error) with patch_property(IconScoreBase, 'msg', Message(self.token_owner)): self.assertRaises(RevertException, self.icx_token.transfer, self.score_address, 10) IRCToken.transfer.assert_not_called() # success case: send 10 token to other token_receiver = Address.from_string("hx" + "4" * 40) self.icx_token.transfer(token_receiver, 10) IRCToken.transfer.assert_called_with(self.icx_token, token_receiver, 10, None)
class TestConverter(unittest.TestCase): def setUp(self): self.patcher = ScorePatcher(Converter) self.patcher.start() self.score_address = Address.from_string("cx" + os.urandom(20).hex()) self.score = Converter(create_db(self.score_address)) self.owner = Address.from_string("hx" + os.urandom(20).hex()) self.token = Address.from_string("cx" + os.urandom(20).hex()) registry = Address.from_string("cx" + os.urandom(20).hex()) max_conversion_fee = 1000000 self.initial_connector_token = Address.from_string( "cx" + os.urandom(20).hex()) self.initial_connector_weight = 500000 with patch_property(IconScoreBase, 'msg', Message(self.owner)): self.score.on_install(self.token, registry, max_conversion_fee, self.initial_connector_token, self.initial_connector_weight) FlexibleTokenController.on_install.assert_called_with( self.score, self.token) self.score._token.set(self.token) self.assertEqual(registry, self.score._registry.get()) self.assertEqual(registry, self.score._prev_registry.get()) self.assertEqual(max_conversion_fee, self.score._max_conversion_fee.get()) self.assertEqual( True, self.score._connectors[ self.initial_connector_token].is_set.get()) self.assertEqual( self.initial_connector_weight, self.score._connectors[ self.initial_connector_token].weight.get()) def tearDown(self): self.patcher.stop() def test_tokenFallback_deposit(self): # Mocks parent functions self.score.getOwner.return_value = self.owner self.score._is_active.return_value = False network_address = Address.from_string("cx" + os.urandom(20).hex()) # success case token = self.initial_connector_token sender = self.owner value = 100 with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(token)), patch.object(InternalCall, 'other_external_call', return_value=network_address) ]): self.score.tokenFallback(sender, value, b'None') # the value is less than zero token = self.initial_connector_token sender = self.owner value = -100 with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(token)), patch.object(InternalCall, 'other_external_call', return_value=network_address) ]): self.assertRaises(RevertException, self.score.tokenFallback, sender, value, b'None') # the sender is not owner token = self.initial_connector_token sender = Address.from_string("hx" + os.urandom(20).hex()) value = 100 with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(token)), patch.object(InternalCall, 'other_external_call', return_value=network_address) ]): self.assertRaises(RevertException, self.score.tokenFallback, sender, value, b'None') # the token is not connector token token = Address.from_string("cx" + os.urandom(20).hex()) sender = self.owner value = 100 with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(token)), patch.object(InternalCall, 'other_external_call', return_value=network_address) ]): self.assertRaises(RevertException, self.score.tokenFallback, sender, value, b'None') # the converter is active self.score._is_active.return_value = True token = self.initial_connector_token sender = self.owner value = 100 with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(token)), patch.object(InternalCall, 'other_external_call', return_value=network_address) ]): self.assertRaises(RevertException, self.score.tokenFallback, sender, value, b'None') def test_tokenFallback_convert_called_wrong_params(self): # Mocks parent functions self.score.getOwner.return_value = self.owner self.score._is_active.return_value = True self.score._convert = Mock() network_address = Address.from_string("cx" + os.urandom(20).hex()) to_token = Address.from_string("cx" + os.urandom(20).hex()) # missing param `minReturn` data = { 'toToken': str(to_token), } token = self.initial_connector_token value = 100 with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(token)), patch.object(InternalCall, 'other_external_call', return_value=network_address) ]): self.assertRaises(RevertException, self.score.tokenFallback, network_address, value, json_dumps(data).encode()) self.score._convert.assert_not_called() def test_tokenFallback_buy_called(self): # Mocks parent functions self.score.getOwner.return_value = self.owner self.score._is_active.return_value = True self.score._buy = Mock() network_address = Address.from_string("cx" + os.urandom(20).hex()) to_token = self.token min_return = 10 data = {'toToken': str(to_token), 'minReturn': min_return} # success case token = self.initial_connector_token value = 100 with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(token)), patch.object(InternalCall, 'other_external_call', return_value=network_address) ]): self.score.tokenFallback(network_address, value, json_dumps(data).encode()) assert_inter_call(self, self.score.address, self.score._registry.get(), 'getAddress', [ScoreRegistry.NETWORK]) self.score._buy.assert_called_with(network_address, token, value, min_return) def test_tokenFallback_sell_called(self): # Mocks parent functions self.score.getOwner.return_value = self.owner self.score._is_active.return_value = True self.score._sell = Mock() network_address = Address.from_string("cx" + os.urandom(20).hex()) to_token = self.initial_connector_token min_return = 10 data = {'toToken': str(to_token), 'minReturn': min_return} # success case token = self.token value = 100 with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(token)), patch.object(InternalCall, 'other_external_call', return_value=network_address) ]): self.score.tokenFallback(network_address, value, json_dumps(data).encode()) assert_inter_call(self, self.score.address, self.score._registry.get(), 'getAddress', [ScoreRegistry.NETWORK]) self.score._sell.assert_called_with(network_address, to_token, value, min_return) def test_tokenFallback_cross_convert_called(self): # Mocks parent functions self.score.getOwner.return_value = self.owner self.score._is_active.return_value = True self.score._convert_cross_connector = Mock() network_address = Address.from_string("cx" + os.urandom(20).hex()) to_token = Address.from_string("cx" + os.urandom(20).hex()) to_token_weight = 500000 self.score.addConnector(to_token, to_token_weight, False) min_return = 10 data = {'toToken': str(to_token), 'minReturn': min_return} # success case token = self.initial_connector_token value = 100 with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(token)), patch.object(InternalCall, 'other_external_call', return_value=network_address) ]): self.score.tokenFallback(network_address, value, json_dumps(data).encode()) assert_inter_call(self, self.score.address, self.score._registry.get(), 'getAddress', [ScoreRegistry.NETWORK]) self.score._convert_cross_connector.assert_called_with( network_address, token, to_token, value, min_return) def test_buy(self): connector_token2 = Address.from_string("cx" + os.urandom(20).hex()) connector_token2_weight = 500000 self.score.addConnector(connector_token2, connector_token2_weight, False) return_amount = 100 return_fee = 1 connector_balance = 100 trader = Address.from_string("cx" + os.urandom(20).hex()) amount = 100 min_return = 100 purchase_return = {'amount': return_amount, 'fee': return_fee} self.score.get_purchase_return = Mock(return_value=purchase_return) self.score.getConnectorBalance = Mock(return_value=connector_balance) inter_call_return = Mock() with patch.object(InternalCall, 'other_external_call', return_value=inter_call_return): result = self.score._buy(trader, connector_token2, amount, min_return) assert_inter_call(self, self.score.address, self.score._token.get(), 'issue', [trader, return_amount]) self.score.Conversion.assert_called_with(connector_token2, self.score._token.get(), trader, amount, return_amount, return_fee) self.score.PriceDataUpdate.assert_called_with( connector_token2, inter_call_return, connector_balance, connector_token2_weight) self.assertEqual(return_amount, result) def test_sell(self): connector_token2 = Address.from_string("cx" + os.urandom(20).hex()) connector_token2_weight = 500000 self.score.addConnector(connector_token2, connector_token2_weight, False) return_amount = 100 return_fee = 1 connector_balance = 1000 trader = Address.from_string("cx" + os.urandom(20).hex()) amount = 100 min_return = 100 sale_return = {'amount': return_amount, 'fee': return_fee} self.score.get_sale_return = Mock(return_value=sale_return) self.score.getConnectorBalance = Mock(return_value=connector_balance) inter_call_return = Mock() with patch.object(InternalCall, 'other_external_call', return_value=inter_call_return): result = self.score._sell(trader, connector_token2, amount, min_return) assert_inter_call(self, self.score.address, self.score._token.get(), 'destroy', [self.score.address, return_amount]) self.score.Conversion.assert_called_with(self.score._token.get(), connector_token2, trader, amount, return_amount, return_fee) self.score.PriceDataUpdate.assert_called_with( connector_token2, inter_call_return, connector_balance, connector_token2_weight) self.assertEqual(return_amount, result) def test_convert_cross_connector(self): connector_token2 = Address.from_string("cx" + os.urandom(20).hex()) connector_token2_weight = 500000 self.score.addConnector(connector_token2, connector_token2_weight, False) return_amount = 100 return_fee = 1 connector_balance = 1000 trader = Address.from_string("cx" + os.urandom(20).hex()) amount = 100 min_return = 100 convert_return = {'amount': return_amount, 'fee': return_fee} self.score.get_cross_connector_return = Mock( return_value=convert_return) self.score.getConnectorBalance = Mock(return_value=connector_balance) inter_call_return = Mock() with patch.object(InternalCall, 'other_external_call', return_value=inter_call_return): self.score._convert_cross_connector(trader, self.initial_connector_token, connector_token2, amount, min_return) assert_inter_call(self, self.score.address, connector_token2, 'transfer', [trader, return_amount, TRANSFER_DATA]) self.score.Conversion.assert_called_with( self.initial_connector_token, connector_token2, trader, amount, return_amount, return_fee) first_price_update_event = self.score.PriceDataUpdate.call_args_list[ 0] self.assertEqual(first_price_update_event[0][0], self.initial_connector_token) self.assertEqual(first_price_update_event[0][1], inter_call_return) self.assertEqual(first_price_update_event[0][2], connector_balance) self.assertEqual(first_price_update_event[0][3], self.initial_connector_weight) second_price_update_event = self.score.PriceDataUpdate.call_args_list[ 1] self.assertEqual(second_price_update_event[0][0], connector_token2) self.assertEqual(second_price_update_event[0][1], inter_call_return) self.assertEqual(second_price_update_event[0][2], connector_balance) self.assertEqual(second_price_update_event[0][3], connector_token2_weight) def test_addConnector(self): self.score.require_owner_only.reset_mock() connector_token = Address.from_string("cx" + os.urandom(20).hex()) connector_weight = 500000 with patch_property(IconScoreBase, 'msg', Message(self.owner)): self.score.addConnector(connector_token, connector_weight, False) self.score.require_owner_only.assert_called() self.assertEqual( connector_weight, self.score._connectors[connector_token].weight.get()) self.assertEqual( False, self.score._connectors[connector_token]. is_virtual_balance_enabled.get()) self.assertEqual( True, self.score._connectors[connector_token].is_set.get()) def test_updateConnector(self): self.score.require_owner_only.reset_mock() connector_token = self.initial_connector_token connector_weight = 100000 with patch_property(IconScoreBase, 'msg', Message(self.owner)): self.score.updateConnector(connector_token, connector_weight, True, 10000) self.score.require_owner_only.assert_called() self.assertEqual( connector_weight, self.score._connectors[connector_token].weight.get()) self.assertEqual( True, self.score._connectors[connector_token]. is_virtual_balance_enabled.get()) self.assertEqual( True, self.score._connectors[connector_token].is_set.get()) def test_updateConnector_wrong_max_weight(self): self.score.require_owner_only.reset_mock() connector_token = self.initial_connector_token connector_weight = 1000001 self.assertRaises(RevertException, self.score.updateConnector, connector_token, connector_weight, True, 10000) def test_disableConnectorPurchases(self): self.score.require_owner_or_manager_only.reset_mock() self.score._conversions_enabled.set(True) with patch_property(IconScoreBase, 'msg', Message(self.owner)): self.score.disableConnectorPurchases(self.initial_connector_token, True) self.score.require_owner_only.assert_called() connector_token = self.score._connectors[ self.initial_connector_token] self.assertEqual(False, connector_token.is_purchase_enabled.get()) self.score.disableConnectorPurchases(self.initial_connector_token, False) self.assertEqual(True, connector_token.is_purchase_enabled.get()) def test_updateRegistry(self): self.score._allow_registry_update.set(True) old_registry = self.score._registry.get() new_registry = Address.from_string("cx" + os.urandom(20).hex()) with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(self.owner)), patch.object(InternalCall, 'other_external_call', return_value=new_registry) ]): self.score.updateRegistry() assert_inter_call(self, self.score.address, old_registry, 'getAddress', [ScoreRegistry.SCORE_REGISTRY]) self.assertEqual(old_registry, self.score._prev_registry.get()) self.assertEqual(new_registry, self.score._registry.get()) def test_restoreRegistry(self): self.score.require_owner_or_manager_only.reset_mock() prev_registry = self.score._prev_registry.get() with patch_property(IconScoreBase, 'msg', Message(self.owner)): self.score.restoreRegistry() self.score.require_owner_or_manager_only.assert_called() self.assertEqual(prev_registry, self.score._prev_registry.get()) self.assertEqual(prev_registry, self.score._registry.get()) def test_disableRegistryUpdate(self): self.score.require_owner_or_manager_only.reset_mock() with patch_property(IconScoreBase, 'msg', Message(self.owner)): self.score.disableRegistryUpdate(True) self.score.require_owner_or_manager_only.assert_called() self.assertEqual(False, self.score._allow_registry_update.get()) self.score.disableRegistryUpdate(False) self.assertEqual(True, self.score._allow_registry_update.get()) def test_disableConversions(self): self.score.require_owner_or_manager_only.reset_mock() self.score._conversions_enabled.set(True) with patch_property(IconScoreBase, 'msg', Message(self.owner)): self.score.disableConversions(True) self.score.require_owner_or_manager_only.assert_called() self.score.ConversionsEnable.assert_called_with(False) self.assertEqual(False, self.score._conversions_enabled.get()) self.score.disableConversions(False) self.assertEqual(True, self.score._conversions_enabled.get()) def test_setConversionFee(self): self.score.require_owner_or_manager_only.reset_mock() old_conversion_fee = self.score._conversion_fee.get() conversion_fee = 10000 with patch_property(IconScoreBase, 'msg', Message(self.owner)): self.score.setConversionFee(conversion_fee) self.score.require_owner_or_manager_only.assert_called() self.score.ConversionFeeUpdate.assert_called_with( old_conversion_fee, conversion_fee) self.assertEqual(self.score._conversion_fee.get(), conversion_fee) def test_withdrawTokens(self): to = Address.from_string("hx" + os.urandom(20).hex()) amount = 100 self.score._is_active.return_value = True self.score._connectors[self.initial_connector_token].is_set.set(False) with patch_property(IconScoreBase, 'msg', Message(self.owner)): self.score.withdrawTokens(self.initial_connector_token, to, amount) self.score._is_active.assert_called() FlexibleTokenController.withdrawTokens.assert_called_with( self.initial_connector_token, to, amount) self.score._is_active.reset_mock() self.score._is_active.return_value = False self.score._connectors[self.initial_connector_token].is_set.set(True) with patch_property(IconScoreBase, 'msg', Message(self.owner)): self.score.withdrawTokens(self.initial_connector_token, to, amount) self.score._is_active.assert_called() FlexibleTokenController.withdrawTokens.assert_called_with( self.initial_connector_token, to, amount) self.score._is_active.reset_mock() self.score._is_active.return_value = False self.score._connectors[self.initial_connector_token].is_set.set(False) with patch_property(IconScoreBase, 'msg', Message(self.owner)): self.score.withdrawTokens(self.initial_connector_token, to, amount) self.score._is_active.assert_called() FlexibleTokenController.withdrawTokens.assert_called_with( self.initial_connector_token, to, amount) def test_withdrawTokens_failure(self): to = Address.from_string("hx" + os.urandom(20).hex()) amount = 100 self.score._is_active.return_value = True self.score._connectors[self.initial_connector_token].is_set.set(True) with patch_property(IconScoreBase, 'msg', Message(self.owner)): self.assertRaises(RevertException, self.score.withdrawTokens, self.initial_connector_token, to, amount) self.score._is_active.assert_called() def test_getConnectorTokenCount(self): size_by_db = len(self.score._connector_tokens) self.assertEqual(size_by_db, self.score.getConnectorTokenCount()) def test_getConversionFee(self): fee_by_db = self.score._conversion_fee.get() self.assertEqual(fee_by_db, self.score.getConversionFee()) def test_getConnector(self): result_dict = self.score.getConnector(self.initial_connector_token) self.assertIn('virtualBalance', result_dict) self.assertIn('weight', result_dict) self.assertIn('isVirtualBalanceEnabled', result_dict) self.assertIn('isPurchaseEnabled', result_dict) self.assertIn('isSet', result_dict) result_dict = self.score.getConnector(ZERO_SCORE_ADDRESS) self.assertNotIn('virtualBalance', result_dict) self.assertNotIn('weight', result_dict) self.assertNotIn('isVirtualBalanceEnabled', result_dict) self.assertNotIn('isPurchaseEnabled', result_dict) self.assertNotIn('isSet', result_dict) def test_getConnectorBalance(self): balance = 100 with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(self.owner)), patch.object(InternalCall, 'other_external_call', return_value=balance) ]): result_balance = self.score.getConnectorBalance( self.initial_connector_token) assert_inter_call(self, self.score.address, self.initial_connector_token, 'balanceOf', [self.score.address]) self.assertEqual(result_balance, balance) def test_getReturn(self): amount = 1000 self.score.get_purchase_return = Mock() self.score.get_sale_return = Mock() self.score.get_cross_connector_return = Mock() from_token = Address.from_string("cx" + os.urandom(20).hex()) to_token = Address.from_string("cx" + os.urandom(20).hex()) with patch.object(IconScoreBase, 'msg', Message(self.owner)): self.score.getReturn(from_token, to_token, amount) self.score.get_cross_connector_return.assert_called_with( from_token, to_token, amount) from_token = self.token to_token = Address.from_string("cx" + os.urandom(20).hex()) with patch.object(IconScoreBase, 'msg', Message(self.owner)): self.score.getReturn(from_token, to_token, amount) self.score.get_sale_return.assert_called_with(to_token, amount) from_token = Address.from_string("cx" + os.urandom(20).hex()) to_token = self.token with patch.object(IconScoreBase, 'msg', Message(self.owner)): self.score.getReturn(from_token, to_token, amount) self.score.get_purchase_return.assert_called_with( from_token, amount) def test_getPurchaseReturn(self): amount = 1000 self.score.getConnectorBalance = Mock(return_value=10000) with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(self.owner)), patch.object(InternalCall, 'other_external_call', return_value=10000), patch.object(FixedMapFormula, 'calculate_purchase_return', return_value=1000) ]): result = self.score.get_purchase_return( self.initial_connector_token, amount) self.assertEqual(1000, result['amount']) self.assertEqual(0, result['fee']) # sets the fee to 1% self.score._max_conversion_fee.set(1000000) self.score._conversion_fee.set(10000) with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(self.owner)), patch.object(InternalCall, 'other_external_call', return_value=10000), patch.object(FixedMapFormula, 'calculate_purchase_return', return_value=1000) ]): result = self.score.get_purchase_return( self.initial_connector_token, amount) self.assertEqual(990, result['amount']) self.assertEqual(10, result['fee']) def test_getSaleReturn(self): amount = 1000 self.score.getConnectorBalance = Mock(return_value=10000) with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(self.owner)), patch.object(InternalCall, 'other_external_call', return_value=10000), patch.object(FixedMapFormula, 'calculate_sale_return', return_value=1000) ]): result = self.score.get_sale_return(self.initial_connector_token, amount) self.assertEqual(1000, result['amount']) self.assertEqual(0, result['fee']) # sets the fee to 1% self.score._max_conversion_fee.set(1000000) self.score._conversion_fee.set(10000) with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(self.owner)), patch.object(InternalCall, 'other_external_call', return_value=10000), patch.object(FixedMapFormula, 'calculate_sale_return', return_value=1000) ]): result = self.score.get_sale_return(self.initial_connector_token, amount) self.assertEqual(990, result['amount']) self.assertEqual(10, result['fee']) def test_getCrossConnectorReturn(self): connector_token2 = Address.from_string("cx" + os.urandom(20).hex()) connector_token2_weight = 500000 self.score.addConnector(connector_token2, connector_token2_weight, False) amount = 1000 self.score.getConnectorBalance = Mock(return_value=10000) with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(self.owner)), patch.object(FixedMapFormula, 'calculate_cross_connector_return', return_value=1000) ]): result = self.score.get_cross_connector_return( self.initial_connector_token, connector_token2, amount) self.assertEqual(1000, result['amount']) self.assertEqual(0, result['fee']) # sets the fee to 1% self.score._max_conversion_fee.set(1000000) self.score._conversion_fee.set(10000) with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(self.owner)), patch.object(FixedMapFormula, 'calculate_cross_connector_return', return_value=1000) ]): result = self.score.get_cross_connector_return( self.initial_connector_token, connector_token2, amount) self.assertEqual(980, result['amount']) self.assertEqual(20, result['fee'])
class TestNetwork(unittest.TestCase): def setUp(self): self.patcher = ScorePatcher(Network) self.patcher.start() self.score_address = Address.from_string("cx" + "1" * 40) self.network_score = Network(create_db(self.score_address)) self.network_owner = Address.from_string("hx" + "1" * 40) self.flexible_token_address_list = [ Address.from_string("cx" + str(i) * 40) for i in range(0, 3) ] self.connector_token_list = [ Address.from_string("cx" + str(i) * 40) for i in range(3, 7) ] self.icx_token = Address.from_string("cx" + "7" * 40) with patch_property(IconScoreBase, 'msg', Message(self.network_owner)): self.network_score.on_install() TokenHolder.on_install.assert_called_with(self.network_score) def tearDown(self): self.patcher.stop() def test_check_valid_path(self): # success case: input the valid path path = [ self.connector_token_list[0], self.flexible_token_address_list[0], self.connector_token_list[1] ] self.network_score._require_valid_path(path) # failure case: input path whose length under 3 invalid_path = [ self.connector_token_list[0], self.flexible_token_address_list[0] ] self.assertRaises(RevertException, self.network_score._require_valid_path, invalid_path) # failure case: input path whose length is more than 21 random = SystemRandom() # use random data to avoid same address is made invalid_path = [ Address.from_string("cx" + str(random.randrange(10)) + str(random.randrange(10)) * 39) in range(0, 22) ] self.assertRaises(RevertException, self.network_score._require_valid_path, invalid_path) # failure case: input path whose length is even invalid_path = [ self.connector_token_list[0], self.flexible_token_address_list[0], self.connector_token_list[1], self.flexible_token_address_list[1] ] self.assertRaises(RevertException, self.network_score._require_valid_path, invalid_path) # failure case: input path which has the same flexible token address in it invalid_path = [ self.connector_token_list[0], self.flexible_token_address_list[0], self.connector_token_list[1], self.flexible_token_address_list[0], self.connector_token_list[1] ] self.assertRaises(RevertException, self.network_score._require_valid_path, invalid_path) # success case: input path which has the same flexible token address in the 'from' or 'to' position in it # path: [connector0 - flexible token0 - flexible token1 - flexible token2, flexible token0] path = [ self.connector_token_list[0], self.flexible_token_address_list[0], self.flexible_token_address_list[1], self.flexible_token_address_list[2], self.flexible_token_address_list[0] ] self.network_score._require_valid_path(path) # success case: input path which has the same flexible tokens that only exist in 'from' or 'to' in it path = [ self.flexible_token_address_list[0], self.flexible_token_address_list[1], self.connector_token_list[0], self.flexible_token_address_list[2], self.flexible_token_address_list[0] ] self.network_score._require_valid_path(path) def test_check_and_convert_bytes_data(self): # failure case: input invalid JSON format data invalid_json_format = dict() invalid_json_format["path"] = "{0},{1},{2}".format( str(self.connector_token_list[0]), str(self.flexible_token_address_list[0]), str(self.connector_token_list[1])) invalid_json_format["for"] = str(self.network_owner) invalid_json_format["minReturn"] = 10 stringed_invalid_json_format = "[" + json.dumps( invalid_json_format) + "}" encoded_invalid_json_format = stringed_invalid_json_format.encode( encoding="utf-8") self.assertRaises(RevertException, self.network_score._convert_bytes_data, encoded_invalid_json_format, self.network_owner) # failure case: input data which is not decoded to utf-8 valid_json_format = dict() valid_json_format["path"] = "{0},{1},{2}".format( str(self.connector_token_list[0]), str(self.flexible_token_address_list[0]), str(self.connector_token_list[1])) valid_json_format["for"] = str(self.network_owner) valid_json_format["minReturn"] = 10 stringed_valid_json_format = json.dumps(valid_json_format) cp037_encoded_valid_json_format = stringed_valid_json_format.encode( encoding='cp037') self.assertRaises(RevertException, self.network_score._convert_bytes_data, cp037_encoded_valid_json_format, self.network_owner) # failure case: input invalid path data (associated with '/') json_format = dict() json_format["path"] = "{0}/{1}/{2}".format( str(self.connector_token_list[0]), str(self.flexible_token_address_list[0]), str(self.connector_token_list[1])) json_format["for"] = str(self.network_owner) json_format["minReturn"] = 10 stringed_valid_json_format = json.dumps(json_format) encoded_valid_json_format = stringed_valid_json_format.encode( encoding='utf-8') self.assertRaises(InvalidParamsException, self.network_score._convert_bytes_data, encoded_valid_json_format, self.network_owner) # failure case: input invalid path data ( has an invalid address as an element ) json_format = dict() json_format["path"] = "{0},{1},{2}".format( str(self.connector_token_list[0]), str("invalid_address"), str(self.connector_token_list[1])) json_format["for"] = str(self.network_owner) json_format["minReturn"] = 10 stringed_valid_json_format = json.dumps(json_format) encoded_valid_json_format = stringed_valid_json_format.encode( encoding='utf-8') self.assertRaises(InvalidParamsException, self.network_score._convert_bytes_data, encoded_valid_json_format, self.network_owner) # failure case: input string type minReturn json_format = dict() json_format["path"] = "{0},{1},{2}".format( str(self.connector_token_list[0]), str(self.flexible_token_address_list[0]), str(self.connector_token_list[1])) json_format["for"] = str(self.network_owner) json_format["minReturn"] = "10" stringed_valid_json_format = json.dumps(json_format) encoded_valid_json_format = stringed_valid_json_format.encode( encoding='utf-8') self.assertRaises(RevertException, self.network_score._convert_bytes_data, encoded_valid_json_format, self.network_owner) # success case: "for" key is not in the data # ( returned data should have token sender address as a "for" key's value ) token_sender = Address.from_string("hx" + "a" * 40) json_format = dict() json_format["path"] = "{0},{1},{2}".format( str(self.connector_token_list[0]), str(self.flexible_token_address_list[0]), str(self.connector_token_list[1])) json_format["minReturn"] = 10 stringed_valid_json_format = json.dumps(json_format) encoded_valid_json_format = stringed_valid_json_format.encode( encoding='utf-8') result_data = self.network_score._convert_bytes_data( encoded_valid_json_format, token_sender) self.assertEqual(token_sender, result_data["for"]) # success case: "for" key is exist but value is None # ( returned dict data should have token sender address as a "for" key's value ) json_format["for"] = None stringed_valid_json_format = json.dumps(json_format) encoded_valid_json_format = stringed_valid_json_format.encode( encoding='utf-8') result_data = self.network_score._convert_bytes_data( encoded_valid_json_format, token_sender) self.assertEqual(token_sender, result_data["for"]) # success case: input data which has "for" key and it's value for_address = Address.from_string("hx" + "b" * 40) json_format["for"] = str(for_address) stringed_valid_json_format = json.dumps(json_format) encoded_valid_json_format = stringed_valid_json_format.encode( encoding='utf-8') result_data = self.network_score._convert_bytes_data( encoded_valid_json_format, token_sender) self.assertEqual(for_address, result_data["for"]) def test_convertFor(self): icx_amount = 10 # failure case: input wrong path format min_return = 10 for_address = Address.from_string("hx" + "a" * 40) invalid_path = "{0}/{1}/{2}".format( str(self.icx_token), str(self.flexible_token_address_list[0]), str(self.connector_token_list[0])) with patch_property(IconScoreBase, 'msg', Message(self.network_owner, value=icx_amount)): self.assertRaises(InvalidParamsException, self.network_score.convertFor, invalid_path, min_return, for_address) # failure case: input path whose has invalid address as an element min_return = 10 for_address = Address.from_string("hx" + "a" * 40) invalid_path = "{0},{1},{2}".format(str(self.icx_token), str("invalid_address"), str(self.connector_token_list[1])) with patch_property(IconScoreBase, 'msg', Message(self.network_owner, value=icx_amount)): self.assertRaises(InvalidParamsException, self.network_score.convertFor, invalid_path, min_return, for_address) # failure case: input min return less than 0 invalid_min_return = -1 for_address = Address.from_string("hx" + "a" * 40) path = "{0},{1},{2}".format(str(self.icx_token), str(self.flexible_token_address_list[0]), str(self.connector_token_list[0])) with patch_property(IconScoreBase, 'msg', Message(self.network_owner, value=icx_amount)): self.assertRaises(RevertException, self.network_score.convertFor, path, invalid_min_return, for_address) # failure case: input path whose first address is not Icx token address min_return = 10 for_address = Address.from_string("hx" + "a" * 40) invalid_path = "{0},{1},{2}".format( str(self.connector_token_list[0]), str(self.flexible_token_address_list[0]), str(self.connector_token_list[1])) with patch_property(IconScoreBase, 'msg', Message(self.network_owner, value=icx_amount)): self.assertRaises(RevertException, self.network_score.convertFor, invalid_path, min_return, for_address) # success case: input valid path min_return = 10 for_address = Address.from_string("hx" + "a" * 40) path = "{0},{1},{2}".format(str(self.icx_token), str(self.flexible_token_address_list[0]), str(self.connector_token_list[1])) self.network_score._icx_tokens[self.icx_token] = True with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(self.network_owner, value=icx_amount)), patch.object(Network, '_convert_for_internal') ]): self.network_score.convertFor(path, min_return, for_address) self.network_score.icx.transfer.assert_called_with( self.icx_token, icx_amount) converted_path = [ self.icx_token, self.flexible_token_address_list[0], self.connector_token_list[1] ] self.network_score._convert_for_internal.assert_called_with( converted_path, icx_amount, min_return, for_address) def test_tokenFallback(self): # success case: input 'conversionResult' to _data ( convert_for_internal should not be called ) from_address = Address.from_string("hx" + "a" * 40) for_address = Address.from_string("hx" + "b" * 40) value = 10 min_return = 5 path = "{0},{1},{2}".format(str(self.connector_token_list[0]), str(self.flexible_token_address_list[0]), str(self.connector_token_list[1])) converted_path = [ Address.from_string(address) for address in path.split(",") ] data = dict() data["path"] = path data["minReturn"] = min_return data["for"] = str(for_address) stringed_data = json.dumps(data) decoded_data = stringed_data.encode(encoding='utf-8') with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(self.connector_token_list[0])), patch.object(Network, '_convert_for_internal') ]): self.network_score.tokenFallback(from_address, value, b'conversionResult') self.network_score._convert_for_internal.assert_not_called() # failure case: input None data to the _data with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(self.connector_token_list[0])), patch.object(Network, '_convert_for_internal') ]): self.assertRaises(RevertException, self.network_score.tokenFallback, from_address, value, b'None') self.assertRaises(RevertException, self.network_score.tokenFallback, from_address, value, None) # failure case: msg.sender is not equal to path[0] ( should be equal ) msg_sender = Address.from_string("cx" + "c" * 40) with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(msg_sender)), patch.object(Network, '_convert_for_internal') ]): self.assertRaises(RevertException, self.network_score.tokenFallback, from_address, value, decoded_data) # success case: input valid data with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(self.connector_token_list[0])), patch.object(Network, '_convert_for_internal'), patch.object(Network, '_require_valid_path'), patch('contracts.network.network.require_positive_value'), patch('contracts.network.network.require_valid_address'), ]) as mocks: self.network_score.tokenFallback(from_address, value, decoded_data) mocks[3].assert_called() # patched mock of require_positive_value mocks[4].assert_called() # patched mock of require_valid_address self.network_score._require_valid_path.assert_called_with( converted_path) self.network_score._convert_for_internal. \ assert_called_with(converted_path, value, min_return, for_address) def test_convert_for_internal(self): min_return = 10 amount_to_convert = 5 convert_result_amount = 10 for_address = Address.from_string("hx" + "a" * 40) icx_token_score_interface = \ self.network_score.create_interface_score(self.icx_token, ProxyScore(ABCIcxToken)) icx_token_score_interface.withdrawTo = PropertyMock() irc_token_score_interface = \ self.network_score.create_interface_score(self.connector_token_list[0], ProxyScore(ABCIRCToken)) irc_token_score_interface.transfer = PropertyMock() # success case: finally converted token is Icx token ( Icx token SCORE's 'withdrawTo' method should be called ) converted_path = [ self.connector_token_list[0], self.flexible_token_address_list[0], self.icx_token ] # '_convert_by_path' method returns 'to' token Address, and converted amount with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(self.network_owner)), patch.object(Network, '_convert_by_path', return_value=(self.icx_token, convert_result_amount)), patch.object(Network, 'create_interface_score', return_value=icx_token_score_interface) ]): # register icx_token self.network_score._icx_tokens[self.icx_token] = True self.network_score._convert_for_internal(converted_path, amount_to_convert, min_return, for_address) icx_token_score_interface.withdrawTo.assert_called_with( convert_result_amount, for_address) # success case: finally converted token is irc token ( token SCORE's 'transfer' method should be called ) converted_path = [ self.icx_token, self.flexible_token_address_list[0], self.connector_token_list[1] ] # '_convert_by_path' method returns 'to' token Address, and converted amount with MultiPatch([ patch_property(IconScoreBase, 'msg', Message(self.network_owner)), patch.object(Network, '_convert_by_path', return_value=(self.connector_token_list[1], convert_result_amount)), patch.object(Network, 'create_interface_score', return_value=irc_token_score_interface) ]): self.network_score._convert_for_internal(converted_path, amount_to_convert, min_return, for_address) irc_token_score_interface.transfer.assert_called_with( for_address, convert_result_amount, b'None') def test_convert_by_path(self): # success case: check all other SCORE's methods called correctly # in this path, 'flexible token' is 1, 3, 'from token' is 0, 2, 'to token' is 2, 4 ( index ) converted_path = [ self.connector_token_list[0], self.flexible_token_address_list[0], self.connector_token_list[1], self.flexible_token_address_list[1], self.connector_token_list[2] ] for_address = Address.from_string("hx" + "a" * 40) # this method substitutes 'create_interface_score' method of IconScoreBase def create_interface_score_mock(token_address, interface_score): if interface_score.__name__ == 'ProxyScore(ABCFlexibleToken)': # add getOwner method to the token address instance # this token instance operates as a converter interface score token_address.getOwner = Mock( return_value="{0} converter address".format(token_address)) else: # add 'transfer' and 'balanceOf' methods to token address # this token instance operates as an IRC token interface score token_address.transfer = PropertyMock() token_address.balanceOf = PropertyMock(return_value=0) return token_address with patch_property(IconScoreBase, 'msg', Message(self.network_owner)): # the amount is set to 0. in this unit test, do not check the exact return value # just check whether if specific methods have been called or not amount = 0 min_return = 10 self.network_score.create_interface_score = create_interface_score_mock actual_to_token, actual_amount = self.network_score.\ _convert_by_path(converted_path, amount, min_return, for_address) self.assertEqual(converted_path[-1], actual_to_token) self.assertEqual(amount, actual_amount) # check flexible token's 'getOwner' method have been called ( flexible token's index is 1, 3 ) for i, flexible_token in enumerate(converted_path): if i % 2 == 1: flexible_token.getOwner.assert_called_once() # check 'from' token's 'transfer' method have been called ( from token's index is 0, 2 ) for i, from_token in enumerate(converted_path): if i % 2 == 0 and i != len(converted_path) - 1: data = dict() data["toToken"] = str(converted_path[i + 2]) # in the last converting, minReturn should be user inputted data (10) data["minReturn"] = min_return if i == len( converted_path) - 3 else 1 encoded_data = json_dumps(data).encode() from_token.transfer.assert_called_once_with( "{0} converter address".format(converted_path[i + 1]), amount, encoded_data) # check 'to' token's getBalanceOf method have been called ( to token's index is 2, 4 ) for i, from_token in enumerate(converted_path): if i % 2 == 0 and i != 0: # 'balanceOf' method should be called twice from_token.balanceOf.assert_called() def test_getExpectedReturnByPath(self): # failure case: input invalid path data ( associated with '/' ) amount = 10 invalid_path = "{0}/{1}/{2}".format( str(self.connector_token_list[0]), str(self.flexible_token_address_list[0]), str(self.connector_token_list[1])) self.assertRaises(InvalidParamsException, self.network_score.getExpectedReturnByPath, invalid_path, amount) # failure case: input invalid path ( has a invalid address as an element ) amount = 10 invalid_path = "{0},{1},{2}".format(str(self.connector_token_list[0]), str("invalid_address"), str(self.connector_token_list[1])) self.assertRaises(InvalidParamsException, self.network_score.getExpectedReturnByPath, invalid_path, amount) # failure case: amount is less than 0 invalid_amount = -1 path = "{0},{1},{2}".format(str(self.connector_token_list[0]), str(self.flexible_token_address_list[0]), str(self.connector_token_list[1])) self.assertRaises(RevertException, self.network_score.getExpectedReturnByPath, path, invalid_amount) # success case: input valid path and amount converted_path = [ self.connector_token_list[0], self.flexible_token_address_list[0], self.connector_token_list[1], self.flexible_token_address_list[1], self.connector_token_list[2] ] stringed_path = ",".join([str(address) for address in converted_path]) amount = 10 def create_interface_score_mock(token_address, interface_score): if interface_score.__name__ == "ProxyScore(ABCFlexibleToken)": token_address.getOwner = Mock(return_value=token_address) return token_address # return converted_path's address instance ( to verify getReturn called or not ) for index, address in enumerate(converted_path): if token_address == address: address.getReturn = Mock(return_value={ "amount": amount + index, "fee": 0 }) return address with patch_property(IconScoreBase, 'msg', Message(self.network_owner)): self.network_score.create_interface_score = create_interface_score_mock actual_amount = self.network_score.getExpectedReturnByPath( stringed_path, amount) expected_final_amount = amount + len(converted_path) - 2 # finally converted amount should be initial amount(10) + last flexible token index number(3) self.assertEqual(expected_final_amount, actual_amount) expected_intermediate_amount = 10 for i in range(1, len(converted_path), 2): converted_path[i].getReturn.\ assert_called_with(converted_path[i-1], converted_path[i+1], expected_intermediate_amount) expected_intermediate_amount += i