Skip to content

Commit

Permalink
Merge pull request #222 from binance-chain/develop
Browse files Browse the repository at this point in the history
validate minitoken send
  • Loading branch information
EnderCrypto authored Jun 1, 2020
2 parents 67556cb + 50b41a5 commit 70b4386
Show file tree
Hide file tree
Showing 9 changed files with 218 additions and 5 deletions.
2 changes: 1 addition & 1 deletion client/lcd/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ func startLCD(logger log.Logger, listenAddr string, cdc *codec.Codec) (net.Liste
return nil, err
}

go tmrpc.StartHTTPServer(listener, createHandler(cdc), logger, &tmrpc.Config{})
go tmrpc.StartHTTPServer(listener, createHandler(cdc), logger, tmrpc.DefaultConfig())
return listener, nil
}

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ require (

replace (
github.com/tendermint/go-amino => github.com/binance-chain/bnc-go-amino v0.14.1-binance.2
github.com/tendermint/iavl => github.com/binance-chain/bnc-tendermint-iavl v0.12.0-binance.3
github.com/tendermint/iavl => github.com/binance-chain/bnc-tendermint-iavl v0.12.0-binance.4
github.com/tendermint/tendermint => github.com/binance-chain/bnc-tendermint v0.32.3-binance.1
github.com/zondax/ledger-cosmos-go => github.com/binance-chain/ledger-cosmos-go v0.9.9-binance.3
golang.org/x/crypto => github.com/tendermint/crypto v0.0.0-20190823143015-45b1026d81ae
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ github.com/binance-chain/bnc-go-amino v0.14.1-binance.2 h1:XcbcfisVItk92UKoGbtNT
github.com/binance-chain/bnc-go-amino v0.14.1-binance.2/go.mod h1:yaElUUxWtv/TC/ldGtlKAvS1vKwokxgJ1d97I+6is80=
github.com/binance-chain/bnc-tendermint v0.32.3-binance.1 h1:LDGvORYLSwsTEQM0W7yrbdgjrAZxQDe18WUTLNuFOEc=
github.com/binance-chain/bnc-tendermint v0.32.3-binance.1/go.mod h1:kN5dNxE8voFtDqx2HjbM8sBIH5cUuMtLg0XEHjqzUiY=
github.com/binance-chain/bnc-tendermint-iavl v0.12.0-binance.3 h1:OyTJet9aGz+c2WKpTf5cAvJNiQeqVFYP4AV9cPpro2M=
github.com/binance-chain/bnc-tendermint-iavl v0.12.0-binance.3/go.mod h1:Zmh8GRdNJB8DULIOBar3JCZp6tSpcvM1NGKfE9U2EzA=
github.com/binance-chain/bnc-tendermint-iavl v0.12.0-binance.4 h1:BhaV2iiGWfRC6iB8HHOYJeUDwtQMB2pUA4ah+KCbBhI=
github.com/binance-chain/bnc-tendermint-iavl v0.12.0-binance.4/go.mod h1:Zmh8GRdNJB8DULIOBar3JCZp6tSpcvM1NGKfE9U2EzA=
github.com/binance-chain/ledger-cosmos-go v0.9.9-binance.3 h1:FFpFbkzlP2HUyxQCm0eoU6mkfgMNynfqZRbeWqlaLdQ=
github.com/binance-chain/ledger-cosmos-go v0.9.9-binance.3/go.mod h1:TULULYTvPuWBxFIZFy6KjJaxJzbHeUderYNB1YhD6N0=
github.com/binance-chain/tss v0.1.2 h1:AyTedSG5HG/WAvM9PDPWjTXQ+dvNdHg3x1c+1a584PQ=
Expand Down
1 change: 1 addition & 0 deletions types/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import "fmt"
var UpgradeMgr = NewUpgradeManager(UpgradeConfig{})

const FixSignBytesOverflow = "FixSignBytesOverflow" // fix json unmarshal overflow when build SignBytes
const BEP8 = "BEP8" // Mini-BEP2 token

var MainNetConfig = UpgradeConfig{
HeightMap: map[string]int64{},
Expand Down
9 changes: 9 additions & 0 deletions x/bank/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@ func handleMsgSend(ctx sdk.Context, k Keeper, msg MsgSend) sdk.Result {
return err.Result()
}
}

if sdk.IsUpgrade(sdk.BEP8) {
am := k.GetAccountKeeper()
for _, in := range msg.Inputs {
if err := checkAndValidateMiniTokenCoins(ctx, am, in.Address, in.Coins); err != nil {
return err.Result()
}
}
}
// NOTE: totalIn == totalOut should already have been checked
tags, err := k.InputOutputCoins(ctx, msg.Inputs, msg.Outputs)
if err != nil {
Expand Down
124 changes: 124 additions & 0 deletions x/bank/handler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package bank

import (
"github.com/stretchr/testify/require"
"testing"

abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"

"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
)

func setup() (sdk.Context, sdk.Handler, BaseKeeper, auth.AccountKeeper) {
ms, authKey := setupMultiStore()

cdc := codec.New()
auth.RegisterBaseAccount(cdc)
accountCache := getAccountCache(cdc, ms, authKey)

ctx := sdk.NewContext(ms, abci.Header{}, sdk.RunTxModeDeliver, log.NewNopLogger()).WithAccountCache(accountCache)
accountKeeper := auth.NewAccountKeeper(cdc, authKey, auth.ProtoBaseAccount)
bankKeeper := NewBaseKeeper(accountKeeper)
handler := NewHandler(bankKeeper)
sdk.UpgradeMgr.AddUpgradeHeight(sdk.BEP8, int64(-1))
return ctx, handler, bankKeeper, accountKeeper
}

func TestHandleSendToken(t *testing.T) {
ctx, handler, bankKeeper, accountKeeper := setup()

ctx = ctx.WithValue(baseapp.TxHashKey, "000")
addr := sdk.AccAddress([]byte("addr1"))
addr2 := sdk.AccAddress([]byte("addr2"))
acc := accountKeeper.NewAccountWithAddress(ctx, addr)
acc2 := accountKeeper.NewAccountWithAddress(ctx, addr2)

accountKeeper.SetAccount(ctx, acc)
require.True(t, bankKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{}))

//transfer BEP2 token Successfully
bankKeeper.SetCoins(ctx, addr, sdk.Coins{sdk.NewCoin("NNB-000", 100)})

msg := createSendMsg(acc.GetAddress(), acc2.GetAddress(), sdk.Coins{sdk.NewCoin("NNB-000", 60)})
sdkResult := handler(ctx, msg)
require.Equal(t, true, sdkResult.Code.IsOK())
require.True(t, bankKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("NNB-000", 40)}))
require.True(t, bankKeeper.GetCoins(ctx, addr2).IsEqual(sdk.Coins{sdk.NewCoin("NNB-000", 60)}))
}

func TestHandleSendMiniToken(t *testing.T) {
ctx, handler, bankKeeper, accountKeeper := setup()

ctx = ctx.WithValue(baseapp.TxHashKey, "000")
addr := sdk.AccAddress([]byte("addr1"))
addr2 := sdk.AccAddress([]byte("addr2"))
addr3 := sdk.AccAddress([]byte("addr3"))
acc := accountKeeper.NewAccountWithAddress(ctx, addr)
acc2 := accountKeeper.NewAccountWithAddress(ctx, addr2)

accountKeeper.SetAccount(ctx, acc)
require.True(t, bankKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{}))

//Transfer Mini token
//Fail to Transfer with value < 1e8
MiniTokenFoo := "foocoin-000M"
bankKeeper.SetCoins(ctx, addr, sdk.Coins{sdk.NewCoin(MiniTokenFoo, 10e8)})
msg := createSendMsg(acc.GetAddress(), acc2.GetAddress(), sdk.Coins{sdk.NewCoin(MiniTokenFoo, 2)})
sdkResult := handler(ctx, msg)
require.Equal(t, false, sdkResult.Code.IsOK())
require.Contains(t, sdkResult.Log, "transfer amount is too small")

//Success with amount >= 1e8
msg = createSendMsg(acc.GetAddress(), acc2.GetAddress(), sdk.Coins{sdk.NewCoin(MiniTokenFoo, 1e8)})
sdkResult = handler(ctx, msg)
require.Equal(t, true, sdkResult.Code.IsOK())
require.True(t, bankKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin(MiniTokenFoo, 9e8)}))
require.True(t, bankKeeper.GetCoins(ctx, addr2).IsEqual(sdk.Coins{sdk.NewCoin(MiniTokenFoo, 1e8)}))

//Fail to Multisend
MiniTokenBar := "barcoin-000M"
bankKeeper.SetCoins(ctx, addr2, sdk.Coins{sdk.NewCoin(MiniTokenBar, 10), sdk.NewCoin(MiniTokenFoo, 1e8)})

inputs := []Input{
NewInput(addr, sdk.Coins{sdk.NewCoin(MiniTokenFoo, 3e8)}),
NewInput(addr2, sdk.Coins{sdk.NewCoin(MiniTokenBar, 3), sdk.NewCoin(MiniTokenFoo, 1e8)}),
}

outputs := []Output{
NewOutput(addr, sdk.Coins{sdk.NewCoin(MiniTokenBar, 1)}),
NewOutput(addr3, sdk.Coins{sdk.NewCoin(MiniTokenBar, 2), sdk.NewCoin(MiniTokenFoo, 4e8)}),
}
msg = NewMsgSend(inputs, outputs)
sdkResult = handler(ctx, msg)
require.Equal(t, false, sdkResult.Code.IsOK())
require.Contains(t, sdkResult.Log, "transfer amount is too small")

//
//Success with all balance
inputs = []Input{
NewInput(addr, sdk.Coins{sdk.NewCoin(MiniTokenFoo, 3e8)}),
NewInput(addr2, sdk.Coins{sdk.NewCoin(MiniTokenBar, 10), sdk.NewCoin(MiniTokenFoo, 1e8)}),
}

outputs = []Output{
NewOutput(addr, sdk.Coins{sdk.NewCoin(MiniTokenBar, 4)}),
NewOutput(addr3, sdk.Coins{sdk.NewCoin(MiniTokenBar, 6), sdk.NewCoin(MiniTokenFoo, 4e8)}),
}
msg = NewMsgSend(inputs, outputs)
sdkResult = handler(ctx, msg)
require.Equal(t, true, sdkResult.Code.IsOK())
require.True(t, bankKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin(MiniTokenBar, 4), sdk.NewCoin(MiniTokenFoo, 6e8)}))
require.True(t, bankKeeper.GetCoins(ctx, addr2).IsEqual(sdk.Coins{}))
require.True(t, bankKeeper.GetCoins(ctx, addr3).IsEqual(sdk.Coins{sdk.NewCoin(MiniTokenBar, 6), sdk.NewCoin(MiniTokenFoo, 4e8)}))
}

func createSendMsg(from sdk.AccAddress, to sdk.AccAddress, coins sdk.Coins) sdk.Msg {
input := NewInput(from, coins)
output := NewOutput(to, coins)
msg := NewMsgSend([]Input{input}, []Output{output})
return msg
}
5 changes: 5 additions & 0 deletions x/bank/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type Keeper interface {
SetCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) sdk.Error
SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Tags, sdk.Error)
AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Tags, sdk.Error)
GetAccountKeeper() auth.AccountKeeper
}

var _ Keeper = (*BaseKeeper)(nil)
Expand Down Expand Up @@ -52,6 +53,10 @@ func (keeper BaseKeeper) SubtractCoins(
return subtractCoins(ctx, keeper.am, addr, amt)
}

func (keeper BaseKeeper) GetAccountKeeper() auth.AccountKeeper {
return keeper.am
}

// AddCoins adds amt to the coins at the addr.
func (keeper BaseKeeper) AddCoins(
ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins,
Expand Down
2 changes: 1 addition & 1 deletion x/bank/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"

codec "github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/store"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
Expand Down
74 changes: 74 additions & 0 deletions x/bank/mini_token_helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package bank

import (
"fmt"
"strings"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
)

const (
MiniTokenSymbolSuffixLen = 4 // probably enough. if it collides (unlikely) the issuer can just use another tx.
MiniTokenSymbolMSuffix = "M"
MiniTokenMinExecutionAmount int64 = 100000000 // 1 with 8 decimal digits
)

func checkAndValidateMiniTokenCoins(ctx sdk.Context, am auth.AccountKeeper, addr sdk.AccAddress, coins sdk.Coins) sdk.Error {
var err sdk.Error
for _, coin := range coins {
if isMiniTokenSymbol(coin.Denom) {
err = validateMiniTokenAmount(ctx, am, addr, coin)
}
if err != nil {
return err
}
}
return nil
}

func isMiniTokenSymbol(symbol string) bool {
parts, err := splitSuffixedTokenSymbol(symbol)
if err != nil {
return false
}
suffixPart := parts[1]

return len(suffixPart) == MiniTokenSymbolSuffixLen && strings.HasSuffix(suffixPart, MiniTokenSymbolMSuffix)
}

func validateMiniTokenAmount(ctx sdk.Context, am auth.AccountKeeper, addr sdk.AccAddress, coin sdk.Coin) sdk.Error {
if MiniTokenMinExecutionAmount <= coin.Amount {
return nil
}

coins := getCoins(ctx, am, addr)
balance := coins.AmountOf(coin.Denom)
if balance < coin.Amount {
return sdk.ErrInsufficientCoins("not enough token to send")
}

useAllBalance := balance == coin.Amount

if !useAllBalance {
return sdk.ErrInvalidCoins(fmt.Sprintf("transfer amount is too small, the min amount is %d or total account balance",
MiniTokenMinExecutionAmount))
}

return nil
}

func splitSuffixedTokenSymbol(suffixed string) ([]string, error) {

split := strings.SplitN(suffixed, "-", 2)

if len(split) != 2 {
return nil, fmt.Errorf("suffixed token symbol must contain a hyphen ('-')")
}

if strings.Contains(split[1], "-") {
return nil, fmt.Errorf("suffixed token symbol must contain just one hyphen ('-')")
}

return split, nil
}

0 comments on commit 70b4386

Please sign in to comment.