diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index f826ae20..37cf352a 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -307,7 +307,7 @@ func NewTerraAppKeepers( keepers.TokenFactoryKeeper = tokenfactorykeeper.NewKeeper( keys[tokenfactorytypes.StoreKey], keepers.AccountKeeper, - keepers.BankKeeper, + &keepers.BankKeeper, keepers.DistrKeeper, appCodec, authtypes.NewModuleAddress(govtypes.ModuleName).String(), diff --git a/integration-tests/src/modules/tokenfactory/tokenfactory.test.ts b/integration-tests/src/modules/tokenfactory/tokenfactory.test.ts index 79014180..301cce71 100644 --- a/integration-tests/src/modules/tokenfactory/tokenfactory.test.ts +++ b/integration-tests/src/modules/tokenfactory/tokenfactory.test.ts @@ -459,7 +459,7 @@ describe("TokenFactory Module (https://github.com/terra-money/core/tree/release/ }]); }); - test("100 token blocked by the smart contract", async () => { + test("100 token blocked by the smart contract before send", async () => { let tx = await wallet.createAndSignTx({ msgs: [ new MsgSend( @@ -477,6 +477,42 @@ describe("TokenFactory Module (https://github.com/terra-money/core/tree/release/ expect(txResult.raw_log) .toStrictEqual(`failed to execute message; message index: 0: failed to call before send hook for denom ${factoryDenom}: Custom Error val: \"Invalid Send Amount\": execute wasm contract failed`); }); + + test("100 token blocked by the smart contract on burn", async () => { + let tx = await wallet.createAndSignTx({ + msgs: [ + new MsgBurn( + tokenFactoryWalletAddr, + Coin.fromString("100" + factoryDenom), + ), + ], + chainID: "test-1", + fee: new Fee(2000_000, new Coins({ uluna: 100_000 })), + }); + let result = await LCD.chain1.tx.broadcastSync(tx, "test-1"); + await blockInclusion(); + let txResult = await LCD.chain1.tx.txInfo(result.txhash, "test-1") as any; + expect(txResult.raw_log) + .toStrictEqual(`failed to execute message; message index: 0: failed to call before send hook for denom ${factoryDenom}: Custom Error val: \"Invalid Send Amount\": execute wasm contract failed`); + }); + + test("100 token blocked by the smart contract on mint", async () => { + let tx = await wallet.createAndSignTx({ + msgs: [ + new MsgMint( + tokenFactoryWalletAddr, + Coin.fromString("100" + factoryDenom), + ), + ], + chainID: "test-1", + fee: new Fee(2000_000, new Coins({ uluna: 100_000 })), + }); + let result = await LCD.chain1.tx.broadcastSync(tx, "test-1"); + await blockInclusion(); + let txResult = await LCD.chain1.tx.txInfo(result.txhash, "test-1") as any; + expect(txResult.raw_log) + .toStrictEqual(`failed to execute message; message index: 0: failed to call before send hook for denom ${factoryDenom}: Custom Error val: \"Invalid Send Amount\": execute wasm contract failed`); + }); }); }) diff --git a/integration-tests/src/setup/init-test-framework.sh b/integration-tests/src/setup/init-test-framework.sh index 2473546d..264adfc9 100755 --- a/integration-tests/src/setup/init-test-framework.sh +++ b/integration-tests/src/setup/init-test-framework.sh @@ -42,6 +42,12 @@ GRPCPORT_2=9090 GRPCWEB_1=8091 GRPCWEB_2=9091 +# Install current version of terra core +echo "Installing current version of the binary..." +cd .. +make install +cd integration-tests + # Stop if it is already running if pgrep -x "$BINARY" >/dev/null; then echo "Terminating $BINARY..." diff --git a/x/bank/keeper/keeper.go b/x/bank/keeper/keeper.go index 90b667e7..8a446efd 100644 --- a/x/bank/keeper/keeper.go +++ b/x/bank/keeper/keeper.go @@ -60,6 +60,39 @@ func (k Keeper) SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.A return k.Keeper.SendCoins(ctx, fromAddr, toAddr, amt) } +// SendCoinsFromAccountToModule transfers coins from an AccAddress to a ModuleAccount. +// It will panic if the module account does not exist. +func (k Keeper) SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error { + recipientAcc := k.ak.GetModuleAccount(ctx, recipientModule) + if recipientAcc == nil { + panic(errorsmod.Wrapf(customterratypes.ErrUnknownAddress, "module account %s does not exist", recipientModule)) + } + err := k.BlockBeforeSend(ctx, senderAddr, recipientAcc.GetAddress(), amt) + if err != nil { + return err + } + k.TrackBeforeSend(ctx, senderAddr, recipientAcc.GetAddress(), amt) + + return k.Keeper.SendCoinsFromAccountToModule(ctx, senderAddr, recipientModule, amt) +} + +// SendCoinsFromModuleToAccount transfers coins from a ModuleAccount to an AccAddress. +// It will panic if the module account does not exist. An error is returned if +// the recipient address is black-listed or if sending the tokens fails. +func (k Keeper) SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error { + senderAddr := k.ak.GetModuleAddress(senderModule) + if senderAddr == nil { + panic(errorsmod.Wrapf(customterratypes.ErrUnknownAddress, "module account %s does not exist", senderModule)) + } + err := k.BlockBeforeSend(ctx, senderAddr, recipientAddr, amt) + if err != nil { + return err + } + k.TrackBeforeSend(ctx, senderAddr, recipientAddr, amt) + + return k.Keeper.SendCoinsFromModuleToAccount(ctx, senderModule, recipientAddr, amt) +} + // SendCoinsFromModuleToManyAccounts transfers coins from a ModuleAccount to multiple AccAddresses. // It will panic if the module account does not exist. An error is returned if // the recipient address is black-listed or if sending the tokens fails. diff --git a/x/bank/types/errors.go b/x/bank/types/errors.go index 1aba6a45..7b955f3b 100644 --- a/x/bank/types/errors.go +++ b/x/bank/types/errors.go @@ -10,4 +10,7 @@ import ( var ( ErrUnknownAddress = sdkerrors.Register(banktypes.ModuleName, 383838, "module account does not exist") + // ErrUnauthorized is used whenever a request without sufficient + // authorization is handled. + ErrUnauthorized = sdkerrors.Register(banktypes.ModuleName, 383839, "unauthorized") ) diff --git a/x/tokenfactory/keeper/bankactions.go b/x/tokenfactory/keeper/bankactions.go index 166b2490..d1f28fbe 100644 --- a/x/tokenfactory/keeper/bankactions.go +++ b/x/tokenfactory/keeper/bankactions.go @@ -3,6 +3,8 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" + errorsmod "cosmossdk.io/errors" + customterratypes "github.com/terra-money/core/v2/x/bank/types" "github.com/terra-money/core/v2/x/tokenfactory/types" ) @@ -39,16 +41,27 @@ func (k Keeper) burnFrom(ctx sdk.Context, amount sdk.Coin, burnFrom string) erro if err != nil { return err } + coins := sdk.NewCoins(amount) err = k.bankKeeper.SendCoinsFromAccountToModule(ctx, addr, types.ModuleName, - sdk.NewCoins(amount)) + coins) + if err != nil { + return err + } + recipientAcc := k.accountKeeper.GetModuleAccount(ctx, types.ModuleName) + if recipientAcc == nil { + panic(errorsmod.Wrapf(customterratypes.ErrUnknownAddress, "module account %s does not exist", recipientAcc)) + } + + err = k.bankKeeper.BlockBeforeSend(ctx, addr, recipientAcc.GetAddress(), coins) if err != nil { return err } + k.bankKeeper.TrackBeforeSend(ctx, addr, recipientAcc.GetAddress(), coins) - return k.bankKeeper.BurnCoins(ctx, types.ModuleName, sdk.NewCoins(amount)) + return k.bankKeeper.BurnCoins(ctx, types.ModuleName, coins) } func (k Keeper) forceTransfer(ctx sdk.Context, amount sdk.Coin, fromAddr string, toAddr string) error { diff --git a/x/tokenfactory/keeper/keeper.go b/x/tokenfactory/keeper/keeper.go index cab562cc..9727c192 100644 --- a/x/tokenfactory/keeper/keeper.go +++ b/x/tokenfactory/keeper/keeper.go @@ -20,7 +20,7 @@ type ( storeKey storetypes.StoreKey accountKeeper types.AccountKeeper - bankKeeper customtypes.Keeper + bankKeeper *customtypes.Keeper contractKeeper types.ContractKeeper communityPoolKeeper types.CommunityPoolKeeper @@ -34,7 +34,7 @@ type ( func NewKeeper( storeKey storetypes.StoreKey, accountKeeper types.AccountKeeper, - bankKeeper customtypes.Keeper, + bankKeeper *customtypes.Keeper, communityPoolKeeper types.CommunityPoolKeeper, cdc codec.BinaryCodec, authority string,