Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/ante/ante.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
// ante.NewSigGasConsumeDecorator(options.AccountKeeper, sigGasConsumer),
// ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler),
smartaccountante.NewSmartAccountAuthDecorator(*options.SmartAccountKeeper, options.WasmKeeper, options.AccountKeeper, sigGasConsumer, options.SignModeHandler),
smartaccountante.NewPreTransactionHookDecorator(*options.SmartAccountKeeper, options.WasmKeeper),
ante.NewIncrementSequenceDecorator(options.AccountKeeper),
ibcante.NewRedundantRelayDecorator(options.IBCkeeper),
}
Expand Down
3 changes: 0 additions & 3 deletions app/keepers/keepers.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package keepers

import (

// #nosec G702

"path/filepath"

"github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v7/router"
Expand Down
5 changes: 2 additions & 3 deletions app/modules.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import (
feegrantmodule "github.com/cosmos/cosmos-sdk/x/feegrant/module"
"github.com/cosmos/cosmos-sdk/x/genutil"
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
"github.com/terra-money/core/v2/x/smartaccount"
smartaccounttypes "github.com/terra-money/core/v2/x/smartaccount/types"

"github.com/cosmos/cosmos-sdk/x/gov"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
Expand Down Expand Up @@ -77,9 +79,6 @@ import (
"github.com/terra-money/alliance/x/alliance"
feeshare "github.com/terra-money/core/v2/x/feeshare"

"github.com/terra-money/core/v2/x/smartaccount"
smartaccounttypes "github.com/terra-money/core/v2/x/smartaccount/types"

ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported"
terrappsparams "github.com/terra-money/core/v2/app/params"

Expand Down
17 changes: 12 additions & 5 deletions app/test_helpers/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (

wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types"
dbm "github.com/cometbft/cometbft-db"
"github.com/cometbft/cometbft/crypto/ed25519"
"github.com/cometbft/cometbft/libs/log"
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
"github.com/stretchr/testify/suite"
Expand All @@ -16,6 +15,8 @@ import (
tokenfactorytypes "github.com/terra-money/core/v2/x/tokenfactory/types"

"github.com/cosmos/cosmos-sdk/baseapp"
secp256k1 "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
Expand All @@ -32,6 +33,7 @@ type AppTestSuite struct {
Ctx sdk.Context
QueryHelper *baseapp.QueryServiceTestHelper
TestAccs []sdk.AccAddress
TestAccPrivs []cryptotypes.PrivKey
EncodingConfig appparams.EncodingConfig
}

Expand Down Expand Up @@ -80,7 +82,9 @@ func (s *AppTestSuite) Setup() {

s.App.Keepers.DistrKeeper.SetFeePool(s.Ctx, distrtypes.InitialFeePool())

s.TestAccs = s.CreateRandomAccounts(3)
testAccounts, privKeys := s.CreateRandomAccounts(3)
s.TestAccs = testAccounts
s.TestAccPrivs = privKeys
}

func (s *AppTestSuite) AssertEventEmitted(ctx sdk.Context, eventTypeExpected string, numEventsExpected int) {
Expand All @@ -96,17 +100,20 @@ func (s *AppTestSuite) AssertEventEmitted(ctx sdk.Context, eventTypeExpected str
}

// CreateRandomAccounts is a function return a list of randomly generated AccAddresses
func (s *AppTestSuite) CreateRandomAccounts(numAccts int) []sdk.AccAddress {
func (s *AppTestSuite) CreateRandomAccounts(numAccts int) ([]sdk.AccAddress, []cryptotypes.PrivKey) {
testAddrs := make([]sdk.AccAddress, numAccts)
testPrivKeys := make([]cryptotypes.PrivKey, numAccts)
for i := 0; i < numAccts; i++ {
pk := ed25519.GenPrivKey().PubKey()
priv := secp256k1.GenPrivKey()
pk := priv.PubKey()
testAddrs[i] = sdk.AccAddress(pk.Address())
testPrivKeys[i] = priv

err := s.FundAcc(testAddrs[i], sdk.NewCoins(sdk.NewInt64Coin("uluna", 100000000)))
s.Require().NoError(err)
}

return testAddrs
return testAddrs, testPrivKeys
}

// FundAcc funds target address with specified amount.
Expand Down
104 changes: 104 additions & 0 deletions x/smartaccount/ante/pretransaction.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package ante

import (
"encoding/json"

sdkerrors "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrortypes "github.com/cosmos/cosmos-sdk/types/errors"
tx2 "github.com/cosmos/cosmos-sdk/types/tx"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"

wasmvmtypes "github.com/CosmWasm/wasmvm/types"
smartaccounttypes "github.com/terra-money/core/v2/x/smartaccount/types"
)

// SmartAccountCheckDecorator does authentication for smart accounts
type PreTransactionHookDecorator struct {
smartaccountKeeper SmartAccountKeeper
wasmKeeper WasmKeeper
}

func NewPreTransactionHookDecorator(sak SmartAccountKeeper, wk WasmKeeper) PreTransactionHookDecorator {
return PreTransactionHookDecorator{
smartaccountKeeper: sak,
wasmKeeper: wk,
}
}

// AnteHandle checks if the tx provides sufficient fee to cover the required fee from the fee market.
func (pth PreTransactionHookDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
setting, ok := ctx.Value(smartaccounttypes.ModuleName).(smartaccounttypes.Setting)
if !ok {
return next(ctx, tx, simulate)
}

if setting.PreTransaction != nil && len(setting.PreTransaction) > 0 {
for _, preTx := range setting.PreTransaction {
contractAddr, err := sdk.AccAddressFromBech32(preTx)
if err != nil {
return ctx, err
}
data, err := BuildPreTransactionHookMsg(tx)
if err != nil {
return ctx, err
}
_, err = pth.wasmKeeper.Sudo(ctx, contractAddr, data)
if err != nil {
return ctx, err
}
}
}

return next(ctx, tx, simulate)
}

// TODO: to refactor
func BuildPreTransactionHookMsg(tx sdk.Tx) ([]byte, error) {
sigTx, ok := tx.(authsigning.SigVerifiableTx)
if !ok {
return nil, sdkerrors.Wrap(sdkerrortypes.ErrInvalidType, "expected SigVerifiableTx")
}

// Signer here is the account that the state transition is affecting
// e.g. Account that is transferring some Coins
signers := sigTx.GetSigners()
// Current only supports one signer (TODO review in the future)
if len(signers) != 1 {
return nil, sdkerrors.Wrap(sdkerrortypes.ErrorInvalidSigner, "only one signer is supported")
}

// Sender here is the account that signed the transaction
// Could be different from the account above (confusingly named signer)
signatures, _ := sigTx.GetSignaturesV2()
if len(signatures) == 0 {
return nil, sdkerrors.Wrap(sdkerrortypes.ErrNoSignatures, "no signatures found")
}
senderAddr, err := sdk.AccAddressFromHexUnsafe(signatures[0].PubKey.Address().String())
if err != nil {
return nil, err
}

msgs := sigTx.GetMsgs()
anyMsgs, err := tx2.SetMsgs(msgs)
if err != nil {
return nil, err
}
var stargateMsgs []wasmvmtypes.CosmosMsg
for _, msg := range anyMsgs {
stargateMsg := wasmvmtypes.StargateMsg{
TypeURL: msg.TypeUrl,
Value: msg.Value,
}
stargateMsgs = append(stargateMsgs, wasmvmtypes.CosmosMsg{
Stargate: &stargateMsg,
})
}
preTx := smartaccounttypes.PreTransaction{
Sender: senderAddr.String(),
Account: signers[0].String(),
Messages: stargateMsgs,
}
msg := smartaccounttypes.SudoMsg{PreTransaction: &preTx}
return json.Marshal(msg)
}
1 change: 1 addition & 0 deletions x/smartaccount/ante/smartaccount_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ func (sad SmartAccountAuthDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simu
return ctx, err
}

ctx = ctx.WithValue(types.ModuleName, setting)
if setting.Authorization != nil && len(setting.Authorization) > 0 {
for _, auth := range setting.Authorization {
// TODO: add code that calls authorization on contracts
Expand Down
42 changes: 0 additions & 42 deletions x/smartaccount/ante/smartaccount_pretx.go

This file was deleted.

55 changes: 55 additions & 0 deletions x/smartaccount/ante/tests/ante_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package tests

import (
wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/tx"
sdk "github.com/cosmos/cosmos-sdk/types"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/terra-money/core/v2/x/smartaccount/ante"
"github.com/terra-money/core/v2/x/smartaccount/test_helpers"
"testing"
)

type AnteTestSuite struct {
test_helpers.SmartAccountTestSuite

Decorator ante.PreTransactionHookDecorator
WasmKeeper *wasmkeeper.PermissionedKeeper
}

func TestAnteSuite(t *testing.T) {
suite.Run(t, new(AnteTestSuite))
}

func (s *AnteTestSuite) Setup() {
s.SmartAccountTestSuite.Setup()
s.WasmKeeper = wasmkeeper.NewDefaultPermissionKeeper(s.App.Keepers.WasmKeeper)
s.Decorator = ante.NewPreTransactionHookDecorator(s.SmartAccountKeeper, s.WasmKeeper)
}

func (s *AnteTestSuite) BuildDefaultMsgTx(accountIndex int, msgs ...sdk.Msg) client.TxBuilder {
pk := s.TestAccPrivs[accountIndex]
txBuilder := s.EncodingConfig.TxConfig.NewTxBuilder()
err := txBuilder.SetMsgs(
msgs...,
)
require.NoError(s.T(), err)
signer := authsigning.SignerData{
ChainID: "test",
AccountNumber: 0,
Sequence: 0,
}
sig, err := tx.SignWithPrivKey(
s.EncodingConfig.TxConfig.SignModeHandler().DefaultMode(),
signer,
txBuilder,
pk,
s.EncodingConfig.TxConfig,
0,
)
txBuilder.SetSignatures(sig)
return txBuilder
}
89 changes: 89 additions & 0 deletions x/smartaccount/ante/tests/pretransaction_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package tests

import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/bank/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/stretchr/testify/require"
"github.com/terra-money/core/v2/x/smartaccount/test_helpers"
smartaccounttypes "github.com/terra-money/core/v2/x/smartaccount/types"
)

func (s *AnteTestSuite) TestPreTransactionHookWithoutSmartAccount() {
s.Setup()
txBuilder := s.BuildDefaultMsgTx(0, &types.MsgSend{
FromAddress: s.TestAccs[0].String(),
ToAddress: s.TestAccs[1].String(),
Amount: sdk.NewCoins(sdk.NewInt64Coin("uluna", 100000000)),
})
_, err := s.Decorator.AnteHandle(s.Ctx, txBuilder.GetTx(), false, sdk.ChainAnteDecorators(sdk.Terminator{}))
require.NoError(s.T(), err)
}

func (s *AnteTestSuite) TestPreTransactionHookWithEmptySmartAccount() {
s.Setup()
s.Ctx = s.Ctx.WithValue(smartaccounttypes.ModuleName, smartaccounttypes.Setting{})
txBuilder := s.BuildDefaultMsgTx(0, &types.MsgSend{
FromAddress: s.TestAccs[0].String(),
ToAddress: s.TestAccs[1].String(),
Amount: sdk.NewCoins(sdk.NewInt64Coin("uluna", 100000000)),
})
_, err := s.Decorator.AnteHandle(s.Ctx, txBuilder.GetTx(), false, sdk.ChainAnteDecorators(sdk.Terminator{}))
require.NoError(s.T(), err)
}

func (s *AnteTestSuite) TestInvalidContractAddress() {
s.Setup()
s.Ctx = s.Ctx.WithValue(smartaccounttypes.ModuleName, smartaccounttypes.Setting{
PreTransaction: []string{s.TestAccs[0].String()},
})
txBuilder := s.BuildDefaultMsgTx(0, &types.MsgSend{
FromAddress: s.TestAccs[0].String(),
ToAddress: s.TestAccs[1].String(),
Amount: sdk.NewCoins(sdk.NewInt64Coin("uluna", 100000000)),
})
_, err := s.Decorator.AnteHandle(s.Ctx, txBuilder.GetTx(), false, sdk.ChainAnteDecorators(sdk.Terminator{}))
require.ErrorContainsf(s.T(), err, "no such contract", "error message: %s", err)
}

func (s *AnteTestSuite) TestSendCoinsWithLimitSendHook() {
s.Setup()

acc := s.TestAccs[0]
codeId, _, err := s.WasmKeeper.Create(s.Ctx, acc, test_helpers.LimitSendOnlyHookWasm, nil)
require.NoError(s.T(), err)
contractAddr, _, err := s.WasmKeeper.Instantiate(s.Ctx, codeId, acc, acc, []byte("{}"), "limit send", sdk.NewCoins())
require.NoError(s.T(), err)

s.Ctx = s.Ctx.WithValue(smartaccounttypes.ModuleName, smartaccounttypes.Setting{
PreTransaction: []string{contractAddr.String()},
})
txBuilder := s.BuildDefaultMsgTx(0, &types.MsgSend{
FromAddress: acc.String(),
ToAddress: acc.String(),
Amount: sdk.NewCoins(sdk.NewInt64Coin("uluna", 100000000)),
})
_, err = s.Decorator.AnteHandle(s.Ctx, txBuilder.GetTx(), false, sdk.ChainAnteDecorators(sdk.Terminator{}))
require.NoError(s.T(), err)
}

func (s *AnteTestSuite) TestStakingWithLimitSendHook() {
s.Setup()

acc := s.TestAccs[0]
codeId, _, err := s.WasmKeeper.Create(s.Ctx, acc, test_helpers.LimitSendOnlyHookWasm, nil)
require.NoError(s.T(), err)
contractAddr, _, err := s.WasmKeeper.Instantiate(s.Ctx, codeId, acc, acc, []byte("{}"), "limit send", sdk.NewCoins())
require.NoError(s.T(), err)

s.Ctx = s.Ctx.WithValue(smartaccounttypes.ModuleName, smartaccounttypes.Setting{
PreTransaction: []string{contractAddr.String()},
})
txBuilder := s.BuildDefaultMsgTx(0, &stakingtypes.MsgDelegate{
DelegatorAddress: acc.String(),
ValidatorAddress: acc.String(),
Amount: sdk.NewInt64Coin("uluna", 100000000),
})
_, err = s.Decorator.AnteHandle(s.Ctx, txBuilder.GetTx(), false, sdk.ChainAnteDecorators(sdk.Terminator{}))
require.ErrorContainsf(s.T(), err, "Unauthorized message type", "error message: %s", err)
}
Loading