github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/ibc-go/modules/apps/29-fee/keeper/escrow_test.go (about) 1 package keeper_test 2 3 import ( 4 "fmt" 5 6 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 7 "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/apps/29-fee/types" 8 transfertypes "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/apps/transfer/types" 9 channeltypes "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/04-channel/types" 10 "github.com/fibonacci-chain/fbc/libs/ibc-go/testing/mock" 11 "github.com/fibonacci-chain/fbc/libs/tendermint/crypto/secp256k1" 12 ) 13 14 func (suite *KeeperTestSuite) TestDistributeFee() { 15 var ( 16 forwardRelayer string 17 forwardRelayerBal sdk.Coin 18 reverseRelayer sdk.AccAddress 19 reverseRelayerBal sdk.Coin 20 refundAcc sdk.AccAddress 21 refundAccBal sdk.Coin 22 packetFee types.PacketFee 23 packetFees []types.PacketFee 24 fee types.Fee 25 ) 26 testCases := []struct { 27 name string 28 malleate func() 29 expResult func() 30 }{ 31 { 32 "success", 33 func() { 34 packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) 35 packetFees = []types.PacketFee{packetFee, packetFee} 36 }, 37 func() { 38 // check if fees has been deleted 39 packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) 40 suite.Require().False(suite.chainA.GetSimApp().IBCFeeKeeper.HasFeesInEscrow(suite.chainA.GetContext(), packetID)) 41 42 // check if the reverse relayer is paid 43 expectedReverseAccBal := reverseRelayerBal.Add(defaultAckFee.ToCoins()[0]).Add(defaultAckFee.ToCoins()[0]) 44 balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), reverseRelayer, sdk.DefaultBondDenom) 45 suite.Require().Equal(expectedReverseAccBal, balance) 46 47 // check if the forward relayer is paid 48 forward, err := sdk.AccAddressFromBech32(forwardRelayer) 49 suite.Require().NoError(err) 50 51 expectedForwardAccBal := forwardRelayerBal.Add(defaultRecvFee.ToCoins()[0]).Add(defaultRecvFee.ToCoins()[0]) 52 balance = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), forward, sdk.DefaultBondDenom) 53 suite.Require().Equal(expectedForwardAccBal, balance) 54 55 // check if the refund acc has been refunded the timeoutFee 56 expectedRefundAccBal := refundAccBal.Add(defaultTimeoutFee.ToCoins()[0].Add(defaultTimeoutFee.ToCoins()[0])) 57 balance = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) 58 suite.Require().Equal(expectedRefundAccBal, balance) 59 60 // check the module acc wallet is now empty 61 balance = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress(), sdk.DefaultBondDenom) 62 suite.Require().Equal(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(0)), balance) 63 }, 64 }, 65 { 66 "success: refund account is module account", 67 func() { 68 refundAcc = suite.chainA.GetSimApp().SupplyKeeper.GetModuleAddress(mock.ModuleName) 69 70 packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) 71 packetFees = []types.PacketFee{packetFee, packetFee} 72 73 // fund mock account 74 err := suite.chainA.GetSimApp().SupplyKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), suite.chainA.SenderAccount().GetAddress(), mock.ModuleName, packetFee.Fee.Total().Add(packetFee.Fee.Total()...).ToCoins()) 75 balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) 76 fmt.Println(balance.String()) 77 suite.Require().NoError(err) 78 }, 79 func() { 80 // check if the refund acc has been refunded the timeoutFee 81 expectedRefundAccBal := refundAccBal.Add(defaultTimeoutFee.ToCoins()[0]).Add(defaultTimeoutFee.ToCoins()[0]) 82 balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) 83 fmt.Println(expectedRefundAccBal.String()) 84 fmt.Println(balance.String()) 85 suite.Require().Equal(expectedRefundAccBal, balance) 86 }, 87 }, 88 { 89 "escrow account out of balance, fee module becomes locked - no distribution", func() { 90 packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) 91 packetFees = []types.PacketFee{packetFee, packetFee} 92 93 // pass in an extra packet fee 94 packetFees = append(packetFees, packetFee) 95 }, 96 func() { 97 packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) 98 99 suite.Require().True(suite.chainA.GetSimApp().IBCFeeKeeper.IsLocked(suite.chainA.GetContext())) 100 suite.Require().True(suite.chainA.GetSimApp().IBCFeeKeeper.HasFeesInEscrow(suite.chainA.GetContext(), packetID)) 101 102 // check if the module acc contains all the fees 103 expectedModuleAccBal := packetFee.Fee.Total().Add(packetFee.Fee.Total()...) 104 balance := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress()) 105 suite.Require().Equal(expectedModuleAccBal.ToCoins(), balance) 106 }, 107 }, 108 { 109 "invalid forward address", 110 func() { 111 packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) 112 packetFees = []types.PacketFee{packetFee, packetFee} 113 114 forwardRelayer = "invalid address" 115 }, 116 func() { 117 // check if the refund acc has been refunded the timeoutFee & recvFee 118 expectedRefundAccBal := refundAccBal.Add(defaultTimeoutFee.ToCoins()[0]).Add(defaultRecvFee.ToCoins()[0]).Add(defaultTimeoutFee.ToCoins()[0]).Add(defaultRecvFee.ToCoins()[0]) 119 balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) 120 suite.Require().Equal(expectedRefundAccBal, balance) 121 }, 122 }, 123 { 124 "invalid forward address: blocked address", 125 func() { 126 packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) 127 packetFees = []types.PacketFee{packetFee, packetFee} 128 129 forwardRelayer = suite.chainA.GetSimApp().SupplyKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress().String() 130 }, 131 func() { 132 // check if the refund acc has been refunded the timeoutFee & recvFee 133 expectedRefundAccBal := refundAccBal.Add(defaultTimeoutFee.ToCoins()[0]).Add(defaultRecvFee.ToCoins()[0]).Add(defaultTimeoutFee.ToCoins()[0]).Add(defaultRecvFee.ToCoins()[0]) 134 balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) 135 suite.Require().Equal(expectedRefundAccBal, balance) 136 }, 137 }, 138 { 139 "invalid receiver address: ack fee returned to sender", 140 func() { 141 packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) 142 packetFees = []types.PacketFee{packetFee, packetFee} 143 144 reverseRelayer = suite.chainA.GetSimApp().SupplyKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress() 145 }, 146 func() { 147 // check if the refund acc has been refunded the timeoutFee & ackFee 148 expectedRefundAccBal := refundAccBal.Add(defaultTimeoutFee.ToCoins()[0]).Add(defaultAckFee.ToCoins()[0]).Add(defaultTimeoutFee.ToCoins()[0]).Add(defaultAckFee.ToCoins()[0]) 149 balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) 150 suite.Require().Equal(expectedRefundAccBal, balance) 151 }, 152 }, 153 { 154 "invalid refund address: no-op, timeout fee remains in escrow", 155 func() { 156 packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) 157 packetFees = []types.PacketFee{packetFee, packetFee} 158 159 packetFees[0].RefundAddress = suite.chainA.GetSimApp().SupplyKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress().String() 160 packetFees[1].RefundAddress = suite.chainA.GetSimApp().SupplyKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress().String() 161 }, 162 func() { 163 // check if the module acc contains the timeoutFee 164 expectedModuleAccBal := sdk.NewCoinAdapter(sdk.DefaultIbcWei, defaultTimeoutFee.Add(defaultTimeoutFee...).AmountOf(sdk.DefaultIbcWei)) 165 balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress(), sdk.DefaultBondDenom) 166 fmt.Println(expectedModuleAccBal.String(), balance.String()) 167 suite.Require().Equal(expectedModuleAccBal.ToCoin(), balance) 168 }, 169 }, 170 } 171 172 for _, tc := range testCases { 173 tc := tc 174 175 suite.Run(tc.name, func() { 176 suite.SetupTest() // reset 177 suite.coordinator.Setup(suite.path) // setup channel 178 179 // setup accounts 180 forwardRelayer = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() 181 reverseRelayer = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) 182 refundAcc = suite.chainA.SenderAccount().GetAddress() 183 184 packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) 185 fee = types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) 186 187 tc.malleate() 188 189 // escrow the packet fees & store the fees in state 190 suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, types.NewPacketFees(packetFees)) 191 err := suite.chainA.GetSimApp().SupplyKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, packetFee.Fee.Total().Add(packetFee.Fee.Total()...).ToCoins()) 192 suite.Require().NoError(err) 193 194 // fetch the account balances before fee distribution (forward, reverse, refund) 195 forwardAccAddress, _ := sdk.AccAddressFromBech32(forwardRelayer) 196 forwardRelayerBal = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), forwardAccAddress, sdk.DefaultBondDenom) 197 reverseRelayerBal = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), reverseRelayer, sdk.DefaultBondDenom) 198 refundAccBal = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) 199 200 suite.chainA.GetSimApp().IBCFeeKeeper.DistributePacketFeesOnAcknowledgement(suite.chainA.GetContext(), forwardRelayer, reverseRelayer, packetFees, packetID) 201 tc.expResult() 202 }) 203 } 204 } 205 206 func (suite *KeeperTestSuite) TestDistributePacketFeesOnTimeout() { 207 var ( 208 timeoutRelayer sdk.AccAddress 209 timeoutRelayerBal sdk.Coin 210 refundAcc sdk.AccAddress 211 refundAccBal sdk.Coin 212 packetFee types.PacketFee 213 packetFees []types.PacketFee 214 ) 215 testCases := []struct { 216 name string 217 malleate func() 218 expResult func() 219 }{ 220 { 221 "success", 222 func() {}, 223 func() { 224 // check if the timeout relayer is paid 225 expectedTimeoutAccBal := timeoutRelayerBal.Add(defaultTimeoutFee.ToCoins()[0]).Add(defaultTimeoutFee.ToCoins()[0]) 226 balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), timeoutRelayer, sdk.DefaultBondDenom) 227 suite.Require().Equal(expectedTimeoutAccBal, balance) 228 229 // check if the refund acc has been refunded the recv/ack fees 230 expectedRefundAccBal := refundAccBal.Add(defaultAckFee.ToCoins()[0]).Add(defaultAckFee.ToCoins()[0]).Add(defaultRecvFee.ToCoins()[0]).Add(defaultRecvFee.ToCoins()[0]) 231 balance = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) 232 suite.Require().Equal(expectedRefundAccBal, balance) 233 234 // check the module acc wallet is now empty 235 balance = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress(), sdk.DefaultBondDenom) 236 suite.Require().Equal(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(0)), balance) 237 }, 238 }, 239 { 240 "escrow account out of balance, fee module becomes locked - no distribution", func() { 241 // pass in an extra packet fee 242 packetFees = append(packetFees, packetFee) 243 }, 244 func() { 245 packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) 246 247 suite.Require().True(suite.chainA.GetSimApp().IBCFeeKeeper.IsLocked(suite.chainA.GetContext())) 248 suite.Require().True(suite.chainA.GetSimApp().IBCFeeKeeper.HasFeesInEscrow(suite.chainA.GetContext(), packetID)) 249 250 // check if the module acc contains all the fees 251 expectedModuleAccBal := packetFee.Fee.Total().Add(packetFee.Fee.Total()...) 252 balance := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress()) 253 fmt.Println(expectedModuleAccBal.String(), balance.String()) 254 suite.Require().Equal(expectedModuleAccBal.ToCoins(), balance) 255 }, 256 }, 257 { 258 "invalid timeout relayer address: timeout fee returned to sender", 259 func() { 260 timeoutRelayer = suite.chainA.GetSimApp().SupplyKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress() 261 }, 262 func() { 263 // check if the refund acc has been refunded the all the fees 264 expectedRefundAccBal := sdk.Coins{refundAccBal}.Add(packetFee.Fee.Total().ToCoins()...).Add(packetFee.Fee.Total().ToCoins()...)[0] 265 balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) 266 suite.Require().Equal(expectedRefundAccBal, balance) 267 }, 268 }, 269 { 270 "invalid refund address: no-op, recv and ack fees remain in escrow", 271 func() { 272 packetFees[0].RefundAddress = suite.chainA.GetSimApp().SupplyKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress().String() 273 packetFees[1].RefundAddress = suite.chainA.GetSimApp().SupplyKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress().String() 274 }, 275 func() { 276 // check if the module acc contains the timeoutFee 277 expectedModuleAccBal := sdk.NewCoinAdapter(sdk.DefaultIbcWei, defaultRecvFee.Add(defaultRecvFee[0]).Add(defaultAckFee[0]).Add(defaultAckFee[0]).AmountOf(sdk.DefaultIbcWei)) 278 balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress(), sdk.DefaultBondDenom) 279 suite.Require().Equal(expectedModuleAccBal.ToCoin(), balance) 280 }, 281 }, 282 } 283 284 for _, tc := range testCases { 285 tc := tc 286 287 suite.Run(tc.name, func() { 288 suite.SetupTest() // reset 289 suite.coordinator.Setup(suite.path) // setup channel 290 291 // setup accounts 292 timeoutRelayer = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) 293 refundAcc = suite.chainA.SenderAccount().GetAddress() 294 295 packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) 296 fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) 297 298 // escrow the packet fees & store the fees in state 299 packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) 300 packetFees = []types.PacketFee{packetFee, packetFee} 301 302 suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, types.NewPacketFees(packetFees)) 303 err := suite.chainA.GetSimApp().SupplyKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, packetFee.Fee.Total().Add(packetFee.Fee.Total()...).ToCoins()) 304 suite.Require().NoError(err) 305 306 tc.malleate() 307 308 // fetch the account balances before fee distribution (forward, reverse, refund) 309 timeoutRelayerBal = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), timeoutRelayer, sdk.DefaultBondDenom) 310 refundAccBal = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) 311 312 suite.chainA.GetSimApp().IBCFeeKeeper.DistributePacketFeesOnTimeout(suite.chainA.GetContext(), timeoutRelayer, packetFees, packetID) 313 314 tc.expResult() 315 }) 316 } 317 } 318 319 func (suite *KeeperTestSuite) TestRefundFeesOnChannelClosure() { 320 var ( 321 expIdentifiedPacketFees []types.IdentifiedPacketFees 322 expEscrowBal sdk.Coins 323 expRefundBal sdk.Coins 324 refundAcc sdk.AccAddress 325 fee types.Fee 326 locked bool 327 expectEscrowFeesToBeDeleted bool 328 ) 329 330 testCases := []struct { 331 name string 332 malleate func() 333 expPass bool 334 }{ 335 { 336 "success", func() { 337 for i := 1; i < 6; i++ { 338 // store the fee in state & update escrow account balance 339 packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(i)) 340 packetFees := types.NewPacketFees([]types.PacketFee{types.NewPacketFee(fee, refundAcc.String(), nil)}) 341 identifiedPacketFees := types.NewIdentifiedPacketFees(packetID, packetFees.PacketFees) 342 343 suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, packetFees) 344 345 err := suite.chainA.GetSimApp().SupplyKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total().ToCoins()) 346 suite.Require().NoError(err) 347 348 expIdentifiedPacketFees = append(expIdentifiedPacketFees, identifiedPacketFees) 349 } 350 }, true, 351 }, 352 { 353 "success with undistributed packet fees on a different channel", func() { 354 for i := 1; i < 6; i++ { 355 // store the fee in state & update escrow account balance 356 packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(i)) 357 packetFees := types.NewPacketFees([]types.PacketFee{types.NewPacketFee(fee, refundAcc.String(), nil)}) 358 identifiedPacketFees := types.NewIdentifiedPacketFees(packetID, packetFees.PacketFees) 359 360 suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, packetFees) 361 362 err := suite.chainA.GetSimApp().SupplyKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total().ToCoins()) 363 suite.Require().NoError(err) 364 365 expIdentifiedPacketFees = append(expIdentifiedPacketFees, identifiedPacketFees) 366 } 367 368 // set packet fee for a different channel 369 packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, "channel-1", uint64(1)) 370 packetFees := types.NewPacketFees([]types.PacketFee{types.NewPacketFee(fee, refundAcc.String(), nil)}) 371 suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, "channel-1") 372 373 suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, packetFees) 374 err := suite.chainA.GetSimApp().SupplyKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total().ToCoins()) 375 suite.Require().NoError(err) 376 377 expEscrowBal = fee.Total().ToCoins() 378 expRefundBal = expRefundBal.Sub(fee.Total().ToCoins()) 379 }, true, 380 }, 381 { 382 "escrow account empty, module should become locked", func() { 383 locked = true 384 385 // store the fee in state without updating escrow account balance 386 packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(1)) 387 packetFees := types.NewPacketFees([]types.PacketFee{types.NewPacketFee(fee, refundAcc.String(), nil)}) 388 identifiedPacketFees := types.NewIdentifiedPacketFees(packetID, packetFees.PacketFees) 389 390 suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, packetFees) 391 392 expIdentifiedPacketFees = []types.IdentifiedPacketFees{identifiedPacketFees} 393 }, 394 true, 395 }, 396 { 397 "escrow account goes negative on second packet, module should become locked", func() { 398 locked = true 399 400 // store 2 fees in state 401 packetID1 := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(1)) 402 packetID2 := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(2)) 403 packetFees := types.NewPacketFees([]types.PacketFee{types.NewPacketFee(fee, refundAcc.String(), nil)}) 404 identifiedPacketFee1 := types.NewIdentifiedPacketFees(packetID1, packetFees.PacketFees) 405 identifiedPacketFee2 := types.NewIdentifiedPacketFees(packetID2, packetFees.PacketFees) 406 407 suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID1, packetFees) 408 suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID2, packetFees) 409 410 // update escrow account balance for 1 fee 411 err := suite.chainA.GetSimApp().SupplyKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total().ToCoins()) 412 suite.Require().NoError(err) 413 414 expIdentifiedPacketFees = []types.IdentifiedPacketFees{identifiedPacketFee1, identifiedPacketFee2} 415 }, true, 416 }, 417 { 418 "invalid refund acc address", func() { 419 // store the fee in state & update escrow account balance 420 expectEscrowFeesToBeDeleted = false 421 packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(1)) 422 packetFees := types.NewPacketFees([]types.PacketFee{types.NewPacketFee(fee, "invalid refund address", nil)}) 423 identifiedPacketFees := types.NewIdentifiedPacketFees(packetID, packetFees.PacketFees) 424 425 suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, packetFees) 426 427 err := suite.chainA.GetSimApp().SupplyKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total().ToCoins()) 428 suite.Require().NoError(err) 429 430 expIdentifiedPacketFees = []types.IdentifiedPacketFees{identifiedPacketFees} 431 432 expEscrowBal = fee.Total().ToCoins() 433 expRefundBal = expRefundBal.Sub(fee.Total().ToCoins()) 434 }, true, 435 }, 436 { 437 "distributing to blocked address is skipped", func() { 438 expectEscrowFeesToBeDeleted = false 439 blockedAddr := suite.chainA.GetSimApp().SupplyKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress().String() 440 441 // store the fee in state & update escrow account balance 442 packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(1)) 443 packetFees := types.NewPacketFees([]types.PacketFee{types.NewPacketFee(fee, blockedAddr, nil)}) 444 identifiedPacketFees := types.NewIdentifiedPacketFees(packetID, packetFees.PacketFees) 445 446 suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, packetFees) 447 448 err := suite.chainA.GetSimApp().SupplyKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total().ToCoins()) 449 suite.Require().NoError(err) 450 451 expIdentifiedPacketFees = []types.IdentifiedPacketFees{identifiedPacketFees} 452 453 expEscrowBal = fee.Total().ToCoins() 454 expRefundBal = expRefundBal.Sub(fee.Total().ToCoins()) 455 }, true, 456 }, 457 } 458 459 for _, tc := range testCases { 460 tc := tc 461 462 suite.Run(tc.name, func() { 463 suite.SetupTest() // reset 464 suite.coordinator.Setup(suite.path) // setup channel 465 expIdentifiedPacketFees = []types.IdentifiedPacketFees{} 466 expEscrowBal = sdk.Coins{} 467 locked = false 468 expectEscrowFeesToBeDeleted = true 469 470 // setup 471 refundAcc = suite.chainA.SenderAccount().GetAddress() 472 moduleAcc := suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress() 473 474 // expected refund balance if the refunds are successful 475 // NOTE: tc.malleate() should transfer from refund balance to correctly set the escrow balance 476 expRefundBal = suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), refundAcc) 477 478 fee = types.Fee{ 479 RecvFee: defaultRecvFee, 480 AckFee: defaultAckFee, 481 TimeoutFee: defaultTimeoutFee, 482 } 483 484 tc.malleate() 485 486 // refundAcc balance before distribution 487 originalRefundBal := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), refundAcc) 488 originalEscrowBal := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), moduleAcc) 489 490 err := suite.chainA.GetSimApp().IBCFeeKeeper.RefundFeesOnChannelClosure(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) 491 492 // refundAcc balance after RefundFeesOnChannelClosure 493 refundBal := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), refundAcc) 494 escrowBal := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), moduleAcc) 495 496 if tc.expPass { 497 suite.Require().NoError(err) 498 } else { 499 suite.Require().Error(err) 500 } 501 502 suite.Require().Equal(locked, suite.chainA.GetSimApp().IBCFeeKeeper.IsLocked(suite.chainA.GetContext())) 503 504 if locked || !tc.expPass { 505 // refund account and escrow account balances should remain unchanged 506 suite.Require().Equal(originalRefundBal, refundBal) 507 suite.Require().Equal(originalEscrowBal, escrowBal) 508 509 // ensure none of the fees were deleted 510 suite.Require().Equal(expIdentifiedPacketFees, suite.chainA.GetSimApp().IBCFeeKeeper.GetIdentifiedPacketFeesForChannel(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID)) 511 } else { 512 if escrowBal == nil { 513 escrowBal = sdk.Coins{} 514 } 515 suite.Require().Equal(expEscrowBal, escrowBal) // escrow balance should be empty 516 suite.Require().Equal(expRefundBal, refundBal) // all packets should have been refunded 517 518 // all fees in escrow should be deleted if expected for this channel 519 suite.Require().Equal(expectEscrowFeesToBeDeleted, len(suite.chainA.GetSimApp().IBCFeeKeeper.GetIdentifiedPacketFeesForChannel(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID)) == 0) 520 } 521 }) 522 } 523 }