From bc140b715d1b6ddf6ed35854d9c80ff51edbaf31 Mon Sep 17 00:00:00 2001 From: Zhong Qiu <36867992+zhongqiuwood@users.noreply.github.com> Date: Tue, 3 Nov 2020 07:32:56 +0800 Subject: [PATCH] Merge PR: date back to stream framework (#363) * databack * rm-x/ammswap/client/rest/tx.go --- Makefile | 2 +- app/genesis/genesis.json | 12 +- app/protocol/protocol_v0.go | 2 +- cmd/okexchaind/rest.go | 2 + go.mod | 15 +- go.sum | 90 ++++++++- x/ammswap/client/cli/query.go | 124 +++++++++++- x/ammswap/client/cli/tx.go | 70 ++++--- x/ammswap/client/rest/query.go | 126 +++++++++++++ x/ammswap/client/rest/rest.go | 2 +- x/ammswap/client/rest/tx.go | 41 ---- x/ammswap/genesis.go | 3 +- x/ammswap/handler.go | 200 +++++++++++--------- x/ammswap/handler_test.go | 283 +++++++++++++++++++++++----- x/ammswap/keeper/keeper.go | 61 ++++++ x/ammswap/keeper/keeper_test.go | 45 ++++- x/ammswap/keeper/querier.go | 109 ++++++++++- x/ammswap/keeper/querier_test.go | 123 ++++++++++-- x/ammswap/types/codec.go | 2 +- x/ammswap/types/keys.go | 6 + x/ammswap/types/msg_test.go | 82 +++++--- x/ammswap/types/msgs.go | 109 ++++++----- x/ammswap/types/querier.go | 10 + x/ammswap/types/swap.go | 60 +++++- x/ammswap/types/test_common.go | 8 +- x/backend/abci.go | 11 +- x/backend/cache/cache.go | 2 - x/backend/cache/cache_test.go | 2 - x/backend/client/cli/query.go | 10 +- x/backend/client/rest/rest.go | 2 +- x/backend/keeper/keeper.go | 35 ++-- x/backend/keeper/keeper_channel.go | 136 ++++++------- x/backend/keeper/querier.go | 58 +++--- x/backend/keeper/querier_v2.go | 16 +- x/backend/keeper_test.go | 35 ++-- x/backend/orm/backend.db | Bin 249856 -> 249856 bytes x/backend/orm/orm.go | 93 +++++---- x/backend/orm/orm_test.go | 16 +- x/backend/types/expected_keepers.go | 6 +- x/backend/types/klines.go | 239 ++++++++++++++++------- x/backend/types/klines_test.go | 2 +- x/common/const.go | 2 + x/common/util.go | 15 ++ x/common/util_test.go | 7 + x/debug/client/cli/debug.go | 19 ++ x/debug/keeper/keeper.go | 4 +- x/debug/keeper/querier.go | 15 ++ x/debug/types/expected_keepers.go | 5 + x/debug/types/keys.go | 1 + x/dex/keeper/querier.go | 6 +- x/order/keeper/keeper.go | 9 - x/order/keeper/keeper_test.go | 2 +- x/order/keeper/memory_cache.go | 14 -- x/order/keeper/memory_cache_test.go | 9 - x/staking/client/cli/tx.go | 17 +- x/token/client/cli/tx.go | 97 ++++------ x/token/handler.go | 84 +++++++-- x/token/keeper.go | 28 ++- x/token/token_test.go | 138 ++++++++++---- x/token/types/codec.go | 1 + x/token/types/confirm_ownership.go | 16 ++ x/token/types/keys.go | 18 +- x/token/types/msgs.go | 67 ++++--- x/token/types/msgs_test.go | 17 +- x/token/types/params.go | 39 ++-- x/token/types/params_test.go | 3 + x/token/types/util.go | 9 +- x/token/types/util_test.go | 28 ++- 68 files changed, 2067 insertions(+), 853 deletions(-) create mode 100644 x/ammswap/client/rest/query.go delete mode 100644 x/ammswap/client/rest/tx.go create mode 100644 x/ammswap/types/querier.go create mode 100644 x/token/types/confirm_ownership.go diff --git a/Makefile b/Makefile index e17195a462..ac1a805e0b 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ CAT := $(if $(filter $(OS),Windows_NT),type,cat) GithubTop=github.com -Version=v0.11.1 +Version=v0.12.2 CosmosSDK=v0.37.9 Tendermint=v0.32.10 Iavl=v0.12.4 diff --git a/app/genesis/genesis.json b/app/genesis/genesis.json index d61bffb4f2..883084a971 100644 --- a/app/genesis/genesis.json +++ b/app/genesis/genesis.json @@ -115,7 +115,7 @@ "amount": [], "gas": "0" }, - "memo": "7f75cd135d02418d17d1092fe3a4ffc1c5d1aebb@127.0.0.1:26656", + "memo": "ab6f676c5d6b4e7c8233ff4ba63d1b5d0d203b56@127.0.0.1:26656", "msg": [ { "type": "okexchain/staking/MsgCreateValidator", @@ -131,7 +131,7 @@ "amount": "0.00100000", "denom": "okt" }, - "pubkey": "okexchainvalconspub1zcjduepqfcprr6x7d44wu4nt0suey3fz6pzp274486s5lua9vx7l3w3xhw2splls6m", + "pubkey": "okexchainvalconspub1zcjduepq83e8r6lrt44sxvg66vhh8l4yhpsr825m97yc7qxu06zhpxezuhhsmalm87", "validator_address": "okexchainvaloper10q0rk5qnyag7wfvvt7rtphlw589m7frshchly8" } } @@ -142,7 +142,7 @@ "type": "tendermint/PubKeySecp256k1", "value": "AgYaL1tZ7ekqvweQhKojG8sDHUfN23qJWviAsTDIWvYU" }, - "signature": "40IhUZ1h5oYh7671R7tRYVyLFwwWU+RIj6J8Qe4lf0MzxtaQ0oFDeShDJk3fKG0nx7q2zV8/hpnXPgoA2OAESQ==" + "signature": "42XTaFLh5Z2Aor2kpY5H32ReUUT6Wa5IZhkGSLMas/gvaPY4Pg5XsFPwUuFJpcj36L+E9BQOjxXhM0VF1rKV7A==" } ] } @@ -176,7 +176,6 @@ }, "mint": { "minter_custom": { - "annual_provisions": "0.00000000", "minted_per_block": [ { "amount": "0.00000000", @@ -185,9 +184,11 @@ ], "next_block_to_update": "0" }, + "original_minted_per_block": "0.05000000", "params": { "blocks_per_year": "10519200", - "inflation_rate": "0.01000000", + "deflation_rate": "0.50000000", + "inflation_epoch": "3", "mint_denom": "okt" } }, @@ -273,6 +274,7 @@ "amount": "0.00000000", "denom": "okt" }, + "ownership_confirm_window": "86400000000000", "transfer_ownership_fee": { "amount": "10.00000000", "denom": "okt" diff --git a/app/protocol/protocol_v0.go b/app/protocol/protocol_v0.go index d34093a1d8..d413cbeb34 100644 --- a/app/protocol/protocol_v0.go +++ b/app/protocol/protocol_v0.go @@ -343,7 +343,7 @@ func (p *ProtocolV0) produceKeepers() { p.upgradeKeeper = upgrade.NewKeeper( p.cdc, p.keys[upgrade.StoreKey], p.protocolKeeper, p.stakingKeeper, p.bankKeeper, upgradeSubspace, ) - p.debugKeeper = debug.NewDebugKeeper(p.cdc, p.keys[debug.StoreKey], p.orderKeeper, p.stakingKeeper, auth.FeeCollectorName, p.Stop) + p.debugKeeper = debug.NewDebugKeeper(p.cdc, p.keys[debug.StoreKey], p.orderKeeper, p.stakingKeeper, &p.crisisKeeper, auth.FeeCollectorName, p.Stop) } // moduleAccountAddrs returns all the module account addresses diff --git a/cmd/okexchaind/rest.go b/cmd/okexchaind/rest.go index 13f99e8e00..42a041bcbb 100644 --- a/cmd/okexchaind/rest.go +++ b/cmd/okexchaind/rest.go @@ -6,6 +6,7 @@ import ( authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest" bankrest "github.com/cosmos/cosmos-sdk/x/bank/client/rest" supplyrest "github.com/cosmos/cosmos-sdk/x/supply/client/rest" + ammswaprest "github.com/okex/okexchain/x/ammswap/client/rest" backendrest "github.com/okex/okexchain/x/backend/client/rest" dexrest "github.com/okex/okexchain/x/dex/client/rest" dist "github.com/okex/okexchain/x/distribution" @@ -36,6 +37,7 @@ func registerRoutesV1(rs *lcd.RestServer) { tokensrest.RegisterRoutes(rs.CliCtx, v1Router, token.ModuleName) backendrest.RegisterRoutes(rs.CliCtx, v1Router) dexrest.RegisterRoutes(rs.CliCtx, v1Router) + ammswaprest.RegisterRoutes(rs.CliCtx, v1Router) supplyrest.RegisterRoutes(rs.CliCtx, v1Router) } diff --git a/go.mod b/go.mod index acb763306e..438b7f3655 100644 --- a/go.mod +++ b/go.mod @@ -3,16 +3,22 @@ module github.com/okex/okexchain go 1.12 require ( + github.com/Comcast/pulsar-client-go v0.1.1 github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c // indirect github.com/cosmos/cosmos-sdk v0.37.8 github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d // indirect github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3 // indirect github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 // indirect + github.com/garyburd/redigo v1.6.2 github.com/go-kit/kit v0.9.0 + github.com/go-redis/redis v6.15.9+incompatible github.com/go-sql-driver/mysql v1.4.1 github.com/gofrs/uuid v3.2.0+incompatible // indirect - github.com/golang/mock v1.3.1 // indirect + github.com/gogo/protobuf v1.3.1 + github.com/golang/protobuf v1.3.2 + github.com/google/uuid v1.1.1 github.com/gorilla/mux v1.7.3 + github.com/gorilla/websocket v1.4.1 github.com/jinzhu/gorm v1.9.2 github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a // indirect github.com/jinzhu/now v1.0.0 // indirect @@ -20,10 +26,11 @@ require ( github.com/lib/pq v1.1.1 // indirect github.com/mattn/go-isatty v0.0.8 // indirect github.com/mattn/go-sqlite3 v1.10.0 // indirect + github.com/nacos-group/nacos-sdk-go v1.0.0 github.com/onsi/ginkgo v1.8.0 // indirect github.com/onsi/gomega v1.5.0 // indirect github.com/pelletier/go-toml v1.4.0 // indirect - github.com/pkg/errors v0.8.1 + github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.0.0 github.com/prometheus/common v0.6.0 // indirect github.com/prometheus/procfs v0.0.3 // indirect @@ -34,7 +41,7 @@ require ( github.com/spf13/cobra v0.0.5 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.6.1 - github.com/stretchr/testify v1.4.0 + github.com/stretchr/testify v1.5.1 github.com/tendermint/go-amino v0.15.1 github.com/tendermint/tendermint v0.32.10 github.com/tendermint/tm-db v0.2.0 @@ -46,7 +53,7 @@ require ( ) replace ( - github.com/cosmos/cosmos-sdk => github.com/okex/cosmos-sdk v0.37.9-okexchain + github.com/cosmos/cosmos-sdk => github.com/okex/cosmos-sdk v0.37.9-okexchain4 github.com/tendermint/iavl => github.com/okex/iavl v0.12.4-okexchain github.com/tendermint/tendermint => github.com/okex/tendermint v0.32.10-okexchain ) diff --git a/go.sum b/go.sum index b0f811cd9a..da2c30e9d4 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ cloud.google.com/go v0.37.4 h1:glPeL3BQJsbF6aIIYfZizMwc5LTYz250bDMjttbBGAU= cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Comcast/pulsar-client-go v0.1.1 h1:5RUXjR8tFyvOE9hOuLZdYYddS3ebzvty5YKQYBIvL/8= +github.com/Comcast/pulsar-client-go v0.1.1/go.mod h1:NltaphN/TDmAapAOKDS2V3CakxmBxe9Nli77nk1EjOM= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= @@ -13,6 +15,8 @@ github.com/Workiva/go-datastructures v1.0.50/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3 github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/aliyun/alibaba-cloud-sdk-go v1.61.18 h1:zOVTBdCKFd9JbCKz9/nt+FovbjPFmb7mUnp8nH9fQBA= +github.com/aliyun/alibaba-cloud-sdk-go v1.61.18/go.mod h1:v8ESoHo4SyHmuB4b1tJqDHxfTGEciD+yhvOU/5s1Rfk= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d h1:1aAija9gr0Hyv4KfQcRcwlmFIrhkDmIj2dz5bkg/s/8= @@ -34,15 +38,21 @@ github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVa github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23 h1:D21IyuvjDCshj1/qq+pCNd3VZOAEI9jy6Bi131YlXgI= +github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/coreos/bbolt v1.3.2 h1:wZwiHHUieZCquLkDL0B8UhzreNWsPHooDAG3q34zk0s= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0 h1:3Jm3tLmsgAYcjC+4Up7hJrFBPr+n7rAqYeSw/SZazuY= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cosmos/go-bip39 v0.0.0-20180618194314-52158e4697b8/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d h1:49RLWk1j44Xu4fjHb6JFYmeUnDORVwHNkDxaQ0ctCVU= @@ -58,6 +68,7 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3 h1:tkum0XDgfR0jcVVXuTsYv/erY2NnEDqwRojbxR1rBYA= github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= @@ -75,17 +86,26 @@ github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojt github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQDg5gKsWoLBOB0n+ZW8s599zru8FJ2/Y= github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= +github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 h1:Ghm4eQYC0nEPnSJdVkTrXpu9KtoVCSo1hg7mtI7G9KU= +github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239/go.mod h1:Gdwt2ce0yfBxPvZrHkprdPPTTS3N5rwmLE8T22KBXlw= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/garyburd/redigo v1.6.2 h1:yE/pwKCrbLpLpQICzYTeZ7JsTA/C53wFTJHaEtRqniM= +github.com/garyburd/redigo v1.6.2/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= +github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= @@ -97,8 +117,10 @@ github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -114,6 +136,7 @@ github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8l github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= @@ -123,6 +146,9 @@ github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -134,8 +160,11 @@ github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0 h1:bM6ZAFZmc/wPFaRDi0d5L7hGEZEx/2u+Tmr2evNHDiI= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -144,6 +173,8 @@ github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 h1:IPJ3dvxmJ4uczJe5YQdrYB16oTJlGSC/OyZDqUk9xX4= +github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869/go.mod h1:cJ6Cj7dQo+O6GJNiMx+Pa94qKj+TG8ONdKHgMNIyyag= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/gorm v1.9.2 h1:lCvgEaqe/HVE+tjAR2mt4HbbHAZsQOv3XAZiEZV37iw= github.com/jinzhu/gorm v1.9.2/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo= @@ -151,10 +182,14 @@ github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a h1:eeaG9XMUvRBYX github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.0.0 h1:6WV8LvwPpDhKjo5U9O6b4+xdG/jTXNPwlDme/MTo8Ns= github.com/jinzhu/now v1.0.0/go.mod h1:oHTiXerJ20+SfYcrdlBO7rzZRJWGwSTQ0iUY2jI6Gfc= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= +github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= @@ -165,6 +200,7 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -173,6 +209,12 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570 h1:0iQektZGS248WXmGIYOwRXSQhD4qn3icjMpuxwO7qlo= +github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570/go.mod h1:BLt8L9ld7wVsvEWQbuLrUZnCMnUmLZ+CGDzKtclrTlE= +github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f h1:sgUSP4zdTUZYZgAGGtN5Lxk92rK+JUFOwf+FT99EEI4= +github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f/go.mod h1:UGmTpUd3rjbtfIpwAPrcfmGf/Z1HS95TATB+m57TPB8= +github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 h1:Bvq8AziQ5jFF4BHGAEDSqwPW1NJS3XshxbRCxtjFAZc= +github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042/go.mod h1:TPpsiPUEh0zFL1Snz4crhMlBe60PYxRHr5oFF3rRYg0= github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= @@ -192,11 +234,14 @@ github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQz github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/okex/cosmos-sdk v0.37.9-okexchain h1:e0yqer6lxFwvMkvS1ebd7rSxRaByjObR3INByjNuTZI= -github.com/okex/cosmos-sdk v0.37.9-okexchain/go.mod h1:HjW0+Q5rWWm+4CaK8f5CIN/xf38vkPA2xue1PB5Nk3A= +github.com/nacos-group/nacos-sdk-go v1.0.0 h1:CufUF7DZca2ZzIrJtMMCDih1sA58BWCglArLMCZArUc= +github.com/nacos-group/nacos-sdk-go v1.0.0/go.mod h1:hlAPn3UdzlxIlSILAyOXKxjFSvDJ9oLzTJ9hLAK1KzA= +github.com/okex/cosmos-sdk v0.37.9-okexchain4 h1:q1YCAUIvHYNd+aVcPOkMOcvRcQUwGkFhKaIgmaVQ5TY= +github.com/okex/cosmos-sdk v0.37.9-okexchain4/go.mod h1:HjW0+Q5rWWm+4CaK8f5CIN/xf38vkPA2xue1PB5Nk3A= github.com/okex/iavl v0.12.4-okexchain h1:fHH/ax1CABQSNiISXIMba3V76qvNZ4HIILaewsMaMbc= github.com/okex/iavl v0.12.4-okexchain/go.mod h1:8LHakzt8/0G3/I8FUU0ReNx98S/EP6eyPJkAUvEXT/o= github.com/okex/tendermint v0.32.10-okexchain h1:fYrmdPNH5e1QGr0lzI4yuBZ6QLv52t4enfoBVAoe5rg= @@ -215,8 +260,9 @@ github.com/pelletier/go-toml v1.4.0 h1:u3Z1r+oOXJIkxqw34zVhyPgjBsm6X2wn21NWs/HfS github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -250,17 +296,21 @@ github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqn github.com/rcrowley/go-metrics v0.0.0-20190704165056-9c2d0518ed81 h1:zQTtDd7fQiF9e80lbl+ShnD9/5NSq5r1EhcS8955ECg= github.com/rcrowley/go-metrics v0.0.0-20190704165056-9c2d0518ed81/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa/go.mod h1:oJyF+mSPHbB5mVY2iO9KV3pTt/QbIkGaO8gQ2WrDbP4= +github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= @@ -286,14 +336,17 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stumble/gorocksdb v0.0.3 h1:9UU+QA1pqFYJuf9+5p7z1IqdE5k0mma4UAeu2wmX8kA= github.com/stumble/gorocksdb v0.0.3/go.mod h1:v6IHdFBXk5DJ1K4FZ0xi+eY737quiiBxYtSWXadLybY= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965 h1:1oFLiOyVl+W7bnBzGhf7BbIv9loSFQcieWWYIjLqcAw= github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= +github.com/tebeka/strftime v0.1.3 h1:5HQXOqWKYRFfNyBMNVc9z5+QzuBtIXy03psIhtdJYto= +github.com/tebeka/strftime v0.1.3/go.mod h1:7wJm3dZlpr4l/oVK0t1HYIc4rMzQ2XJlOMIUJUJH6XQ= github.com/tendermint/btcd v0.1.1 h1:0VcxPfflS2zZ3RiOAHkBiFUcPvbtRj5O7zHmcJWHV7s= github.com/tendermint/btcd v0.1.1/go.mod h1:DC6/m53jtQzr/NFmMNEu0rxf18/ktVoVtMrnDD5pN+U= github.com/tendermint/crypto v0.0.0-20180820045704-3764759f34a5 h1:u8i49c+BxloX3XQ55cvzFNXplizZP/q00i+IlttUjAU= @@ -305,11 +358,17 @@ github.com/tendermint/go-amino v0.15.1/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoM github.com/tendermint/tm-db v0.1.1/go.mod h1:0cPKWu2Mou3IlxecH+MEUSYc1Ch537alLe6CpFrKzgw= github.com/tendermint/tm-db v0.2.0 h1:rJxgdqn6fIiVJZy4zLpY1qVlyD0TU6vhkT4kEf71TQQ= github.com/tendermint/tm-db v0.2.0/go.mod h1:0cPKWu2Mou3IlxecH+MEUSYc1Ch537alLe6CpFrKzgw= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3 h1:kF/7m/ZU+0D4Jj5eZ41Zm3IH/J8OElK1Qtd7tVKAwLk= +github.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3/go.mod h1:QDlpd3qS71vYtakd2hmdpqhJ9nwv6mD6A30bQ1BPBFE= +github.com/ugorji/go v1.1.4 h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8 h1:3SVOIvH7Ae1KRYyQWRjXWJEA9sS/c/pjvH++55Gr648= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/willf/bitset v1.1.10 h1:NotGKqX0KwQ72NUzqrjZq5ipPNDQex9lo3WpaS8L2sc= github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/zondax/hid v0.9.0 h1:eiT3P6vNxAEVxXMw66eZUAAnU2zD33JBkfG/EnfAKl8= @@ -319,14 +378,23 @@ go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM= +go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -334,6 +402,9 @@ golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTk golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -346,6 +417,7 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -373,6 +445,7 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -385,6 +458,11 @@ golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= @@ -407,8 +485,10 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= @@ -424,3 +504,5 @@ honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/x/ammswap/client/cli/query.go b/x/ammswap/client/cli/query.go index f8b0406de3..d52d28881d 100644 --- a/x/ammswap/client/cli/query.go +++ b/x/ammswap/client/cli/query.go @@ -4,10 +4,11 @@ import ( "fmt" "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/version" "github.com/okex/okexchain/x/ammswap/types" "github.com/spf13/cobra" "strings" @@ -28,6 +29,9 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { flags.GetCommands( GetCmdSwapTokenPair(queryRoute, cdc), GetCmdQueryParams(queryRoute, cdc), + GetCmdAllSwapTokenPairs(queryRoute, cdc), + GetCmdRedeemableAssets(queryRoute, cdc), + GetCmdQueryBuyAmount(queryRoute, cdc), )..., ) @@ -37,25 +41,25 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { //GetCmdSwapTokenPair query exchange with token name func GetCmdSwapTokenPair(queryRoute string, cdc *codec.Codec) *cobra.Command { return &cobra.Command{ - Use: "pool-info [token]", + Use: "pool [base-token] [quote-token]", Short: "Query pool info by token name", - Long: strings.TrimSpace( + Long: strings.TrimSpace( fmt.Sprintf(`Query pool info by token name. Example: -$ okexchaincli query swap pool-info eth-355 +$ okexchaincli query swap pool eth-355 `), ), - Args: cobra.ExactArgs(1), + Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) - tokenName := args[0] + baseToken := args[0] + quoteToken := args[1] - res, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s/%s", queryRoute, types.QuerySwapTokenPair, tokenName), nil) + res, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s/%s/%s", queryRoute, types.QuerySwapTokenPair, baseToken, quoteToken), nil) if err != nil { - fmt.Printf("exchange - %s doesn't exist. error:%s \n", tokenName, err.Error()) - return nil + return err } fmt.Println(string(res)) @@ -64,6 +68,48 @@ $ okexchaincli query swap pool-info eth-355 } } +// GetCmdQueryBuyAmount queries amount of base/quote token by the given amount of quote/base token +func GetCmdQueryBuyAmount(queryRoute string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "amount [token-to-sell] [token-name-to-buy]", + Short: "Query how many token returned by the given amount of token to sell", + Long: strings.TrimSpace( + fmt.Sprintf( + `Query how many base token returned by the given amount of quote token. + +Example: +$ %s query swap amount 100eth-245 xxb`, version.ClientName, + ), + ), + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + sellToken, err := sdk.ParseDecCoin(args[0]) + if err != nil { + return err + } + params := types.QueryBuyAmountParams{ + SoldToken: sellToken, + TokenToBuy: args[1], + } + bz, err := cdc.MarshalJSON(params) + if err != nil { + return err + } + tp, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryBuyAmount), bz) + if err != nil { + return err + } + + var buyAmt sdk.Dec + cdc.MustUnmarshalJSON(tp, &buyAmt) + + return cliCtx.PrintOutput(buyAmt) + }, + } +} + +// GetCmdQueryParams queries the parameters of the AMM swap system func GetCmdQueryParams(queryRoute string, cdc *codec.Codec) *cobra.Command { return &cobra.Command{ Use: "params", @@ -92,3 +138,63 @@ $ %s query swap params }, } } + + +//GetCmdAllSwapTokenPairs lists all info of pools +func GetCmdAllSwapTokenPairs(queryRoute string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "pools", + Short: "Query infomation of all pools", + Long: strings.TrimSpace( + fmt.Sprintf(`Query infomation of all pools. +Example: +$ okexchaincli query swap pools +`), + ), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + + res, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", queryRoute, types.QuerySwapTokenPairs), nil) + if err != nil { + return err + } + if res == nil || len(res) == 0 || string(res) == "null" { + fmt.Println("empty SwapTokenPairs") + }else { + fmt.Println(string(res)) + } + + return nil + }, + } +} + + +//GetCmdRedeemableAssets query redeemable assets by specifying the number of lpt +func GetCmdRedeemableAssets(queryRoute string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "redeemable-assets [base-token] [quote-token] [pool-token-amount]", + Short: "Query redeemable assets by specifying pool token amount", + Long: strings.TrimSpace( + fmt.Sprintf(`Query redeemable assets by specifying pool token amount. +Example: +$ okexchaincli query swap redeemable-assets eth xxb 1 +`), + ), + Args: cobra.ExactArgs(3), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + baseTokenName := args[0] + quoteTokenName := args[1] + liquidity := args[2] + res, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s/%s/%s/%s", queryRoute, types.QueryRedeemableAssets, baseTokenName, quoteTokenName, liquidity), nil) + if err != nil { + return err + } + + fmt.Println(string(res)) + return nil + }, + } +} \ No newline at end of file diff --git a/x/ammswap/client/cli/tx.go b/x/ammswap/client/cli/tx.go index 5b12de9f85..9c299d3343 100644 --- a/x/ammswap/client/cli/tx.go +++ b/x/ammswap/client/cli/tx.go @@ -11,9 +11,24 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + "github.com/okex/okexchain/x/ammswap/types" "github.com/spf13/cobra" +) - "github.com/okex/okexchain/x/ammswap/types" +// flags +const ( + flagMinLiquidity = "min-liquidity" + flagMaxBaseAmount = "max-base-amount" + flagQuoteAmount = "quote-amount" + flagDeadlineDuration = "deadline-duration" + flagLiquidity = "liquidity" + flagMinBaseAmount = "min-base-amount" + flagMinQuoteAmount = "min-quote-amount" + flagSellAmount = "sell-amount" + flagMinBuyAmount = "min-buy-amount" + flagRecipient = "recipient" + flagToken0 = "token0" + flagToken1 = "token1" ) // GetTxCmd returns the transaction commands for this module @@ -46,7 +61,7 @@ func getCmdAddLiquidity(cdc *codec.Codec) *cobra.Command { fmt.Sprintf(`add liquidity. Example: -$ okexchaincli tx swap add-liquidity --max-base-amount 10eth-355 --quote-amount 100okt --min-liquidity 0.001 +$ okexchaincli tx swap add-liquidity --max-base-amount 10eth-355 --quote-amount 100btc-366 --min-liquidity 0.001 `), ), @@ -77,10 +92,13 @@ $ okexchaincli tx swap add-liquidity --max-base-amount 10eth-355 --quote-amount }, } - cmd.Flags().StringVarP(&minLiquidity, "min-liquidity", "l", "", "Minimum number of sender will mint if total pool token supply is greater than 0") - cmd.Flags().StringVarP(&maxBaseAmount, "max-base-amount", "", "", "Maximum number of base amount deposited. Deposits max amount if total pool token supply is 0. For example \"100xxb\"") - cmd.Flags().StringVarP("eAmount, "quote-amount", "q", "", "The number of quote amount. For example \"100okb\"") - cmd.Flags().StringVarP(&deadlineDuration, "deadline-duration", "d", "30s", "Duration after which this transaction can no longer be executed. such as \"300ms\", \"1.5h\" or \"2h45m\". Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".") + cmd.Flags().StringVarP(&minLiquidity, flagMinLiquidity, "l", "", "Minimum number of sender will mint if total pool token supply is greater than 0") + cmd.Flags().StringVarP(&maxBaseAmount, flagMaxBaseAmount, "", "", "Maximum number of base amount deposited. Deposits max amount if total pool token supply is 0. For example \"100xxb\"") + cmd.Flags().StringVarP("eAmount, flagQuoteAmount, "q", "", "The number of quote amount. For example \"100okb\"") + cmd.Flags().StringVarP(&deadlineDuration, flagDeadlineDuration, "d", "30s", "Duration after which this transaction can no longer be executed. such as \"300ms\", \"1.5h\" or \"2h45m\". Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".") + cmd.MarkFlagRequired(flagMinLiquidity) + cmd.MarkFlagRequired(flagMaxBaseAmount) + cmd.MarkFlagRequired(flagQuoteAmount) return cmd } @@ -97,7 +115,7 @@ func getCmdRemoveLiquidity(cdc *codec.Codec) *cobra.Command { fmt.Sprintf(`remove liquidity. Example: -$ okexchaincli tx swap remove-liquidity --liquidity 1 --min-base-amount 10eth-355 --min-quote-amount 1okt +$ okexchaincli tx swap remove-liquidity --liquidity 1 --min-base-amount 10eth-355 --min-quote-amount 1btc-366 `), ), @@ -128,16 +146,20 @@ $ okexchaincli tx swap remove-liquidity --liquidity 1 --min-base-amount 10eth-35 }, } - cmd.Flags().StringVarP(&liquidity, "liquidity", "l", "", "Liquidity amount of sender will burn") - cmd.Flags().StringVarP(&minBaseAmount, "min-base-amount", "", "", "Minimum number of base amount withdrawn") - cmd.Flags().StringVarP(&minQuoteAmount, "min-quote-amount", "q", "", "Minimum number of quote amount withdrawn") - cmd.Flags().StringVarP(&deadlineDuration, "deadline-duration", "d", "30s", "Duration after which this transaction can no longer be executed. such as \"300ms\", \"1.5h\" or \"2h45m\". Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".") + cmd.Flags().StringVarP(&liquidity, flagLiquidity, "l", "", "Liquidity amount of sender will burn") + cmd.Flags().StringVarP(&minBaseAmount, flagMinBaseAmount, "", "", "Minimum number of base amount withdrawn") + cmd.Flags().StringVarP(&minQuoteAmount, flagMinQuoteAmount, "q", "", "Minimum number of quote amount withdrawn") + cmd.Flags().StringVarP(&deadlineDuration, flagDeadlineDuration, "d", "30s", "Duration after which this transaction can no longer be executed. such as \"300ms\", \"1.5h\" or \"2h45m\". Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".") + cmd.MarkFlagRequired(flagLiquidity) + cmd.MarkFlagRequired(flagMinBaseAmount) + cmd.MarkFlagRequired(flagMinQuoteAmount) return cmd } func getCmdCreateExchange(cdc *codec.Codec) *cobra.Command { // flags - var token string + var token0 string + var token1 string cmd := &cobra.Command{ Use: "create-pair", Short: "create token pair", @@ -145,7 +167,7 @@ func getCmdCreateExchange(cdc *codec.Codec) *cobra.Command { fmt.Sprintf(`create token pair. Example: -$ okexchaincli tx swap create-pair --token eth-355 --fees 0.01okt +$ okexchaincli tx swap create-pair --token0 eth-355 --token1 btc-366 --fees 0.01okt `), ), @@ -153,13 +175,16 @@ $ okexchaincli tx swap create-pair --token eth-355 --fees 0.01okt RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) - msg := types.NewMsgCreateExchange(token, cliCtx.FromAddress) + msg := types.NewMsgCreateExchange(token0, token1, cliCtx.FromAddress) return utils.CompleteAndBroadcastTxCLI(txBldr, cliCtx, []sdk.Msg{msg}) }, } - cmd.Flags().StringVarP(&token, "token", "t", "", "Create an AMM swap pair by token name") + cmd.Flags().StringVar(&token0, flagToken0, "", "the base token name is required to create an AMM swap pair") + cmd.Flags().StringVar(&token1, flagToken1, "", "the quote token name is required to create an AMM swap pair") + cmd.MarkFlagRequired(flagToken0) + cmd.MarkFlagRequired(flagToken1) return cmd } @@ -176,7 +201,7 @@ func getCmdTokenSwap(cdc *codec.Codec) *cobra.Command { fmt.Sprintf(`swap token. Example: -$ okexchaincli tx swap token --sell-amount 1eth-355 --min-buy-amount 60okt +$ okexchaincli tx swap token --sell-amount 1eth-355 --min-buy-amount 60btc-366 `), ), @@ -207,20 +232,23 @@ $ okexchaincli tx swap token --sell-amount 1eth-355 --min-buy-amount 60okt } } - msg := types.NewMsgTokenToNativeToken(soldTokenAmount, minBoughtTokenAmount, + msg := types.NewMsgTokenToToken(soldTokenAmount, minBoughtTokenAmount, deadline, recip, cliCtx.FromAddress) return utils.CompleteAndBroadcastTxCLI(txBldr, cliCtx, []sdk.Msg{msg}) }, } - cmd.Flags().StringVarP(&soldTokenAmount, "sell-amount", "", "", + cmd.Flags().StringVarP(&soldTokenAmount, flagSellAmount, "", "", "Amount expected to sell") - cmd.Flags().StringVarP(&minBoughtTokenAmount, "min-buy-amount", "", "", + cmd.Flags().StringVarP(&minBoughtTokenAmount, flagMinBuyAmount, "", "", "Minimum amount expected to buy") - cmd.Flags().StringVarP(&recipient, "recipient", "", "", + cmd.Flags().StringVarP(&recipient, flagRecipient, "", "", "The address to receive the amount bought") - cmd.Flags().StringVarP(&deadline, "deadline", "", "100s", + cmd.Flags().StringVarP(&deadline, flagDeadlineDuration, "", "100s", "Duration after which this transaction can no longer be executed. such as \"300ms\", \"1.5h\" or \"2h45m\". Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".") + cmd.MarkFlagRequired(flagSellAmount) + cmd.MarkFlagRequired(flagMinBuyAmount) + return cmd } diff --git a/x/ammswap/client/rest/query.go b/x/ammswap/client/rest/query.go new file mode 100644 index 0000000000..c9186c40de --- /dev/null +++ b/x/ammswap/client/rest/query.go @@ -0,0 +1,126 @@ +package rest + +import ( + "encoding/json" + "fmt" + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/rest" + "github.com/gorilla/mux" + "github.com/okex/okexchain/x/ammswap/types" + "github.com/okex/okexchain/x/common" + "net/http" + "strings" +) + +func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router) { + r = r.PathPrefix("/" + types.ModuleName).Subrouter() + r.HandleFunc("/swap_token_pair", querySwapTokenPairHandler(cliCtx)).Methods("GET") + r.HandleFunc("/swap_token_pairs", querySwapTokenPairsHandler(cliCtx)).Methods("GET") + r.HandleFunc("/params", queryParamsHandler(cliCtx)).Methods("GET") + r.HandleFunc("/buy_amount", queryBuyAmountHandler(cliCtx)).Methods("GET") + r.HandleFunc("/redeemable_assets", queryRedeemableAssetsHandler(cliCtx)).Methods("GET") +} + +func querySwapTokenPairHandler(cliContext context.CLIContext) func(http.ResponseWriter, *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + baseToken := r.URL.Query().Get("base_token") + quoteToken := r.URL.Query().Get("quote_token") + + res, _, err := cliContext.QueryWithData(fmt.Sprintf("custom/%s/%s/%s/%s", types.QuerierRoute, types.QuerySwapTokenPair, baseToken, quoteToken), nil) + if err != nil { + common.HandleErrorMsg(w, cliContext, err.Error()) + return + } + + formatAndReturnResult(w, cliContext, res) + } + +} + +func querySwapTokenPairsHandler(cliContext context.CLIContext) func(http.ResponseWriter, *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + + res, _, err := cliContext.QueryWithData(fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QuerySwapTokenPairs), nil) + if err != nil { + common.HandleErrorMsg(w, cliContext, err.Error()) + return + } + + formatAndReturnResult(w, cliContext, res) + } + +} + +func queryParamsHandler(cliContext context.CLIContext) func(http.ResponseWriter, *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + + res, _, err := cliContext.QueryWithData(fmt.Sprintf("custom/%s/params", types.QuerierRoute), nil) + if err != nil { + common.HandleErrorMsg(w, cliContext, err.Error()) + return + } + + formatAndReturnResult(w, cliContext, res) + } + +} + +func queryBuyAmountHandler(cliContext context.CLIContext) func(http.ResponseWriter, *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + soldTokenStr := r.URL.Query().Get("sold_token") + tokenToBuyStr := r.URL.Query().Get("token_to_buy") + + sellToken, err := sdk.ParseDecCoin(soldTokenStr) + if err != nil { + common.HandleErrorMsg(w, cliContext, err.Error()) + return + } + params := types.QueryBuyAmountParams{ + SoldToken: sellToken, + TokenToBuy: tokenToBuyStr, + } + bz, err := codec.Cdc.MarshalJSON(params) + if err != nil { + common.HandleErrorMsg(w, cliContext, err.Error()) + return + } + res, _, err := cliContext.QueryWithData(fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryBuyAmount), bz) + if err != nil { + common.HandleErrorMsg(w, cliContext, err.Error()) + return + } + + formatAndReturnResult(w, cliContext, res) + } + +} + +func queryRedeemableAssetsHandler(cliContext context.CLIContext) func(http.ResponseWriter, *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + baseTokenName := r.URL.Query().Get("base_token_name") + quoteTokenName := r.URL.Query().Get("quote_token_name") + liquidity := r.URL.Query().Get("liquidity") + res, _, err := cliContext.QueryWithData(fmt.Sprintf("custom/%s/%s/%s/%s/%s", types.QuerierRoute, types.QueryRedeemableAssets, baseTokenName, quoteTokenName, liquidity), nil) + if err != nil { + common.HandleErrorMsg(w, cliContext, err.Error()) + return + } + formatAndReturnResult(w, cliContext, res) + } + +} + +func formatAndReturnResult(w http.ResponseWriter, cliContext context.CLIContext, data []byte) { + replaceStr := "replaceHere" + result := common.GetBaseResponse(replaceStr) + resultJson, err := json.Marshal(result) + if err != nil { + common.HandleErrorMsg(w, cliContext, err.Error()) + return + } + resultJson = []byte(strings.Replace(string(resultJson), "\"" + replaceStr + "\"", string(data), 1)) + + rest.PostProcessResponse(w, cliContext, resultJson) +} \ No newline at end of file diff --git a/x/ammswap/client/rest/rest.go b/x/ammswap/client/rest/rest.go index 07602f4f31..06c953c78c 100644 --- a/x/ammswap/client/rest/rest.go +++ b/x/ammswap/client/rest/rest.go @@ -8,5 +8,5 @@ import ( // RegisterRoutes registers ammswap-related REST handlers to a router func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) { - registerTxRoutes(cliCtx, r) + registerQueryRoutes(cliCtx, r) } diff --git a/x/ammswap/client/rest/tx.go b/x/ammswap/client/rest/tx.go deleted file mode 100644 index b8b226ae0a..0000000000 --- a/x/ammswap/client/rest/tx.go +++ /dev/null @@ -1,41 +0,0 @@ -package rest - -import ( - "encoding/json" - "fmt" - "net/http" - - "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/types/rest" - "github.com/gorilla/mux" - "github.com/okex/okexchain/x/ammswap/types" - "github.com/okex/okexchain/x/common" -) - -func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) { - r.HandleFunc("/ammswap/exchange", swapExchangeHandler(cliCtx)).Methods("GET") -} - -func swapExchangeHandler(cliCtx context.CLIContext) func(http.ResponseWriter, *http.Request) { - return func(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - tokenName := vars["token"] - - res, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/ammswap/swapTokenPair/%s", tokenName), nil) - if err != nil { - common.HandleErrorMsg(w, cliCtx, err.Error()) - return - } - - exchange := types.SwapTokenPair{} - codec.Cdc.MustUnmarshalJSON(res, exchange) - response := common.GetBaseResponse(exchange) - resBytes, err := json.Marshal(response) - if err != nil { - common.HandleErrorMsg(w, cliCtx, err.Error()) - return - } - rest.PostProcessResponse(w, cliCtx, resBytes) - } -} diff --git a/x/ammswap/genesis.go b/x/ammswap/genesis.go index 987117e0d6..206e76a470 100644 --- a/x/ammswap/genesis.go +++ b/x/ammswap/genesis.go @@ -4,6 +4,7 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + tokentypes "github.com/okex/okexchain/x/token/types" "github.com/okex/okexchain/x/ammswap/types" ) @@ -27,7 +28,7 @@ func ValidateGenesis(data GenesisState) error { if !record.BasePooledCoin.IsValid() { return fmt.Errorf("invalid SwapTokenPairRecord: BasePooledCoin: %s", record.BasePooledCoin) } - if !types.ValidatePoolTokenName(record.PoolTokenName) { + if !tokentypes.NotAllowedOriginSymbol(record.PoolTokenName) { return fmt.Errorf("invalid SwapTokenPairRecord: PoolToken: %s. Error: invalid PoolToken", record.PoolTokenName) } } diff --git a/x/ammswap/handler.go b/x/ammswap/handler.go index 7f01d55de3..f6bdec4832 100644 --- a/x/ammswap/handler.go +++ b/x/ammswap/handler.go @@ -2,7 +2,7 @@ package ammswap import ( "fmt" - + "github.com/okex/okexchain/x/ammswap/keeper" "github.com/okex/okexchain/x/ammswap/types" "github.com/okex/okexchain/x/common" "github.com/okex/okexchain/x/common/perf" @@ -32,10 +32,10 @@ func NewHandler(k Keeper) sdk.Handler { handlerFun = func() sdk.Result { return handleMsgCreateExchange(ctx, k, msg) } - case types.MsgTokenToNativeToken: - name = "handleMsgTokenToNativeToken" + case types.MsgTokenToToken: + name = "handleMsgTokenToToken" handlerFun = func() sdk.Result { - return handleMsgTokenToTokenExchange(ctx, k, msg) + return handleMsgTokenToToken(ctx, k, msg) } default: errMsg := fmt.Sprintf("Invalid msg type: %v", msg.Type()) @@ -47,66 +47,73 @@ func NewHandler(k Keeper) sdk.Handler { } } -func handleMsgTokenToTokenExchange(ctx sdk.Context, k Keeper, msg types.MsgTokenToNativeToken) sdk.Result { - if msg.SoldTokenAmount.Denom != sdk.DefaultBondDenom && msg.MinBoughtTokenAmount.Denom != sdk.DefaultBondDenom { - return handleMsgTokenToToken(ctx, k, msg) +func handleMsgTokenToToken(ctx sdk.Context, k Keeper, msg types.MsgTokenToToken) sdk.Result { + _, err := k.GetSwapTokenPair(ctx, msg.GetSwapTokenPairName()) + if err != nil { + return swapTokenByRouter(ctx, k, msg) + } else { + return swapToken(ctx, k, msg) } - return handleMsgTokenToNativeToken(ctx, k, msg) } func handleMsgCreateExchange(ctx sdk.Context, k Keeper, msg types.MsgCreateExchange) sdk.Result { event := sdk.NewEvent(sdk.EventTypeMessage, sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName)) - err := k.IsTokenExist(ctx, msg.Token) + + // 0. check if 2 tokens exist + err := k.IsTokenExist(ctx, msg.Token0Name) if err != nil { return sdk.Result{ - Code: sdk.CodeInternal, - Log: err.Error(), + Code: sdk.CodeInternal, Log: err.Error(), } } - tokenPair := msg.Token + "_" + common.NativeToken + err = k.IsTokenExist(ctx, msg.Token1Name) + if err != nil { + return sdk.Result{ + Code: sdk.CodeInternal, Log: err.Error(), + } + } - swapTokenPair, err := k.GetSwapTokenPair(ctx, tokenPair) + // 1. check if the token pair exists + tokenPairName := msg.GetSwapTokenPairName() + _, err = k.GetSwapTokenPair(ctx, tokenPairName) if err == nil { return sdk.Result{ - Code: sdk.CodeInternal, - Log: "Failed: exchange already exists", + Code: sdk.CodeInternal, Log: "Failed: the swap pair already exists", } } - poolName := types.PoolTokenPrefix + msg.Token - baseToken := sdk.NewDecCoinFromDec(msg.Token, sdk.ZeroDec()) - quoteToken := sdk.NewDecCoinFromDec(common.NativeToken, sdk.ZeroDec()) - poolToken, err := k.GetPoolTokenInfo(ctx, poolName) + // 2. check if the pool token exists + poolTokenName := types.GetPoolTokenName(msg.Token0Name, msg.Token1Name) + _, err = k.GetPoolTokenInfo(ctx, poolTokenName) if err == nil { - return sdk.Result{ - Code: sdk.CodeInternal, - Log: "Failed: pool token already exists", + return sdk.Result { + Code: sdk.CodeInternal, Log: "Failed: the pool token already exists", } } - k.NewPoolToken(ctx, poolName) - event = event.AppendAttributes(sdk.NewAttribute("pool-token", poolToken.OriginalSymbol)) - swapTokenPair.BasePooledCoin = baseToken - swapTokenPair.QuotePooledCoin = quoteToken - swapTokenPair.PoolTokenName = poolName - k.SetSwapTokenPair(ctx, tokenPair, swapTokenPair) + // 3. create the pool token + k.NewPoolToken(ctx, poolTokenName) + + // 4. create the token pair + swapTokenPair := types.NewSwapPair(msg.Token0Name, msg.Token1Name) + k.SetSwapTokenPair(ctx, tokenPairName, swapTokenPair) - event = event.AppendAttributes(sdk.NewAttribute("token-pair", tokenPair)) + event = event.AppendAttributes(sdk.NewAttribute("pool-token-name", poolTokenName)) + event = event.AppendAttributes(sdk.NewAttribute("token-pair", tokenPairName)) ctx.EventManager().EmitEvent(event) return sdk.Result{Events: ctx.EventManager().Events()} } func handleMsgAddLiquidity(ctx sdk.Context, k Keeper, msg types.MsgAddLiquidity) sdk.Result { event := sdk.NewEvent(sdk.EventTypeMessage, sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName)) - if msg.Deadline < ctx.BlockTime().Unix() { return sdk.Result{ Code: sdk.CodeInternal, Log: "Failed: block time exceeded deadline", } } - swapTokenPair, err := k.GetSwapTokenPair(ctx, msg.GetSwapTokenPair()) + swapTokenPair, err := k.GetSwapTokenPair(ctx, msg.GetSwapTokenPairName()) if err != nil { return sdk.Result{ Code: sdk.CodeInternal, @@ -126,17 +133,24 @@ func handleMsgAddLiquidity(ctx sdk.Context, k Keeper, msg types.MsgAddLiquidity) baseTokens.Amount = msg.MaxBaseAmount.Amount liquidity = sdk.NewDec(1) } else if swapTokenPair.BasePooledCoin.IsPositive() && swapTokenPair.QuotePooledCoin.IsPositive() { - baseTokens.Amount = mulAndQuo(msg.QuoteAmount.Amount, swapTokenPair.BasePooledCoin.Amount, swapTokenPair.QuotePooledCoin.Amount) - + baseTokens.Amount = common.MulAndQuo(msg.QuoteAmount.Amount, swapTokenPair.BasePooledCoin.Amount, swapTokenPair.QuotePooledCoin.Amount) totalSupply := k.GetPoolTokenAmount(ctx, swapTokenPair.PoolTokenName) + if baseTokens.IsZero() { + baseTokens.Amount = sdk.NewDecWithPrec(1, sdk.Precision) + } if totalSupply.IsZero() { return sdk.Result{ Code: sdk.CodeInternal, Log: fmt.Sprintf("unexpected totalSupply in pool token %s", poolToken.String()), } } - liquidity = mulAndQuo(msg.QuoteAmount.Amount, totalSupply, swapTokenPair.QuotePooledCoin.Amount) - + liquidity = common.MulAndQuo(msg.QuoteAmount.Amount, totalSupply, swapTokenPair.QuotePooledCoin.Amount) + if liquidity.IsZero() { + return sdk.Result{ + Code: sdk.CodeInternal, + Log: fmt.Sprintf("failed to add liquidity"), + } + } } else { return sdk.Result{ Code: sdk.CodeInternal, @@ -174,7 +188,7 @@ func handleMsgAddLiquidity(ctx sdk.Context, k Keeper, msg types.MsgAddLiquidity) // update swapTokenPair swapTokenPair.QuotePooledCoin = swapTokenPair.QuotePooledCoin.Add(msg.QuoteAmount) swapTokenPair.BasePooledCoin = swapTokenPair.BasePooledCoin.Add(baseTokens) - k.SetSwapTokenPair(ctx, msg.GetSwapTokenPair(), swapTokenPair) + k.SetSwapTokenPair(ctx, msg.GetSwapTokenPairName(), swapTokenPair) // update poolToken poolCoins := sdk.NewDecCoinFromDec(poolToken.Symbol, liquidity) @@ -201,7 +215,7 @@ func handleMsgRemoveLiquidity(ctx sdk.Context, k Keeper, msg types.MsgRemoveLiqu Log: "Failed: block time exceeded deadline", } } - swapTokenPair, err := k.GetSwapTokenPair(ctx, msg.GetSwapTokenPair()) + swapTokenPair, err := k.GetSwapTokenPair(ctx, msg.GetSwapTokenPairName()) if err != nil { return sdk.Result{ Code: sdk.CodeInternal, @@ -218,21 +232,22 @@ func handleMsgRemoveLiquidity(ctx sdk.Context, k Keeper, msg types.MsgRemoveLiqu } } - baseDec := mulAndQuo(swapTokenPair.BasePooledCoin.Amount, liquidity, poolTokenAmount) - quoteDec := mulAndQuo(swapTokenPair.QuotePooledCoin.Amount, liquidity, poolTokenAmount) + baseDec := common.MulAndQuo(swapTokenPair.BasePooledCoin.Amount, liquidity, poolTokenAmount) + quoteDec := common.MulAndQuo(swapTokenPair.QuotePooledCoin.Amount, liquidity, poolTokenAmount) + baseAmount := sdk.NewDecCoinFromDec(swapTokenPair.BasePooledCoin.Denom, baseDec) quoteAmount := sdk.NewDecCoinFromDec(swapTokenPair.QuotePooledCoin.Denom, quoteDec) if baseAmount.IsLT(msg.MinBaseAmount) { return sdk.Result{ Code: sdk.CodeInternal, - Log: fmt.Sprintf("Failed: The available base Amount(%s) are less than min base Amount(%s)", baseAmount.String(), msg.MinBaseAmount.String()), + Log: fmt.Sprintf("Failed: available base amount(%s) are less than min base amount(%s)", baseAmount.String(), msg.MinBaseAmount.String()), } } if quoteAmount.IsLT(msg.MinQuoteAmount) { return sdk.Result{ Code: sdk.CodeInternal, - Log: "Failed: available quote amount are less than least quote amount", + Log: fmt.Sprintf("Failed: available quote amount(%s) are less than least quote amount(%s)", quoteAmount.String(), msg.MinQuoteAmount.String()), } } @@ -252,7 +267,7 @@ func handleMsgRemoveLiquidity(ctx sdk.Context, k Keeper, msg types.MsgRemoveLiqu // update swapTokenPair swapTokenPair.QuotePooledCoin = swapTokenPair.QuotePooledCoin.Sub(quoteAmount) swapTokenPair.BasePooledCoin = swapTokenPair.BasePooledCoin.Sub(baseAmount) - k.SetSwapTokenPair(ctx, msg.GetSwapTokenPair(), swapTokenPair) + k.SetSwapTokenPair(ctx, msg.GetSwapTokenPairName(), swapTokenPair) // update poolToken poolCoins := sdk.NewDecCoinFromDec(swapTokenPair.PoolTokenName, liquidity) @@ -260,7 +275,7 @@ func handleMsgRemoveLiquidity(ctx sdk.Context, k Keeper, msg types.MsgRemoveLiqu if err != nil { return sdk.Result{ Code: sdk.CodeInternal, - Log: "failed to burn pool token", + Log: fmt.Sprintf("Failed to burn pool token: %s", err.Error()), } } @@ -270,7 +285,7 @@ func handleMsgRemoveLiquidity(ctx sdk.Context, k Keeper, msg types.MsgRemoveLiqu return sdk.Result{Events: ctx.EventManager().Events()} } -func handleMsgTokenToNativeToken(ctx sdk.Context, k Keeper, msg types.MsgTokenToNativeToken) sdk.Result { +func swapToken(ctx sdk.Context, k Keeper, msg types.MsgTokenToToken) sdk.Result { event := sdk.NewEvent(sdk.EventTypeMessage, sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName)) if err := common.HasSufficientCoins(msg.Sender, k.GetTokenKeeper().GetCoins(ctx, msg.Sender), @@ -286,15 +301,27 @@ func handleMsgTokenToNativeToken(ctx sdk.Context, k Keeper, msg types.MsgTokenTo Log: "Failed: block time exceeded deadline", } } - swapTokenPair, err := k.GetSwapTokenPair(ctx, msg.GetSwapTokenPair()) + swapTokenPair, err := k.GetSwapTokenPair(ctx, msg.GetSwapTokenPairName()) if err != nil { return sdk.Result{ Code: sdk.CodeInternal, Log: err.Error(), } } + if swapTokenPair.BasePooledCoin.IsZero() || swapTokenPair.QuotePooledCoin.IsZero() { + return sdk.Result{ + Code: sdk.CodeInternal, + Log: fmt.Sprintf("failed to swap token: empty pool: %s", swapTokenPair.String()), + } + } params := k.GetParams(ctx) - tokenBuy := calculateTokenToBuy(swapTokenPair, msg, params) + tokenBuy := keeper.CalculateTokenToBuy(swapTokenPair, msg.SoldTokenAmount, msg.MinBoughtTokenAmount.Denom, params) + if tokenBuy.IsZero() { + return sdk.Result{ + Code: sdk.CodeInternal, + Log: fmt.Sprintf("amount(%s) is too small to swap", tokenBuy.String()), + } + } if tokenBuy.Amount.LT(msg.MinBoughtTokenAmount.Amount) { return sdk.Result{ Code: sdk.CodeInternal, @@ -312,7 +339,7 @@ func handleMsgTokenToNativeToken(ctx sdk.Context, k Keeper, msg types.MsgTokenTo return sdk.Result{Events: ctx.EventManager().Events()} } -func handleMsgTokenToToken(ctx sdk.Context, k Keeper, msg types.MsgTokenToNativeToken) sdk.Result { +func swapTokenByRouter(ctx sdk.Context, k Keeper, msg types.MsgTokenToToken) sdk.Result { event := sdk.NewEvent(sdk.EventTypeMessage, sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName)) if msg.Deadline < ctx.BlockTime().Unix() { @@ -325,18 +352,24 @@ func handleMsgTokenToToken(ctx sdk.Context, k Keeper, msg types.MsgTokenToNative sdk.DecCoins{msg.SoldTokenAmount}); err != nil { return sdk.Result{ Code: sdk.CodeInsufficientCoins, - Log: err.Error(), + Log: fmt.Sprintf("Failed to swap token by router %s: %s", sdk.DefaultBondDenom, err.Error()), } } - tokenPairOne := msg.SoldTokenAmount.Denom + "_" + sdk.DefaultBondDenom + tokenPairOne := types.GetSwapTokenPairName(msg.SoldTokenAmount.Denom, sdk.DefaultBondDenom) swapTokenPairOne, err := k.GetSwapTokenPair(ctx, tokenPairOne) if err != nil { return sdk.Result{ Code: sdk.CodeInternal, - Log: err.Error(), + Log: fmt.Sprintf("Failed to swap token by router %s: %s", sdk.DefaultBondDenom, err.Error()), + } + } + if swapTokenPairOne.BasePooledCoin.IsZero() || swapTokenPairOne.QuotePooledCoin.IsZero() { + return sdk.Result{ + Code: sdk.CodeInternal, + Log: fmt.Sprintf("failed to swap token: empty pool: %s", swapTokenPairOne.String()), } } - tokenPairTwo := msg.MinBoughtTokenAmount.Denom + "_" + sdk.DefaultBondDenom + tokenPairTwo := types.GetSwapTokenPairName(msg.MinBoughtTokenAmount.Denom, sdk.DefaultBondDenom) swapTokenPairTwo, err := k.GetSwapTokenPair(ctx, tokenPairTwo) if err != nil { return sdk.Result{ @@ -344,17 +377,35 @@ func handleMsgTokenToToken(ctx sdk.Context, k Keeper, msg types.MsgTokenToNative Log: err.Error(), } } + if swapTokenPairTwo.BasePooledCoin.IsZero() || swapTokenPairTwo.QuotePooledCoin.IsZero() { + return sdk.Result{ + Code: sdk.CodeInternal, + Log: fmt.Sprintf("failed to swap token: empty pool: %s", swapTokenPairTwo.String()), + } + } nativeAmount := sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, sdk.MustNewDecFromStr("0")) params := k.GetParams(ctx) msgOne := msg msgOne.MinBoughtTokenAmount = nativeAmount - tokenNative := calculateTokenToBuy(swapTokenPairOne, msgOne, params) - + tokenNative := keeper.CalculateTokenToBuy(swapTokenPairOne, msgOne.SoldTokenAmount, msgOne.MinBoughtTokenAmount.Denom, params) + if tokenNative.IsZero() { + return sdk.Result{ + Code: sdk.CodeInternal, + Log: fmt.Sprintf("Failed: selled token amount is too little to buy any token"), + } + } msgTwo := msg msgTwo.SoldTokenAmount = tokenNative - tokenBuy := calculateTokenToBuy(swapTokenPairOne, msgTwo, params) - + tokenBuy := keeper.CalculateTokenToBuy(swapTokenPairTwo, msgTwo.SoldTokenAmount, msgTwo.MinBoughtTokenAmount.Denom, params) + // sanity check. user may set MinBoughtTokenAmount to zero on front end. + // if set zero,this will not return err + if tokenBuy.IsZero() { + return sdk.Result{ + Code: sdk.CodeInternal, + Log: fmt.Sprintf("Failed: amount(%s) is too small to swap", tokenBuy.String()), + } + } if tokenBuy.Amount.LT(msg.MinBoughtTokenAmount.Amount) { return sdk.Result{ Code: sdk.CodeInternal, @@ -366,7 +417,6 @@ func handleMsgTokenToToken(ctx sdk.Context, k Keeper, msg types.MsgTokenToNative if !res.IsOK() { return res } - //TODO if fail,revert last swap res = swapTokenNativeToken(ctx, k, swapTokenPairTwo, tokenBuy, msgTwo) if !res.IsOK() { return res @@ -378,25 +428,9 @@ func handleMsgTokenToToken(ctx sdk.Context, k Keeper, msg types.MsgTokenToNative return sdk.Result{Events: ctx.EventManager().Events()} } -//calculate the amount to buy -func calculateTokenToBuy(swapTokenPair SwapTokenPair, msg types.MsgTokenToNativeToken, params types.Params) sdk.DecCoin { - var inputReserve, outputReserve sdk.Dec - if msg.SoldTokenAmount.Denom == sdk.DefaultBondDenom { - inputReserve = swapTokenPair.QuotePooledCoin.Amount - outputReserve = swapTokenPair.BasePooledCoin.Amount - } else { - inputReserve = swapTokenPair.BasePooledCoin.Amount - outputReserve = swapTokenPair.QuotePooledCoin.Amount - } - tokenBuyAmt := getInputPrice(msg.SoldTokenAmount.Amount, inputReserve, outputReserve, params.FeeRate) - tokenBuy := sdk.NewDecCoinFromDec(msg.MinBoughtTokenAmount.Denom, tokenBuyAmt) - - return tokenBuy -} - func swapTokenNativeToken( ctx sdk.Context, k Keeper, swapTokenPair SwapTokenPair, tokenBuy sdk.DecCoin, - msg types.MsgTokenToNativeToken, + msg types.MsgTokenToToken, ) sdk.Result { // transfer coins err := k.SendCoinsToPool(ctx, sdk.DecCoins{msg.SoldTokenAmount}, msg.Sender) @@ -416,23 +450,17 @@ func swapTokenNativeToken( } // update swapTokenPair - if msg.SoldTokenAmount.Denom == sdk.DefaultBondDenom { + if msg.MinBoughtTokenAmount.Denom < msg.SoldTokenAmount.Denom { swapTokenPair.QuotePooledCoin = swapTokenPair.QuotePooledCoin.Add(msg.SoldTokenAmount) swapTokenPair.BasePooledCoin = swapTokenPair.BasePooledCoin.Sub(tokenBuy) } else { swapTokenPair.QuotePooledCoin = swapTokenPair.QuotePooledCoin.Sub(tokenBuy) swapTokenPair.BasePooledCoin = swapTokenPair.BasePooledCoin.Add(msg.SoldTokenAmount) } - k.SetSwapTokenPair(ctx, msg.GetSwapTokenPair(), swapTokenPair) + k.SetSwapTokenPair(ctx, msg.GetSwapTokenPairName(), swapTokenPair) return sdk.Result{} } -func getInputPrice(inputAmount, inputReserve, outputReserve, feeRate sdk.Dec) sdk.Dec { - inputAmountWithFee := inputAmount.Mul(sdk.OneDec().Sub(feeRate).Mul(sdk.NewDec(1000))) - denominator := inputReserve.Mul(sdk.NewDec(1000)).Add(inputAmountWithFee) - return mulAndQuo(inputAmountWithFee, outputReserve, denominator) -} - func coinSort(coins sdk.DecCoins) sdk.DecCoins { var newCoins sdk.DecCoins for _, coin := range coins { @@ -444,13 +472,3 @@ func coinSort(coins sdk.DecCoins) sdk.DecCoins { return newCoins } -var ( - // 10^8 - auxiliaryDec = sdk.NewDec(100000000) -) - -// mulAndQuo returns a * b / c -func mulAndQuo(a, b, c sdk.Dec) sdk.Dec { - a = a.Mul(auxiliaryDec) - return a.Mul(b).Quo(c).Quo(auxiliaryDec) -} diff --git a/x/ammswap/handler_test.go b/x/ammswap/handler_test.go index 9b448f97a1..cb5a0e3f3a 100644 --- a/x/ammswap/handler_test.go +++ b/x/ammswap/handler_test.go @@ -8,6 +8,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/supply" + "github.com/okex/okexchain/x/ammswap/keeper" "github.com/okex/okexchain/x/ammswap/types" token "github.com/okex/okexchain/x/token/types" "github.com/stretchr/testify/require" @@ -19,40 +20,63 @@ func TestHandleMsgCreateExchange(t *testing.T) { keeper := mapp.swapKeeper mapp.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: 2}}) ctx := mapp.BaseApp.NewContext(false, abci.Header{}).WithBlockHeight(10) - testToken := initToken(types.TestBasePooledToken) - mapp.supplyKeeper.SetSupply(ctx, supply.NewSupply(mapp.TotalCoinsSupply)) handler := NewHandler(keeper) - msg := types.NewMsgCreateExchange(testToken.Symbol, addrKeysSlice[0].Address) - // test case1: token is not exist - result := handler(ctx, msg) - require.NotNil(t, result.Log) + testToken := initToken(types.TestBasePooledToken) + testToken2 := initToken(types.TestBasePooledToken2) + testQuoteToken := initToken(types.TestQuotePooledToken) mapp.tokenKeeper.NewToken(ctx, testToken) + mapp.tokenKeeper.NewToken(ctx, testToken2) + mapp.tokenKeeper.NewToken(ctx, testQuoteToken) - // test case2: success - result = handler(ctx, msg) - require.Equal(t, "", result.Log) - - // check account balance - acc := mapp.AccountKeeper.GetAccount(ctx, addrKeysSlice[0].Address) - expectCoins := sdk.DecCoins{ - sdk.NewDecCoinFromDec(types.TestQuotePooledToken, sdk.MustNewDecFromStr("100")), - sdk.NewDecCoinFromDec(types.TestBasePooledToken, sdk.MustNewDecFromStr("100")), - sdk.NewDecCoinFromDec(types.TestBasePooledToken2, sdk.MustNewDecFromStr("100")), - sdk.NewDecCoinFromDec(types.TestBasePooledToken3, sdk.MustNewDecFromStr("100")), + tests := []struct { + testCase string + token0 string + token1 string + addr sdk.AccAddress + expectedCode sdk.CodeType + }{ + { + testCase: "token is not exist", + token0: testToken.Symbol, + token1: types.TestBasePooledToken3, + addr: addrKeysSlice[0].Address, + expectedCode: sdk.CodeInternal}, + { + testCase: "success", + token0: testToken.Symbol, + token1: testQuoteToken.Symbol, + addr: addrKeysSlice[0].Address, + expectedCode: sdk.CodeOK,}, + { + testCase: "success(The lexicographic order of BaseTokenName must be less than QuoteTokenName)", + token0: testToken2.Symbol, + token1: testToken.Symbol, + addr: addrKeysSlice[0].Address, + expectedCode: sdk.CodeOK}, + { + testCase: "swapTokenPair already exists", + token0: testToken.Symbol, + token1: testQuoteToken.Symbol, + addr: addrKeysSlice[0].Address, + expectedCode: sdk.CodeInternal}, + } + for _, testCase := range tests { + fmt.Println(testCase.testCase) + addLiquidityMsg := types.NewMsgCreateExchange(testCase.token0, testCase.token1, testCase.addr) + result := handler(ctx, addLiquidityMsg) + require.Equal(t, testCase.expectedCode, result.Code) + if result.IsOK() { + expectedSwapTokenPairName := types.GetSwapTokenPairName(testCase.token0, testCase.token1) + swapTokenPair, err := keeper.GetSwapTokenPair(ctx, expectedSwapTokenPairName) + expectedBaseTokenName, expectedQuoteTokenName := types.GetBaseQuoteTokenName(testCase.token0, testCase.token1) + require.Nil(t, err) + require.Equal(t, expectedBaseTokenName, swapTokenPair.BasePooledCoin.Denom) + require.Equal(t, expectedQuoteTokenName, swapTokenPair.QuotePooledCoin.Denom) + } } - require.EqualValues(t, expectCoins.String(), acc.GetCoins().String()) - - expectSwapTokenPair := types.GetTestSwapTokenPair() - swapTokenPair, err := keeper.GetSwapTokenPair(ctx, types.TestSwapTokenPairName) - require.Nil(t, err) - require.EqualValues(t, expectSwapTokenPair, swapTokenPair) - - // test case3: swapTokenPair already exists - result = handler(ctx, msg) - require.NotNil(t, result.Log) } func initToken(name string) token.Token { @@ -74,18 +98,27 @@ func TestHandleMsgAddLiquidity(t *testing.T) { mapp.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: 2}}) ctx := mapp.BaseApp.NewContext(false, abci.Header{}).WithBlockHeight(10).WithBlockTime(time.Now()) testToken := initToken(types.TestBasePooledToken) + testQuoteToken := initToken(types.TestQuotePooledToken) mapp.supplyKeeper.SetSupply(ctx, supply.NewSupply(mapp.TotalCoinsSupply)) handler := NewHandler(keeper) - msg := types.NewMsgCreateExchange(testToken.Symbol, addrKeysSlice[0].Address) + msg := types.NewMsgCreateExchange(testToken.Symbol, types.TestQuotePooledToken, addrKeysSlice[0].Address) mapp.tokenKeeper.NewToken(ctx, testToken) + mapp.tokenKeeper.NewToken(ctx, testQuoteToken) result := handler(ctx, msg) require.Equal(t, "", result.Log) + testQuoteToken2 := initToken(types.TestBasePooledToken2) + mapp.tokenKeeper.NewToken(ctx, testQuoteToken2) + msgPool2 := types.NewMsgCreateExchange(testToken.Symbol, types.TestBasePooledToken2, addrKeysSlice[0].Address) + result2 := handler(ctx, msgPool2) + require.Equal(t, "", result2.Log) + minLiquidity := sdk.NewDec(1) maxBaseAmount := sdk.NewDecCoinFromDec(types.TestBasePooledToken, sdk.NewDec(10000)) quoteAmount := sdk.NewDecCoinFromDec(types.TestQuotePooledToken, sdk.NewDec(10000)) + quoteAmount2 := sdk.NewDecCoinFromDec(types.TestBasePooledToken2, sdk.NewDec(10000)) nonExistMaxBaseAmount := sdk.NewDecCoinFromDec("abc", sdk.NewDec(10000)) invalidMinLiquidity := sdk.NewDec(1000) invalidMaxBaseAmount := sdk.NewDecCoinFromDec(types.TestBasePooledToken, sdk.NewDec(1)) @@ -104,6 +137,7 @@ func TestHandleMsgAddLiquidity(t *testing.T) { exceptResultCode sdk.CodeType }{ {"success", minLiquidity, maxBaseAmount, quoteAmount, deadLine, addr, 0}, + {"success(not native token)", minLiquidity, maxBaseAmount, quoteAmount2, deadLine, addr, 0}, {"blockTime exceeded deadline", minLiquidity, maxBaseAmount, quoteAmount, 0, addr, sdk.CodeInternal}, {"unknown swapTokenPair", minLiquidity, nonExistMaxBaseAmount, quoteAmount, deadLine, addr, sdk.CodeInternal}, {"The required baseTokens are greater than MaxBaseAmount", minLiquidity, invalidMaxBaseAmount, quoteAmount, deadLine, addr, sdk.CodeInternal}, @@ -116,6 +150,27 @@ func TestHandleMsgAddLiquidity(t *testing.T) { result = handler(ctx, addLiquidityMsg) require.Equal(t, testCase.exceptResultCode, result.Code) } + + acc := mapp.AccountKeeper.GetAccount(ctx, addr) + require.False(t, acc.GetCoins().Empty()) + queryCheck := make(map[string]sdk.Dec) + var err error + testPoolToken := types.GetPoolTokenName(types.TestBasePooledToken, types.TestQuotePooledToken) + queryCheck[testPoolToken], err = sdk.NewDecFromStr("1") + testPoolToken2 := types.GetPoolTokenName(types.TestBasePooledToken, types.TestBasePooledToken2) + queryCheck[testPoolToken2], err = sdk.NewDecFromStr("1") + require.Nil(t, err) + queryCheck[types.TestQuotePooledToken] = sdk.NewDec(90000) + queryCheck[types.TestBasePooledToken] = sdk.NewDec(80000) + queryCheck[types.TestBasePooledToken2] = sdk.NewDec(90000) + queryCheck[types.TestBasePooledToken3] = sdk.NewDec(100000) + + for _, c := range acc.GetCoins() { + fmt.Println(c) + value, ok := queryCheck[c.Denom] + require.True(t, ok) + require.Equal(t, value, c.Amount) + } } func TestHandleMsgRemoveLiquidity(t *testing.T) { @@ -124,15 +179,23 @@ func TestHandleMsgRemoveLiquidity(t *testing.T) { mapp.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: 2}}) ctx := mapp.BaseApp.NewContext(false, abci.Header{}).WithBlockHeight(10).WithBlockTime(time.Now()) testToken := initToken(types.TestBasePooledToken) + testQuoteToken := initToken(types.TestQuotePooledToken) mapp.supplyKeeper.SetSupply(ctx, supply.NewSupply(mapp.TotalCoinsSupply)) handler := NewHandler(keeper) - msg := types.NewMsgCreateExchange(testToken.Symbol, addrKeysSlice[0].Address) + msg := types.NewMsgCreateExchange(testToken.Symbol, types.TestQuotePooledToken, addrKeysSlice[0].Address) mapp.tokenKeeper.NewToken(ctx, testToken) + mapp.tokenKeeper.NewToken(ctx, testQuoteToken) result := handler(ctx, msg) require.Equal(t, "", result.Log) + testQuoteToken2 := initToken(types.TestBasePooledToken2) + mapp.tokenKeeper.NewToken(ctx, testQuoteToken2) + msgPool2 := types.NewMsgCreateExchange(testToken.Symbol, types.TestBasePooledToken2, addrKeysSlice[0].Address) + result2 := handler(ctx, msgPool2) + require.Equal(t, "", result2.Log) + minLiquidity := sdk.NewDec(1) maxBaseAmount := sdk.NewDecCoinFromDec(types.TestBasePooledToken, sdk.NewDec(10000)) quoteAmount := sdk.NewDecCoinFromDec(types.TestQuotePooledToken, sdk.NewDec(10000)) @@ -143,10 +206,16 @@ func TestHandleMsgRemoveLiquidity(t *testing.T) { result = handler(ctx, addLiquidityMsg) require.Equal(t, "", result.Log) + quoteAmount2 := sdk.NewDecCoinFromDec(types.TestBasePooledToken2, sdk.NewDec(10000)) + addLiquidityMsg2 := types.NewMsgAddLiquidity(minLiquidity, maxBaseAmount, quoteAmount2, deadLine, addr) + result = handler(ctx, addLiquidityMsg2) + require.Equal(t, "", result.Log) + liquidity, err := sdk.NewDecFromStr("0.01") require.Nil(t, err) minBaseAmount := sdk.NewDecCoinFromDec(types.TestBasePooledToken, sdk.NewDec(1)) minQuoteAmount := sdk.NewDecCoinFromDec(types.TestQuotePooledToken, sdk.NewDec(1)) + minQuoteAmount2 := sdk.NewDecCoinFromDec(types.TestBasePooledToken2, sdk.NewDec(1)) nonExistMinBaseAmount := sdk.NewDecCoinFromDec("abc", sdk.NewDec(10000)) invalidMinBaseAmount := sdk.NewDecCoinFromDec(types.TestBasePooledToken, sdk.NewDec(1000000)) invalidMinQuoteAmount := sdk.NewDecCoinFromDec(types.TestQuotePooledToken, sdk.NewDec(1000000)) @@ -161,7 +230,8 @@ func TestHandleMsgRemoveLiquidity(t *testing.T) { addr sdk.AccAddress exceptResultCode sdk.CodeType }{ - {"success", liquidity, minBaseAmount, minQuoteAmount, deadLine, addr, 0}, + {"success", liquidity, minBaseAmount, minQuoteAmount, deadLine, addr, sdk.CodeOK}, + {"success(not native token)", liquidity, minBaseAmount, minQuoteAmount2, deadLine, addr, sdk.CodeOK}, {"blockTime exceeded deadline", liquidity, minBaseAmount, minQuoteAmount, 0, addr, sdk.CodeInternal}, {"unknown swapTokenPair", liquidity, nonExistMinBaseAmount, minQuoteAmount, deadLine, addr, sdk.CodeInternal}, {"The available baseAmount are less than MinBaseAmount", liquidity, invalidMinBaseAmount, minQuoteAmount, deadLine, addr, sdk.CodeInternal}, @@ -170,10 +240,30 @@ func TestHandleMsgRemoveLiquidity(t *testing.T) { } for _, testCase := range tests { + fmt.Println(testCase.testCase) addLiquidityMsg := types.NewMsgRemoveLiquidity(testCase.liquidity, testCase.minBaseAmount, testCase.minQuoteAmount, testCase.deadLine, testCase.addr) result = handler(ctx, addLiquidityMsg) require.Equal(t, testCase.exceptResultCode, result.Code) } + + acc := mapp.AccountKeeper.GetAccount(ctx, addr) + require.False(t, acc.GetCoins().Empty()) + queryCheck := make(map[string]sdk.Dec) + testPoolToken := types.GetPoolTokenName(types.TestBasePooledToken, types.TestQuotePooledToken) + queryCheck[testPoolToken], err = sdk.NewDecFromStr("0.99") + testPoolToken2 := types.GetPoolTokenName(types.TestBasePooledToken, types.TestBasePooledToken2) + queryCheck[testPoolToken2], err = sdk.NewDecFromStr("0.99") + require.Nil(t, err) + queryCheck[types.TestQuotePooledToken] = sdk.NewDec(90100) + queryCheck[types.TestBasePooledToken] = sdk.NewDec(80200) + queryCheck[types.TestBasePooledToken2] = sdk.NewDec(90100) + queryCheck[types.TestBasePooledToken3] = sdk.NewDec(100000) + + for _, c := range acc.GetCoins() { + value, ok := queryCheck[c.Denom] + require.True(t, ok) + require.Equal(t, value, c.Amount) + } } func TestHandleMsgTokenToTokenExchange(t *testing.T) { @@ -184,14 +274,16 @@ func TestHandleMsgTokenToTokenExchange(t *testing.T) { testToken := initToken(types.TestBasePooledToken) secondTestTokenName := types.TestBasePooledToken2 secondTestToken := initToken(secondTestTokenName) + testQuoteToken := initToken(types.TestQuotePooledToken) mapp.swapKeeper.SetParams(ctx, types.DefaultParams()) mapp.supplyKeeper.SetSupply(ctx, supply.NewSupply(mapp.TotalCoinsSupply)) handler := NewHandler(keeper) - msgCreateExchange := types.NewMsgCreateExchange(testToken.Symbol, addrKeysSlice[0].Address) - msgCreateExchange2 := types.NewMsgCreateExchange(secondTestToken.Symbol, addrKeysSlice[0].Address) + msgCreateExchange := types.NewMsgCreateExchange(testToken.Symbol, types.TestQuotePooledToken, addrKeysSlice[0].Address) + msgCreateExchange2 := types.NewMsgCreateExchange(secondTestToken.Symbol, types.TestQuotePooledToken, addrKeysSlice[0].Address) mapp.tokenKeeper.NewToken(ctx, testToken) mapp.tokenKeeper.NewToken(ctx, secondTestToken) + mapp.tokenKeeper.NewToken(ctx, testQuoteToken) result := handler(ctx, msgCreateExchange) require.Equal(t, "", result.Log) @@ -227,7 +319,6 @@ func TestHandleMsgTokenToTokenExchange(t *testing.T) { unkownSoldTokenAmount2 := sdk.NewDecCoinFromDec(types.TestBasePooledToken3, sdk.NewDec(1)) insufficientSoldTokenAmount2 := sdk.NewDecCoinFromDec(types.TestBasePooledToken, sdk.NewDec(10000000)) invalidMinBoughtTokenAmount2 := sdk.NewDecCoinFromDec(secondTestTokenName, sdk.NewDec(100000)) - tests := []struct { testCase string minBoughtTokenAmount sdk.DecCoin @@ -252,20 +343,126 @@ func TestHandleMsgTokenToTokenExchange(t *testing.T) { for _, testCase := range tests { fmt.Println(testCase.testCase) - addLiquidityMsg := types.NewMsgTokenToNativeToken(testCase.soldTokenAmount, testCase.minBoughtTokenAmount, testCase.deadLine, testCase.recipient, testCase.addr) + addLiquidityMsg := types.NewMsgTokenToToken(testCase.soldTokenAmount, testCase.minBoughtTokenAmount, testCase.deadLine, testCase.recipient, testCase.addr) result = handler(ctx, addLiquidityMsg) fmt.Println(result.Log) require.Equal(t, testCase.exceptResultCode, result.Code) } + + acc := mapp.AccountKeeper.GetAccount(ctx, addr) + require.False(t, acc.GetCoins().Empty()) + queryCheck := make(map[string]sdk.Dec) + var err error + testPoolToken1 := types.GetPoolTokenName(types.TestBasePooledToken, types.TestQuotePooledToken) + queryCheck[testPoolToken1], err = sdk.NewDecFromStr("2") + require.Nil(t, err) + testPoolToken2 := types.GetPoolTokenName(types.TestBasePooledToken2, types.TestQuotePooledToken) + queryCheck[testPoolToken2], err = sdk.NewDecFromStr("1") + require.Nil(t, err) + queryCheck[types.TestQuotePooledToken] = sdk.NewDec(69998) + queryCheck[types.TestBasePooledToken], err = sdk.NewDecFromStr("79999.99380121") + require.Nil(t, err) + queryCheck[types.TestBasePooledToken2], err = sdk.NewDecFromStr("90001.98782155") + require.Nil(t, err) + queryCheck[types.TestBasePooledToken3] = sdk.NewDec(100000) + + for _, c := range acc.GetCoins() { + value, ok := queryCheck[c.Denom] + require.True(t, ok) + require.Equal(t, value, c.Amount) + } +} + +func TestHandleMsgTokenToTokenDirectly(t *testing.T) { + mapp, addrKeysSlice := getMockAppWithBalance(t, 1, 100000) + keeper := mapp.swapKeeper + mapp.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: 2}}) + ctx := mapp.BaseApp.NewContext(false, abci.Header{}).WithBlockHeight(10).WithBlockTime(time.Now()) + testToken := initToken(types.TestBasePooledToken) + secondTestToken := initToken(types.TestBasePooledToken2) + mapp.swapKeeper.SetParams(ctx, types.DefaultParams()) + + mapp.supplyKeeper.SetSupply(ctx, supply.NewSupply(mapp.TotalCoinsSupply)) + handler := NewHandler(keeper) + msgCreateExchange := types.NewMsgCreateExchange(testToken.Symbol, secondTestToken.Symbol, addrKeysSlice[0].Address) + mapp.tokenKeeper.NewToken(ctx, testToken) + mapp.tokenKeeper.NewToken(ctx, secondTestToken) + + result := handler(ctx, msgCreateExchange) + require.Equal(t, "", result.Log) + + minLiquidity := sdk.NewDec(1) + maxBaseAmount := sdk.NewDecCoinFromDec(testToken.Symbol, sdk.NewDec(10000)) + quoteAmount := sdk.NewDecCoinFromDec(secondTestToken.Symbol, sdk.NewDec(10000)) + deadLine := time.Now().Unix() + addr := addrKeysSlice[0].Address + + addLiquidityMsg := types.NewMsgAddLiquidity(minLiquidity, maxBaseAmount, quoteAmount, deadLine, addr) + result = handler(ctx, addLiquidityMsg) + require.Equal(t, "", result.Log) + + minBoughtTokenAmount := sdk.NewDecCoinFromDec(testToken.Symbol, sdk.NewDec(1)) + deadLine = time.Now().Unix() + soldTokenAmount := sdk.NewDecCoinFromDec(secondTestToken.Symbol, sdk.NewDec(2)) + + tests := []struct { + testCase string + minBoughtTokenAmount sdk.DecCoin + soldTokenAmount sdk.DecCoin + deadLine int64 + recipient sdk.AccAddress + addr sdk.AccAddress + exceptResultCode sdk.CodeType + }{ + { + testCase: "(tokenToTokenDirectly) success", + minBoughtTokenAmount: minBoughtTokenAmount, + soldTokenAmount: soldTokenAmount, + deadLine: deadLine, + recipient: addr, + addr: addr, + exceptResultCode: sdk.CodeOK}, + } + + for _, testCase := range tests { + fmt.Println(testCase.testCase) + addLiquidityMsg := types.NewMsgTokenToToken(testCase.soldTokenAmount, testCase.minBoughtTokenAmount, testCase.deadLine, testCase.recipient, testCase.addr) + result = handler(ctx, addLiquidityMsg) + fmt.Println(result.Log) + require.Equal(t, testCase.exceptResultCode, result.Code) + + } + + acc := mapp.AccountKeeper.GetAccount(ctx, addr) + require.False(t, acc.GetCoins().Empty()) + queryCheck := make(map[string]sdk.Dec) + var err error + testPoolToken1 := types.GetPoolTokenName(testToken.Symbol, secondTestToken.Symbol) + queryCheck[testPoolToken1], err = sdk.NewDecFromStr("1") + require.Nil(t, err) + + queryCheck[types.TestBasePooledToken], err = sdk.NewDecFromStr("90001.99360247") + require.Nil(t, err) + queryCheck[types.TestBasePooledToken2] = sdk.NewDec(89998) + require.Nil(t, err) + queryCheck[types.TestBasePooledToken3] = sdk.NewDec(100000) + queryCheck[types.TestQuotePooledToken] = sdk.NewDec(100000) + + for _, c := range acc.GetCoins() { + fmt.Println() + value, ok := queryCheck[c.Denom] + require.True(t, ok) + require.Equal(t, value, c.Amount) + } } func TestGetInputPrice(t *testing.T) { defaultFeeRate := sdk.NewDecWithPrec(3, 3) - inputAmount := sdk.NewDecWithPrec(1, 8) + inputAmount := sdk.NewDecWithPrec(0, 8) inputReserve := sdk.NewDec(100) outputReserve := sdk.NewDec(100) - res := getInputPrice(inputAmount, inputReserve, outputReserve, defaultFeeRate) + res := keeper.GetInputPrice(inputAmount, inputReserve, outputReserve, defaultFeeRate) require.Equal(t, inputAmount, res) } @@ -276,11 +473,13 @@ func TestRandomData(t *testing.T) { ctx := mapp.BaseApp.NewContext(false, abci.Header{}).WithBlockHeight(10).WithBlockTime(time.Now()) mapp.swapKeeper.SetParams(ctx, types.DefaultParams()) testToken := initToken(types.TestBasePooledToken) + testQuoteToken := initToken(types.TestQuotePooledToken) mapp.supplyKeeper.SetSupply(ctx, supply.NewSupply(mapp.TotalCoinsSupply)) handler := NewHandler(keeper) mapp.tokenKeeper.NewToken(ctx, testToken) - msgCreateExchange := types.NewMsgCreateExchange(testToken.Symbol, addrKeysSlice[0].Address) + mapp.tokenKeeper.NewToken(ctx, testQuoteToken) + msgCreateExchange := types.NewMsgCreateExchange(testToken.Symbol, types.TestQuotePooledToken, addrKeysSlice[0].Address) result := handler(ctx, msgCreateExchange) require.Equal(t, "", result.Log) addr := addrKeysSlice[0].Address @@ -296,7 +495,7 @@ func TestRandomData(t *testing.T) { case 1: msg = buildRandomMsgRemoveLiquidity(addr) case 2: - msg = buildRandomMsgTokenToNativeToken(addr) + msg = buildRandomMsgTokenToToken(addr) } res := handler(ctx, msg) if !res.Code.IsOK() { @@ -331,17 +530,17 @@ func buildRandomMsgRemoveLiquidity(addr sdk.AccAddress) types.MsgRemoveLiquidity return msg } -func buildRandomMsgTokenToNativeToken(addr sdk.AccAddress) types.MsgTokenToNativeToken { +func buildRandomMsgTokenToToken(addr sdk.AccAddress) types.MsgTokenToToken { minBoughtTokenAmount := sdk.NewDecCoinFromDec(types.TestBasePooledToken, sdk.NewDec(0)) d := rand.Intn(100) + 1 soldTokenAmount := sdk.NewDecCoinFromDec(types.TestQuotePooledToken, sdk.NewDecWithPrec(int64(d), 8)) deadLine := time.Now().Unix() judge := rand.Intn(2) - var msg types.MsgTokenToNativeToken + var msg types.MsgTokenToToken if judge == 0 { - msg = types.NewMsgTokenToNativeToken(soldTokenAmount, minBoughtTokenAmount, deadLine, addr, addr) + msg = types.NewMsgTokenToToken(soldTokenAmount, minBoughtTokenAmount, deadLine, addr, addr) } else { - msg = types.NewMsgTokenToNativeToken(minBoughtTokenAmount, soldTokenAmount, deadLine, addr, addr) + msg = types.NewMsgTokenToToken(minBoughtTokenAmount, soldTokenAmount, deadLine, addr, addr) } return msg diff --git a/x/ammswap/keeper/keeper.go b/x/ammswap/keeper/keeper.go index 7b6867822c..80bc62112e 100644 --- a/x/ammswap/keeper/keeper.go +++ b/x/ammswap/keeper/keeper.go @@ -1,7 +1,9 @@ package keeper import ( + "errors" "fmt" + "github.com/okex/okexchain/x/common" "github.com/tendermint/tendermint/libs/log" @@ -44,6 +46,9 @@ func (k Keeper) GetSwapTokenPair(ctx sdk.Context, tokenPairName string) (types.S var item types.SwapTokenPair byteKey := types.GetTokenPairKey(tokenPairName) rawItem := store.Get(byteKey) + if rawItem == nil { + return types.SwapTokenPair{}, errors.New(fmt.Sprintf("non-existent swapTokenPair: %s", tokenPairName)) + } err := k.cdc.UnmarshalBinaryLengthPrefixed(rawItem, &item) if err != nil { return types.SwapTokenPair{}, err @@ -71,6 +76,17 @@ func (k Keeper) GetSwapTokenPairsIterator(ctx sdk.Context) sdk.Iterator { return sdk.KVStorePrefixIterator(store, types.TokenPairPrefixKey) } +func (k Keeper) GetSwapTokenPairs(ctx sdk.Context) []types.SwapTokenPair { + var result []types.SwapTokenPair + iterator := k.GetSwapTokenPairsIterator(ctx) + for ; iterator.Valid(); iterator.Next() { + tokenPair := types.SwapTokenPair{} + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(iterator.Value(), &tokenPair) + result = append(result, tokenPair) + } + return result +} + // NewPoolToken new token func (k Keeper) NewPoolToken(ctx sdk.Context, symbol string) { poolToken := types.InitPoolToken(symbol) @@ -134,3 +150,48 @@ func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) { func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { k.paramSpace.SetParamSet(ctx, ¶ms) } + + +func (k Keeper) GetRedeemableAssets(ctx sdk.Context,baseAmountName, quoteAmountName string, liquidity sdk.Dec) (baseAmount, quoteAmount sdk.DecCoin, err error) { + err = types.ValidateBaseAndQuoteAmount(baseAmountName, quoteAmountName) + if err != nil { + return + } + swapTokenPairName := types.GetSwapTokenPairName(baseAmountName, quoteAmountName) + swapTokenPair, err := k.GetSwapTokenPair(ctx, swapTokenPairName) + if err != nil { + return + } + poolTokenAmount := k.GetPoolTokenAmount(ctx, swapTokenPair.PoolTokenName) + if poolTokenAmount.LT(liquidity) { + return baseAmount, quoteAmount, errors.New("insufficient pool token") + } + + baseDec := common.MulAndQuo(swapTokenPair.BasePooledCoin.Amount, liquidity, poolTokenAmount) + quoteDec := common.MulAndQuo(swapTokenPair.QuotePooledCoin.Amount, liquidity, poolTokenAmount) + baseAmount = sdk.NewDecCoinFromDec(swapTokenPair.BasePooledCoin.Denom, baseDec) + quoteAmount = sdk.NewDecCoinFromDec(swapTokenPair.QuotePooledCoin.Denom, quoteDec) + return baseAmount, quoteAmount, nil +} + +//CalculateTokenToBuy calculates the amount to buy +func CalculateTokenToBuy(swapTokenPair types.SwapTokenPair, sellToken sdk.DecCoin, buyTokenDenom string, params types.Params) sdk.DecCoin { + var inputReserve, outputReserve sdk.Dec + if buyTokenDenom < sellToken.Denom { + inputReserve = swapTokenPair.QuotePooledCoin.Amount + outputReserve = swapTokenPair.BasePooledCoin.Amount + } else { + inputReserve = swapTokenPair.BasePooledCoin.Amount + outputReserve = swapTokenPair.QuotePooledCoin.Amount + } + tokenBuyAmt := GetInputPrice(sellToken.Amount, inputReserve, outputReserve, params.FeeRate) + tokenBuy := sdk.NewDecCoinFromDec(buyTokenDenom, tokenBuyAmt) + + return tokenBuy +} + +func GetInputPrice(inputAmount, inputReserve, outputReserve, feeRate sdk.Dec) sdk.Dec { + inputAmountWithFee := inputAmount.MulTruncate(sdk.OneDec().Sub(feeRate).MulTruncate(sdk.NewDec(1000))) + denominator := inputReserve.MulTruncate(sdk.NewDec(1000)).Add(inputAmountWithFee) + return common.MulAndQuo(inputAmountWithFee, outputReserve, denominator) +} diff --git a/x/ammswap/keeper/keeper_test.go b/x/ammswap/keeper/keeper_test.go index 03ccc139bc..29ab1a9926 100644 --- a/x/ammswap/keeper/keeper_test.go +++ b/x/ammswap/keeper/keeper_test.go @@ -6,13 +6,13 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/supply" "github.com/okex/okexchain/x/ammswap/types" - "github.com/okex/okexchain/x/common" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" ) +const addrTest = "okexchain1a20d4xmqj4m9shtm0skt0aaahsgeu4h6746fs2" + func TestKeeper_GetPoolTokenInfo(t *testing.T) { - addrTest := "okexchain1a20d4xmqj4m9shtm0skt0aaahsgeu4h6746fs2" mapp, _ := GetTestInput(t, 1) keeper := mapp.swapKeeper mapp.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: 2}}) @@ -20,7 +20,7 @@ func TestKeeper_GetPoolTokenInfo(t *testing.T) { mapp.supplyKeeper.SetSupply(ctx, supply.NewSupply(mapp.TotalCoinsSupply)) // init a pool token - symbol := types.PoolTokenPrefix + common.TestToken + symbol := types.GetPoolTokenName(types.TestBasePooledToken, types.TestQuotePooledToken) keeper.NewPoolToken(ctx, symbol) poolToken, err := keeper.GetPoolTokenInfo(ctx, symbol) require.Nil(t, err) @@ -40,3 +40,42 @@ func TestKeeper_GetPoolTokenInfo(t *testing.T) { balance := mapp.bankKeeper.GetCoins(ctx, sdk.AccAddress(addrTest)) require.NotNil(t, balance) } + +func TestKeeper_GetSwapTokenPairs(t *testing.T) { + mapp, _ := GetTestInput(t, 1) + keeper := mapp.swapKeeper + mapp.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: 2}}) + ctx := mapp.BaseApp.NewContext(false, abci.Header{}).WithBlockHeight(10) + mapp.supplyKeeper.SetSupply(ctx, supply.NewSupply(mapp.TotalCoinsSupply)) + + swapTokenPair := types.GetTestSwapTokenPair() + keeper.SetSwapTokenPair(ctx, types.TestSwapTokenPairName, swapTokenPair) + + expectedSwapTokenPairList := []types.SwapTokenPair{swapTokenPair} + swapTokenPairList := keeper.GetSwapTokenPairs(ctx) + require.Equal(t, expectedSwapTokenPairList, swapTokenPairList) +} + +func TestKeeper_GetRedeemableAssets(t *testing.T) { + mapp, _ := GetTestInput(t, 1) + keeper := mapp.swapKeeper + mapp.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: 2}}) + ctx := mapp.BaseApp.NewContext(false, abci.Header{}).WithBlockHeight(10) + mapp.supplyKeeper.SetSupply(ctx, supply.NewSupply(mapp.TotalCoinsSupply)) + + swapTokenPair := types.GetTestSwapTokenPair() + tokenNumber := sdk.NewDec(100) + swapTokenPair.QuotePooledCoin.Amount = tokenNumber + swapTokenPair.BasePooledCoin.Amount = tokenNumber + keeper.SetSwapTokenPair(ctx, types.TestSwapTokenPairName, swapTokenPair) + poolToken := types.InitPoolToken(swapTokenPair.PoolTokenName) + initPoolTokenAmount := sdk.NewDecCoinFromDec(swapTokenPair.PoolTokenName, sdk.NewDec(1)) + err := keeper.MintPoolCoinsToUser(ctx, sdk.DecCoins{initPoolTokenAmount}, sdk.AccAddress(addrTest)) + require.Nil(t, err) + mapp.tokenKeeper.NewToken(ctx, poolToken) + + expectedBaseAmount, expectedQuoteAmount := swapTokenPair.BasePooledCoin, swapTokenPair.QuotePooledCoin + baseAmount, quoteAmount, err := keeper.GetRedeemableAssets(ctx, swapTokenPair.BasePooledCoin.Denom, swapTokenPair.QuotePooledCoin.Denom, initPoolTokenAmount.Amount) + require.Equal(t, expectedBaseAmount, baseAmount) + require.Equal(t, expectedQuoteAmount, quoteAmount) +} \ No newline at end of file diff --git a/x/ammswap/keeper/querier.go b/x/ammswap/keeper/querier.go index 7afb963bdb..2b116454b8 100644 --- a/x/ammswap/keeper/querier.go +++ b/x/ammswap/keeper/querier.go @@ -1,7 +1,7 @@ package keeper import ( - "github.com/okex/okexchain/x/common" + "fmt" abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -16,6 +16,12 @@ func NewQuerier(k Keeper) sdk.Querier { return querySwapTokenPair(ctx, path[1:], req, k) case types.QueryParams: return queryParams(ctx, path[1:], req, k) + case types.QuerySwapTokenPairs: + return querySwapTokenPairs(ctx, path[1:], req, k) + case types.QueryRedeemableAssets: + return queryRedeemableAssets(ctx, path[1:], req, k) + case types.QueryBuyAmount: + return queryBuyAmount(ctx, path[1:], req, k) default: return nil, sdk.ErrUnknownRequest("unknown swap query endpoint") } @@ -23,17 +29,106 @@ func NewQuerier(k Keeper) sdk.Querier { } // nolint -func querySwapTokenPair(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, - err sdk.Error) { - tokenPairName := path[0] + "_" + common.NativeToken - tokenPair, error := keeper.GetSwapTokenPair(ctx, tokenPairName) - if error != nil { - return nil, sdk.ErrUnknownRequest(error.Error()) +func querySwapTokenPair( + ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper, +) (res []byte, err sdk.Error) { + baseAmountName := path[0] + quoteAmountName := path[1] + errToken := types.ValidateBaseAndQuoteAmount(baseAmountName, quoteAmountName) + if errToken != nil { + return nil, sdk.ErrUnknownRequest(errToken.Error()) + } + tokenPairName := types.GetSwapTokenPairName(baseAmountName, quoteAmountName) + tokenPair, errSwapTokenPair := keeper.GetSwapTokenPair(ctx, tokenPairName) + if errSwapTokenPair != nil { + return nil, sdk.ErrUnknownRequest(errSwapTokenPair.Error()) } bz := keeper.cdc.MustMarshalJSON(tokenPair) return bz, nil } +// nolint +func queryBuyAmount( + ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper, +) ([]byte, sdk.Error) { + var queryParams types.QueryBuyAmountParams + err := keeper.cdc.UnmarshalJSON(req.Data, &queryParams) + if err != nil { + return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + } + errToken := types.ValidateSwapAmountName(queryParams.TokenToBuy) + if errToken != nil { + return nil, sdk.ErrUnknownRequest(errToken.Error()) + } + errToken = types.ValidateSwapAmountName(queryParams.SoldToken.Denom) + if errToken != nil { + return nil, sdk.ErrUnknownRequest(errToken.Error()) + } + params := keeper.GetParams(ctx) + var buyAmount sdk.Dec + swapTokenPair := types.GetSwapTokenPairName(queryParams.SoldToken.Denom, queryParams.TokenToBuy) + tokenPair, errTokenPair := keeper.GetSwapTokenPair(ctx, swapTokenPair) + if errTokenPair == nil { + if tokenPair.BasePooledCoin.IsZero() || tokenPair.QuotePooledCoin.IsZero() { + return nil, sdk.ErrInternal(fmt.Sprintf("failed to query buy amount: empty pool: %s", tokenPair.String())) + } + buyAmount = CalculateTokenToBuy(tokenPair, queryParams.SoldToken, queryParams.TokenToBuy, params).Amount + }else { + tokenPairName1 := types.GetSwapTokenPairName(queryParams.SoldToken.Denom, sdk.DefaultBondDenom) + tokenPair1, err := keeper.GetSwapTokenPair(ctx, tokenPairName1) + if err != nil { + return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + } + if tokenPair1.BasePooledCoin.IsZero() || tokenPair1.QuotePooledCoin.IsZero() { + return nil, sdk.ErrInternal(fmt.Sprintf("failed to query buy amount: empty pool: %s", tokenPair1.String())) + } + tokenPairName2 := types.GetSwapTokenPairName(queryParams.TokenToBuy, sdk.DefaultBondDenom) + tokenPair2, err := keeper.GetSwapTokenPair(ctx, tokenPairName2) + if err != nil { + return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + } + if tokenPair2.BasePooledCoin.IsZero() || tokenPair2.QuotePooledCoin.IsZero() { + return nil, sdk.ErrInternal(fmt.Sprintf("failed to query buy amount: empty pool: %s", tokenPair2.String())) + } + nativeToken := CalculateTokenToBuy(tokenPair1, queryParams.SoldToken, sdk.DefaultBondDenom, params) + buyAmount = CalculateTokenToBuy(tokenPair2, nativeToken, queryParams.TokenToBuy, params).Amount + } + + bz := keeper.cdc.MustMarshalJSON(buyAmount) + + return bz, nil +} + func queryParams(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { return keeper.cdc.MustMarshalJSON(keeper.GetParams(ctx)), nil } + +// nolint +func querySwapTokenPairs(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, + err sdk.Error) { + return keeper.cdc.MustMarshalJSON(keeper.GetSwapTokenPairs(ctx)), nil +} + + +// nolint +func queryRedeemableAssets(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, + err sdk.Error) { + baseAmountName := path[0] + quoteAmountName := path[1] + errToken := types.ValidateBaseAndQuoteAmount(baseAmountName, quoteAmountName) + if errToken != nil { + return nil, sdk.ErrUnknownRequest(errToken.Error()) + } + liquidity, decErr := sdk.NewDecFromStr(path[2]) + if decErr != nil { + return nil, sdk.ErrUnknownRequest("invalid params: liquidity") + } + var tokenList sdk.DecCoins + baseToken, quoteToken, redeemErr := keeper.GetRedeemableAssets(ctx, baseAmountName, quoteAmountName, liquidity) + if redeemErr != nil { + return nil, sdk.ErrUnknownRequest(redeemErr.Error()) + } + tokenList = append(tokenList, baseToken, quoteToken) + bz := keeper.cdc.MustMarshalJSON(tokenList) + return bz, nil +} \ No newline at end of file diff --git a/x/ammswap/keeper/querier_test.go b/x/ammswap/keeper/querier_test.go index 5cb65c188c..4466d7e60b 100644 --- a/x/ammswap/keeper/querier_test.go +++ b/x/ammswap/keeper/querier_test.go @@ -1,39 +1,44 @@ package keeper import ( + "github.com/cosmos/cosmos-sdk/x/mock" "testing" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/supply" "github.com/okex/okexchain/x/ammswap/types" - "github.com/okex/okexchain/x/common" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" ) -func TestNewQuerier(t *testing.T) { - mapp, _ := GetTestInput(t, 1) - keeper := mapp.swapKeeper +func initQurierTest(t *testing.T) (*TestInput, mock.AddrKeysSlice, sdk.Context, Keeper, sdk.Querier) { + mapp, addrSlice := GetTestInput(t, 1) mapp.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: 2}}) ctx := mapp.BaseApp.NewContext(false, abci.Header{}).WithBlockHeight(10) mapp.supplyKeeper.SetSupply(ctx, supply.NewSupply(mapp.TotalCoinsSupply)) + keeper := mapp.swapKeeper + keeper.SetParams(ctx, types.DefaultParams()) + return mapp, addrSlice, ctx, keeper, NewQuerier(mapp.swapKeeper) +} + +func TestNewQuerier(t *testing.T) { + _, _, ctx, keeper, querier := initQurierTest(t) // querier with wrong path - querier := NewQuerier(keeper) - path0 := []string{"any", common.TestToken} + path0 := []string{"any", types.TestBasePooledToken} tokenpair, err := querier(ctx, path0, abci.RequestQuery{}) require.NotNil(t, err) require.Nil(t, tokenpair) // querier with wrong token - path := []string{types.QuerySwapTokenPair, common.TestToken} + path := []string{types.QuerySwapTokenPair, types.TestBasePooledToken, types.TestQuotePooledToken} tokenpair, err = querier(ctx, path, abci.RequestQuery{}) require.NotNil(t, err) require.Nil(t, tokenpair) // add new tokenpair and querier - tokenPair := common.TestToken + "_" + common.NativeToken - swapTokenPair := initTokenPair(common.TestToken) + tokenPair := types.TestSwapTokenPairName + swapTokenPair := types.GetTestSwapTokenPair() keeper.SetSwapTokenPair(ctx, tokenPair, swapTokenPair) tokenpair, err = querier(ctx, path, abci.RequestQuery{}) require.Nil(t, err) @@ -42,7 +47,7 @@ func TestNewQuerier(t *testing.T) { // check the value result := &types.SwapTokenPair{} keeper.cdc.MustUnmarshalJSON(tokenpair, result) - require.EqualValues(t, result.BasePooledCoin.Denom, common.TestToken) + require.EqualValues(t, result.BasePooledCoin.Denom, types.TestBasePooledToken) // delete tokenpair and querier keeper.DeleteSwapTokenPair(ctx, tokenPair) @@ -51,16 +56,98 @@ func TestNewQuerier(t *testing.T) { require.Nil(t, tokenpair) } -func initTokenPair(token string) types.SwapTokenPair { - poolName := types.PoolTokenPrefix + token - baseToken := sdk.NewDecCoinFromDec(token, sdk.ZeroDec()) - quoteToken := sdk.NewDecCoinFromDec(common.NativeToken, sdk.ZeroDec()) +func TestQueryParams(t *testing.T) { + _, _, ctx, keeper, querier := initQurierTest(t) + + path0 := []string{types.QueryParams} + resultBytes, err := querier(ctx, path0, abci.RequestQuery{}) + require.Nil(t, err) + result := types.Params{} + keeper.cdc.MustUnmarshalJSON(resultBytes, &result) + require.Equal(t, types.DefaultParams(), result) +} + +func TestQuerySwapTokenPairs(t *testing.T) { + _, _, ctx, keeper, querier := initQurierTest(t) + + tokenPair := types.TestSwapTokenPairName + swapTokenPair := types.GetTestSwapTokenPair() + keeper.SetSwapTokenPair(ctx, tokenPair, swapTokenPair) + + path := []string{types.QuerySwapTokenPairs} + resultBytes, err := querier(ctx, path, abci.RequestQuery{}) + require.Nil(t, err) + var result []types.SwapTokenPair + keeper.cdc.MustUnmarshalJSON(resultBytes, &result) + expectedSwapTokenPairList := []types.SwapTokenPair{swapTokenPair} + require.Equal(t, expectedSwapTokenPairList, result) +} +func initTestPool(t *testing.T, addrList mock.AddrKeysSlice, mapp *TestInput, + ctx sdk.Context, keeper Keeper, baseTokenAmount, quoteTokenAmount sdk.DecCoin, poolTokenAmount sdk.Dec) types.SwapTokenPair{ swapTokenPair := types.SwapTokenPair{ - BasePooledCoin: baseToken, - QuotePooledCoin: quoteToken, - PoolTokenName: poolName, + QuotePooledCoin: quoteTokenAmount, + BasePooledCoin: baseTokenAmount, + PoolTokenName: types.GetPoolTokenName(baseTokenAmount.Denom, quoteTokenAmount.Denom), } - + keeper.SetSwapTokenPair(ctx, types.GetSwapTokenPairName(baseTokenAmount.Denom, quoteTokenAmount.Denom), swapTokenPair) + poolToken := types.InitPoolToken(swapTokenPair.PoolTokenName) + initPoolTokenAmount := sdk.NewDecCoinFromDec(swapTokenPair.PoolTokenName, poolTokenAmount) + mapp.tokenKeeper.NewToken(ctx, poolToken) + err := keeper.MintPoolCoinsToUser(ctx, sdk.DecCoins{initPoolTokenAmount}, addrList[0].Address) + require.Nil(t, err) return swapTokenPair } + +func TestQueryRedeemableAssets(t *testing.T) { + mapp, addrList, ctx, keeper, querier := initQurierTest(t) + + baseTokenAmount := sdk.NewDecCoinFromDec(types.TestBasePooledToken, sdk.NewDec(100)) + quoteTokenAmount := sdk.NewDecCoinFromDec(types.TestQuotePooledToken, sdk.NewDec(100)) + poolTokenAmount := sdk.NewDec(1) + swapTokenPair := initTestPool(t, addrList, mapp, ctx, keeper, baseTokenAmount, quoteTokenAmount, poolTokenAmount) + + + path := []string{types.QueryRedeemableAssets, swapTokenPair.BasePooledCoin.Denom, swapTokenPair.QuotePooledCoin.Denom, poolTokenAmount.String()} + resultBytes, err := querier(ctx, path, abci.RequestQuery{}) + require.Nil(t, err) + var result []sdk.DecCoin + keeper.cdc.MustUnmarshalJSON(resultBytes, &result) + expectedAmountList := []sdk.DecCoin{swapTokenPair.BasePooledCoin, swapTokenPair.QuotePooledCoin} + require.Equal(t, expectedAmountList, result) +} + +func TestQueryBuyAmount(t *testing.T) { + mapp, addrList, ctx, keeper, querier := initQurierTest(t) + + baseTokenAmount := sdk.NewDecCoinFromDec(types.TestBasePooledToken, sdk.NewDec(100)) + quoteTokenAmount := sdk.NewDecCoinFromDec(types.TestQuotePooledToken, sdk.NewDec(100)) + poolTokenAmount := sdk.NewDec(1) + swapTokenPair := initTestPool(t, addrList, mapp, ctx, keeper, baseTokenAmount, quoteTokenAmount, poolTokenAmount) + + path := []string{types.QueryBuyAmount} + var queryParams types.QueryBuyAmountParams + queryParams.SoldToken = swapTokenPair.QuotePooledCoin + queryParams.TokenToBuy = swapTokenPair.BasePooledCoin.Denom + requestBytes := keeper.cdc.MustMarshalJSON(queryParams) + resultBytes, err := querier(ctx, path, abci.RequestQuery{Data: requestBytes}) + require.Nil(t, err) + var result string + keeper.cdc.MustUnmarshalJSON(resultBytes, &result) + expectedToken := "49.92488733" + require.Equal(t, expectedToken, result) + + baseTokenAmount2 := sdk.NewDecCoinFromDec(types.TestBasePooledToken2, sdk.NewDec(100)) + quoteTokenAmount2 := sdk.NewDecCoinFromDec(types.TestQuotePooledToken, sdk.NewDec(100)) + poolTokenAmount2 := sdk.NewDec(1) + swapTokenPair2 := initTestPool(t, addrList, mapp, ctx, keeper, baseTokenAmount2, quoteTokenAmount2, poolTokenAmount2) + + queryParams.SoldToken = swapTokenPair2.BasePooledCoin + queryParams.TokenToBuy = swapTokenPair.BasePooledCoin.Denom + requestBytes = keeper.cdc.MustMarshalJSON(queryParams) + resultBytes, err = querier(ctx, path, abci.RequestQuery{Data: requestBytes}) + require.Nil(t, err) + keeper.cdc.MustUnmarshalJSON(resultBytes, &result) + expectedToken = "33.23323333" + require.Equal(t, expectedToken, result) +} \ No newline at end of file diff --git a/x/ammswap/types/codec.go b/x/ammswap/types/codec.go index 6b7b8eb568..b53699db25 100644 --- a/x/ammswap/types/codec.go +++ b/x/ammswap/types/codec.go @@ -9,7 +9,7 @@ func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(MsgAddLiquidity{}, "okexchain/ammswap/MsgAddLiquidity", nil) cdc.RegisterConcrete(MsgRemoveLiquidity{}, "okexchain/ammswap/MsgRemoveLiquidity", nil) cdc.RegisterConcrete(MsgCreateExchange{}, "okexchain/ammswap/MsgCreateExchange", nil) - cdc.RegisterConcrete(MsgTokenToNativeToken{}, "okexchain/ammswap/MsgSwapToken", nil) + cdc.RegisterConcrete(MsgTokenToToken{}, "okexchain/ammswap/MsgSwapToken", nil) } // ModuleCdc defines the module codec diff --git a/x/ammswap/types/keys.go b/x/ammswap/types/keys.go index 7816cec89f..c73be83479 100644 --- a/x/ammswap/types/keys.go +++ b/x/ammswap/types/keys.go @@ -16,7 +16,13 @@ const ( // QuerySwapTokenPair query endpoints supported by the swap Querier QuerySwapTokenPair = "swapTokenPair" + QuerySwapTokenPairs = "swapTokenPairs" + + QueryRedeemableAssets = "queryRedeemableAssets" + QueryParams = "params" + + QueryBuyAmount = "buy" ) var ( diff --git a/x/ammswap/types/msg_test.go b/x/ammswap/types/msg_test.go index b1c7b30481..6f2e211afe 100644 --- a/x/ammswap/types/msg_test.go +++ b/x/ammswap/types/msg_test.go @@ -4,6 +4,7 @@ import ( "encoding/hex" "encoding/json" "fmt" + "github.com/okex/okexchain/x/common" "testing" "time" @@ -17,7 +18,7 @@ func TestMsgCreateExchange(t *testing.T) { addr, err := hex.DecodeString(addrStr) require.Nil(t, err) testToken := InitPoolToken(TestBasePooledToken) - msg := NewMsgCreateExchange(testToken.Symbol, addr) + msg := NewMsgCreateExchange(testToken.Symbol, TestQuotePooledToken, addr) require.Nil(t, msg.ValidateBasic()) require.Equal(t, RouterKey, msg.Route()) require.Equal(t, "create_exchange", msg.Type()) @@ -28,6 +29,9 @@ func TestMsgCreateExchange(t *testing.T) { require.Nil(t, err) resAddr := msg.GetSigners()[0] require.EqualValues(t, addr, resAddr) + + expectTokenPair := TestBasePooledToken + "_" + TestQuotePooledToken + require.Equal(t, expectTokenPair, msg.GetSwapTokenPairName()) } func TestMsgCreateExchangeInvalid(t *testing.T) { @@ -35,18 +39,26 @@ func TestMsgCreateExchangeInvalid(t *testing.T) { require.Nil(t, err) tests := []struct { testCase string - symbol string + symbol0 string + symbol1 string addr sdk.AccAddress exceptResultCode sdk.CodeType }{ - {"success", "xxx", addr, sdk.CodeOK}, - {"nil addr", "xxx", nil, sdk.CodeInvalidAddress}, - {"invalid token", "1ab", addr, sdk.CodeUnknownRequest}, + {"success", "aaa", common.NativeToken, addr, sdk.CodeOK}, + {"success", "aaa", "bbb", addr, sdk.CodeOK}, + {"success", "bbb", "aaa", addr, sdk.CodeOK}, + {"nil addr", "aaa", common.NativeToken, nil, sdk.CodeInvalidAddress}, + {"invalid token", "1ab",common.NativeToken, addr, sdk.CodeInvalidCoins}, + {"invalid token", common.NativeToken, common.NativeToken, addr, sdk.CodeInvalidCoins}, + //{"The lexicographic order of BaseTokenName must be less than QuoteTokenName", "xxb", addr, sdk.CodeUnknownRequest}, + } - for _, testCase := range tests { - msg := NewMsgCreateExchange(testCase.symbol, testCase.addr) + for i, testCase := range tests { + msg := NewMsgCreateExchange(testCase.symbol0, testCase.symbol1, testCase.addr) err := msg.ValidateBasic() - if err == nil && testCase.exceptResultCode == sdk.CodeOK { + fmt.Println(i, err) + if err == nil { + require.Equal(t, testCase.exceptResultCode, sdk.CodeOK) continue } require.Equal(t, testCase.exceptResultCode, err.Code()) @@ -73,7 +85,7 @@ func TestMsgAddLiquidity(t *testing.T) { require.EqualValues(t, addr, resAddr) expectTokenPair := TestBasePooledToken + "_" + TestQuotePooledToken - require.Equal(t, expectTokenPair, msg.GetSwapTokenPair()) + require.Equal(t, expectTokenPair, msg.GetSwapTokenPairName()) } func TestMsgAddLiquidityInvalid(t *testing.T) { @@ -99,18 +111,22 @@ func TestMsgAddLiquidityInvalid(t *testing.T) { addr sdk.AccAddress exceptResultCode sdk.CodeType }{ - {"success", minLiquidity, maxBaseAmount, quoteAmount, deadLine, addr, 0}, + {"success", minLiquidity, maxBaseAmount, quoteAmount, deadLine, addr, sdk.CodeOK}, {"tokens must be positive", minLiquidity, maxBaseAmount, notPositiveQuoteAmount, deadLine, addr, sdk.CodeUnknownRequest}, {"invalid MaxBaseAmount", minLiquidity, invalidMaxBaseAmount, quoteAmount, deadLine, addr, sdk.CodeUnknownRequest}, {"invalid QuoteAmount", minLiquidity, maxBaseAmount, invalidQuoteAmount, deadLine, addr, sdk.CodeUnknownRequest}, - {"quote token only supports native token", minLiquidity, maxBaseAmount, notNativeQuoteAmount, deadLine, addr, sdk.CodeUnknownRequest}, + {"success(quote token supports any type of tokens)", minLiquidity, maxBaseAmount, notNativeQuoteAmount, deadLine, addr, sdk.CodeOK}, {"empty sender", minLiquidity, maxBaseAmount, quoteAmount, deadLine, nil, sdk.CodeInvalidAddress}, + {"invalid token", minLiquidity, maxBaseAmount, maxBaseAmount, deadLine, addr, sdk.CodeUnknownRequest}, + {"The lexicographic order of BaseTokenName must be less than QuoteTokenName", minLiquidity, quoteAmount, maxBaseAmount, deadLine, addr, sdk.CodeUnknownRequest}, } - for _, testCase := range tests { + for i, testCase := range tests { fmt.Println(testCase.testCase) msg := NewMsgAddLiquidity(testCase.minLiquidity, testCase.maxBaseAmount, testCase.quoteAmount, testCase.deadLine, testCase.addr) err := msg.ValidateBasic() - if err == nil && testCase.exceptResultCode == sdk.CodeOK { + fmt.Println(i, err) + if err == nil { + require.Equal(t, testCase.exceptResultCode, sdk.CodeOK) continue } require.Equal(t, testCase.exceptResultCode, err.Code()) @@ -139,7 +155,7 @@ func TestMsgRemoveLiquidity(t *testing.T) { require.EqualValues(t, addr, resAddr) expectTokenPair := TestBasePooledToken + "_" + TestQuotePooledToken - require.Equal(t, expectTokenPair, msg.GetSwapTokenPair()) + require.Equal(t, expectTokenPair, msg.GetSwapTokenPairName()) } func TestMsgRemoveLiquidityInvalid(t *testing.T) { @@ -166,48 +182,53 @@ func TestMsgRemoveLiquidityInvalid(t *testing.T) { addr sdk.AccAddress exceptResultCode sdk.CodeType }{ - {"success", liquidity, minBaseAmount, minQuoteAmount, deadLine, addr, 0}, + {"success", liquidity, minBaseAmount, minQuoteAmount, deadLine, addr, sdk.CodeOK}, {"empty sender", liquidity, minBaseAmount, minQuoteAmount, deadLine, nil, sdk.CodeInvalidAddress}, {"coins must be positive", notPositiveLiquidity, minBaseAmount, minQuoteAmount, deadLine, addr, sdk.CodeUnknownRequest}, {"invalid MinBaseAmount", liquidity, invalidMinBaseAmount, minQuoteAmount, deadLine, addr, sdk.CodeUnknownRequest}, {"invalid MinQuoteAmount", liquidity, minBaseAmount, invalidMinQuoteAmount, deadLine, addr, sdk.CodeUnknownRequest}, - {"quote token only supports native token", liquidity, minBaseAmount, notNativeQuoteAmount, deadLine, addr, sdk.CodeUnknownRequest}, + {"success(quote token supports any type of tokens)", liquidity, minBaseAmount, notNativeQuoteAmount, deadLine, addr, sdk.CodeOK}, + {"invalid token", liquidity, minBaseAmount, minBaseAmount, deadLine, addr, sdk.CodeUnknownRequest}, + {"The lexicographic order of BaseTokenName must be less than QuoteTokenName", liquidity, minQuoteAmount, minBaseAmount, deadLine, addr, sdk.CodeUnknownRequest}, + + } for _, testCase := range tests { msg := NewMsgRemoveLiquidity(testCase.liquidity, testCase.minBaseAmount, testCase.minQuoteAmount, testCase.deadLine, testCase.addr) err := msg.ValidateBasic() - if err == nil && testCase.exceptResultCode == sdk.CodeOK { + if err == nil { + require.Equal(t, testCase.exceptResultCode, sdk.CodeOK) continue } require.Equal(t, testCase.exceptResultCode, err.Code()) } } -func TestMsgTokenToNativeToken(t *testing.T) { +func TestMsgTokenToToken(t *testing.T) { addr, err := hex.DecodeString(addrStr) require.Nil(t, err) minBoughtTokenAmount := sdk.NewDecCoinFromDec(TestBasePooledToken, sdk.NewDec(1)) deadLine := time.Now().Unix() soldTokenAmount := sdk.NewDecCoinFromDec(TestQuotePooledToken, sdk.NewDec(2)) - msg := NewMsgTokenToNativeToken(soldTokenAmount, minBoughtTokenAmount, deadLine, addr, addr) + msg := NewMsgTokenToToken(soldTokenAmount, minBoughtTokenAmount, deadLine, addr, addr) require.Nil(t, msg.ValidateBasic()) require.Equal(t, RouterKey, msg.Route()) require.Equal(t, TypeMsgTokenSwap, msg.Type()) bytesMsg := msg.GetSignBytes() - resMsg := &MsgTokenToNativeToken{} + resMsg := &MsgTokenToToken{} err = json.Unmarshal(bytesMsg, resMsg) require.Nil(t, err) resAddr := msg.GetSigners()[0] require.EqualValues(t, addr, resAddr) expectTokenPair := TestBasePooledToken + "_" + TestQuotePooledToken - require.Equal(t, expectTokenPair, msg.GetSwapTokenPair()) - msg = NewMsgTokenToNativeToken(minBoughtTokenAmount, soldTokenAmount, deadLine, addr, addr) - require.Equal(t, expectTokenPair, msg.GetSwapTokenPair()) + require.Equal(t, expectTokenPair, msg.GetSwapTokenPairName()) + msg = NewMsgTokenToToken(minBoughtTokenAmount, soldTokenAmount, deadLine, addr, addr) + require.Equal(t, expectTokenPair, msg.GetSwapTokenPairName()) } -func TestMsgTokenToNativeTokenInvalid(t *testing.T) { +func TestMsgTokenToTokenInvalid(t *testing.T) { addr, err := hex.DecodeString(addrStr) require.Nil(t, err) minBoughtTokenAmount := sdk.NewDecCoinFromDec(TestBasePooledToken, sdk.NewDec(1)) @@ -217,6 +238,8 @@ func TestMsgTokenToNativeTokenInvalid(t *testing.T) { invalidMinBoughtTokenAmount.Denom = "1aaa" invalidSoldTokenAmount := sdk.NewDecCoinFromDec(TestQuotePooledToken, sdk.NewDec(2)) invalidSoldTokenAmount.Denom = "1sdf" + invalidSoldTokenAmount2 := sdk.NewDecCoinFromDec(TestQuotePooledToken, sdk.NewDec(0)) + invalidSoldTokenAmount2.Denom = "aaa" notNativeSoldTokenAmount := sdk.NewDecCoinFromDec("abc", sdk.NewDec(2)) tests := []struct { @@ -231,14 +254,19 @@ func TestMsgTokenToNativeTokenInvalid(t *testing.T) { {"success", minBoughtTokenAmount, soldTokenAmount, deadLine, addr, addr, sdk.CodeOK}, {"empty sender", minBoughtTokenAmount, soldTokenAmount, deadLine, addr, nil, sdk.CodeInvalidAddress}, {"empty recipient", minBoughtTokenAmount, soldTokenAmount, deadLine, nil, addr, sdk.CodeInvalidAddress}, - {"both token to sell and token to buy do not contain native token", minBoughtTokenAmount, notNativeSoldTokenAmount, deadLine, addr, addr, sdk.CodeUnknownRequest}, + {"success(both token to sell and token to buy do not contain native token)", minBoughtTokenAmount, notNativeSoldTokenAmount, deadLine, addr, addr, sdk.CodeOK}, {"invalid SoldTokenAmount", soldTokenAmount, invalidSoldTokenAmount, deadLine, addr, addr, sdk.CodeUnknownRequest}, {"invalid MinBoughtTokenAmount", invalidMinBoughtTokenAmount, soldTokenAmount, deadLine, addr, addr, sdk.CodeUnknownRequest}, + {"invalid token", minBoughtTokenAmount, minBoughtTokenAmount, deadLine, addr, addr, sdk.CodeUnknownRequest}, + {"invalid SoldTokenAmount(zero)", minBoughtTokenAmount, invalidSoldTokenAmount2, deadLine, addr, addr, sdk.CodeUnknownRequest}, + + } for _, testCase := range tests { - msg := NewMsgTokenToNativeToken(testCase.soldTokenAmount, testCase.minBoughtTokenAmount, testCase.deadLine, testCase.recipient, testCase.addr) + msg := NewMsgTokenToToken(testCase.soldTokenAmount, testCase.minBoughtTokenAmount, testCase.deadLine, testCase.recipient, testCase.addr) err := msg.ValidateBasic() - if err == nil && testCase.exceptResultCode == sdk.CodeOK { + if err == nil { + require.Equal(t, testCase.exceptResultCode, sdk.CodeOK) continue } require.Equal(t, testCase.exceptResultCode, err.Code()) diff --git a/x/ammswap/types/msgs.go b/x/ammswap/types/msgs.go index f7f62a69a7..c5f780515d 100644 --- a/x/ammswap/types/msgs.go +++ b/x/ammswap/types/msgs.go @@ -1,10 +1,7 @@ package types import ( - "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/okex/okexchain/x/common" ) // PoolSwap message types and routes @@ -44,8 +41,11 @@ func (msg MsgAddLiquidity) ValidateBasic() sdk.Error { if msg.Sender.Empty() { return sdk.ErrInvalidAddress(msg.Sender.String()) } + if msg.MinLiquidity.IsNegative() { + return sdk.ErrUnknownRequest("invalid minimum of liquidity") + } if !(msg.MaxBaseAmount.IsPositive() && msg.QuoteAmount.IsPositive()) { - return sdk.ErrUnknownRequest("token amount must be positive") + return sdk.ErrUnknownRequest("invalid base amount or quote amount") } if !msg.MaxBaseAmount.IsValid() { return sdk.ErrUnknownRequest("invalid MaxBaseAmount") @@ -53,9 +53,11 @@ func (msg MsgAddLiquidity) ValidateBasic() sdk.Error { if !msg.QuoteAmount.IsValid() { return sdk.ErrUnknownRequest("invalid QuoteAmount") } - if msg.QuoteAmount.Denom != common.NativeToken { - return sdk.ErrUnknownRequest("quote token only supports " + common.NativeToken) + err := ValidateBaseAndQuoteAmount(msg.MaxBaseAmount.Denom, msg.QuoteAmount.Denom) + if err != nil { + return sdk.ErrUnknownRequest(err.Error()) } + return nil } @@ -70,8 +72,8 @@ func (msg MsgAddLiquidity) GetSigners() []sdk.AccAddress { } // GetSwapTokenPair defines token pair -func (msg MsgAddLiquidity) GetSwapTokenPair() string { - return msg.MaxBaseAmount.Denom + "_" + msg.QuoteAmount.Denom +func (msg MsgAddLiquidity) GetSwapTokenPairName() string { + return GetSwapTokenPairName(msg.MaxBaseAmount.Denom, msg.QuoteAmount.Denom) } // MsgRemoveLiquidity burns pool tokens to withdraw okt and Tokens at current ratio. @@ -106,16 +108,17 @@ func (msg MsgRemoveLiquidity) ValidateBasic() sdk.Error { return sdk.ErrInvalidAddress(msg.Sender.String()) } if !(msg.Liquidity.IsPositive()) { - return sdk.ErrUnknownRequest("token amount must be positive") + return sdk.ErrUnknownRequest("invalid liquidity") } if !msg.MinBaseAmount.IsValid() { - return sdk.ErrUnknownRequest("invalid MinBaseAmount") + return sdk.ErrUnknownRequest("invalid minimum of base amount") } if !msg.MinQuoteAmount.IsValid() { - return sdk.ErrUnknownRequest("invalid MinQuoteAmount") + return sdk.ErrUnknownRequest("invalid minimum of quote amount") } - if msg.MinQuoteAmount.Denom != common.NativeToken { - return sdk.ErrUnknownRequest("quote token only supports " + common.NativeToken) + err := ValidateBaseAndQuoteAmount(msg.MinBaseAmount.Denom, msg.MinQuoteAmount.Denom) + if err != nil { + return sdk.ErrUnknownRequest(err.Error()) } return nil } @@ -131,21 +134,23 @@ func (msg MsgRemoveLiquidity) GetSigners() []sdk.AccAddress { } // GetSwapTokenPair defines token pair -func (msg MsgRemoveLiquidity) GetSwapTokenPair() string { - return msg.MinBaseAmount.Denom + "_" + msg.MinQuoteAmount.Denom +func (msg MsgRemoveLiquidity) GetSwapTokenPairName() string { + return GetSwapTokenPairName(msg.MinBaseAmount.Denom, msg.MinQuoteAmount.Denom) } // MsgCreateExchange creates a new exchange with token type MsgCreateExchange struct { - Token string `json:"token"` // Token - Sender sdk.AccAddress `json:"sender"` // Sender + Token0Name string `json:"token0_name"` + Token1Name string `json:"token1_name"` + Sender sdk.AccAddress `json:"sender"` // Sender } // NewMsgCreateExchange create a new exchange with token -func NewMsgCreateExchange(token string, sender sdk.AccAddress) MsgCreateExchange { +func NewMsgCreateExchange(token0Name string, token1Name string, sender sdk.AccAddress) MsgCreateExchange { return MsgCreateExchange{ - Token: token, - Sender: sender, + Token0Name: token0Name, + Token1Name: token1Name, + Sender: sender, } } @@ -160,8 +165,16 @@ func (msg MsgCreateExchange) ValidateBasic() sdk.Error { if msg.Sender.Empty() { return sdk.ErrInvalidAddress(msg.Sender.String()) } - if sdk.ValidateDenom(msg.Token) != nil || ValidatePoolTokenName(msg.Token) { - return sdk.ErrUnknownRequest("invalid Token") + if err := ValidateSwapAmountName(msg.Token0Name); err != nil { + return sdk.ErrInvalidCoins(err.Error()) + } + + if err := ValidateSwapAmountName(msg.Token1Name); err != nil { + return sdk.ErrInvalidCoins(err.Error()) + } + + if msg.Token0Name == msg.Token1Name { + return sdk.ErrInvalidCoins("Token0Name should not equal to Token1Name") } return nil } @@ -176,8 +189,13 @@ func (msg MsgCreateExchange) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.Sender} } -// MsgTokenToNativeToken define the message for swap between token and DefaultBondDenom -type MsgTokenToNativeToken struct { +// GetSwapTokenPair defines token pair +func (msg MsgCreateExchange) GetSwapTokenPairName() string { + return GetSwapTokenPairName(msg.Token0Name, msg.Token1Name) +} + +// MsgTokenToToken define the message for swap between token and DefaultBondDenom +type MsgTokenToToken struct { SoldTokenAmount sdk.DecCoin `json:"sold_token_amount"` // Amount of Tokens sold. MinBoughtTokenAmount sdk.DecCoin `json:"min_bought_token_amount"` // Minimum token purchased. Deadline int64 `json:"deadline"` // Time after which this transaction can no longer be executed. @@ -185,11 +203,11 @@ type MsgTokenToNativeToken struct { Sender sdk.AccAddress `json:"sender"` // Sender } -// NewMsgTokenToNativeToken is a constructor function for MsgTokenOKTSwap -func NewMsgTokenToNativeToken( +// NewMsgTokenToToken is a constructor function for MsgTokenOKTSwap +func NewMsgTokenToToken( soldTokenAmount, minBoughtTokenAmount sdk.DecCoin, deadline int64, recipient, sender sdk.AccAddress, -) MsgTokenToNativeToken { - return MsgTokenToNativeToken{ +) MsgTokenToToken { + return MsgTokenToToken{ SoldTokenAmount: soldTokenAmount, MinBoughtTokenAmount: minBoughtTokenAmount, Deadline: deadline, @@ -199,13 +217,13 @@ func NewMsgTokenToNativeToken( } // Route should return the name of the module -func (msg MsgTokenToNativeToken) Route() string { return RouterKey } +func (msg MsgTokenToToken) Route() string { return RouterKey } // Type should return the action -func (msg MsgTokenToNativeToken) Type() string { return TypeMsgTokenSwap } +func (msg MsgTokenToToken) Type() string { return TypeMsgTokenSwap } // ValidateBasic runs stateless checks on the message -func (msg MsgTokenToNativeToken) ValidateBasic() sdk.Error { +func (msg MsgTokenToToken) ValidateBasic() sdk.Error { if msg.Sender.Empty() { return sdk.ErrInvalidAddress(msg.Sender.String()) } @@ -214,37 +232,36 @@ func (msg MsgTokenToNativeToken) ValidateBasic() sdk.Error { return sdk.ErrInvalidAddress(msg.Recipient.String()) } - if msg.SoldTokenAmount.Denom != sdk.DefaultBondDenom && msg.MinBoughtTokenAmount.Denom != sdk.DefaultBondDenom { - return sdk.ErrUnknownRequest(fmt.Sprintf("both token to sell and token to buy do not contain %s,"+ - " quote token only supports %s", sdk.DefaultBondDenom, sdk.DefaultBondDenom)) - } if !(msg.SoldTokenAmount.IsPositive()) { - return sdk.ErrUnknownRequest("token amount must be positive") + return sdk.ErrUnknownRequest("invalid sold token amount") } if !msg.SoldTokenAmount.IsValid() { - return sdk.ErrUnknownRequest("invalid SoldTokenAmount") + return sdk.ErrUnknownRequest("invalid sold token amount") } if !msg.MinBoughtTokenAmount.IsValid() { - return sdk.ErrUnknownRequest("invalid MinBoughtTokenAmount") + return sdk.ErrUnknownRequest("invalid minimum of bought token amount") + } + + baseAmountName, quoteAmountName := GetBaseQuoteTokenName(msg.SoldTokenAmount.Denom, msg.MinBoughtTokenAmount.Denom) + err := ValidateBaseAndQuoteAmount(baseAmountName, quoteAmountName) + if err != nil { + return sdk.ErrUnknownRequest(err.Error()) } return nil } // GetSignBytes encodes the message for signing -func (msg MsgTokenToNativeToken) GetSignBytes() []byte { +func (msg MsgTokenToToken) GetSignBytes() []byte { return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg)) } // GetSigners defines whose signature is required -func (msg MsgTokenToNativeToken) GetSigners() []sdk.AccAddress { +func (msg MsgTokenToToken) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.Sender} } // GetSwapTokenPair defines token pair -func (msg MsgTokenToNativeToken) GetSwapTokenPair() string { - if msg.SoldTokenAmount.Denom == sdk.DefaultBondDenom { - return msg.MinBoughtTokenAmount.Denom + "_" + msg.SoldTokenAmount.Denom - } - return msg.SoldTokenAmount.Denom + "_" + msg.MinBoughtTokenAmount.Denom -} +func (msg MsgTokenToToken) GetSwapTokenPairName() string { + return GetSwapTokenPairName(msg.MinBoughtTokenAmount.Denom, msg.SoldTokenAmount.Denom) +} \ No newline at end of file diff --git a/x/ammswap/types/querier.go b/x/ammswap/types/querier.go new file mode 100644 index 0000000000..7614853d30 --- /dev/null +++ b/x/ammswap/types/querier.go @@ -0,0 +1,10 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type QueryBuyAmountParams struct { + SoldToken sdk.DecCoin + TokenToBuy string +} diff --git a/x/ammswap/types/swap.go b/x/ammswap/types/swap.go index c4f96bfe07..f15ad53e8f 100644 --- a/x/ammswap/types/swap.go +++ b/x/ammswap/types/swap.go @@ -1,17 +1,17 @@ package types import ( + "errors" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/supply" token "github.com/okex/okexchain/x/token/types" "fmt" - "regexp" "strings" ) // PoolTokenPrefix defines pool token prefix name -const PoolTokenPrefix = "ammswap-" +const PoolTokenPrefix = "ammswap_" // SwapTokenPair defines token pair exchange type SwapTokenPair struct { @@ -20,6 +20,17 @@ type SwapTokenPair struct { PoolTokenName string `json:"pool_token_name"` // The name of pool token } +func NewSwapPair(token0, token1 string) SwapTokenPair { + base, quote := GetBaseQuoteTokenName(token0, token1) + + swapTokenPair := SwapTokenPair{ + sdk.NewDecCoinFromDec(quote, sdk.ZeroDec()), + sdk.NewDecCoinFromDec(base, sdk.ZeroDec()), + GetPoolTokenName(token0, token1), + } + return swapTokenPair +} + // NewSwapTokenPair is a constructor function for SwapTokenPair func NewSwapTokenPair(quotePooledCoin sdk.DecCoin, basePooledCoin sdk.DecCoin, poolTokenName string) *SwapTokenPair { swapTokenPair := &SwapTokenPair{ @@ -56,9 +67,44 @@ func InitPoolToken(poolTokenName string) token.Token { } } -// ValidatePoolTokenName validates the format of specified pool token name -func ValidatePoolTokenName(tokenName string) bool { - var poolTokenFormat = fmt.Sprintf(`^(%s)[a-z][a-z0-9]{0,9}(\-[a-f0-9]{3})?$`, PoolTokenPrefix) - var poolTokenRegExp = regexp.MustCompile(poolTokenFormat) - return poolTokenRegExp.MatchString(tokenName) +func GetSwapTokenPairName(token0, token1 string) string { + baseTokenName, quoteTokenName := GetBaseQuoteTokenName(token0, token1) + return baseTokenName + "_" + quoteTokenName } + +func GetBaseQuoteTokenName(token0, token1 string) (string, string) { + if token0 < token1 { + return token0, token1 + } + return token1, token0 +} + +func ValidateBaseAndQuoteAmount(baseAmountName, quoteAmountName string) error { + if baseAmountName > quoteAmountName { + return errors.New("The lexicographic order of BaseTokenName must be less than QuoteTokenName") + }else if baseAmountName == quoteAmountName { + return errors.New("BaseTokenName should not equal to QuoteTokenName") + } + if err := ValidateSwapAmountName(baseAmountName); err != nil { + return err + } + + if err := ValidateSwapAmountName(quoteAmountName); err != nil { + return err + } + return nil +} + +func ValidateSwapAmountName(amountName string) error { + if sdk.ValidateDenom(amountName) != nil { + return errors.New(fmt.Sprintf("invalid token name: %s", amountName)) + } + if token.NotAllowedOriginSymbol(amountName) { + return errors.New(fmt.Sprintf("liquidity-pool-token(with prefix \"%s\") is not allowed to be a base or quote token", PoolTokenPrefix)) + } + return nil +} + +func GetPoolTokenName(token1, token2 string) string { + return PoolTokenPrefix + GetSwapTokenPairName(token1, token2) +} \ No newline at end of file diff --git a/x/ammswap/types/test_common.go b/x/ammswap/types/test_common.go index abe3f48437..086baadb30 100644 --- a/x/ammswap/types/test_common.go +++ b/x/ammswap/types/test_common.go @@ -6,9 +6,9 @@ import ( ) // nolint -const TestBasePooledToken = "xxb" -const TestBasePooledToken2 = "yyb" -const TestBasePooledToken3 = "zzb" +const TestBasePooledToken = "aab" +const TestBasePooledToken2 = "ccb" +const TestBasePooledToken3 = "ddb" const TestQuotePooledToken = common.NativeToken const TestSwapTokenPairName = TestBasePooledToken + "_" + TestQuotePooledToken @@ -17,6 +17,6 @@ func GetTestSwapTokenPair() SwapTokenPair { return SwapTokenPair{ QuotePooledCoin: sdk.NewDecCoinFromDec(TestQuotePooledToken, sdk.NewDec(0)), BasePooledCoin: sdk.NewDecCoinFromDec(TestBasePooledToken, sdk.NewDec(0)), - PoolTokenName: PoolTokenPrefix + TestBasePooledToken, + PoolTokenName: GetPoolTokenName(TestBasePooledToken, TestQuotePooledToken), } } diff --git a/x/backend/abci.go b/x/backend/abci.go index 0222093618..77f76f2610 100644 --- a/x/backend/abci.go +++ b/x/backend/abci.go @@ -67,8 +67,15 @@ func storeDealAndMatchResult(ctx sdk.Context, keeper Keeper) { } } - ts := keeper.Orm.GetMaxBlockTimestamp() - keeper.UpdateTickersBuffer(ts-types.SecondsInADay, ts+1, keeper.Cache.ProductsBuf) + // update ticker + var productList []string + for _, result := range results { + productList = append(productList, result.Product) + } + if len(productList) > 0 { + ts := keeper.Orm.GetMaxBlockTimestamp() + keeper.UpdateTickersBuffer(ts-types.SecondsInADay, ts+1, productList) + } } func storeFeeDetails(keeper Keeper) { diff --git a/x/backend/cache/cache.go b/x/backend/cache/cache.go index 39ce2e6861..2cbd0fa5f4 100644 --- a/x/backend/cache/cache.go +++ b/x/backend/cache/cache.go @@ -9,7 +9,6 @@ type Cache struct { // persist in memory LatestTicker map[string]*types.Ticker - ProductsBuf []string } // NewCache return cache pointer address, called at NewKeeper @@ -17,7 +16,6 @@ func NewCache() *Cache { return &Cache{ Transactions: make([]*types.Transaction, 0, 2000), LatestTicker: make(map[string]*types.Ticker), - ProductsBuf: make([]string, 0, 200), } } diff --git a/x/backend/cache/cache_test.go b/x/backend/cache/cache_test.go index 756b426b17..8e4cc48dec 100644 --- a/x/backend/cache/cache_test.go +++ b/x/backend/cache/cache_test.go @@ -13,8 +13,6 @@ func TestCache(t *testing.T) { require.Equal(t, 0, len(cache.Transactions)) require.Equal(t, 2000, cap(cache.Transactions)) require.Equal(t, 0, len(cache.LatestTicker)) - require.Equal(t, 0, len(cache.ProductsBuf)) - require.Equal(t, 200, cap(cache.ProductsBuf)) txs := []*types.Transaction{ {TxHash: "hash1", Type: types.TxTypeTransfer, Address: "addr1", Symbol: common.TestToken, Side: types.TxSideFrom, Quantity: "10.0", Fee: "0.1" + common.NativeToken, Timestamp: 100}, diff --git a/x/backend/client/cli/query.go b/x/backend/client/cli/query.go index 7cc7b3571c..64476dfebf 100644 --- a/x/backend/client/cli/query.go +++ b/x/backend/client/cli/query.go @@ -168,7 +168,7 @@ func GetCmdCandles(queryRoute string, cdc *codec.Codec) *cobra.Command { } cmd.Flags().IntP("granularity", "g", 60, "[60/180/300/900/1800/3600/7200/14400/21600/43200/86400/604800], second in unit") cmd.Flags().StringP("product", "p", "", "name of token pair") - cmd.Flags().IntP("limit", "", 1, "at most 1000") + cmd.Flags().IntP("limit", "", 10, "at most 1000") return cmd } @@ -364,7 +364,7 @@ func GetBlockTxHashesCommand(queryRoute string, cdc *codec.Codec) *cobra.Command cmd := &cobra.Command{ Use: "block-tx-hashes [height]", Short: "Get txs hash list for a the block at given height", - Args: cobra.MaximumNArgs(1), + Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) height, err := strconv.ParseInt(args[0], 10, 64) @@ -372,7 +372,7 @@ func GetBlockTxHashesCommand(queryRoute string, cdc *codec.Codec) *cobra.Command return err } - txHashes, err := GetBlockTxHashes(cliCtx, &height) + txHashes, err := GetBlockTxHashes(cliCtx, height) if err != nil { return err } @@ -390,7 +390,7 @@ func GetBlockTxHashesCommand(queryRoute string, cdc *codec.Codec) *cobra.Command } // GetBlockTxHashes return tx hashes in the block of the given height -func GetBlockTxHashes(cliCtx context.CLIContext, height *int64) ([]string, error) { +func GetBlockTxHashes(cliCtx context.CLIContext, height int64) ([]string, error) { // get the node node, err := cliCtx.GetNode() if err != nil { @@ -400,7 +400,7 @@ func GetBlockTxHashes(cliCtx context.CLIContext, height *int64) ([]string, error // header -> BlockchainInfo // header, tx -> Block // results -> BlockResults - res, err := node.Block(height) + res, err := node.Block(&height) if err != nil { return nil, err } diff --git a/x/backend/client/rest/rest.go b/x/backend/client/rest/rest.go index d66c738794..057b03f5a5 100644 --- a/x/backend/client/rest/rest.go +++ b/x/backend/client/rest/rest.go @@ -389,7 +389,7 @@ func blockTxHashesHandler(cliCtx context.CLIContext) http.HandlerFunc { common.HandleErrorMsg(w, cliCtx, err.Error()) return } - res, err := cli.GetBlockTxHashes(cliCtx, &blockHeight) + res, err := cli.GetBlockTxHashes(cliCtx, blockHeight) if err != nil { common.HandleErrorMsg(w, cliCtx, err.Error()) return diff --git a/x/backend/keeper/keeper.go b/x/backend/keeper/keeper.go index 00da65f38d..b305883956 100644 --- a/x/backend/keeper/keeper.go +++ b/x/backend/keeper/keeper.go @@ -60,7 +60,7 @@ func NewKeeper(orderKeeper types.OrderKeeper, tokenKeeper types.TokenKeeper, dex // websocket channel k.wsChan = make(chan types.IWebsocket, types.WebsocketChanCapacity) k.ticker3sChan = make(chan types.IWebsocket, types.WebsocketChanCapacity) - go generateKline1M(k.stopChan, k.Config, k.Orm, &k.Logger, k) + go generateKline1M(k) // init ticker buffer ts := time.Now().Unix() @@ -230,16 +230,11 @@ func (k Keeper) GetDexFees(ctx sdk.Context, dexHandlingAddr, product string, off } func (k Keeper) getAllProducts(ctx sdk.Context) []string { - products := []string{} tokenPairs := k.dexKeeper.GetTokenPairs(ctx) - for _, tp := range tokenPairs { - if tp != nil { - products = append(products, fmt.Sprintf("%s_%s", tp.BaseAssetSymbol, tp.QuoteAssetSymbol)) - } + products := make([]string, len(tokenPairs)) + for i := 0; i < len(tokenPairs); i++ { + products[i] = tokenPairs[i].Name() } - - k.Cache.ProductsBuf = products - return products } @@ -276,7 +271,7 @@ func (k Keeper) GetCandlesWithTime(product string, granularity, size int, ts int return nil, err } -func (k Keeper) getCandlesByMarketKeeper(product string, granularity, size int) (r [][]string, err error) { +func (k Keeper) getCandlesByMarketKeeper(productID uint64, granularity, size int) (r [][]string, err error) { if !k.Config.EnableBackend { return nil, fmt.Errorf("backend is not enabled, no candle found, maintian.conf: %+v", k.Config) } @@ -291,7 +286,7 @@ func (k Keeper) getCandlesByMarketKeeper(product string, granularity, size int) return nil, fmt.Errorf("parameter's not correct, size: %d, granularity: %d", size, granularity) } - klines, err := k.marketKeeper.GetKlineByInstrument(product, granularity, size) + klines, err := k.marketKeeper.GetKlineByProductID(productID, granularity, size) if err == nil && klines != nil && len(klines) > 0 { return klines, err } @@ -420,12 +415,12 @@ func (k Keeper) getAllTickers() []types.Ticker { func (k Keeper) mergeTicker3SecondEvents() (err error) { - sysTicker := time.NewTicker(time.Second) + sysTicker := time.NewTicker(3 * time.Second) merge := func() *types.MergedTickersEvent { tickersMap := map[string]types.IWebsocket{} for len(k.ticker3sChan) > 0 { - ticker, ok := <- k.ticker3sChan + ticker, ok := <-k.ticker3sChan if !ok { break } @@ -452,15 +447,13 @@ func (k Keeper) mergeTicker3SecondEvents() (err error) { for { select { - case t := <-sysTicker.C: - if t.Second() % 3 == 0 { - mEvt := merge() - if mEvt != nil { - k.pushWSItem(mEvt) - } + case <-sysTicker.C: + mEvt := merge() + if mEvt != nil { + k.pushWSItem(mEvt) } - case <- k.stopChan: + case <-k.stopChan: break } } -} \ No newline at end of file +} diff --git a/x/backend/keeper/keeper_channel.go b/x/backend/keeper/keeper_channel.go index 4c9b14d997..9a8bbd4fcd 100644 --- a/x/backend/keeper/keeper_channel.go +++ b/x/backend/keeper/keeper_channel.go @@ -7,19 +7,17 @@ import ( "github.com/okex/okexchain/x/backend/config" "github.com/okex/okexchain/x/backend/orm" "github.com/okex/okexchain/x/backend/types" - - "github.com/tendermint/tendermint/libs/log" ) -func pushAllKline1m(klines map[string][]types.KlineM1, keeper Keeper, nextStartTS int64) { +func pushAllKline1M(klines map[string][]types.KlineM1, keeper Keeper, nextStartTS int64) { keeper.Logger.Debug("pushAllKline1m_1", "klines", klines) if klines != nil && len(klines) > 0 { - for _, klineArr := range klines { - if klineArr == nil { + for _, kline := range klines { + if kline == nil { continue } - for _, k := range klineArr { + for _, k := range kline { keeper.Logger.Debug("pushAllKline1m_2", "kline", &k) keeper.pushWSItem(&k) } @@ -32,54 +30,53 @@ func pushAllKline1m(klines map[string][]types.KlineM1, keeper Keeper, nextStartT } } -func generateKline1M(stop chan struct{}, conf *config.Config, o *orm.ORM, log *log.Logger, keeper Keeper) { - o.Debug("[backend] generateKline1M go routine started") +func generateKline1M(keeper Keeper) { + keeper.Logger.Debug("[backend] generateKline1M go routine started") defer types.PrintStackIfPanic() startTS, endTS := int64(0), time.Now().Unix()-60 time.Sleep(3 * time.Second) - if o.GetMaxBlockTimestamp() > 0 { - endTS = o.GetMaxBlockTimestamp() + if keeper.Orm.GetMaxBlockTimestamp() > 0 { + endTS = keeper.Orm.GetMaxBlockTimestamp() } //ds := DealDataSource{orm: orm} - ds := orm.MergeResultDataSource{Orm: o} - anchorNewStartTS, _, newKline1s, err := o.CreateKline1min(startTS, endTS, &ds) + ds := orm.MergeResultDataSource{Orm: keeper.Orm} + anchorNewStartTS, _, newKline1s, err := keeper.Orm.CreateKline1M(startTS, endTS, &ds) if err != nil { - (*log).Debug(fmt.Sprintf("[backend] error: %+v \n", err)) + keeper.Logger.Debug(fmt.Sprintf("[backend] generateKline1M go routine error: %+v \n", err)) } - pushAllKline1m(newKline1s, keeper, anchorNewStartTS) + pushAllKline1M(newKline1s, keeper, anchorNewStartTS) waitInSecond := int(60+types.Kline1GoRoutineWaitInSecond-time.Now().Second()) % 60 timer := time.NewTimer(time.Duration(waitInSecond * int(time.Second))) interval := time.Second * 60 ticker := time.NewTicker(interval) - go CleanUpKlines(stop, o, conf) - var klineNotifyChans *map[int]chan struct{} + go CleanUpKlines(keeper.stopChan, keeper.Orm, keeper.Config) + klineNotifyChans := generateSyncKlineMXChans() work := func() { - if o.GetMaxBlockTimestamp() == 0 { + currentBlockTimestamp := keeper.Orm.GetMaxBlockTimestamp() + if currentBlockTimestamp == 0 { return } + keeper.Logger.Debug(fmt.Sprintf("[backend] generateKline1M line1M [%d, %d) [%s, %s)", + anchorNewStartTS, currentBlockTimestamp, types.TimeString(anchorNewStartTS), types.TimeString(currentBlockTimestamp))) - crrtBlkTS := o.GetMaxBlockTimestamp() - (*log).Debug(fmt.Sprintf("[backend] line1M [%d, %d) [%s, %s)", - anchorNewStartTS, crrtBlkTS, types.TimeString(anchorNewStartTS), types.TimeString(crrtBlkTS))) - - anchorNextStart, _, newKline1s, err := o.CreateKline1min(anchorNewStartTS, crrtBlkTS, &ds) - (*log).Debug(fmt.Sprintf("[backend] generateKline1M's actually merge period [%s, %s)", + anchorNextStart, _, newKline1s, err := keeper.Orm.CreateKline1M(anchorNewStartTS, currentBlockTimestamp, &ds) + keeper.Logger.Debug(fmt.Sprintf("[backend] generateKline1M's actually merge period [%s, %s)", types.TimeString(anchorNewStartTS), types.TimeString(anchorNextStart))) if err != nil { - (*log).Debug(fmt.Sprintf("[backend] generateKline1M error: %s", err.Error())) + keeper.Logger.Debug(fmt.Sprintf("[backend] generateKline1M go routine error: %s", err.Error())) } else { // if new klines created, push them if anchorNextStart > anchorNewStartTS { - pushAllKline1m(newKline1s, keeper, anchorNewStartTS) + pushAllKline1M(newKline1s, keeper, anchorNewStartTS) if klineNotifyChans != nil { for _, ch := range *klineNotifyChans { - ch <- struct{}{} + ch <- anchorNewStartTS } } anchorNewStartTS = anchorNextStart @@ -90,9 +87,8 @@ func generateKline1M(stop chan struct{}, conf *config.Config, o *orm.ORM, log *l work() - klineNotifyChans = generateSyncKlineMXChans() for freq, ntfCh := range *klineNotifyChans { - go generateKlinesMX(ntfCh, stop, freq, o, keeper) + go generateKlinesMX(ntfCh, freq, keeper) } for { @@ -102,20 +98,19 @@ func generateKline1M(stop chan struct{}, conf *config.Config, o *orm.ORM, log *l ticker = time.NewTicker(interval) case <-ticker.C: work() - case <-stop: + case <-keeper.stopChan: break - } } } -func generateSyncKlineMXChans() *map[int]chan struct{} { - notifyChans := map[int]chan struct{}{} +func generateSyncKlineMXChans() *map[int]chan int64 { + notifyChans := map[int]chan int64{} klineMap := types.GetAllKlineMap() for freq := range klineMap { if freq > 60 { - notifyCh := make(chan struct{}, 1) + notifyCh := make(chan int64, 1) notifyChans[freq] = notifyCh } } @@ -123,15 +118,14 @@ func generateSyncKlineMXChans() *map[int]chan struct{} { return ¬ifyChans } - func pushAllKlineXm(klines map[string][]interface{}, keeper Keeper, klineType string, nextStartTS int64) { - if klines != nil && len(klines) >0 { - for _, klineArr := range klines { - if klineArr == nil { + if klines != nil && len(klines) > 0 { + for _, kline := range klines { + if kline == nil { continue } - for _, k := range klineArr { + for _, k := range kline { baseLine := k.(types.IWebsocket) keeper.pushWSItem(baseLine) } @@ -144,75 +138,55 @@ func pushAllKlineXm(klines map[string][]interface{}, keeper Keeper, klineType st } } -func generateKlinesMX(notifyChan chan struct{}, stop chan struct{}, refreshInterval int, o *orm.ORM, keeper Keeper) { - o.Debug(fmt.Sprintf("[backend] generateKlineMX-#%d# go routine started", refreshInterval)) +func generateKlinesMX(notifyChan chan int64, refreshInterval int, keeper Keeper) { + keeper.Logger.Debug(fmt.Sprintf("[backend] generateKlineMX-#%d# go routine started", refreshInterval)) destKName := types.GetKlineTableNameByFreq(refreshInterval) destK, err := types.NewKlineFactory(destKName, nil) if err != nil { - o.Error(fmt.Sprintf("[backend] NewKlineFactory error: %s", err.Error())) + keeper.Logger.Error(fmt.Sprintf("[backend] generateKlineMX-#%d# NewKlineFactory error: %s", refreshInterval, err.Error())) } destIKline := destK.(types.IKline) - startTS, endTS := int64(0), time.Now().Unix()-int64(destIKline.GetFreqInSecond()) - anchorNewStartTS, _, newKlines, err := o.MergeKlineM1(startTS, endTS, destIKline) + //startTS, endTS := int64(0), time.Now().Unix()-int64(destIKline.GetFreqInSecond()) + startTS, endTS := int64(0), time.Now().Unix()+int64(destIKline.GetFreqInSecond()) + anchorNewStartTS, _, newKlines, err := keeper.Orm.MergeKlineM1(startTS, endTS, destIKline) if err != nil { - o.Error(fmt.Sprintf("[backend] MergeKlineM1 error: %s", err.Error())) + keeper.Logger.Debug(fmt.Sprintf("[backend] generateKlineMX-#%d# error: %s", refreshInterval, err.Error())) } else { pushAllKlineXm(newKlines, keeper, destIKline.GetTableName(), anchorNewStartTS) } - //waitInSecond := int(60+KlineX_GOROUTINE_WAIT_IN_SECOND-time.Now().Second()) % 60 - crrTS := time.Now().Unix() - waitInSecond := int64(destIKline.GetFreqInSecond()) - (crrTS - destIKline.GetAnchorTimeTS(crrTS)) + types.KlinexGoRoutineWaitInSecond + 60 - timer := time.NewTimer(time.Duration(int(waitInSecond) * int(time.Second))) - interval := time.Duration(destIKline.GetFreqInSecond() * int(time.Second)) - o.Debug(fmt.Sprintf("[backend] duaration: %+v(%d s) IKline: %+v ", interval, destIKline.GetFreqInSecond(), destIKline)) - ticker := time.NewTicker(interval) - - work := func() { - if o.GetMaxBlockTimestamp() == 0 { + work := func(startTS int64) { + latestBlockTS := keeper.Orm.GetMaxBlockTimestamp() + if latestBlockTS == 0 { return } + latestBlockTS += int64(destIKline.GetFreqInSecond()) + keeper.Logger.Debug(fmt.Sprintf("[backend] entering generateKlinesMX-#%d# [%d, %d)[%s, %s)", + destIKline.GetFreqInSecond(), startTS, latestBlockTS, types.TimeString(startTS), types.TimeString(latestBlockTS))) - latestBlockTS := o.GetMaxBlockTimestamp() - - o.Debug(fmt.Sprintf("[backend] entering generateKlinesMX-#%d# [%d, %d)[%s, %s)", - destIKline.GetFreqInSecond(), anchorNewStartTS, latestBlockTS, types.TimeString(anchorNewStartTS), types.TimeString(latestBlockTS))) + anchorNextStart, _, newKlines, err := keeper.Orm.MergeKlineM1(startTS, latestBlockTS, destIKline) - anchorNextStart, _, newKlines, err := o.MergeKlineM1(anchorNewStartTS, latestBlockTS, destIKline) - - o.Debug(fmt.Sprintf("[backend] generateKlinesMX-#%d#'s actually merge period [%s, %s)", + keeper.Logger.Debug(fmt.Sprintf("[backend] generateKlinesMX-#%d#'s actually merge period [%s, %s)", destIKline.GetFreqInSecond(), types.TimeString(anchorNewStartTS), types.TimeString(anchorNextStart))) if err != nil { - o.Error(fmt.Sprintf("[backend] error: %s", err.Error())) + keeper.Logger.Error(fmt.Sprintf("[backend] generateKlinesMX-#%d# error: %s", destIKline.GetFreqInSecond(), err.Error())) } else { - if anchorNextStart > anchorNewStartTS { - anchorNewStartTS = anchorNextStart - pushAllKlineXm(newKlines, keeper, destIKline.GetTableName(), anchorNewStartTS) + if len(newKlines) > 0 { + pushAllKlineXm(newKlines, keeper, destIKline.GetTableName(), anchorNextStart) } } } for { select { - case <-notifyChan: - time.Sleep(time.Second) - if anchorNewStartTS > 0 && time.Now().Unix() < anchorNewStartTS+int64(destIKline.GetFreqInSecond()) { - break - } else { - work() - ticker = time.NewTicker(interval) - } - - case <-ticker.C: - work() - case <-timer.C: - work() - case <-stop: + case startTS := <-notifyChan: + work(startTS) + case <-keeper.stopChan: break } } @@ -220,7 +194,7 @@ func generateKlinesMX(notifyChan chan struct{}, stop chan struct{}, refreshInter // nolint func CleanUpKlines(stop chan struct{}, o *orm.ORM, conf *config.Config) { - o.Debug(fmt.Sprintf("[backend] cleanUpKlines go routine started. MaintainConf: %+v", *conf)) + o.Debug(fmt.Sprintf("[backend] CleanUpKlines go routine started. MaintainConf: %+v", *conf)) interval := time.Duration(60 * int(time.Second)) ticker := time.NewTicker(time.Duration(int(60-time.Now().Second()) * int(time.Second))) @@ -233,7 +207,7 @@ func CleanUpKlines(stop chan struct{}, o *orm.ORM, conf *config.Config) { for _, ktype := range m { expiredDays := conf.CleanUpsKeptDays[ktype] if expiredDays != 0 { - o.Debug(fmt.Sprintf("[backend] entering cleanUpKlines, "+ + o.Debug(fmt.Sprintf("[backend] entering CleanUpKlines, "+ "fired time: %s(currentTS: %d), kline type: %s", conf.CleanUpsTime, now.Unix(), ktype)) //anchorTS := now.Add(-time.Duration(int(time.Second) * 1440 * expiredDays)).Unix() anchorTS := now.Add(-time.Duration(int(time.Second) * types.SecondsInADay * expiredDays)).Unix() diff --git a/x/backend/keeper/querier.go b/x/backend/keeper/querier.go index 7ac6091ce2..521d2c22d1 100644 --- a/x/backend/keeper/querier.go +++ b/x/backend/keeper/querier.go @@ -133,7 +133,7 @@ func queryDeals(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Ke if params.Side != "" && params.Side != orderTypes.BuyOrder && params.Side != orderTypes.SellOrder { return nil, sdk.ErrUnknownRequest(fmt.Sprintf("Side should not be %s", params.Side)) } - if params.Page <= 0 || params.PerPage <= 0 { + if params.Page < 0 || params.PerPage < 0 { return nil, sdk.ErrUnknownRequest(fmt.Sprintf("invalid page %d or per_page %d", params.Page, params.PerPage)) } @@ -159,7 +159,7 @@ func queryMatchResults(ctx sdk.Context, path []string, req abci.RequestQuery, ke if err != nil { return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) } - if params.Page <= 0 || params.PerPage <= 0 { + if params.Page < 0 || params.PerPage < 0 { return nil, sdk.ErrUnknownRequest(fmt.Sprintf("invalid page %d or per_page %d", params.Page, params.PerPage)) } offset, limit := common.GetPage(params.Page, params.PerPage) @@ -188,7 +188,7 @@ func queryFeeDetails(ctx sdk.Context, path []string, req abci.RequestQuery, keep if err != nil { return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("invalid address", err.Error())) } - if params.Page <= 0 || params.PerPage <= 0 { + if params.Page < 0 || params.PerPage < 0 { return nil, sdk.ErrUnknownRequest(fmt.Sprintf("invalid page %d or per_page %d", params.Page, params.PerPage)) } @@ -214,7 +214,10 @@ func queryCandleList(ctx sdk.Context, path []string, req abci.RequestQuery, keep if err != nil { return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) } - if params.Product != "" && keeper.dexKeeper.GetTokenPair(ctx, params.Product) == nil { + if params.Product == "" { + return nil, sdk.ErrUnknownRequest("invalid params: product is required") + } + if keeper.dexKeeper.GetTokenPair(ctx, params.Product) == nil { return nil, sdk.ErrUnknownRequest(fmt.Sprintf("product %s does not exist", params.Product)) } @@ -241,14 +244,17 @@ func queryCandleListFromMarketKeeper(ctx sdk.Context, path []string, req abci.Re if err != nil { return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) } - if params.Product != "" && keeper.dexKeeper.GetTokenPair(ctx, params.Product) == nil { + if params.Product == "" { + return nil, sdk.ErrUnknownRequest("invalid params: product is required") + } + tokenPair := keeper.dexKeeper.GetTokenPair(ctx, params.Product) + if tokenPair == nil { return nil, sdk.ErrUnknownRequest(fmt.Sprintf("product %s does not exist", params.Product)) } ctx.Logger().Debug(fmt.Sprintf("queryCandleList : %+v", params)) // should init token pair map here - keeper.marketKeeper.InitTokenPairMap(ctx, keeper.dexKeeper) - restData, err := keeper.getCandlesByMarketKeeper(params.Product, params.Granularity, params.Size) + restData, err := keeper.getCandlesByMarketKeeper(tokenPair.ID, params.Granularity, params.Size) var response *common.BaseResponse if err != nil { @@ -280,6 +286,11 @@ func queryTickerList(ctx sdk.Context, path []string, req abci.RequestQuery, keep products = keeper.getAllProducts(ctx) } + // set default count to 10 + if params.Count <= 0 { + params.Count = 10 + } + addedTickers := []types.Ticker{} tickers := keeper.GetTickers(products, params.Count) for _, p := range products { @@ -332,8 +343,6 @@ func queryTickerListFromMarketKeeper(ctx sdk.Context, path []string, req abci.Re if err := keeper.cdc.UnmarshalJSON(req.Data, ¶ms); err != nil { return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data, ", err.Error())) } - keeper.marketKeeper.InitTokenPairMap(ctx, keeper.dexKeeper) - tickers, err := keeper.marketKeeper.GetTickers() var products []string if params.Product != "" { @@ -345,12 +354,19 @@ func queryTickerListFromMarketKeeper(ctx sdk.Context, path []string, req abci.Re products = keeper.getAllProducts(ctx) } - var addedTickers []map[string]string - for _, p := range products { + // set default count to 10 + if params.Count <= 0 { + params.Count = 10 + } + + allTickers, err := keeper.marketKeeper.GetTickerByProducts(products) + var filterTickers []map[string]string + for _, p := range products { exists := false - for _, t := range tickers { + for _, t := range allTickers { if p == t["product"] { + filterTickers = append(filterTickers, t) exists = true break } @@ -370,24 +386,20 @@ func queryTickerListFromMarketKeeper(ctx sdk.Context, path []string, req abci.Re //"changePercentage": "0.00%", "timestamp": time.Now().UTC().Format("2006-01-02T15:04:05.000Z"), } - addedTickers = append(addedTickers, tmpTicker) + filterTickers = append(filterTickers, tmpTicker) } } - if len(addedTickers) > 0 { - tickers = append(tickers, addedTickers...) - } - - if len(tickers) > params.Count { - tickers = tickers[0:params.Count] + if len(filterTickers) > params.Count { + filterTickers = filterTickers[0:params.Count] } var response *common.BaseResponse if err != nil { response = common.GetErrorResponse(-1, "", err.Error()) } else { - response = common.GetBaseResponse(tickers) + response = common.GetBaseResponse(filterTickers) } bz, err := json.Marshal(response) @@ -408,7 +420,7 @@ func queryOrderList(ctx sdk.Context, path []string, req abci.RequestQuery, keepe if err != nil { return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("invalid address", err.Error())) } - if params.Page <= 0 || params.PerPage <= 0 { + if params.Page < 0 || params.PerPage < 0 { return nil, sdk.ErrUnknownRequest(fmt.Sprintf("invalid page %d or per_page %d", params.Page, params.PerPage)) } offset, limit := common.GetPage(params.Page, params.PerPage) @@ -439,7 +451,7 @@ func queryTxList(ctx sdk.Context, path []string, req abci.RequestQuery, keeper K if err != nil { return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("invalid address", err.Error())) } - if params.Page <= 0 || params.PerPage <= 0 { + if params.Page < 0 || params.PerPage < 0 { return nil, sdk.ErrUnknownRequest(fmt.Sprintf("invalid page %d or per_page %d", params.Page, params.PerPage)) } offset, limit := common.GetPage(params.Page, params.PerPage) @@ -464,7 +476,7 @@ func queryDexFees(ctx sdk.Context, path []string, req abci.RequestQuery, keeper if err != nil { return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) } - if params.Page <= 0 || params.PerPage <= 0 { + if params.Page < 0 || params.PerPage < 0 { return nil, sdk.ErrUnknownRequest(fmt.Sprintf("invalid page %d or per_page %d", params.Page, params.PerPage)) } offset, limit := common.GetPage(params.Page, params.PerPage) diff --git a/x/backend/keeper/querier_v2.go b/x/backend/keeper/querier_v2.go index 2727b88721..48b5cf9ba3 100644 --- a/x/backend/keeper/querier_v2.go +++ b/x/backend/keeper/querier_v2.go @@ -17,8 +17,8 @@ func queryTickerFromMarketKeeperV2(ctx sdk.Context, path []string, req abci.Requ return nil, sdk.ErrInternal(err.Error()) } - keeper.marketKeeper.InitTokenPairMap(ctx, keeper.dexKeeper) - tickers, err := keeper.marketKeeper.GetTickers() + products := keeper.getAllProducts(ctx) + tickers, err := keeper.marketKeeper.GetTickerByProducts(products) if err != nil { return nil, sdk.ErrInternal(err.Error()) } @@ -56,8 +56,8 @@ func queryTickerFromMarketKeeperV2(ctx sdk.Context, path []string, req abci.Requ } func queryTickerListFromMarketKeeperV2(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { - keeper.marketKeeper.InitTokenPairMap(ctx, keeper.dexKeeper) - tickers, err := keeper.marketKeeper.GetTickers() + products := keeper.getAllProducts(ctx) + tickers, err := keeper.marketKeeper.GetTickerByProducts(products) if err != nil { return nil, sdk.ErrInternal(err.Error()) } @@ -234,11 +234,13 @@ func queryCandleListFromMarketKeeperV2(ctx sdk.Context, path []string, req abci. if err != nil { return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) } - + tokenPair := keeper.dexKeeper.GetTokenPair(ctx, params.Product) + if tokenPair == nil { + return nil, sdk.ErrUnknownRequest(fmt.Sprintf("product %s does not exist", params.Product)) + } ctx.Logger().Debug(fmt.Sprintf("queryCandleList : %+v", params)) // should init token pair map here - keeper.marketKeeper.InitTokenPairMap(ctx, keeper.dexKeeper) - restData, err := keeper.getCandlesByMarketKeeper(params.Product, params.Granularity, params.Size) + restData, err := keeper.getCandlesByMarketKeeper(tokenPair.ID, params.Granularity, params.Size) if err != nil { return nil, sdk.ErrInternal(err.Error()) } diff --git a/x/backend/keeper_test.go b/x/backend/keeper_test.go index 37bc5d7398..5edd473891 100644 --- a/x/backend/keeper_test.go +++ b/x/backend/keeper_test.go @@ -118,7 +118,7 @@ func TestKeeper_Tx(t *testing.T) { ctx = mapp.NewContext(true, abci.Header{}) getTxs, _ := mapp.backendKeeper.GetTransactionList(ctx, addrKeysSlice[0].Address.String(), 0, 0, 0, 0, 200) - require.EqualValues(t, 2*len(msgOrderNew.OrderItems) + 1, len(getTxs)) + require.EqualValues(t, 2*len(msgOrderNew.OrderItems)+1, len(getTxs)) getTxs, _ = mapp.backendKeeper.GetTransactionList(ctx, addrKeysSlice[1].Address.String(), 0, 0, 0, 0, 200) require.EqualValues(t, 1, len(getTxs)) @@ -193,7 +193,7 @@ func TestKeeper_FixJira85(t *testing.T) { // 3. UpdateTickers Again ts := time.Now().Unix() - mapp.backendKeeper.UpdateTickersBuffer(ts-types.SecondsInADay, ts+1, mapp.backendKeeper.Cache.ProductsBuf) + mapp.backendKeeper.UpdateTickersBuffer(ts-types.SecondsInADay, ts+1, nil) tickers = mapp.backendKeeper.GetTickers(nil, 100) require.True(t, len(tickers) > 1) for _, ti := range tickers { @@ -363,37 +363,36 @@ func TestKeeper_getCandles(t *testing.T) { } } - -func buildNewOrderMsg(sender sdk.AccAddress, product string, price string, quantity string) orderTypes.MsgNewOrders{ +func buildNewOrderMsg(sender sdk.AccAddress, product string, price string, quantity string) orderTypes.MsgNewOrders { var OrderItems []orderTypes.OrderItem - for i :=0 ;i < 25; i++ { - OrderItems = append(OrderItems,orderTypes.OrderItem{ - Product: product, - Side: types.BuyOrder, - Price: sdk.MustNewDecFromStr(price), - Quantity: sdk.MustNewDecFromStr(quantity), - } ) + for i := 0; i < 25; i++ { + OrderItems = append(OrderItems, orderTypes.OrderItem{ + Product: product, + Side: types.BuyOrder, + Price: sdk.MustNewDecFromStr(price), + Quantity: sdk.MustNewDecFromStr(quantity), + }) } - for i :=0 ;i < 25; i++ { - OrderItems = append(OrderItems,orderTypes.OrderItem{ + for i := 0; i < 25; i++ { + OrderItems = append(OrderItems, orderTypes.OrderItem{ Product: product, Side: types.SellOrder, Price: sdk.MustNewDecFromStr(price), Quantity: sdk.MustNewDecFromStr(quantity), - } ) + }) } return orderTypes.MsgNewOrders{ - Sender: sender, + Sender: sender, OrderItems: OrderItems, } } -func buildCancelOrderMsg(sender sdk.AccAddress, blockHeight, orderNum int) orderTypes.MsgCancelOrders{ +func buildCancelOrderMsg(sender sdk.AccAddress, blockHeight, orderNum int) orderTypes.MsgCancelOrders { var orderIds []string for idx := 0; idx < orderNum; idx++ { - orderIds = append(orderIds, orderTypes.FormatOrderID(int64(blockHeight), int64(idx + 1))) + orderIds = append(orderIds, orderTypes.FormatOrderID(int64(blockHeight), int64(idx+1))) } msgCancelOrder := orderTypes.MsgCancelOrders{ @@ -402,4 +401,4 @@ func buildCancelOrderMsg(sender sdk.AccAddress, blockHeight, orderNum int) order } return msgCancelOrder -} \ No newline at end of file +} diff --git a/x/backend/orm/backend.db b/x/backend/orm/backend.db index e8b8126c9c8fe3aee2a805a362a706bc8c1e60b9..fc09cd0137f02167da4bc5f1a37b1a5988d07a83 100644 GIT binary patch delta 919 zcmcJMKS)AR6vpql@A-Tga(p29=S9AvW=GpHTJuj(TcCwoLk7HB4&%2)1h=ay9TABZ8yQtL z7FCN9Q|%Tdx~Vv^NhHiuEaNlgP0fH4T=pm`H|I0;9T4w0_;}^P!>{C&c#sGmFS}cT z8GcG<1?JQ`#k#;YwIr00)nYKcI*J%c$rhk^N3kf;oXv?HLh%x?iI<{*3)DSBjvv5S zwGSwomw=m12YNavI{08v4ET zPX{4GWGn2s!0)E`NbnJRBJv)!(U_1yS+4}{F-&zbuBlF_+3SMan7nI{x|5T3{igz2 l)Lk^?G`ynZf5@8ehd^Co<3I5YrE-Q0B))w~=l-F@w@=kO|C#^* delta 378 zcmZY3u}T9$5C-7=cQ@fUmC2zV#E5qWtW{!RmjqiiDJ+GYlFq^u7U_)GOM=LjUK#}( zArKdWppBIY=mQwA2`Pm50E*s;g`5L3Ff+yX*LV~eiJhVvN7cds8 ziRE&{C=UOr^&gc}57eV!nEQ&b(#YGPnT*Gn%>(VNgqe6B)TfcQDtMrn8)RiF$Y)Qj quSS@{Ex)Ni<}PI&?(cYqtAq8^(OBZb`}=z0zLrJ);as@F4f`8e6>10o diff --git a/x/backend/orm/orm.go b/x/backend/orm/orm.go index 1e41738779..99cd1f0fda 100644 --- a/x/backend/orm/orm.go +++ b/x/backend/orm/orm.go @@ -383,35 +383,57 @@ func (orm *ORM) getOpenCloseKline(startTS, endTS int64, product string, firstK i } func (orm *ORM) getMinTimestamp(tbName string) int64 { - sql := fmt.Sprintf("select min(Timestamp) as ts from %s", tbName) ts := int64(-1) + count := 0 - r := orm.db.Raw(sql).Row() - if r != nil { - if err := r.Scan(&ts); err != nil { - orm.Error("failed to execute scan result, error:" + err.Error()) - } + raw := orm.db.Raw(sql) + raw.Count(&count) + if count == 0 { + return ts } - return ts + if err := raw.Row().Scan(&ts); err != nil { + orm.Error("failed to execute scan result, error:" + err.Error()) + } + return ts } func (orm *ORM) getMaxTimestamp(tbName string) int64 { - sql := fmt.Sprintf("select max(Timestamp) as ts from %s", tbName) ts := int64(-1) + count := 0 - r := orm.db.Raw(sql).Row() - if r != nil { - if err := r.Scan(&ts); err != nil { - orm.Error("failed to execute scan result, error:" + err.Error()) - } + raw := orm.db.Raw(sql) + raw.Count(&count) + if count == 0 { + return ts + } + + if err := raw.Row().Scan(&ts); err != nil { + orm.Error("failed to execute scan result, error:" + err.Error()) } return ts +} +func (orm *ORM) getMergingKlineTimestamp(tbName string, timestamp int64) int64 { + sql := fmt.Sprintf("select max(Timestamp) as ts from %s where Timestamp <=%d", tbName, timestamp) + ts := int64(-1) + count := 0 + + raw := orm.db.Raw(sql) + raw.Count(&count) + if count == 0 { + return ts + } + + if err := raw.Row().Scan(&ts); err != nil { + orm.Error("failed to execute scan result, error:" + err.Error()) + } + + return ts } func (orm *ORM) getDealsMinTimestamp() int64 { @@ -486,8 +508,8 @@ func (dm *MergeResultDataSource) getOpenClosePrice(startTS, endTS int64, product return openDeal.Price, closeDeal.Price } -// CreateKline1min batch insert into Kline1M -func (orm *ORM) CreateKline1min(startTS, endTS int64, dataSource IKline1MDataSource) ( +// CreateKline1M batch insert into Kline1M +func (orm *ORM) CreateKline1M(startTS, endTS int64, dataSource IKline1MDataSource) ( anchorEndTS int64, newProductCnt int, newKlineInfo map[string][]types.KlineM1, err error) { orm.singleEntryLock.Lock() defer orm.singleEntryLock.Unlock() @@ -513,9 +535,6 @@ func (orm *ORM) CreateKline1min(startTS, endTS int64, dataSource IKline1MDataSou } } - tx := orm.db.Begin() - defer orm.deferRollbackTx(tx, err) - anchorTime := time.Unix(acTS, 0).UTC() anchorStartTime := time.Date( anchorTime.Year(), anchorTime.Month(), anchorTime.Day(), anchorTime.Hour(), anchorTime.Minute(), 0, 0, time.UTC) @@ -525,6 +544,7 @@ func (orm *ORM) CreateKline1min(startTS, endTS int64, dataSource IKline1MDataSou nextTimeStamp := nextTime.Unix() for nextTimeStamp <= endTS { sql := dataSource.getMaxMinSumByGroupSQL(anchorStartTime.Unix(), nextTime.Unix()) + orm.Debug(fmt.Sprintf("CreateKline1M sql:%s", sql)) rows, err := orm.db.Raw(sql).Rows() if rows != nil && err == nil { @@ -534,10 +554,9 @@ func (orm *ORM) CreateKline1min(startTS, endTS int64, dataSource IKline1MDataSou var cnt int if err = rows.Scan(&product, &quantity, &high, &low, &cnt); err != nil { - orm.Error("failed to execute scan result, error:" + err.Error() + " sql: " + sql) + orm.Error(fmt.Sprintf("CreateKline1M failed to execute scan result, error:%s sql:%s", err.Error(), sql)) } if cnt > 0 { - openPrice, closePrice := dataSource.getOpenClosePrice(anchorStartTime.Unix(), nextTime.Unix(), product) b := types.BaseKline{ @@ -556,26 +575,26 @@ func (orm *ORM) CreateKline1min(startTS, endTS int64, dataSource IKline1MDataSou } if err = rows.Close(); err != nil { - orm.Error("failed to execute close rows, error:" + err.Error()) + orm.Error(fmt.Sprintf("CreateKline1M failed to execute close rows, error:%s", err.Error())) } } anchorStartTime = nextTime nextTime = anchorStartTime.Add(time.Minute) nextTimeStamp = nextTime.Unix() - } // 3. Batch insert into Kline1Min - + tx := orm.db.Begin() + defer orm.deferRollbackTx(tx, err) for _, klines := range productKlines { for _, kline := range klines { // TODO: it should be a replacement here. ret := tx.Create(&kline) if ret.Error != nil { - orm.Error(fmt.Sprintf("[backend] failed to create kline Error: %+v, kline: %s", ret.Error, kline.PrettyTimeString())) + orm.Error(fmt.Sprintf("CreateKline1M failed to create kline Error: %+v, kline: %s", ret.Error, kline.PrettyTimeString())) } else { - orm.Debug(fmt.Sprintf("[backend] success to create in %s, %s %s", kline.GetTableName(), types.TimeString(kline.Timestamp), kline.PrettyTimeString())) + orm.Debug(fmt.Sprintf("CreateKline1M success to create in %s, %s %s", kline.GetTableName(), types.TimeString(kline.Timestamp), kline.PrettyTimeString())) } } @@ -583,7 +602,7 @@ func (orm *ORM) CreateKline1min(startTS, endTS int64, dataSource IKline1MDataSou tx.Commit() anchorEndTS = anchorStartTime.Unix() - (*orm.logger).Debug(fmt.Sprintf("[backend] CreateKline1min return klinesMap: %+v", productKlines)) + orm.Debug(fmt.Sprintf("CreateKline1M return klinesMap: %+v", productKlines)) return anchorEndTS, len(productKlines), productKlines, nil } @@ -729,8 +748,8 @@ func (orm *ORM) MergeKlineM1(startTS, endTS int64, destKline types.IKline) ( // 1. Get anchor start time. acTS := startTS - maxTSPersistent := orm.getKlineMaxTimestamp(destKline) - if maxTSPersistent > 0 && maxTSPersistent > startTS { + maxTSPersistent := orm.getMergingKlineTimestamp(destKline.GetTableName(), startTS) + if maxTSPersistent > 0 { acTS = maxTSPersistent } @@ -744,9 +763,6 @@ func (orm *ORM) MergeKlineM1(startTS, endTS int64, destKline types.IKline) ( } } - tx := orm.db.Begin() - defer orm.deferRollbackTx(tx, err) - var anchorStartTime time.Time if maxTSPersistent > 0 { anchorTime := time.Unix(acTS, 0).UTC() @@ -758,19 +774,19 @@ func (orm *ORM) MergeKlineM1(startTS, endTS int64, destKline types.IKline) ( // 2. Get anchor end time. anchorEndTime := endTS - orm.Debug(fmt.Sprintf("[backend] MergeKlineM1 KlinesMX-#%d# [%s, %s)", + orm.Debug(fmt.Sprintf("[backend] MergeKlineM1 KlinesMX-#%d# [%s, %s]", destKline.GetFreqInSecond(), types.TimeString(anchorStartTime.Unix()), types.TimeString(anchorEndTime))) // 3. Collect product's kline by deals productKlines := map[string][]interface{}{} interval := time.Duration(int(time.Second) * destKline.GetFreqInSecond()) nextTime := anchorStartTime.Add(interval) - nextTimeStamp := nextTime.Unix() - for nextTimeStamp <= anchorEndTime { + for nextTime.Unix() <= anchorEndTime { sql := fmt.Sprintf("select %d, product, sum(volume) as volume, max(high) as high, min(low) as low, count(*) as cnt from %s "+ "where Timestamp >= %d and Timestamp < %d group by product", anchorStartTime.Unix(), klineM1.(types.IKline).GetTableName(), anchorStartTime.Unix(), nextTime.Unix()) - + orm.Debug(fmt.Sprintf("[backend] MergeKlineM1 KlinesMX-#%d# sql=%s", + destKline.GetFreqInSecond(), sql)) rows, err := orm.db.Raw(sql).Rows() if rows != nil && err == nil { @@ -813,15 +829,14 @@ func (orm *ORM) MergeKlineM1(startTS, endTS int64, destKline types.IKline) ( anchorStartTime = nextTime nextTime = anchorStartTime.Add(interval) - nextTimeStamp = nextTime.Unix() } // 4. Batch insert into Kline1Min - + tx := orm.db.Begin() + defer orm.deferRollbackTx(tx, err) for _, klines := range productKlines { for _, kline := range klines { - // TODO: it should be a replacement here. - ret := tx.Create(kline) + ret := tx.Delete(kline).Create(kline) if ret.Error != nil { orm.Error(fmt.Sprintf("Error: %+v, kline: %s", ret.Error, kline.(types.IKline).PrettyTimeString())) } else { diff --git a/x/backend/orm/orm_test.go b/x/backend/orm/orm_test.go index 7d89f7d28b..5437ff9777 100644 --- a/x/backend/orm/orm_test.go +++ b/x/backend/orm/orm_test.go @@ -186,7 +186,6 @@ func testORMAllInOne(t *testing.T, orm *ORM) { assert.True(t, len(deals) == len(allDeals) && deals != nil) var allDealVolume, allKM1Volume, allKM3Volume float64 for _, d := range deals { - fmt.Printf("%+v\n", d) allDealVolume += d.Quantity } @@ -204,27 +203,22 @@ func testORMAllInOne(t *testing.T, orm *ORM) { if endTS%60 == 0 { endTS += 1 } - anchorEndTS, cnt, newKlinesM1, err := orm.CreateKline1min(0, endTS, &ds) - fmt.Printf("CreateKline1min ERROR: %+v", err) - assert.True(t, err == nil, cnt == 3) + anchorEndTS, cnt, newKlinesM1, err := orm.CreateKline1M(0, endTS, &ds) + assert.True(t, err == nil) assert.True(t, len(newKlinesM1) == cnt) products, _ := orm.getAllUpdatedProducts(0, time.Now().Unix()) assert.True(t, len(products) > 0) - fmt.Printf("%+v \n", products) - _, cnt, newKlinesM1, err = orm.CreateKline1min(anchorEndTS, time.Now().Unix()+1, &ds) - fmt.Printf("CreateKline1min ERROR: %+v", err) - assert.True(t, err == nil, cnt == 1) + _, cnt, newKlinesM1, err = orm.CreateKline1M(anchorEndTS, time.Now().Unix()+1, &ds) + assert.True(t, err == nil) maxTS := orm.getKlineMaxTimestamp(&types.KlineM1{}) assert.True(t, maxTS < ts) r, e := orm.getLatestKlineM1ByProduct(product, 100) assert.True(t, r != nil && e == nil) - fmt.Printf("NOW : %s\n", types.TimeString(ts)) for _, v := range *r { - //fmt.Printf("%d, %+v\n", v.GetTimestamp(), v.PrettyTimeString()) allKM1Volume += v.Volume } @@ -387,7 +381,7 @@ func constructLocalBackendDB(orm *ORM) (err error) { m := types.GetAllKlineMap() crrTs := time.Now().Unix() ds := DealDataSource{orm: orm} - if _, _, _, err := orm.CreateKline1min(0, crrTs, &ds); err != nil { + if _, _, _, err := orm.CreateKline1M(0, crrTs, &ds); err != nil { return err } diff --git a/x/backend/types/expected_keepers.go b/x/backend/types/expected_keepers.go index 0060e3a26c..fdf3a7971e 100644 --- a/x/backend/types/expected_keepers.go +++ b/x/backend/types/expected_keepers.go @@ -36,8 +36,6 @@ type DexKeeper interface { // MarketKeeper expected market keeper which would get data from pulsar & redis type MarketKeeper interface { - InitTokenPairMap(ctx sdk.Context, dk DexKeeper) - GetTickers() ([]map[string]string, error) - GetTickerByInstruments(instruments []string) map[string]Ticker - GetKlineByInstrument(instrument string, granularity, size int) ([][]string, error) + GetTickerByProducts(products []string) ([]map[string]string, error) + GetKlineByProductID(productID uint64, granularity, size int) ([][]string, error) } diff --git a/x/backend/types/klines.go b/x/backend/types/klines.go index 1348cfb5bd..c99adba3f4 100644 --- a/x/backend/types/klines.go +++ b/x/backend/types/klines.go @@ -10,18 +10,21 @@ import ( ) const ( - KlineTypeM1 = "kline_m1" - KlineTypeM3 = "kline_m3" - KlineTypeM5 = "kline_m5" - KlineTypeM15 = "kline_m15" - KlineTypeM30 = "kline_m30" - KlineTypeM60 = "kline_m60" - KlineTypeM120 = "kline_m120" - KlineTypeM240 = "kline_m240" - KlineTypeM360 = "kline_m360" - KlineTypeM720 = "kline_m720" - KlineTypeM1440 = "kline_m1440" - KlineTypeM10080 = "kline_m10080" + KlineTypeM1 = "kline_m1" + KlineTypeM3 = "kline_m3" + KlineTypeM5 = "kline_m5" + KlineTypeM15 = "kline_m15" + KlineTypeM30 = "kline_m30" + KlineTypeM60 = "kline_m60" + KlineTypeM120 = "kline_m120" + KlineTypeM240 = "kline_m240" + KlineTypeM360 = "kline_m360" + KlineTypeM720 = "kline_m720" + KlineTypeM1440 = "kline_m1440" + KlineTypeM4320 = "kline_m4320" + KlineTypeM10080 = "kline_m10080" + KlineTypeM44640 = "kline_m44640" + KlineTypeM525600 = "kline_m525600" ) // nolint @@ -37,39 +40,44 @@ type IKline interface { GetLow() float64 GetVolume() float64 PrettyTimeString() string - GetBrifeInfo() []string + GetBriefInfo() []string } var ( kline2channel = map[string]string{ - KlineTypeM1: "dex_spot/candle60s", - KlineTypeM3: "dex_spot/candle180s", - KlineTypeM5: "dex_spot/candle300s", - KlineTypeM15: "dex_spot/candle900s", - KlineTypeM30: "dex_spot/candle1800s", - KlineTypeM60: "dex_spot/candle3600s", - KlineTypeM120: "dex_spot/candle7200s", - KlineTypeM240: "dex_spot/candle14400s", - KlineTypeM360: "dex_spot/candle21600s", - KlineTypeM720: "dex_spot/candle43200s", - KlineTypeM1440: "dex_spot/candle86400s", - KlineTypeM10080: "dex_spot/candle604800s", + KlineTypeM1: "dex_spot/candle60s", + KlineTypeM3: "dex_spot/candle180s", + KlineTypeM5: "dex_spot/candle300s", + KlineTypeM15: "dex_spot/candle900s", + KlineTypeM30: "dex_spot/candle1800s", + KlineTypeM60: "dex_spot/candle3600s", + KlineTypeM120: "dex_spot/candle7200s", + KlineTypeM240: "dex_spot/candle14400s", + KlineTypeM360: "dex_spot/candle21600s", + KlineTypeM720: "dex_spot/candle43200s", + KlineTypeM1440: "dex_spot/candle86400s", + KlineTypeM4320: "dex_spot/candle259200s", + KlineTypeM10080: "dex_spot/candle604800s", + KlineTypeM44640: "dex_spot/candle2678400s", + KlineTypeM525600: "dex_spot/candle31536000s", } - klineType2Freq = map[string]int { - KlineTypeM1: 60, - KlineTypeM3: 180, - KlineTypeM5: 300, - KlineTypeM15: 900, - KlineTypeM30: 1800, - KlineTypeM60: 3600, - KlineTypeM120: 7200, - KlineTypeM240: 14400, - KlineTypeM360: 21600, - KlineTypeM720: 43200, - KlineTypeM1440: 86400, - KlineTypeM10080: 604800, - + klineType2Freq = map[string]int{ + KlineTypeM1: 60, + KlineTypeM3: 180, + KlineTypeM5: 300, + KlineTypeM15: 900, + KlineTypeM30: 1800, + KlineTypeM60: 3600, + KlineTypeM120: 7200, + KlineTypeM240: 14400, + KlineTypeM360: 21600, + KlineTypeM720: 43200, + KlineTypeM1440: 86400, + KlineTypeM4320: 259200, + KlineTypeM10080: 604800, + KlineTypeM44640: 2678400, + KlineTypeM525600: 31536000, } ) @@ -209,8 +217,8 @@ func (b *BaseKline) GetVolume() float64 { return b.Volume } -// GetBrifeInfo return array of kline data -func (b *BaseKline) GetBrifeInfo() []string { +// GetBriefInfo return array of kline data +func (b *BaseKline) GetBriefInfo() []string { m := []string{ time.Unix(b.GetTimestamp(), 0).UTC().Format("2006-01-02T15:04:05.000Z"), fmt.Sprintf("%.4f", b.GetOpen()), @@ -223,9 +231,9 @@ func (b *BaseKline) GetBrifeInfo() []string { } func (b *BaseKline) FormatResult() interface{} { - result := map[string] interface{}{} + result := map[string]interface{}{} result["instrument_id"] = b.Product - result["candle"] = b.GetBrifeInfo() + result["candle"] = b.GetBriefInfo() return result } @@ -254,7 +262,7 @@ func NewKlineM1(b *BaseKline) *KlineM1 { // GetFreqInSecond return 60 func (k *KlineM1) GetFreqInSecond() int { - return 60 + return klineType2Freq[k.GetTableName()] } // GetTableName return kline_m1 @@ -281,7 +289,7 @@ func (k *KlineM3) GetTableName() string { // GetFreqInSecond return 180 func (k *KlineM3) GetFreqInSecond() int { - return 60 * 3 + return klineType2Freq[k.GetTableName()] } // KlineM5 define kline data in 5 minutes @@ -303,7 +311,7 @@ func (k *KlineM5) GetTableName() string { // GetFreqInSecond return 300 func (k *KlineM5) GetFreqInSecond() int { - return 60 * 5 + return klineType2Freq[k.GetTableName()] } // KlineM15 define kline data in 15 minutes @@ -325,7 +333,7 @@ func (k *KlineM15) GetTableName() string { // GetFreqInSecond return 900 func (k *KlineM15) GetFreqInSecond() int { - return 60 * 15 + return klineType2Freq[k.GetTableName()] } // KlineM30 define kline data in 30 minutes @@ -347,7 +355,7 @@ func (k *KlineM30) GetTableName() string { // GetFreqInSecond return 1800 func (k *KlineM30) GetFreqInSecond() int { - return 60 * 30 + return klineType2Freq[k.GetTableName()] } // KlineM60 define kline data in 1 hour @@ -369,7 +377,7 @@ func (k *KlineM60) GetTableName() string { // GetFreqInSecond return 3600 func (k *KlineM60) GetFreqInSecond() int { - return 60 * 60 + return klineType2Freq[k.GetTableName()] } // KlineM120 define kline data in 2 hours @@ -391,7 +399,7 @@ func (k *KlineM120) GetTableName() string { // GetFreqInSecond return 7200 func (k *KlineM120) GetFreqInSecond() int { - return 60 * 120 + return klineType2Freq[k.GetTableName()] } // KlineM240 define kline data in 4 hours @@ -413,7 +421,7 @@ func (k *KlineM240) GetTableName() string { // GetFreqInSecond return 14400 func (k *KlineM240) GetFreqInSecond() int { - return 14400 + return klineType2Freq[k.GetTableName()] } // KlineM360 define kline data in 6 hours @@ -435,7 +443,7 @@ func (k *KlineM360) GetTableName() string { // GetFreqInSecond return 21600 func (k *KlineM360) GetFreqInSecond() int { - return 21600 + return klineType2Freq[k.GetTableName()] } // KlineM720 define kline data in 12 hours @@ -457,7 +465,7 @@ func (k *KlineM720) GetTableName() string { // GetFreqInSecond return 43200 func (k *KlineM720) GetFreqInSecond() int { - return 43200 + return klineType2Freq[k.GetTableName()] } // KlineM1440 define kline data in 1 day @@ -479,7 +487,29 @@ func (k *KlineM1440) GetTableName() string { // GetFreqInSecond return 86400 func (k *KlineM1440) GetFreqInSecond() int { - return 86400 + return klineType2Freq[k.GetTableName()] +} + +// KlineM4320 define kline data in 1 day +type KlineM4320 struct { + *BaseKline +} + +// NewKlineM4320 create a instance of KlineM4320 +func NewKlineM4320(b *BaseKline) *KlineM4320 { + k := KlineM4320{b} + k.impl = &k + return &k +} + +// GetTableName return kline_m4320 +func (k *KlineM4320) GetTableName() string { + return KlineTypeM4320 +} + +// GetFreqInSecond return 259200 +func (k *KlineM4320) GetFreqInSecond() int { + return klineType2Freq[k.GetTableName()] } // KlineM10080 define kline data in 1 week @@ -501,7 +531,51 @@ func (k *KlineM10080) GetTableName() string { // GetFreqInSecond return 604800 func (k *KlineM10080) GetFreqInSecond() int { - return 604800 + return klineType2Freq[k.GetTableName()] +} + +// KlineM44640 define kline data in 1 day +type KlineM44640 struct { + *BaseKline +} + +// NewKlineM44640 create a instance of KlineM44640 +func NewKlineM44640(b *BaseKline) *KlineM44640 { + k := KlineM44640{b} + k.impl = &k + return &k +} + +// GetTableName return kline_m44640 +func (k *KlineM44640) GetTableName() string { + return KlineTypeM44640 +} + +// GetFreqInSecond return 2678400 +func (k *KlineM44640) GetFreqInSecond() int { + return klineType2Freq[k.GetTableName()] +} + +// KlineM525600 define kline data in 1 day +type KlineM525600 struct { + *BaseKline +} + +// NewKlineM525600 create a instance of KlineM525600 +func NewKlineM525600(b *BaseKline) *KlineM525600 { + k := KlineM525600{b} + k.impl = &k + return &k +} + +// GetTableName return kline_m525600 +func (k *KlineM525600) GetTableName() string { + return KlineTypeM525600 +} + +// GetFreqInSecond return 31536000 +func (k *KlineM525600) GetFreqInSecond() int { + return klineType2Freq[k.GetTableName()] } // MustNewKlineFactory will panic when err occurred during NewKlineFactory @@ -544,8 +618,14 @@ func NewKlineFactory(name string, baseK *BaseKline) (r interface{}, err error) { return NewKlineM720(b), nil case KlineTypeM1440: return NewKlineM1440(b), nil + case KlineTypeM4320: + return NewKlineM4320(b), nil case KlineTypeM10080: return NewKlineM10080(b), nil + case KlineTypeM44640: + return NewKlineM44640(b), nil + case KlineTypeM525600: + return NewKlineM525600(b), nil } return nil, errors.New("No kline constructor function found.") @@ -553,20 +633,22 @@ func NewKlineFactory(name string, baseK *BaseKline) (r interface{}, err error) { // GetAllKlineMap return map about kline table names func GetAllKlineMap() map[int]string { - return map[int]string{ - 60: KlineTypeM1, - 180: KlineTypeM3, - 300: KlineTypeM5, - 900: KlineTypeM15, - 1800: KlineTypeM30, - 3600: KlineTypeM60, - 7200: KlineTypeM120, - 14400: KlineTypeM240, - 21600: KlineTypeM360, - 43200: KlineTypeM720, - 86400: KlineTypeM1440, - 604800: KlineTypeM10080, + 60: KlineTypeM1, + 180: KlineTypeM3, + 300: KlineTypeM5, + 900: KlineTypeM15, + 1800: KlineTypeM30, + 3600: KlineTypeM60, + 7200: KlineTypeM120, + 14400: KlineTypeM240, + 21600: KlineTypeM360, + 43200: KlineTypeM720, + 86400: KlineTypeM1440, + 259200: KlineTypeM4320, + 604800: KlineTypeM10080, + 2678400: KlineTypeM44640, + 31536000: KlineTypeM525600, } } @@ -580,7 +662,6 @@ func GetKlineTableNameByFreq(freq int) string { // NewKlinesFactory generate kline type by type of kline func NewKlinesFactory(name string) (r interface{}, err error) { - switch name { case KlineTypeM1: return &[]KlineM1{}, nil @@ -604,8 +685,14 @@ func NewKlinesFactory(name string) (r interface{}, err error) { return &[]KlineM720{}, nil case KlineTypeM1440: return &[]KlineM1440{}, nil + case KlineTypeM4320: + return &[]KlineM4320{}, nil case KlineTypeM10080: return &[]KlineM10080{}, nil + case KlineTypeM44640: + return &[]KlineM44640{}, nil + case KlineTypeM525600: + return &[]KlineM525600{}, nil } return nil, errors.New("No klines constructor function found.") @@ -666,10 +753,22 @@ func ToIKlinesArray(klines interface{}, endTS int64, doPadding bool) []IKline { r2 := r.(KlineM1440) r2.impl = &r2 originKlines = append(originKlines, &r2) + case KlineM4320: + r2 := r.(KlineM4320) + r2.impl = &r2 + originKlines = append(originKlines, &r2) case KlineM10080: r2 := r.(KlineM10080) r2.impl = &r2 originKlines = append(originKlines, &r2) + case KlineM44640: + r2 := r.(KlineM44640) + r2.impl = &r2 + originKlines = append(originKlines, &r2) + case KlineM525600: + r2 := r.(KlineM525600) + r2.impl = &r2 + originKlines = append(originKlines, &r2) } } } @@ -744,7 +843,7 @@ func ToRestfulData(klines *[]IKline, limit int) [][]string { } for _, k := range (*klines)[from:to] { - m = append(m, k.GetBrifeInfo()) + m = append(m, k.GetBriefInfo()) } return m } diff --git a/x/backend/types/klines_test.go b/x/backend/types/klines_test.go index 1fbfa4b69d..ee89a34234 100644 --- a/x/backend/types/klines_test.go +++ b/x/backend/types/klines_test.go @@ -103,7 +103,7 @@ func TestBaseKLine(t *testing.T) { nil, } - bi := bk.GetBrifeInfo() + bi := bk.GetBriefInfo() assert.True(t, bi[1] == "100.0000") assert.True(t, bi[2] == "103.0000") assert.True(t, bi[3] == "99.0000") diff --git a/x/common/const.go b/x/common/const.go index 598c97f0be..b74a3b7e72 100644 --- a/x/common/const.go +++ b/x/common/const.go @@ -8,4 +8,6 @@ import ( const ( NativeToken = sdk.DefaultBondDenom TestToken = "xxb" + + blackHoleHex = "0000000000000000000000000000000000000000" ) diff --git a/x/common/util.go b/x/common/util.go index fe31fe0124..595292aa1c 100644 --- a/x/common/util.go +++ b/x/common/util.go @@ -3,6 +3,7 @@ package common import ( "encoding/binary" "fmt" + "math/big" "net/http" "os" "runtime" @@ -107,3 +108,17 @@ func SkipSysTestChecker(t *testing.T) { t.SkipNow() } } + +// mulAndQuo returns a * b / c +func MulAndQuo(a, b, c sdk.Dec) sdk.Dec { + // 10^8 + auxiliaryDec := sdk.NewDecFromBigInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(sdk.Precision), nil)) + a = a.MulTruncate(auxiliaryDec) + return a.MulTruncate(b).QuoTruncate(c).QuoTruncate(auxiliaryDec) +} + +// BlackHoleAddress returns the black hole address +func BlackHoleAddress() sdk.AccAddress { + addr, _ := sdk.AccAddressFromHex(blackHoleHex) + return addr +} diff --git a/x/common/util_test.go b/x/common/util_test.go index 81ba0150d8..889c0fcbb8 100644 --- a/x/common/util_test.go +++ b/x/common/util_test.go @@ -111,3 +111,10 @@ func TestHasSufCoins(t *testing.T) { err = HasSufficientCoins(addr, availCoins, spendCoins) require.Nil(t, err) } + +func TestBlackHoleAddress(t *testing.T) { + addr := BlackHoleAddress() + a := addr.String() + fmt.Println(a) + require.Equal(t, addr.String(), "okexchain1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqupa6dx") +} diff --git a/x/debug/client/cli/debug.go b/x/debug/client/cli/debug.go index 50ef85f08d..b6b5cc5ed0 100644 --- a/x/debug/client/cli/debug.go +++ b/x/debug/client/cli/debug.go @@ -25,6 +25,7 @@ func GetDebugCmd(cdc *codec.Codec) *cobra.Command { CmdSetLogLevel(queryRoute, cdc), CmdDumpStore(queryRoute, cdc), CmdSanityCheck(queryRoute, cdc), + CmdInvariantCheck(queryRoute, cdc), )...) return queryCmd @@ -104,3 +105,21 @@ func CmdSanityCheck(queryRoute string, cdc *codec.Codec) *cobra.Command { }, } } + +// CmdInvariantCheck does invariants check +func CmdInvariantCheck(queryRoute string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "invariant-check", + Short: "check the invariant of all module", + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + res, _, err := cliCtx.QueryWithData( + fmt.Sprintf("custom/%s/%s", queryRoute, types.InvariantCheck), nil) + if err != nil { + return err + } + fmt.Println(string(res)) + return nil + }, + } +} diff --git a/x/debug/keeper/keeper.go b/x/debug/keeper/keeper.go index f52f08b3b7..5d0c0a1ed3 100644 --- a/x/debug/keeper/keeper.go +++ b/x/debug/keeper/keeper.go @@ -17,10 +17,11 @@ type Keeper struct { orderKeeper types.OrderKeeper StopFunc func() stakingKeeper types.StakingKeeper + crisisKeeper types.CrisisKeeper } func NewDebugKeeper(cdc *codec.Codec, storeKey sdk.StoreKey, - orderKeeper types.OrderKeeper, stakingKeeper types.StakingKeeper, + orderKeeper types.OrderKeeper, stakingKeeper types.StakingKeeper, crisisKeeper types.CrisisKeeper, feePoolModuleName string, stop func()) Keeper { return Keeper{ storeKey: storeKey, @@ -29,6 +30,7 @@ func NewDebugKeeper(cdc *codec.Codec, storeKey sdk.StoreKey, orderKeeper: orderKeeper, StopFunc: stop, stakingKeeper: stakingKeeper, + crisisKeeper: crisisKeeper, } } diff --git a/x/debug/keeper/querier.go b/x/debug/keeper/querier.go index 00b7856403..204c25afb5 100644 --- a/x/debug/keeper/querier.go +++ b/x/debug/keeper/querier.go @@ -1,6 +1,7 @@ package keeper import ( + "fmt" "strings" "github.com/okex/okexchain/x/staking" @@ -21,6 +22,8 @@ func NewDebugger(keeper Keeper) sdk.Querier { return setLogLevel(path[1:]) case types.SanityCheckShares: return sanityCheckShares(ctx, keeper) + case types.InvariantCheck: + return invariantCheck(ctx, keeper) default: return nil, sdk.ErrUnknownRequest("unknown common query endpoint") } @@ -60,3 +63,15 @@ func sanityCheckShares(ctx sdk.Context, keeper Keeper) ([]byte, sdk.Error) { } return []byte("sanity check passed"), nil } + +func invariantCheck(ctx sdk.Context, keeper Keeper) (res []byte, err sdk.Error) { + defer func() { + if e := recover(); e != nil { + res, err = []byte(fmt.Sprintf("failed to check ivariant:\n\t%v", e)), nil + } + }() + + keeper.crisisKeeper.AssertInvariants(ctx) + + return []byte("invariant check passed"), nil +} diff --git a/x/debug/types/expected_keepers.go b/x/debug/types/expected_keepers.go index 0ce78b4591..5e07b6a93b 100644 --- a/x/debug/types/expected_keepers.go +++ b/x/debug/types/expected_keepers.go @@ -13,3 +13,8 @@ type StakingKeeper interface { GetAllValidators(ctx sdk.Context) (validators staking.Validators) GetValidatorAllShares(ctx sdk.Context, valAddr sdk.ValAddress) staking.SharesResponses } + +type CrisisKeeper interface { + AssertInvariants(ctx sdk.Context) + Invariants() []sdk.Invariant +} diff --git a/x/debug/types/keys.go b/x/debug/types/keys.go index f2b1f996e5..d713811999 100644 --- a/x/debug/types/keys.go +++ b/x/debug/types/keys.go @@ -16,4 +16,5 @@ const ( DumpStore = "dump" SetLogLevel = "set-loglevel" SanityCheckShares = "sanity-check-shares" + InvariantCheck = "invariant-check" ) diff --git a/x/dex/keeper/querier.go b/x/dex/keeper/querier.go index cb1c2bb5bf..ee26360737 100644 --- a/x/dex/keeper/querier.go +++ b/x/dex/keeper/querier.go @@ -47,7 +47,7 @@ func queryProduct(ctx sdk.Context, req abci.RequestQuery, keeper IKeeper) (res [ offset, limit := common.GetPage(int(params.Page), int(params.PerPage)) - if offset < 0 || limit <= 0 { + if offset < 0 || limit < 0 { return nil, sdk.ErrUnknownRequest(fmt.Sprintf("invalid params: page=%d or per_page=%d", params.Page, params.PerPage)) } @@ -113,7 +113,7 @@ func queryDeposits(ctx sdk.Context, req abci.RequestQuery, keeper IKeeper) (res } offset, limit := common.GetPage(int(params.Page), int(params.PerPage)) - if offset < 0 || limit <= 0 { + if offset < 0 || limit < 0 { return nil, sdk.ErrUnknownRequest(fmt.Sprintf("invalid params: page=%d or per_page=%d", params.Page, params.PerPage)) } @@ -177,7 +177,7 @@ func queryMatchOrder(ctx sdk.Context, req abci.RequestQuery, keeper IKeeper) (re } offset, limit := common.GetPage(int(params.Page), int(params.PerPage)) - if offset < 0 || limit <= 0 { + if offset < 0 || limit < 0 { return nil, sdk.ErrUnknownRequest(fmt.Sprintf("invalid params: page=%d or per_page=%d", params.Page, params.PerPage)) } tokenPairs := keeper.GetTokenPairsOrdered(ctx) diff --git a/x/order/keeper/keeper.go b/x/order/keeper/keeper.go index 838568fd6e..de6c18524a 100644 --- a/x/order/keeper/keeper.go +++ b/x/order/keeper/keeper.go @@ -452,23 +452,14 @@ func (k Keeper) AddCollectedFees(ctx sdk.Context, coins sdk.DecCoins, from sdk.A // GetParams gets inflation params from the global param store func (k Keeper) GetParams(ctx sdk.Context) *types.Params { - // get params from cache - cacheParams := k.cache.GetParams() - if cacheParams != nil { - return cacheParams - } - - // if param not stored in cache, get param from KVStore and cache it var param types.Params k.paramSpace.GetParamSet(ctx, ¶m) - k.cache.SetParams(¶m) return ¶m } // SetParams sets inflation params from the global param store func (k Keeper) SetParams(ctx sdk.Context, params *types.Params) { k.paramSpace.SetParamSet(ctx, params) - k.cache.SetParams(params) } // nolint diff --git a/x/order/keeper/keeper_test.go b/x/order/keeper/keeper_test.go index 76833093f0..32c4bf0512 100644 --- a/x/order/keeper/keeper_test.go +++ b/x/order/keeper/keeper_test.go @@ -67,7 +67,7 @@ func TestCache(t *testing.T) { order.Sender = testInput.TestAddrs[0] err = keeper.PlaceOrder(ctx, order) require.Nil(t, err) - require.EqualValues(t, 1, keeper.GetCache().params.OrderExpireBlocks) + require.EqualValues(t, 1, keeper.GetParams(ctx).OrderExpireBlocks) require.EqualValues(t, 1, keeper.GetOperationMetric().OpenNum) // current cache diff --git a/x/order/keeper/memory_cache.go b/x/order/keeper/memory_cache.go index 7617b09ebf..d71d5e5547 100644 --- a/x/order/keeper/memory_cache.go +++ b/x/order/keeper/memory_cache.go @@ -12,8 +12,6 @@ type Cache struct { blockMatchResult *types.BlockMatchResult handlerTxMsgResult []bitset.BitSet - params *types.Params - // for statistic cancelNum int64 // canceled orders num in this block expireNum int64 // expired orders num in this block @@ -26,7 +24,6 @@ func NewCache() *Cache { return &Cache{ updatedOrderIDs: []string{}, blockMatchResult: nil, - params: nil, } } @@ -35,7 +32,6 @@ func (c *Cache) reset() { c.updatedOrderIDs = []string{} c.blockMatchResult = &types.BlockMatchResult{} c.handlerTxMsgResult = []bitset.BitSet{} - c.params = nil c.cancelNum = 0 c.expireNum = 0 @@ -103,16 +99,6 @@ func (c *Cache) getBlockMatchResult() *types.BlockMatchResult { return c.blockMatchResult } -// nolint -func (c *Cache) SetParams(params *types.Params) { - c.params = params -} - -// nolint -func (c *Cache) GetParams() *types.Params { - return c.params -} - func (c *Cache) getUpdatedOrderIDs() []string { return c.updatedOrderIDs } diff --git a/x/order/keeper/memory_cache_test.go b/x/order/keeper/memory_cache_test.go index 2f81c73fef..7848c47cf5 100644 --- a/x/order/keeper/memory_cache_test.go +++ b/x/order/keeper/memory_cache_test.go @@ -30,11 +30,6 @@ func TestCache_GetCancelNum(t *testing.T) { require.EqualValues(t, 0, cache.GetFullFillNum()) require.EqualValues(t, 0, cache.GetPartialFillNum()) - feeParams := types.DefaultTestParams() - cache.SetParams(&feeParams) - - require.EqualValues(t, types.DefaultOrderExpireBlocks, cache.params.OrderExpireBlocks) - res := types.BlockMatchResult{ BlockHeight: 0, ResultMap: nil, @@ -43,8 +38,4 @@ func TestCache_GetCancelNum(t *testing.T) { cache.setBlockMatchResult(&res) require.NotEqual(t, 0, cache.getBlockMatchResult().TimeStamp) - - cache.reset() - require.Nil(t, cache.GetParams()) - } diff --git a/x/staking/client/cli/tx.go b/x/staking/client/cli/tx.go index 690f0cec90..6538b7f934 100644 --- a/x/staking/client/cli/tx.go +++ b/x/staking/client/cli/tx.go @@ -132,12 +132,11 @@ func GetCmdEditValidator(cdc *codec.Codec) *cobra.Command { //__________________________________________________________ var ( - //defaultTokens = sdk.TokensFromConsensusPower(100) - //defaultAmount = defaultTokens.String() + sdk.DefaultBondDenom - //defaultCommissionRate = "0.1" - //defaultCommissionMaxRate = "0.2" - //defaultCommissionMaxChangeRate = "0.01" - defaultMinSelfDelegation = "0.001" + common.NativeToken +//defaultTokens = sdk.TokensFromConsensusPower(100) +//defaultAmount = defaultTokens.String() + sdk.DefaultBondDenom +//defaultCommissionRate = "0.1" +//defaultCommissionMaxRate = "0.2" +//defaultCommissionMaxChangeRate = "0.01" ) // CreateValidatorMsgHelpers returns the flagset, particular flags, and a description of defaults @@ -221,9 +220,9 @@ func BuildCreateValidatorMsg(cliCtx context.CLIContext, txBldr auth.TxBuilder) ( ) // get the initial validator min self delegation - minSelfDelegation, err := sdk.ParseDecCoin(defaultMinSelfDelegation) - if err != nil { - return txBldr, nil, err + minSelfDelegation := sdk.DecCoin{ + Amount: types.DefaultMinSelfDelegation, + Denom: common.NativeToken, } msg := types.NewMsgCreateValidator( diff --git a/x/token/client/cli/tx.go b/x/token/client/cli/tx.go index 884bded614..fca829c3bc 100644 --- a/x/token/client/cli/tx.go +++ b/x/token/client/cli/tx.go @@ -7,7 +7,6 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" @@ -66,7 +65,7 @@ func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { getCmdTokenMint(cdc), getCmdTokenMultiSend(cdc), getCmdTransferOwnership(cdc), - getMultiSignsCmd(cdc), + getCmdConfirmOwnership(cdc), getCmdTokenEdit(cdc), )...) @@ -284,7 +283,6 @@ func getCmdTransferOwnership(cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "transfer-ownership", Short: "change the owner of the token", - //Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) @@ -315,8 +313,7 @@ func getCmdTransferOwnership(cdc *codec.Codec) *cobra.Command { } msg := types.NewMsgTransferOwnership(from, toBytes, symbol) - - return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}) + return utils.CompleteAndBroadcastTxCLI(txBldr, cliCtx, []sdk.Msg{msg}) }, } cmd.Flags().StringP("symbol", "s", "", "symbol of the token to be transferred") @@ -324,63 +321,6 @@ func getCmdTransferOwnership(cdc *codec.Codec) *cobra.Command { return cmd } -// nolint -func getMultiSignsCmd(cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ - Use: "multisigns", - Short: "append signature to the chown unsignedtx file", - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - cliCtx := context.NewCLIContext().WithCodec(cdc) - txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) - - stdTx, err := utils.ReadStdTxFromFile(cdc, args[0]) - if err != nil { - return err - } - - if len(stdTx.Msgs) == 0 { - return err - } - - msg, ok := stdTx.Msgs[0].(types.MsgTransferOwnership) - if !ok { - // todo - return errSign - } - - flags := cmd.Flags() - _, err = flags.GetString(From) - if err != nil { - return errFromNotValid - } - - // - passphrase, err := keys.GetPassphrase(cliCtx.GetFromName()) - if err != nil { - return err - } - ToSignature, _, err := txBldr.Keybase().Sign(cliCtx.GetFromName(), passphrase, msg.GetSignBytes()) - if err != nil { - return errSign - } - info, err := txBldr.Keybase().Get(cliCtx.GetFromName()) - if err != nil { - return err - } - stdSig := auth.StdSignature{ - PubKey: info.GetPubKey(), - Signature: ToSignature, - } - msg.ToSignature = stdSig - - return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}) - - }, - } - return cmd -} - // SendTxCmd will create a transaction to send and sign func SendTxCmd(cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ @@ -477,3 +417,36 @@ func getCmdTokenEdit(cdc *codec.Codec) *cobra.Command { return cmd } + +// getCmdConfirmOwnership is the CLI command for sending a ConfirmOwnership transaction +func getCmdConfirmOwnership(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "confirm-ownership", + Short: "confirm the transfer-ownership of the token", + RunE: func(cmd *cobra.Command, args []string) error { + + cliCtx := context.NewCLIContext().WithCodec(cdc) + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + if err := authTypes.NewAccountRetriever(cliCtx).EnsureExists(cliCtx.FromAddress); err != nil { + return err + } + flags := cmd.Flags() + + symbol, err := flags.GetString(Symbol) + if err != nil { + return errSymbolNotValid + } + _, err = flags.GetString(From) + if err != nil { + return errFromNotValid + } + + from := cliCtx.GetFromAddress() + + msg := types.NewMsgConfirmOwnership(from, symbol) + return utils.CompleteAndBroadcastTxCLI(txBldr, cliCtx, []sdk.Msg{msg}) + }, + } + cmd.Flags().StringP("symbol", "s", "", "symbol of the token to be transferred") + return cmd +} diff --git a/x/token/handler.go b/x/token/handler.go index 813aeb346e..3895e78a65 100644 --- a/x/token/handler.go +++ b/x/token/handler.go @@ -3,6 +3,8 @@ package token import ( "fmt" + "github.com/okex/okexchain/x/common" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/okex/okexchain/x/common/perf" "github.com/okex/okexchain/x/common/version" @@ -51,9 +53,14 @@ func NewTokenHandler(keeper Keeper, protocolVersion version.ProtocolVersionType) } case types.MsgTransferOwnership: - name = "handleMsgTokenChown" + name = "handleMsgTransferOwnership" + handlerFun = func() sdk.Result { + return handleMsgTransferOwnership(ctx, keeper, msg, logger) + } + case types.MsgConfirmOwnership: + name = "handleMsgConfirmOwnership" handlerFun = func() sdk.Result { - return handleMsgTokenChown(ctx, keeper, msg, logger) + return handleMsgConfirmOwnership(ctx, keeper, msg, logger) } case types.MsgTokenModify: @@ -311,7 +318,7 @@ func handleMsgSend(ctx sdk.Context, keeper Keeper, msg types.MsgSend, logger log return sdk.Result{Events: ctx.EventManager().Events()} } -func handleMsgTokenChown(ctx sdk.Context, keeper Keeper, msg types.MsgTransferOwnership, logger log.Logger) sdk.Result { +func handleMsgTransferOwnership(ctx sdk.Context, keeper Keeper, msg types.MsgTransferOwnership, logger log.Logger) sdk.Result { tokenInfo := keeper.GetTokenInfo(ctx, msg.Symbol) if !tokenInfo.Owner.Equals(msg.FromAddress) { @@ -319,12 +326,26 @@ func handleMsgTokenChown(ctx sdk.Context, keeper Keeper, msg types.MsgTransferOw msg.FromAddress.String(), msg.Symbol)).Result() } - // first remove it from the raw owner - keeper.DeleteUserToken(ctx, tokenInfo.Owner, tokenInfo.Symbol) - - tokenInfo.Owner = msg.ToAddress - keeper.NewToken(ctx, tokenInfo) + confirmOwnership, exist := keeper.GetConfirmOwnership(ctx, msg.Symbol) + if exist && !ctx.BlockTime().After(confirmOwnership.Expire) { + return sdk.ErrInternal(fmt.Sprintf("repeated transfer-ownership of token(%s) is not allowed", msg.Symbol)).Result() + } + if msg.ToAddress.Equals(common.BlackHoleAddress()) { // transfer ownership to black hole + // first remove it from the raw owner + keeper.DeleteUserToken(ctx, tokenInfo.Owner, tokenInfo.Symbol) + tokenInfo.Owner = msg.ToAddress + keeper.NewToken(ctx, tokenInfo) + } else { + // set confirm ownership info + expireTime := ctx.BlockTime().Add(keeper.GetParams(ctx).OwnershipConfirmWindow) + confirmOwnership = &types.ConfirmOwnership{ + Symbol: msg.Symbol, + Address: msg.ToAddress, + Expire: expireTime, + } + keeper.SetConfirmOwnership(ctx, confirmOwnership) + } // deduction fee feeDecCoins := keeper.GetParams(ctx).FeeChown.ToCoins() err := keeper.supplyKeeper.SendCoinsFromAccountToModule(ctx, msg.FromAddress, keeper.feeCollectorName, feeDecCoins) @@ -333,13 +354,13 @@ func handleMsgTokenChown(ctx sdk.Context, keeper Keeper, msg types.MsgTransferOw feeDecCoins.String())).Result() } - var name = "handleMsgTokenChown" + var name = "handleMsgTransferOwnership" if logger != nil { logger.Debug(fmt.Sprintf("BlockHeight<%d>, handler<%s>\n"+ - " msg\n"+ + " msg\n"+ " result\n", ctx.BlockHeight(), name, - msg.FromAddress, msg.ToAddress, msg.Symbol, msg.ToSignature, + msg.FromAddress, msg.ToAddress, msg.Symbol, msg.Symbol)) } @@ -353,6 +374,47 @@ func handleMsgTokenChown(ctx sdk.Context, keeper Keeper, msg types.MsgTransferOw return sdk.Result{Events: ctx.EventManager().Events()} } +func handleMsgConfirmOwnership(ctx sdk.Context, keeper Keeper, msg types.MsgConfirmOwnership, logger log.Logger) sdk.Result { + confirmOwnership, exist := keeper.GetConfirmOwnership(ctx, msg.Symbol) + if !exist { + return sdk.ErrUnknownRequest(fmt.Sprintf("no transfer-ownership of token (%s) to confirm", + msg.Address.String())).Result() + } + if ctx.BlockTime().After(confirmOwnership.Expire) { + // delete ownership confirming information + keeper.DeleteConfirmOwnership(ctx, confirmOwnership.Symbol) + return sdk.ErrInternal(fmt.Sprintf("transfer-ownership is expired, expire time (%s)", confirmOwnership.Expire.String())).Result() + } + if !confirmOwnership.Address.Equals(msg.Address) { + return sdk.ErrUnauthorized(fmt.Sprintf("%s is expected as the new owner", + confirmOwnership.Address.String())).Result() + } + + tokenInfo := keeper.GetTokenInfo(ctx, msg.Symbol) + // first remove it from the raw owner + keeper.DeleteUserToken(ctx, tokenInfo.Owner, tokenInfo.Symbol) + tokenInfo.Owner = msg.Address + keeper.NewToken(ctx, tokenInfo) + + // delete ownership confirming information + keeper.DeleteConfirmOwnership(ctx, confirmOwnership.Symbol) + + var name = "handleMsgConfirmOwnership" + logger.Debug(fmt.Sprintf("BlockHeight<%d>, handler<%s>\n"+ + " msg\n"+ + " result\n", + ctx.BlockHeight(), name, msg.Address, msg.Symbol, msg.Symbol)) + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(sdk.AttributeKeyFee, keeper.GetParams(ctx).FeeChown.String()), + ), + ) + return sdk.Result{Events: ctx.EventManager().Events()} +} + func handleMsgTokenModify(ctx sdk.Context, keeper Keeper, msg types.MsgTokenModify, logger log.Logger) sdk.Result { token := keeper.GetTokenInfo(ctx, msg.Symbol) // check owner diff --git a/x/token/keeper.go b/x/token/keeper.go index ab229d4790..f8360f4a2e 100644 --- a/x/token/keeper.go +++ b/x/token/keeper.go @@ -167,7 +167,7 @@ func (k Keeper) SendCoinsFromAccountToAccount(ctx sdk.Context, from, to sdk.AccA if k.bankKeeper.BlacklistedAddr(to) { return types.ErrBlockedRecipient(DefaultCodespace, to.String()) } - + return k.bankKeeper.SendCoins(ctx, from, to, amt) } @@ -402,3 +402,29 @@ func addTokenSuffix(ctx sdk.Context, keeper Keeper, originalSymbol string) (name } return name, true } + +// GetConfirmOwnership returns ownership confirming information +func (k Keeper) GetConfirmOwnership(ctx sdk.Context, symbol string) (confirmOwnership *types.ConfirmOwnership, exist bool) { + store := ctx.KVStore(k.tokenStoreKey) + bytes := store.Get(types.GetConfirmOwnershipKey(symbol)) + if bytes == nil { + return nil, false + } + + k.cdc.MustUnmarshalBinaryBare(bytes, &confirmOwnership) + return confirmOwnership, true +} + +// SetConfirmOwnership sets ownership confirming information to db +func (k Keeper) SetConfirmOwnership(ctx sdk.Context, confirmOwnership *types.ConfirmOwnership) { + store := ctx.KVStore(k.tokenStoreKey) + key := types.GetConfirmOwnershipKey(confirmOwnership.Symbol) + store.Set(key, k.cdc.MustMarshalBinaryBare(confirmOwnership)) +} + +// DeleteConfirmOwnership deletes ownership confirming information from db +func (k Keeper) DeleteConfirmOwnership(ctx sdk.Context, symbol string) { + store := ctx.KVStore(k.tokenStoreKey) + key := types.GetConfirmOwnershipKey(symbol) + store.Delete(key) +} diff --git a/x/token/token_test.go b/x/token/token_test.go index 9d69c36879..9d09558293 100644 --- a/x/token/token_test.go +++ b/x/token/token_test.go @@ -107,7 +107,7 @@ func getMockDexApp(t *testing.T, numGenAccs int) (mockDexApp *MockDexApp, keeper mockDexApp.SetEndBlocker(getEndBlocker(mockDexApp.tokenKeeper)) mockDexApp.SetInitChainer(getInitChainer(mockDexApp.App, mockDexApp.bankKeeper, mockDexApp.supplyKeeper, []exported.ModuleAccountI{feeCollectorAcc})) - intQuantity := int64(100) + intQuantity := int64(100000) valTokens := sdk.NewDec(intQuantity) coins := sdk.DecCoins{ sdk.NewDecCoinFromDec(common.NativeToken, valTokens), @@ -447,20 +447,8 @@ ok-bok-bok-bok-bok-bok-bok-bok-bok-bok-bok-bok-bok-bok-bok-bok-bok-bok-bok-bok-b //test if zzb is not exist invalidmsg := types.NewMsgTransferOwnership(fromAddr, toAddr, "zzb") - bSig, err := toPriKey.Sign(invalidmsg.GetSignBytes()) - require.NoError(t, err) - invalidmsg.ToSignature.PubKey = toPubKey - invalidmsg.ToSignature.Signature = bSig TokenChown = append(TokenChown, createTokenMsg(t, app, ctx, testAccounts[0], invalidmsg)) - //test if zzb is not exist - tokenNotExist := types.NewMsgTransferOwnership(fromAddr, toAddr, "zzb") - bSig, err = toPriKey.Sign(tokenNotExist.GetSignBytes()) - require.NoError(t, err) - tokenNotExist.ToSignature.PubKey = toPubKey - tokenNotExist.ToSignature.Signature = bSig - TokenChown = append(TokenChown, createTokenMsg(t, app, ctx, testAccounts[0], tokenNotExist)) - //test addTokenSuffix->ValidSymbol addTokenSuffix(ctx, keeper, "notexist") @@ -468,22 +456,14 @@ ok-bok-bok-bok-bok-bok-bok-bok-bok-bok-bok-bok-bok-bok-bok-bok-bok-bok-bok-bok-b symbName := "okb-b85" //addTokenSuffix(ctx,keeper,common.NativeToken) //change owner from F to T tokenChownMsg := types.NewMsgTransferOwnership(fromAddr, toAddr, symbName) - bSig, err = toPriKey.Sign(tokenChownMsg.GetSignBytes()) - require.NoError(t, err) - tokenChownMsg.ToSignature.PubKey = toPubKey - tokenChownMsg.ToSignature.Signature = bSig TokenChown = append(TokenChown, createTokenMsg(t, app, ctx, testAccounts[0], tokenChownMsg)) ctx = mockApplyBlock(t, app, TokenChown, 4) } func TestUpdateUserTokenRelationship(t *testing.T) { - toPriKey := secp256k1.GenPrivKey() - toPubKey := toPriKey.PubKey() - toAddr := sdk.AccAddress(toPubKey.Address()) - intQuantity := int64(30000) - genAccs, testAccounts := CreateGenAccounts(1, + genAccs, testAccounts := CreateGenAccounts(2, sdk.DecCoins{ sdk.NewDecCoinFromDec(common.NativeToken, sdk.NewDec(intQuantity)), }) @@ -511,17 +491,22 @@ func TestUpdateUserTokenRelationship(t *testing.T) { var TokenChown []auth.StdTx //test if zzb is not exist - chownMsg := types.NewMsgTransferOwnership(testAccounts[0].baseAccount.Address, toAddr, tokenName) - bSig, err := toPriKey.Sign(chownMsg.GetSignBytes()) - require.NoError(t, err) - chownMsg.ToSignature.PubKey = toPubKey - chownMsg.ToSignature.Signature = bSig + chownMsg := types.NewMsgTransferOwnership(testAccounts[0].baseAccount.Address, testAccounts[1].baseAccount.Address, tokenName) TokenChown = append(TokenChown, createTokenMsg(t, app, ctx, testAccounts[0], chownMsg)) ctx = mockApplyBlock(t, app, TokenChown, 4) + tokens = keeper.GetUserTokensInfo(ctx, testAccounts[0].baseAccount.Address) + require.EqualValues(t, 1, len(tokens)) + + confirmMsg := types.NewMsgConfirmOwnership(testAccounts[1].baseAccount.Address, tokenName) + ctx = mockApplyBlock(t, app, []auth.StdTx{createTokenMsg(t, app, ctx, testAccounts[1], confirmMsg)}, 5) + tokens = keeper.GetUserTokensInfo(ctx, testAccounts[0].baseAccount.Address) require.EqualValues(t, 0, len(tokens)) + + tokens = keeper.GetUserTokensInfo(ctx, testAccounts[1].baseAccount.Address) + require.EqualValues(t, 1, len(tokens)) } func TestCreateTokenIssue(t *testing.T) { @@ -990,10 +975,6 @@ func TestTxFailedFeeTable(t *testing.T) { // failed TransferOwnership msg: no such token failedChownMsg := types.NewMsgTransferOwnership(testAccounts[0].baseAccount.Address, toAddr, "nob") - bSig, err := toPriKey.Sign(failedChownMsg.GetSignBytes()) - require.NoError(t, err) - failedChownMsg.ToSignature.PubKey = toPubKey - failedChownMsg.ToSignature.Signature = bSig failTestSets := []struct { name string @@ -1048,10 +1029,6 @@ func TestTxSuccessFeeTable(t *testing.T) { successfulEditMsg := types.NewMsgTokenModify(symbolAfterIssue, "edit msg", "xxb coin ", true, true, testAccounts[0].baseAccount.Address) successfulChownMsg := types.NewMsgTransferOwnership(testAccounts[0].baseAccount.Address, toAddr, symbolAfterIssue) - bSig, err := toPriKey.Sign(successfulChownMsg.GetSignBytes()) - require.NoError(t, err) - successfulChownMsg.ToSignature.PubKey = toPubKey - successfulChownMsg.ToSignature.Signature = bSig successfulTestSets := []struct { description string @@ -1124,3 +1101,94 @@ func TestBlockedAddrSend(t *testing.T) { } } + +func TestHandleTransferOwnership(t *testing.T) { + app, keeper, testAccounts := getMockDexApp(t, 2) + app.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: 2}}) + ctx := app.BaseApp.NewContext(false, abci.Header{}).WithBlockHeight(3) + ctxPassedOwnershipConfirmWindow := app.BaseApp.NewContext(false, abci.Header{}).WithBlockTime(ctx.BlockTime().Add(types.DefaultOwnershipConfirmWindow * 2)) + handler := NewTokenHandler(keeper, version.ProtocolVersionV0) + + param := types.DefaultParams() + app.tokenKeeper.SetParams(ctx, param) + + // issue token + symbol := "xxb" + msgNewIssue := types.NewMsgTokenIssue("xxb desc", symbol, symbol, symbol, + "1000000", testAccounts[0], true) + result := handler(ctx, msgNewIssue) + require.True(t, result.IsOK()) + + tokenName := getTokenSymbol(ctx, keeper, symbol) + + // test case + tests := []struct { + ctx sdk.Context + msg sdk.Msg + expectedCode sdk.CodeType + }{ + // case 1. sender is not the owner of token + { + ctx: ctx, + msg: types.NewMsgTransferOwnership(testAccounts[1], testAccounts[0], tokenName), + expectedCode: sdk.CodeUnauthorized, + }, + // case 2. transfer ownership to testAccounts[1] successfully + { + ctx: ctx, + msg: types.NewMsgTransferOwnership(testAccounts[0], testAccounts[1], tokenName), + expectedCode: sdk.CodeOK, + }, + // case 3. confirm ownership not exists + { + ctx: ctx, + msg: types.NewMsgConfirmOwnership(testAccounts[1], "not-exist-token"), + expectedCode: sdk.CodeUnknownRequest, + }, + // case 4. sender is not the owner of ConfirmOwnership + { + ctx: ctx, + msg: types.NewMsgConfirmOwnership(testAccounts[0], tokenName), + expectedCode: sdk.CodeUnauthorized, + }, + // case 5. confirm ownership expired + { + ctx: ctxPassedOwnershipConfirmWindow, + msg: types.NewMsgConfirmOwnership(testAccounts[1], tokenName), + expectedCode: sdk.CodeInternal, + }, + // case 6. confirm ownership successfully + { + ctx: ctx, + msg: types.NewMsgTransferOwnership(testAccounts[0], testAccounts[1], tokenName), + expectedCode: sdk.CodeOK, + }, + { + ctx: ctx, + msg: types.NewMsgConfirmOwnership(testAccounts[1], tokenName), + expectedCode: sdk.CodeOK, + }, + + // case 7. transfer ownership to testAccounts[0] successfully + { + ctx: ctx, + msg: types.NewMsgTransferOwnership(testAccounts[1], testAccounts[0], tokenName), + expectedCode: sdk.CodeOK, + }, + // case 8. confirm ownership exists but expired, and transfer to black hole successfully + { + ctx: ctxPassedOwnershipConfirmWindow, + msg: types.NewMsgTransferOwnership(testAccounts[1], common.BlackHoleAddress(), tokenName), + expectedCode: sdk.CodeOK, + }, + } + + for _, testCase := range tests { + result := handler(testCase.ctx, testCase.msg) + require.Equal(t, testCase.expectedCode, result.Code) + } + + token := keeper.GetTokenInfo(ctx, tokenName) + require.True(t, token.Owner.Equals(common.BlackHoleAddress())) + +} diff --git a/x/token/types/codec.go b/x/token/types/codec.go index 7629dda019..b41feffcd5 100644 --- a/x/token/types/codec.go +++ b/x/token/types/codec.go @@ -12,6 +12,7 @@ func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(MsgMultiSend{}, "okexchain/token/MsgMultiTransfer", nil) cdc.RegisterConcrete(MsgSend{}, "okexchain/token/MsgTransfer", nil) cdc.RegisterConcrete(MsgTransferOwnership{}, "okexchain/token/MsgTransferOwnership", nil) + cdc.RegisterConcrete(MsgConfirmOwnership{}, "okexchain/token/MsgConfirmOwnership", nil) cdc.RegisterConcrete(MsgTokenModify{}, "okexchain/token/MsgModify", nil) // for test diff --git a/x/token/types/confirm_ownership.go b/x/token/types/confirm_ownership.go new file mode 100644 index 0000000000..d545c092a9 --- /dev/null +++ b/x/token/types/confirm_ownership.go @@ -0,0 +1,16 @@ +package types + +import ( + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// DefaultOwnershipConfirmWindow defines default confirm window +const DefaultOwnershipConfirmWindow = 24 * time.Hour + +type ConfirmOwnership struct { + Symbol string `json:"symbol"` + Address sdk.AccAddress `json:"address"` + Expire time.Time `json:expire` +} diff --git a/x/token/types/keys.go b/x/token/types/keys.go index 24754ffeaa..008e95a22a 100644 --- a/x/token/types/keys.go +++ b/x/token/types/keys.go @@ -37,11 +37,12 @@ const ( ) var ( - TokenKey = []byte{0x00} // the address prefix of the token's symbol - TokenNumberKey = []byte{0x01} // key for token number address - LockKey = []byte{0x02} // the address prefix of the locked coins - LockedFeeKey = []byte{0x04} // the address prefix of the locked order fee coins - PrefixUserTokenKey = []byte{0x03} // the address prefix of the user-token relationship + TokenKey = []byte{0x00} // the address prefix of the token's symbol + TokenNumberKey = []byte{0x01} // key for token number address + LockKey = []byte{0x02} // the address prefix of the locked coins + PrefixUserTokenKey = []byte{0x03} // the address prefix of the user-token relationship + LockedFeeKey = []byte{0x04} // the address prefix of the locked order fee coins + PrefixConfirmOwnershipKey = []byte{0x05} // the prefix of the confirm ownership key ) func GetUserTokenPrefix(owner sdk.AccAddress) []byte { @@ -65,7 +66,6 @@ func GetLockFeeAddress(addr sdk.AccAddress) []byte { return append(LockedFeeKey, addr.Bytes()...) } -//// Key for getting a specific proposal from the store -//func keyDexListAsset(asset string) []byte { -// return []byte(fmt.Sprintf("asset:%s", asset)) -//} +func GetConfirmOwnershipKey(symbol string) []byte { + return append(PrefixConfirmOwnershipKey, []byte(symbol)...) +} diff --git a/x/token/types/msgs.go b/x/token/types/msgs.go index 68db04c849..388b44357a 100644 --- a/x/token/types/msgs.go +++ b/x/token/types/msgs.go @@ -3,7 +3,6 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" ) const ( @@ -257,8 +256,6 @@ type MsgTransferOwnership struct { FromAddress sdk.AccAddress `json:"from_address"` ToAddress sdk.AccAddress `json:"to_address"` Symbol string `json:"symbol"` - //FromSignature auth.StdSignature `json:"from_signature"` - ToSignature auth.StdSignature `json:"to_signature"` } func NewMsgTransferOwnership(from, to sdk.AccAddress, symbol string) MsgTransferOwnership { @@ -266,8 +263,6 @@ func NewMsgTransferOwnership(from, to sdk.AccAddress, symbol string) MsgTransfer FromAddress: from, ToAddress: to, Symbol: symbol, - //FromSignature: auth.StdSignature{}, - ToSignature: auth.StdSignature{}, } } @@ -289,10 +284,6 @@ func (msg MsgTransferOwnership) ValidateBasic() sdk.Error { if sdk.ValidateDenom(msg.Symbol) != nil { return sdk.ErrUnknownRequest("failed to check transferownership msg because invalid token symbol: " + msg.Symbol) } - - if !msg.checkMultiSign() { - return sdk.ErrUnauthorized("failed to check transferownership msg because invalid multi signature") - } return nil } @@ -305,23 +296,6 @@ func (msg MsgTransferOwnership) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.FromAddress} } -func (msg MsgTransferOwnership) checkMultiSign() bool { - // check pubkey - if msg.ToSignature.PubKey == nil { - return false - } - - if !sdk.AccAddress(msg.ToSignature.PubKey.Address()).Equals(msg.ToAddress) { - return false - } - - // check multisign - toSignature := msg.ToSignature - msg.ToSignature = auth.StdSignature{} - toValid := toSignature.VerifyBytes(msg.GetSignBytes(), toSignature.Signature) - return toValid -} - type MsgTokenModify struct { Owner sdk.AccAddress `json:"owner"` Symbol string `json:"symbol"` @@ -382,3 +356,44 @@ func (msg MsgTokenModify) GetSignBytes() []byte { func (msg MsgTokenModify) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.Owner} } + +// MsgConfirmOwnership - high level transaction of the coin module +type MsgConfirmOwnership struct { + Symbol string `json:"symbol"` + Address sdk.AccAddress `json:"new_owner"` +} + +func NewMsgConfirmOwnership(newOwner sdk.AccAddress, symbol string) MsgConfirmOwnership { + return MsgConfirmOwnership{ + Symbol: symbol, + Address: newOwner, + } +} + +func (msg MsgConfirmOwnership) Route() string { return RouterKey } + +func (msg MsgConfirmOwnership) Type() string { return "confirm" } + +func (msg MsgConfirmOwnership) ValidateBasic() sdk.Error { + if msg.Address.Empty() { + return sdk.ErrInvalidAddress("failed to check confirmownership msg because miss sender address") + } + + if len(msg.Symbol) == 0 { + return sdk.ErrUnknownRequest("failed to check confirmownership msg because symbol cannot be empty") + } + + if sdk.ValidateDenom(msg.Symbol) != nil { + return sdk.ErrUnknownRequest("failed to check confirmownership msg because invalid token symbol: " + msg.Symbol) + } + return nil +} + +func (msg MsgConfirmOwnership) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg MsgConfirmOwnership) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Address} +} diff --git a/x/token/types/msgs_test.go b/x/token/types/msgs_test.go index 5ef9f9d3eb..616b81aadf 100644 --- a/x/token/types/msgs_test.go +++ b/x/token/types/msgs_test.go @@ -273,9 +273,8 @@ func TestNewMsgTransferOwnership(t *testing.T) { transferOwnershipMsg MsgTransferOwnership err sdk.Error }{ - {NewMsgTransferOwnership(fromAddr, toAddr, common.NativeToken), sdk.ErrUnauthorized("failed to check transferownership msg because invalid multi signature")}, - {NewMsgTransferOwnership(sdk.AccAddress{}, toAddr, common.NativeToken), sdk.ErrInvalidAddress("failed to check transferownership msg because miss sender address")}, {NewMsgTransferOwnership(fromAddr, sdk.AccAddress{}, common.NativeToken), sdk.ErrInvalidAddress("failed to check transferownership msg because miss recipient address")}, + {NewMsgTransferOwnership(sdk.AccAddress{}, toAddr, common.NativeToken), sdk.ErrInvalidAddress("failed to check transferownership msg because miss sender address")}, {NewMsgTransferOwnership(fromAddr, toAddr, ""), sdk.ErrUnknownRequest("failed to check transferownership msg because symbol cannot be empty")}, {NewMsgTransferOwnership(fromAddr, toAddr, "1okb-ads"), sdk.ErrUnknownRequest("failed to check transferownership msg because invalid token symbol: 1okb-ads")}, } @@ -285,20 +284,6 @@ func TestNewMsgTransferOwnership(t *testing.T) { } transferOwnershipMsg := testCase[0].transferOwnershipMsg - ret := transferOwnershipMsg.checkMultiSign() - if !ret { - //pubKey not set,test ValidateBasic - bret := transferOwnershipMsg.ValidateBasic() - require.NotNil(t, bret) - //error pubKey - transferOwnershipMsg.ToSignature.PubKey = fromPubKey - if !transferOwnershipMsg.checkMultiSign() { - //unequal with toPubKey address , try again - transferOwnershipMsg.ToSignature.PubKey = toPubKey - require.NotNil(t, transferOwnershipMsg.checkMultiSign()) - require.NotNil(t, transferOwnershipMsg.GetSignBytes()) - } - } transferOwnershipMsg.Route() transferOwnershipMsg.Type() signAddr := transferOwnershipMsg.GetSigners() diff --git a/x/token/types/params.go b/x/token/types/params.go index 8c19e716b2..9a30e11c64 100644 --- a/x/token/types/params.go +++ b/x/token/types/params.go @@ -3,6 +3,7 @@ package types import ( "fmt" "strings" + "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/okex/okexchain/x/common" @@ -14,26 +15,28 @@ const ( DefaultFeeMint = "10" DefaultFeeBurn = "10" DefaultFeeModify = "0" - DefaultFeeChown = "10" + DefaultFeeChown = "10" ) var ( - KeyFeeIssue = []byte("FeeIssue") - KeyFeeMint = []byte("FeeMint") - KeyFeeBurn = []byte("FeeBurn") - KeyFeeModify = []byte("FeeModify") - KeyFeeChown = []byte("FeeChown") + KeyFeeIssue = []byte("FeeIssue") + KeyFeeMint = []byte("FeeMint") + KeyFeeBurn = []byte("FeeBurn") + KeyFeeModify = []byte("FeeModify") + KeyFeeChown = []byte("FeeChown") + KeyOwnershipConfirmWindow = []byte("OwnershipConfirmWindow") ) var _ params.ParamSet = &Params{} // mint parameters type Params struct { - FeeIssue sdk.DecCoin `json:"issue_fee"` - FeeMint sdk.DecCoin `json:"mint_fee"` - FeeBurn sdk.DecCoin `json:"burn_fee"` - FeeModify sdk.DecCoin `json:"modify_fee"` - FeeChown sdk.DecCoin `json:"transfer_ownership_fee"` + FeeIssue sdk.DecCoin `json:"issue_fee"` + FeeMint sdk.DecCoin `json:"mint_fee"` + FeeBurn sdk.DecCoin `json:"burn_fee"` + FeeModify sdk.DecCoin `json:"modify_fee"` + FeeChown sdk.DecCoin `json:"transfer_ownership_fee"` + OwnershipConfirmWindow time.Duration `json:"ownership_confirm_window"` } // ParamKeyTable for auth module @@ -51,17 +54,19 @@ func (p *Params) ParamSetPairs() params.ParamSetPairs { {KeyFeeBurn, &p.FeeBurn}, {KeyFeeModify, &p.FeeModify}, {KeyFeeChown, &p.FeeChown}, + {KeyOwnershipConfirmWindow, &p.OwnershipConfirmWindow}, } } // DefaultParams returns a default set of parameters. func DefaultParams() Params { return Params{ - FeeIssue: sdk.NewDecCoinFromDec(common.NativeToken, sdk.MustNewDecFromStr(DefaultFeeIssue)), - FeeMint: sdk.NewDecCoinFromDec(common.NativeToken, sdk.MustNewDecFromStr(DefaultFeeMint)), - FeeBurn: sdk.NewDecCoinFromDec(common.NativeToken, sdk.MustNewDecFromStr(DefaultFeeBurn)), - FeeModify: sdk.NewDecCoinFromDec(common.NativeToken, sdk.MustNewDecFromStr(DefaultFeeModify)), - FeeChown: sdk.NewDecCoinFromDec(common.NativeToken, sdk.MustNewDecFromStr(DefaultFeeChown)), + FeeIssue: sdk.NewDecCoinFromDec(common.NativeToken, sdk.MustNewDecFromStr(DefaultFeeIssue)), + FeeMint: sdk.NewDecCoinFromDec(common.NativeToken, sdk.MustNewDecFromStr(DefaultFeeMint)), + FeeBurn: sdk.NewDecCoinFromDec(common.NativeToken, sdk.MustNewDecFromStr(DefaultFeeBurn)), + FeeModify: sdk.NewDecCoinFromDec(common.NativeToken, sdk.MustNewDecFromStr(DefaultFeeModify)), + FeeChown: sdk.NewDecCoinFromDec(common.NativeToken, sdk.MustNewDecFromStr(DefaultFeeChown)), + OwnershipConfirmWindow: DefaultOwnershipConfirmWindow, } } @@ -74,6 +79,6 @@ func (p Params) String() string { sb.WriteString(fmt.Sprintf("FeeBurn: %s\n", p.FeeBurn)) sb.WriteString(fmt.Sprintf("FeeModify: %s\n", p.FeeModify)) sb.WriteString(fmt.Sprintf("FeeChown: %s\n", p.FeeChown)) - + sb.WriteString(fmt.Sprintf("OwnershipConfirmWindow: %s\n", p.OwnershipConfirmWindow)) return sb.String() } diff --git a/x/token/types/params_test.go b/x/token/types/params_test.go index d6929dce0a..ca33be2137 100644 --- a/x/token/types/params_test.go +++ b/x/token/types/params_test.go @@ -17,7 +17,9 @@ FeeMint: 10.00000000` + common.NativeToken + ` FeeBurn: 10.00000000` + common.NativeToken + ` FeeModify: 0.00000000` + common.NativeToken + ` FeeChown: 10.00000000` + common.NativeToken + ` +OwnershipConfirmWindow: 24h0m0s ` + paramStr := param.String() require.EqualValues(t, expectedString, paramStr) @@ -27,6 +29,7 @@ FeeChown: 10.00000000` + common.NativeToken + ` {Key: KeyFeeBurn, Value: ¶m.FeeBurn}, {Key: KeyFeeModify, Value: ¶m.FeeModify}, {Key: KeyFeeChown, Value: ¶m.FeeChown}, + {Key: KeyOwnershipConfirmWindow, Value: ¶m.OwnershipConfirmWindow}, } require.EqualValues(t, psp, param.ParamSetPairs()) diff --git a/x/token/types/util.go b/x/token/types/util.go index 944b7c187c..c870f19a43 100644 --- a/x/token/types/util.go +++ b/x/token/types/util.go @@ -68,11 +68,12 @@ func (acc DecAccount) String() string { ) } +func NotAllowedOriginSymbol(name string) bool { + return notAllowedOriginSymbol.MatchString(name) +} + func ValidOriginalSymbol(name string) bool { - if notAllowedOriginSymbol.MatchString(name) { - return false - } - return regOriginalSymbol.MatchString(name) + return !NotAllowedOriginSymbol(name) && regOriginalSymbol.MatchString(name) } // Convert a formatted json string into a TransferUnit array diff --git a/x/token/types/util_test.go b/x/token/types/util_test.go index ae9a701f8f..969dffd716 100644 --- a/x/token/types/util_test.go +++ b/x/token/types/util_test.go @@ -160,16 +160,22 @@ func TestValidateDenom(t *testing.T) { name := "abc" require.Nil(t, sdk.ValidateDenom(name)) - name = notAllowedPrefix + "-abc" + name = "abc-123" require.Nil(t, sdk.ValidateDenom(name)) - name = notAllowedPrefix + "-abc-1af" - require.Nil(t, sdk.ValidateDenom(name)) + name = "abc-ts3" + require.NotNil(t, sdk.ValidateDenom(name)) + + name = notAllowedPrefix + "_abc" + require.NotNil(t, sdk.ValidateDenom(name)) + + name = notAllowedPrefix + "_abc-1af" + require.NotNil(t, sdk.ValidateDenom(name)) - name = notAllowedPrefix + "-abcde-aaa" + name = notAllowedPrefix + "_abcde-aaa_abtc-e12" require.Nil(t, sdk.ValidateDenom(name)) - name = notAllowedPrefix + "f-abcde-aaa" + name = notAllowedPrefix + "_f-abcde-aaa" require.NotNil(t, sdk.ValidateDenom(name)) name = "pool-abcde-aaa" @@ -180,4 +186,16 @@ func TestValidateDenom(t *testing.T) { name = "pool-abc" require.Nil(t, sdk.ValidateDenom(name)) + + name = notAllowedPrefix + "_abc" + require.NotNil(t, sdk.ValidateDenom(name)) + + name = notAllowedPrefix + "_abc" + "-bcd" + require.NotNil(t, sdk.ValidateDenom(name)) + + name = notAllowedPrefix + "_abc" + "_bcd-1234" + require.NotNil(t, sdk.ValidateDenom(name)) + + name = notAllowedPrefix + "_abc-123" + "_bcd" + require.Nil(t, sdk.ValidateDenom(name)) } \ No newline at end of file