Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BEP70 - Support busd pair listing and trading #710

Merged
merged 13 commits into from
Apr 27, 2020
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,9 @@ vendor
*.swp
.vscode/*.json

# Test generate tmp files
app/data
app/apptest/data
app_test/data
plugins/param/data
plugins/tokens/data
7 changes: 6 additions & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ type BinanceChain struct {
publicationConfig *config.PublicationConfig
publisher pub.MarketDataPublisher

dexConfig *config.DexConfig

// Unlike tendermint, we don't need implement a no-op metrics, usage of this field should
// check nil-ness to know whether metrics collection is turn on
// TODO(#246): make it an aggregated wrapper of all component metrics (i.e. DexKeeper, StakeKeeper)
Expand All @@ -119,6 +121,7 @@ func NewBinanceChain(logger log.Logger, db dbm.DB, traceStore io.Writer, baseApp
upgradeConfig: ServerContext.UpgradeConfig,
abciQueryBlackList: getABCIQueryBlackList(ServerContext.QueryConfig),
publicationConfig: ServerContext.PublicationConfig,
dexConfig: ServerContext.DexConfig,
}
// set upgrade config
SetUpgradeConfig(app.upgradeConfig)
Expand Down Expand Up @@ -263,6 +266,7 @@ func SetUpgradeConfig(upgradeConfig *config.UpgradeConfig) {
upgrade.Mgr.AddUpgradeHeight(upgrade.LotSizeOptimization, upgradeConfig.LotSizeUpgradeHeight)
upgrade.Mgr.AddUpgradeHeight(upgrade.ListingRuleUpgrade, upgradeConfig.ListingRuleUpgradeHeight)
upgrade.Mgr.AddUpgradeHeight(upgrade.FixZeroBalance, upgradeConfig.FixZeroBalanceHeight)
upgrade.Mgr.AddUpgradeHeight(upgrade.BEP70, upgradeConfig.BEP70Height)

// register store keys of upgrade
upgrade.Mgr.RegisterStoreKeys(upgrade.BEP9, common.TimeLockStoreKey.Name())
Expand Down Expand Up @@ -302,7 +306,8 @@ func (app *BinanceChain) initRunningMode() {

func (app *BinanceChain) initDex(pairMapper dex.TradingPairMapper) {
app.DexKeeper = dex.NewOrderKeeper(common.DexStoreKey, app.AccountKeeper, pairMapper,
app.RegisterCodespace(dex.DefaultCodespace), app.baseConfig.OrderKeeperConcurrency, app.Codec,
app.RegisterCodespace(dex.DefaultCodespace), app.baseConfig.OrderKeeperConcurrency,
app.dexConfig.BUSDSymbol, app.Codec,
app.publicationConfig.ShouldPublishAny())
app.DexKeeper.SubscribeParamChange(app.ParamHub)

Expand Down
25 changes: 23 additions & 2 deletions app/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ BEP6Height = {{ .UpgradeConfig.BEP6Height }}
BEP9Height = {{ .UpgradeConfig.BEP9Height }}
# Block height of BEP10 upgrade
BEP10Height = {{ .UpgradeConfig.BEP10Height }}
# Block height of BEP19Height upgrade
# Block height of BEP19 upgrade
BEP19Height = {{ .UpgradeConfig.BEP19Height }}
# Block height of BEP12 upgrade
BEP12Height = {{ .UpgradeConfig.BEP12Height }}
Expand All @@ -67,6 +67,8 @@ LotSizeUpgradeHeight = {{ .UpgradeConfig.LotSizeUpgradeHeight }}
ListingRuleUpgradeHeight = {{ .UpgradeConfig.ListingRuleUpgradeHeight }}
# Block height of FixZeroBalanceHeight upgrade
FixZeroBalanceHeight = {{ .UpgradeConfig.FixZeroBalanceHeight }}
# Block height to BEP70 upgrade
BEP70Height = {{ .UpgradeConfig.BEP70Height }}

[query]
# ABCI query interface black list, suggested value: ["custom/gov/proposals", "custom/timelock/timelocks", "custom/atomicSwap/swapcreator", "custom/atomicSwap/swaprecipient"]
Expand Down Expand Up @@ -152,6 +154,10 @@ logFileRoot = "{{ .LogConfig.LogFileRoot }}"
logFilePath = "{{ .LogConfig.LogFilePath }}"
# Number of logs keep in memory before writing to file
logBuffSize = {{ .LogConfig.LogBuffSize }}

[dex]
# The suffixed symbol of BUSD
BUSDSymbol = "{{ .DexConfig.BUSDSymbol }}"
`

type BinanceChainContext struct {
Expand All @@ -178,6 +184,7 @@ type BinanceChainConfig struct {
*BaseConfig `mapstructure:"base"`
*UpgradeConfig `mapstructure:"upgrade"`
*QueryConfig `mapstructure:"query"`
*DexConfig `mapstructure:"dex"`
}

func DefaultBinanceChainConfig() *BinanceChainConfig {
Expand All @@ -188,6 +195,7 @@ func DefaultBinanceChainConfig() *BinanceChainConfig {
BaseConfig: defaultBaseConfig(),
UpgradeConfig: defaultUpgradeConfig(),
QueryConfig: defaultQueryConfig(),
DexConfig: defaultGovConfig(),
}
}

Expand Down Expand Up @@ -358,7 +366,9 @@ type UpgradeConfig struct {
// Hubble Upgrade
BEP12Height int64 `mapstructure:"BEP12Height"`
// Archimedes Upgrade
BEP3Height int64 `mapstructure:"BEP3Height"`
BEP3Height int64 `mapstructure:"BEP3Height"`
BEP70Height int64 `mapstructure:"BEP70Height"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you put the config after bep67, we group these configs by upgrade name


// TODO: add upgrade name
FixSignBytesOverflowHeight int64 `mapstructure:"FixSignBytesOverflowHeight"`
LotSizeUpgradeHeight int64 `mapstructure:"LotSizeUpgradeHeight"`
Expand All @@ -375,6 +385,7 @@ func defaultUpgradeConfig() *UpgradeConfig {
BEP19Height: 1,
BEP12Height: 1,
BEP3Height: 1,
BEP70Height: 1,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

FixSignBytesOverflowHeight: math.MaxInt64,
LotSizeUpgradeHeight: math.MaxInt64,
ListingRuleUpgradeHeight: math.MaxInt64,
Expand All @@ -392,6 +403,16 @@ func defaultQueryConfig() *QueryConfig {
}
}

type DexConfig struct {
BUSDSymbol string `mapstructure:"BUSDSymbol"`
}

func defaultGovConfig() *DexConfig {
return &DexConfig{
BUSDSymbol: "",
}
}

func (context *BinanceChainContext) ParseAppConfigInPlace() error {
// this piece of code should be consistent with bindFlagsLoadViper
// vendor/github.com/tendermint/tendermint/libs/cli/setup.go:125
Expand Down
2 changes: 1 addition & 1 deletion app/pub/keeper_pub_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func setupKeeperTest(t *testing.T) (*assert.Assertions, *require.Assertions) {
ctx = sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, sdk.RunTxModeDeliver, logger).WithAccountCache(accountCache)

pairMapper := store.NewTradingPairMapper(cdc, common.PairStoreKey)
keeper = orderPkg.NewKeeper(capKey2, am, pairMapper, sdk.NewCodespacer().RegisterNext(dextypes.DefaultCodespace), 2, cdc, true)
keeper = orderPkg.NewKeeper(capKey2, am, pairMapper, sdk.NewCodespacer().RegisterNext(dextypes.DefaultCodespace), 2, "", cdc, true)
tradingPair := dextypes.NewTradingPair("XYZ-000", types.NativeTokenSymbol, 1e8)
keeper.PairMapper.AddTradingPair(ctx, tradingPair)
keeper.AddEngine(tradingPair)
Expand Down
3 changes: 3 additions & 0 deletions common/upgrade/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ const (
BEP12 = "BEP12" // https://github.com/binance-chain/BEPs/pull/17
// Archimedes Upgrade
BEP3 = "BEP3" // https://github.com/binance-chain/BEPs/pull/30
// BUSD Pair Upgrade
BEP70 = "BEP70" // supporting listing and trading BUSD pairs
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed


// TODO: add upgrade name
FixSignBytesOverflow = sdk.FixSignBytesOverflow
LotSizeOptimization = "LotSizeOptimization"
Expand Down
2 changes: 1 addition & 1 deletion plugins/dex/list/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func MakeKeepers(cdc *codec.Codec) (ms sdkStore.CommitMultiStore, orderKeeper *o
codespacer := sdk.NewCodespacer()
pairMapper := store.NewTradingPairMapper(cdc, pairKey)
orderKeeper = order.NewKeeper(common.DexStoreKey, accKeeper, pairMapper,
codespacer.RegisterNext(dexTypes.DefaultCodespace), 2, cdc, false)
codespacer.RegisterNext(dexTypes.DefaultCodespace), 2, "", cdc, false)

tokenMapper = tokenStore.NewMapper(cdc, tokenKey)

Expand Down
132 changes: 91 additions & 41 deletions plugins/dex/order/fee.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"math"
"math/big"

"github.com/binance-chain/node/common/upgrade"

sdk "github.com/cosmos/cosmos-sdk/types"

tmlog "github.com/tendermint/tendermint/libs/log"
Expand Down Expand Up @@ -42,16 +44,18 @@ var (
)

type FeeManager struct {
cdc *wire.Codec
logger tmlog.Logger
FeeConfig FeeConfig
cdc *wire.Codec
logger tmlog.Logger
FeeConfig FeeConfig
BUSDSymbol string
}

func NewFeeManager(cdc *wire.Codec, storeKey sdk.StoreKey, logger tmlog.Logger) *FeeManager {
func NewFeeManager(cdc *wire.Codec, storeKey sdk.StoreKey, busdSymbol string, logger tmlog.Logger) *FeeManager {
return &FeeManager{
cdc: cdc,
logger: logger,
FeeConfig: NewFeeConfig(),
cdc: cdc,
logger: logger,
FeeConfig: NewFeeConfig(),
BUSDSymbol: busdSymbol,
}
}

Expand Down Expand Up @@ -109,17 +113,7 @@ func (m *FeeManager) CalcExpiresFee(balances sdk.Coins, expireType transferEvent
func (m *FeeManager) calcTradeFeeForSingleTransfer(balances sdk.Coins, tran *Transfer, engines map[string]*matcheng.MatchEng) types.Fee {
var feeToken sdk.Coin

var nativeFee int64
var isOverflow bool
if tran.IsNativeIn() {
// always have enough balance to pay the fee.
nativeFee = m.calcTradeFee(big.NewInt(tran.in), FeeByNativeToken).Int64()
return types.NewFee(sdk.Coins{sdk.NewCoin(types.NativeTokenSymbol, nativeFee)}, types.FeeForProposer)
} else if tran.IsNativeOut() {
nativeFee, isOverflow = m.calcNativeFee(types.NativeTokenSymbol, tran.out, engines)
} else {
nativeFee, isOverflow = m.calcNativeFee(tran.inAsset, tran.in, engines)
}
nativeFee, isOverflow := m.calcNativeFee(tran, engines)

if isOverflow || nativeFee == 0 || nativeFee > balances.AmountOf(types.NativeTokenSymbol) {
// 1. if the fee is too low and round to 0, we charge by inAsset
Expand All @@ -133,33 +127,54 @@ func (m *FeeManager) calcTradeFeeForSingleTransfer(balances sdk.Coins, tran *Tra
return types.NewFee(sdk.Coins{feeToken}, types.FeeForProposer)
}

func (m *FeeManager) calcNativeFee(inSymbol string, inQty int64, engines map[string]*matcheng.MatchEng) (fee int64, isOverflow bool) {
var nativeNotional *big.Int
if isNativeToken(inSymbol) {
nativeNotional = big.NewInt(inQty)
func (m *FeeManager) calcNativeFee(tran *Transfer, engines map[string]*matcheng.MatchEng) (fee int64, isOverflow bool) {
tranNativeValue := m.calcTranValueMeasureBySymbol(types.NativeTokenSymbol, tran, engines)
nativeFee := m.calcTradeFee(tranNativeValue, FeeByNativeToken)
if nativeFee.IsInt64() {
return nativeFee.Int64(), false
}
return 0, true
}

// calculate transfer value measured by giving symbol, e.g., BNB
func (m *FeeManager) calcTranValueMeasureBySymbol(symbol string, tran *Transfer, engines map[string]*matcheng.MatchEng) *big.Int {
if symbol == tran.inAsset {
return big.NewInt(tran.in)
} else if symbol == tran.outAsset {
return big.NewInt(tran.out)
} else {
// price against native token,
// both `nativeNotional` and `feeByNativeToken` may overflow when it's a non-BNB pair like ABC_XYZ
if engine, ok := engines[utils.Assets2TradingPair(inSymbol, types.NativeTokenSymbol)]; ok {
// XYZ_BNB
nativeNotional = utils.CalBigNotional(engine.LastTradePrice, inQty)
} else {
var notional *big.Int
if engine, ok := m.getEngine(engines, tran.inAsset, symbol); ok {
// e.g., XYZ_BNB
notional = utils.CalBigNotional(engine.LastTradePrice, tran.in)
return notional
} else if engine, ok := m.getEngine(engines, symbol, tran.inAsset); ok {
// BNB_XYZ
engine := engines[utils.Assets2TradingPair(types.NativeTokenSymbol, inSymbol)]
var amount big.Int
nativeNotional = amount.Div(
notional = amount.Div(
amount.Mul(
big.NewInt(inQty),
big.NewInt(tran.in),
big.NewInt(cmnUtils.Fixed8One.ToInt64())),
big.NewInt(engine.LastTradePrice))
return notional
} else {
// for BUSD pairs, it is possible that there is no trading pair between BNB and inAsset, e.g., BUSD_XYZ
if sdk.IsUpgrade(upgrade.BEP70) {
var busdQty = big.NewInt(0)
if market, ok := m.getEngine(engines, symbol, m.BUSDSymbol); ok {
var tmp big.Int
busdQty = tmp.Div(tmp.Mul(
big.NewInt(1),
big.NewInt(cmnUtils.Fixed8One.ToInt64())),
big.NewInt(market.LastTradePrice))
} else if market, ok := m.getEngine(engines, m.BUSDSymbol, symbol); ok {
busdQty = utils.CalBigNotional(market.LastTradePrice, 1)
}
return busdQty.Mul(busdQty, m.calcTranValueMeasureBySymbol(m.BUSDSymbol, tran, engines))
}
}
}

nativeFee := m.calcTradeFee(nativeNotional, FeeByNativeToken)
if nativeFee.IsInt64() {
return nativeFee.Int64(), false
}
return 0, true
return big.NewInt(0)
}

// DEPRECATED
Expand Down Expand Up @@ -238,18 +253,47 @@ func (m *FeeManager) CalcFixedFee(balances sdk.Coins, eventType transferEventTyp
} else {
// the amount may overflow int64, so use big.Int instead.
// TODO: (perf) may remove the big.Int use to improve the performance
var amount *big.Int
if market, ok := engines[utils.Assets2TradingPair(inAsset, types.NativeTokenSymbol)]; ok {
var amount = big.NewInt(0)
if market, ok := m.getEngine(engines, inAsset, types.NativeTokenSymbol); ok {
// XYZ_BNB
var tmp big.Int
amount = tmp.Div(tmp.Mul(
big.NewInt(feeAmount),
big.NewInt(cmnUtils.Fixed8One.ToInt64())),
big.NewInt(market.LastTradePrice))
} else {
} else if market, ok := m.getEngine(engines, types.NativeTokenSymbol, inAsset); ok {
// BNB_XYZ
market = engines[utils.Assets2TradingPair(types.NativeTokenSymbol, inAsset)]
amount = utils.CalBigNotional(market.LastTradePrice, feeAmount)
} else {
// for BUSD pairs, it is possible that there is no trading pair between BNB and inAsset, e.g., BUSD -> XYZ
if sdk.IsUpgrade(upgrade.BEP70) {
var intermediateAmount = big.NewInt(0)
if market, ok := m.getEngine(engines, m.BUSDSymbol, types.NativeTokenSymbol); ok {
var tmp big.Int
intermediateAmount = tmp.Div(tmp.Mul(
big.NewInt(feeAmount),
big.NewInt(cmnUtils.Fixed8One.ToInt64())),
big.NewInt(market.LastTradePrice))
} else if market, ok := m.getEngine(engines, types.NativeTokenSymbol, m.BUSDSymbol); ok {
intermediateAmount = utils.CalBigNotional(market.LastTradePrice, feeAmount)
}

var intermediateAmountTmp int64
if intermediateAmount.IsInt64() {
intermediateAmountTmp = intermediateAmount.Int64()
} else {
intermediateAmountTmp = math.MaxInt64
}
if market, ok := m.getEngine(engines, inAsset, m.BUSDSymbol); ok {
var tmp big.Int
amount = tmp.Div(tmp.Mul(
big.NewInt(intermediateAmountTmp),
big.NewInt(cmnUtils.Fixed8One.ToInt64())),
big.NewInt(market.LastTradePrice))
} else if market, ok := m.getEngine(engines, m.BUSDSymbol, inAsset); ok {
amount = utils.CalBigNotional(market.LastTradePrice, intermediateAmountTmp)
}
}
}

if amount.IsInt64() {
Expand Down Expand Up @@ -391,3 +435,9 @@ func ParamToFeeConfig(feeParams []param.FeeParam) *FeeConfig {
}
return nil
}

// Get engine for trading pair baseAsset_quoteAsset
func (m *FeeManager) getEngine(engines map[string]*matcheng.MatchEng, baseAsset, quoteAsset string) (engine *matcheng.MatchEng, ok bool) {
engine, ok = engines[utils.Assets2TradingPair(baseAsset, quoteAsset)]
return
}
Loading