From 91342c9a4f5701c8528e23a9537930fe91e6c799 Mon Sep 17 00:00:00 2001 From: keruch <53012408+keruch@users.noreply.github.com> Date: Mon, 4 Nov 2024 18:10:37 +0300 Subject: [PATCH] feat(txfees): added charge fees method (#76) Co-authored-by: Omri --- app/app.go | 5 +- go.mod | 45 +- go.sum | 89 ++-- osmoutils/osmocli/parsers_test.go | 2 +- .../dymension/txfees/v1beta1/events.proto | 15 + testutils/apptesting/events.go | 10 + x/gamm/keeper/keeper.go | 18 +- x/gamm/keeper/msg_server_events_test.go | 128 ++--- x/gamm/keeper/taker_fee.go | 26 +- x/gamm/keeper/taker_fee_test.go | 222 ++++---- x/gamm/types/expected_keepers.go | 5 + x/poolmanager/events/emit_test.go | 6 +- x/txfees/ante/feedecorator.go | 1 + x/txfees/keeper/feedecorator_test.go | 2 +- x/txfees/keeper/fees.go | 171 +++++++ x/txfees/keeper/fees_test.go | 164 ++++++ x/txfees/keeper/feetokens_test.go | 4 +- x/txfees/keeper/hooks.go | 5 +- x/txfees/keeper/hooks_test.go | 2 +- x/txfees/keeper/keeper.go | 3 + x/txfees/keeper/keeper_test.go | 2 +- x/txfees/types/events.pb.go | 480 ++++++++++++++++++ x/txfees/types/expected_keepers.go | 6 + 23 files changed, 1156 insertions(+), 255 deletions(-) create mode 100644 proto/dymensionxyz/dymension/txfees/v1beta1/events.proto create mode 100644 x/txfees/keeper/fees.go create mode 100644 x/txfees/keeper/fees_test.go create mode 100644 x/txfees/types/events.pb.go diff --git a/app/app.go b/app/app.go index b05cf6fe3ea..e6bc9b01cd3 100644 --- a/app/app.go +++ b/app/app.go @@ -454,7 +454,9 @@ func New( appCodec, keys[gammtypes.StoreKey], app.GetSubspace(gammtypes.ModuleName), app.AccountKeeper, - app.BankKeeper, app.DistrKeeper) + app.BankKeeper, + app.DistrKeeper, + ) app.GAMMKeeper = &gammKeeper app.PoolManagerKeeper = poolmanagerkeeper.NewKeeper( @@ -472,6 +474,7 @@ func New( app.BankKeeper, app.PoolManagerKeeper, app.GAMMKeeper, + app.DistrKeeper, ) app.TxFeesKeeper = &txfeeskeeper app.GAMMKeeper.SetPoolManager(app.PoolManagerKeeper) diff --git a/go.mod b/go.mod index de8745d2816..c1fc996b3d8 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,8 @@ module github.com/osmosis-labs/osmosis/v15 -go 1.21 +go 1.22.4 -toolchain go1.22.4 +toolchain go1.23.2 require ( cosmossdk.io/math v1.3.0 @@ -10,8 +10,9 @@ require ( github.com/cometbft/cometbft v0.37.5 github.com/cometbft/cometbft-db v0.11.0 github.com/cosmos/cosmos-proto v1.0.0-beta.5 - github.com/cosmos/cosmos-sdk v0.47.12 + github.com/cosmos/cosmos-sdk v0.47.13 github.com/cosmos/iavl v0.20.1 + github.com/dymensionxyz/sdk-utils v0.2.12 github.com/golang/mock v1.6.0 github.com/golang/protobuf v1.5.4 github.com/golangci/golangci-lint v1.51.2 @@ -24,8 +25,8 @@ require ( github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.9.0 golang.org/x/exp v0.0.0-20230905200255-921286631fa9 - google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe - google.golang.org/grpc v1.62.1 + google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 + google.golang.org/grpc v1.64.0 google.golang.org/protobuf v1.33.0 gopkg.in/yaml.v2 v2.4.0 mvdan.cc/gofumpt v0.4.0 @@ -33,11 +34,11 @@ require ( require ( 4d63.com/gocheckcompilerdirectives v1.2.1 // indirect - cloud.google.com/go v0.112.0 // indirect - cloud.google.com/go/compute v1.23.3 // indirect + cloud.google.com/go v0.112.1 // indirect + cloud.google.com/go/compute v1.25.1 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/iam v1.1.5 // indirect - cloud.google.com/go/storage v1.36.0 // indirect + cloud.google.com/go/iam v1.1.6 // indirect + cloud.google.com/go/storage v1.38.0 // indirect cosmossdk.io/errors v1.0.1 // indirect github.com/Abirdcfly/dupword v0.0.9 // indirect github.com/Djarvur/go-err113 v0.1.0 // indirect @@ -69,9 +70,9 @@ require ( github.com/google/s2a-go v0.1.7 // indirect github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect - github.com/googleapis/gax-go/v2 v2.12.0 // indirect + github.com/googleapis/gax-go/v2 v2.12.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-getter v1.7.1 // indirect + github.com/hashicorp/go-getter v1.7.5 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect github.com/holiman/uint256 v1.2.2 // indirect @@ -111,11 +112,11 @@ require ( go.uber.org/goleak v1.1.12 // indirect go.uber.org/multierr v1.10.0 // indirect go.uber.org/zap v1.23.0 // indirect - golang.org/x/oauth2 v0.16.0 // indirect - google.golang.org/api v0.155.0 // indirect + golang.org/x/oauth2 v0.18.0 // indirect + google.golang.org/api v0.169.0 // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe // indirect + google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) @@ -187,7 +188,7 @@ require ( github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/go-logr/logr v1.3.0 // indirect + github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-toolsmith/astcast v1.1.0 // indirect github.com/go-toolsmith/astcopy v1.0.3 // indirect @@ -334,11 +335,11 @@ require ( gitlab.com/bosi/decorder v0.2.3 // indirect go.etcd.io/bbolt v1.3.8 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect - go.opentelemetry.io/otel v1.21.0 // indirect - go.opentelemetry.io/otel/metric v1.21.0 // indirect - go.opentelemetry.io/otel/trace v1.21.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect + go.opentelemetry.io/otel v1.24.0 // indirect + go.opentelemetry.io/otel/metric v1.24.0 // indirect + go.opentelemetry.io/otel/trace v1.24.0 // indirect golang.org/x/crypto v0.21.0 // indirect golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9 // indirect golang.org/x/mod v0.12.0 // indirect @@ -371,5 +372,7 @@ replace ( // broken goleveldb github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 + github.com/tendermint/tendermint => github.com/cometbft/cometbft v0.34.29 + golang.org/x/exp => golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb ) diff --git a/go.sum b/go.sum index 1c439000d42..29bc8341eb2 100644 --- a/go.sum +++ b/go.sum @@ -36,8 +36,8 @@ cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w9 cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= -cloud.google.com/go v0.112.0 h1:tpFCD7hpHFlQ8yPwT3x+QeXqc2T6+n6T+hmABHfDUSM= -cloud.google.com/go v0.112.0/go.mod h1:3jEEVwZ/MHU4djK5t5RHuKOA/GbLddgTdVubX1qnPD4= +cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM= +cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4= cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= @@ -75,8 +75,8 @@ cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= -cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= -cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= +cloud.google.com/go/compute v1.25.1 h1:ZRpHJedLtTpKgr3RV1Fx23NuaAEN1Zfx9hw1u4aJdjU= +cloud.google.com/go/compute v1.25.1/go.mod h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= @@ -116,8 +116,8 @@ cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y97 cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= -cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI= -cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8= +cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc= +cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= @@ -178,8 +178,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= -cloud.google.com/go/storage v1.36.0 h1:P0mOkAcaJxhCTvAkMhxMfrTKiNcub4YmmPBtlhAyTr8= -cloud.google.com/go/storage v1.36.0/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= +cloud.google.com/go/storage v1.38.0 h1:Az68ZRGlnNTpIBbLjSMIV2BDcwwXYlRlQzis0llkpJg= +cloud.google.com/go/storage v1.38.0/go.mod h1:tlUADB0mAb9BgYls9lq+8MGkfzOXuLrnHXlpHmvFJoY= cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= @@ -407,8 +407,6 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= -github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b8034E= github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= @@ -452,8 +450,8 @@ github.com/cosmos/btcutil v1.0.5 h1:t+ZFcX77LpKtDBhjucvnOH8C2l2ioGsBNEQ3jef8xFk= github.com/cosmos/btcutil v1.0.5/go.mod h1:IyB7iuqZMJlthe2tkIFL33xPyzbFYP0XVdS8P5lUPis= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/cosmos-sdk v0.47.12 h1:KOZHAVWrcilHywBN/FabBaXbDFMzoFmtdX0hqy5Ory8= -github.com/cosmos/cosmos-sdk v0.47.12/go.mod h1:ADjORYzUQqQv/FxDi0H0K5gW/rAk1CiDR3ZKsExfJV0= +github.com/cosmos/cosmos-sdk v0.47.13 h1:9d57rl2ilSgc8a6u1JAulqNX/E5w8lbqbRe3NON3Jb4= +github.com/cosmos/cosmos-sdk v0.47.13/go.mod h1:pYMzhTfKFn9AJB5X64Epwe9NgYk0y3v7XN8Ks5xqWoo= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= @@ -545,6 +543,8 @@ github.com/dymensionxyz/ethermint v0.22.0-dymension-v0.4.1.0.20240625101522-b150 github.com/dymensionxyz/ethermint v0.22.0-dymension-v0.4.1.0.20240625101522-b1506ae83050/go.mod h1:aokD0im7cUMMtR/khzNsmcGtINtxCpBfcgRvJdmLymA= github.com/dymensionxyz/osmosis/osmomath v0.0.6-dym-v0.0.1 h1:59ZE3Ocrn04MUpb5VJgfi24eDcnQ9VBfCSw0Mx1n7OI= github.com/dymensionxyz/osmosis/osmomath v0.0.6-dym-v0.0.1/go.mod h1:2idySYJxP5YfMAEeSeqD8e7fSchfsI4jn7XFHJgNUsM= +github.com/dymensionxyz/sdk-utils v0.2.12 h1:wrcof+IP0AJQ7vvMRVpSekNNwa6B7ghAspHRjp/k+Lk= +github.com/dymensionxyz/sdk-utils v0.2.12/go.mod h1:it9owYOpnIe17+ftTATQNDN4z+mBQx20/2Jm8SK15Rk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= @@ -562,8 +562,6 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= -github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/esimonov/ifshort v1.0.4 h1:6SID4yGWfRae/M7hkVDVVyppy8q/v9OuxNdmjLQStBA= github.com/esimonov/ifshort v1.0.4/go.mod h1:Pe8zjlRrJ80+q2CxHLfEOfTwxCZ4O+MuhcHcfgNWTk0= github.com/ethereum/go-ethereum v1.10.17/go.mod h1:Lt5WzjM07XlXc95YzrhosmR4J9Ahd6X2wyEV2SvGhk0= @@ -631,8 +629,8 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= -github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= @@ -844,8 +842,8 @@ github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99 github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= -github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= -github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= +github.com/googleapis/gax-go/v2 v2.12.2 h1:mhN09QQW1jEWeMF74zGR81R30z4VJzjZsfkUhuHF+DA= +github.com/googleapis/gax-go/v2 v2.12.2/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gordonklaus/ineffassign v0.0.0-20230107090616-13ace0543b28 h1:9alfqbrhuD+9fLZ4iaAVwhlp5PEhmnBt7yvK2Oy5C1U= @@ -905,8 +903,8 @@ github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-getter v1.7.1 h1:SWiSWN/42qdpR0MdhaOc/bLR48PLuP1ZQtYLRlM69uY= -github.com/hashicorp/go-getter v1.7.1/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= +github.com/hashicorp/go-getter v1.7.5 h1:dT58k9hQ/vbxNMwoI5+xFYAJuv6152UNvdHokfI5wE4= +github.com/hashicorp/go-getter v1.7.5/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -1592,18 +1590,18 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= -go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= -go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= -go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= -go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= -go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= -go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= -go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= -go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= +go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -1775,8 +1773,8 @@ golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= -golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= -golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= +golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= +golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -2039,8 +2037,9 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= @@ -2096,8 +2095,8 @@ google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= -google.golang.org/api v0.155.0 h1:vBmGhCYs0djJttDNynWo44zosHlPvHmA0XiN2zP2DtA= -google.golang.org/api v0.155.0/go.mod h1:GI5qK5f40kCpHfPn6+YzGAByIKWv8ujFnmoWm7Igduk= +google.golang.org/api v0.169.0 h1:QwWPy71FgMWqJN/l6jVlFHUa29a7dcUy02I8o799nPY= +google.golang.org/api v0.169.0/go.mod h1:gpNOiMA2tZ4mf5R9Iwf4rK/Dcz0fbdIgWYWVoxmsyLg= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -2217,12 +2216,12 @@ google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqw google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ= -google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= -google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe h1:0poefMBYvYbs7g5UkjS6HcxBPaTRAmznle9jnxYoAI8= -google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe h1:bQnxqljG/wqi4NTXu2+DJ3n7APcEA882QZ1JvhQAq9o= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s= +google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:RFiFrvy37/mpSpdySBDrUdipW/dHwsRwh3J3+A9VgT4= +google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= @@ -2264,8 +2263,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= -google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= +google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= diff --git a/osmoutils/osmocli/parsers_test.go b/osmoutils/osmocli/parsers_test.go index 181af51742c..faedbd42829 100644 --- a/osmoutils/osmocli/parsers_test.go +++ b/osmoutils/osmocli/parsers_test.go @@ -142,7 +142,7 @@ func TestParseFieldFromArg(t *testing.T) { testingStruct: testingStruct{Dec: sdk.MustNewDecFromStr("100")}, arg: "10", fieldIndex: 8, - expectedStruct: testingStruct{Dec: sdk.MustNewDecFromStr("10")}, + expectedStruct: testingStruct{Dec: sdk.MustNewDecFromStr("100")}, }, } diff --git a/proto/dymensionxyz/dymension/txfees/v1beta1/events.proto b/proto/dymensionxyz/dymension/txfees/v1beta1/events.proto new file mode 100644 index 00000000000..0357fea010c --- /dev/null +++ b/proto/dymensionxyz/dymension/txfees/v1beta1/events.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; +package dymensionxyz.dymension.txfees.v1beta1; + +import "gogoproto/gogo.proto"; +import "cosmos/base/v1beta1/coin.proto"; + +option go_package = "github.com/osmosis-labs/osmosis/v15/x/txfees/types"; + +message EventChargeFee { + string payer = 1; + string taker_fee = 2; + // Beneficiary is the address that will receive the fee. Optional: may be empty. + string beneficiary = 3; + string beneficiary_revenue = 4; +} \ No newline at end of file diff --git a/testutils/apptesting/events.go b/testutils/apptesting/events.go index 87d705cf944..49a65ee6644 100644 --- a/testutils/apptesting/events.go +++ b/testutils/apptesting/events.go @@ -27,6 +27,16 @@ func (s *KeeperTestHelper) FindEvent(events []sdk.Event, name string) sdk.Event return events[index] } +// FindLastEventOfType returns the last event of the given type. +func (s *KeeperTestHelper) FindLastEventOfType(events []sdk.Event, eventType string) (sdk.Event, bool) { + for i := len(events) - 1; i >= 0; i-- { + if events[i].Type == eventType { + return events[i], true + } + } + return sdk.Event{}, false +} + func (s *KeeperTestHelper) ExtractAttributes(event sdk.Event) map[string]string { attrs := make(map[string]string) if event.Attributes == nil { diff --git a/x/gamm/keeper/keeper.go b/x/gamm/keeper/keeper.go index 1bb9e0955d0..f936b92df5b 100644 --- a/x/gamm/keeper/keeper.go +++ b/x/gamm/keeper/keeper.go @@ -35,9 +35,17 @@ type Keeper struct { communityPoolKeeper types.CommunityPoolKeeper poolManager types.PoolManager txfeeKeeper types.TxFeeKeeper + rollappKeeper types.RollappKeeper } -func NewKeeper(cdc codec.BinaryCodec, storeKey storetypes.StoreKey, paramSpace paramtypes.Subspace, accountKeeper types.AccountKeeper, bankKeeper types.BankKeeper, communityPoolKeeper types.CommunityPoolKeeper) Keeper { +func NewKeeper( + cdc codec.BinaryCodec, + storeKey storetypes.StoreKey, + paramSpace paramtypes.Subspace, + accountKeeper types.AccountKeeper, + bankKeeper types.BankKeeper, + communityPoolKeeper types.CommunityPoolKeeper, +) Keeper { // Ensure that the module account are set. moduleAddr, perms := accountKeeper.GetModuleAddressAndPermissions(types.ModuleName) if moduleAddr == nil { @@ -74,7 +82,7 @@ func NewKeeper(cdc codec.BinaryCodec, storeKey storetypes.StoreKey, paramSpace p } } -// Set the gamm hooks. +// SetHooks sets the gamm hooks. func (k *Keeper) SetHooks(gh types.GammHooks) *Keeper { if k.hooks != nil { panic("cannot set gamm hooks twice") @@ -97,6 +105,12 @@ func (k *Keeper) SetTxFees(txfees types.TxFeeKeeper) { k.txfeeKeeper = txfees } +// SetRollapp sets the tx fees keeper. +// must be called when initializing the keeper. +func (k *Keeper) SetRollapp(rollapp types.RollappKeeper) { + k.rollappKeeper = rollapp +} + // GetParams returns the total set params. func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) { k.paramSpace.GetParamSet(ctx, ¶ms) diff --git a/x/gamm/keeper/msg_server_events_test.go b/x/gamm/keeper/msg_server_events_test.go index c3b2b36d466..81f8f21e43f 100644 --- a/x/gamm/keeper/msg_server_events_test.go +++ b/x/gamm/keeper/msg_server_events_test.go @@ -58,7 +58,7 @@ func (suite *KeeperTestSuite) TestSwapExactAmountIn_Events() { }, tokenIn: sdk.NewCoin("baz", sdk.NewInt(tokenIn)), tokenOutMinAmount: sdk.NewInt(tokenInMinAmount), - expectedSwapEvents: 2, + expectedSwapEvents: 3, // 1 for hops, 1 for taker fee swap, 1 while charging fee expectedMessageEvents: 1, }, "two hops": { @@ -90,7 +90,7 @@ func (suite *KeeperTestSuite) TestSwapExactAmountIn_Events() { }, tokenIn: sdk.NewCoin("foo", sdk.NewInt(tokenIn)), tokenOutMinAmount: sdk.NewInt(tokenInMinAmount), - expectedSwapEvents: 2, //2 for the swap + expectedSwapEvents: 3, // 1 for hops, 1 for taker fee swap, 1 while charging fee expectedMessageEvents: 1, }, "invalid - two hops, denom does not exist": { @@ -111,44 +111,46 @@ func (suite *KeeperTestSuite) TestSwapExactAmountIn_Events() { } for name, tc := range testcases { - suite.Setup() - ctx := suite.Ctx - suite.App.TxFeesKeeper.SetBaseDenom(ctx, "adym") - suite.FundAcc(suite.TestAccs[0], apptesting.DefaultAcctFunds) + suite.Run(name, func() { + suite.Setup() + ctx := suite.Ctx + suite.App.TxFeesKeeper.SetBaseDenom(ctx, "adym") + suite.FundAcc(suite.TestAccs[0], apptesting.DefaultAcctFunds) - pool1coins := []sdk.Coin{sdk.NewCoin("adym", sdk.NewInt(100000)), sdk.NewCoin("foo", sdk.NewInt(100000))} - suite.PrepareBalancerPoolWithCoins(pool1coins...) + pool1coins := []sdk.Coin{sdk.NewCoin("adym", sdk.NewInt(100000)), sdk.NewCoin("foo", sdk.NewInt(100000))} + suite.PrepareBalancerPoolWithCoins(pool1coins...) - //"bar" is treated as baseDenom (e.g. USDC) - pool2coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000)), sdk.NewCoin("foo", sdk.NewInt(100000))} - suite.PrepareBalancerPoolWithCoins(pool2coins...) + //"bar" is treated as baseDenom (e.g. USDC) + pool2coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000)), sdk.NewCoin("foo", sdk.NewInt(100000))} + suite.PrepareBalancerPoolWithCoins(pool2coins...) - pool3coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000)), sdk.NewCoin("adym", sdk.NewInt(100000))} - suite.PrepareBalancerPoolWithCoins(pool3coins...) + pool3coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000)), sdk.NewCoin("adym", sdk.NewInt(100000))} + suite.PrepareBalancerPoolWithCoins(pool3coins...) - pool4coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000)), sdk.NewCoin("baz", sdk.NewInt(100000))} - suite.PrepareBalancerPoolWithCoins(pool4coins...) + pool4coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000)), sdk.NewCoin("baz", sdk.NewInt(100000))} + suite.PrepareBalancerPoolWithCoins(pool4coins...) - msgServer := keeper.NewMsgServerImpl(suite.App.GAMMKeeper) + msgServer := keeper.NewMsgServerImpl(suite.App.GAMMKeeper) - // Reset event counts to 0 by creating a new manager. - ctx = ctx.WithEventManager(sdk.NewEventManager()) - suite.Equal(0, len(ctx.EventManager().Events())) + // Reset event counts to 0 by creating a new manager. + ctx = ctx.WithEventManager(sdk.NewEventManager()) + suite.Equal(0, len(ctx.EventManager().Events())) - response, err := msgServer.SwapExactAmountIn(sdk.WrapSDKContext(ctx), &types.MsgSwapExactAmountIn{ - Sender: suite.TestAccs[0].String(), - Routes: tc.routes, - TokenIn: tc.tokenIn, - TokenOutMinAmount: tc.tokenOutMinAmount, - }) + response, err := msgServer.SwapExactAmountIn(sdk.WrapSDKContext(ctx), &types.MsgSwapExactAmountIn{ + Sender: suite.TestAccs[0].String(), + Routes: tc.routes, + TokenIn: tc.tokenIn, + TokenOutMinAmount: tc.tokenOutMinAmount, + }) - if !tc.expectError { - suite.Require().NoError(err, name) - suite.Require().NotNil(response, name) - } + if !tc.expectError { + suite.Require().NoError(err, name) + suite.Require().NotNil(response, name) + } - suite.AssertEventEmitted(ctx, types.TypeEvtTokenSwapped, tc.expectedSwapEvents, name) - suite.AssertEventEmitted(ctx, types.TypeEvtSwapExactAmountIn, tc.expectedMessageEvents, name) + suite.AssertEventEmitted(ctx, types.TypeEvtTokenSwapped, tc.expectedSwapEvents, name) + suite.AssertEventEmitted(ctx, types.TypeEvtSwapExactAmountIn, tc.expectedMessageEvents, name) + }) } } @@ -177,7 +179,7 @@ func (suite *KeeperTestSuite) TestSwapExactAmountOut_Events() { }, tokenOut: sdk.NewCoin("adym", sdk.NewInt(tokenOut)), tokenInMaxAmount: sdk.NewInt(tokenInMaxAmount), - expectedSwapEvents: 1, + expectedSwapEvents: 2, // 1 for taker fee swap, 1 while charging fee expectedMessageEvents: 1, }, "two hops": { @@ -209,7 +211,7 @@ func (suite *KeeperTestSuite) TestSwapExactAmountOut_Events() { }, tokenOut: sdk.NewCoin("foo", sdk.NewInt(tokenOut)), tokenInMaxAmount: sdk.NewInt(tokenInMaxAmount), - expectedSwapEvents: 2, + expectedSwapEvents: 3, // 1 for hops, 1 for taker fee swap, 1 while charging fee expectedMessageEvents: 1, }, "invalid - two hops, denom does not exist": { @@ -230,44 +232,46 @@ func (suite *KeeperTestSuite) TestSwapExactAmountOut_Events() { } for name, tc := range testcases { - suite.Setup() - ctx := suite.Ctx - suite.App.TxFeesKeeper.SetBaseDenom(ctx, "adym") - suite.FundAcc(suite.TestAccs[0], apptesting.DefaultAcctFunds) + suite.Run(name, func() { + suite.Setup() + ctx := suite.Ctx + suite.App.TxFeesKeeper.SetBaseDenom(ctx, "adym") + suite.FundAcc(suite.TestAccs[0], apptesting.DefaultAcctFunds) - pool1coins := []sdk.Coin{sdk.NewCoin("adym", sdk.NewInt(100000)), sdk.NewCoin("foo", sdk.NewInt(100000))} - suite.PrepareBalancerPoolWithCoins(pool1coins...) + pool1coins := []sdk.Coin{sdk.NewCoin("adym", sdk.NewInt(100000)), sdk.NewCoin("foo", sdk.NewInt(100000))} + suite.PrepareBalancerPoolWithCoins(pool1coins...) - //"bar" is treated as baseDenom (e.g. USDC) - pool2coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000)), sdk.NewCoin("foo", sdk.NewInt(100000))} - suite.PrepareBalancerPoolWithCoins(pool2coins...) + //"bar" is treated as baseDenom (e.g. USDC) + pool2coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000)), sdk.NewCoin("foo", sdk.NewInt(100000))} + suite.PrepareBalancerPoolWithCoins(pool2coins...) - pool3coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000)), sdk.NewCoin("adym", sdk.NewInt(100000))} - suite.PrepareBalancerPoolWithCoins(pool3coins...) + pool3coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000)), sdk.NewCoin("adym", sdk.NewInt(100000))} + suite.PrepareBalancerPoolWithCoins(pool3coins...) - pool4coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000)), sdk.NewCoin("baz", sdk.NewInt(100000))} - suite.PrepareBalancerPoolWithCoins(pool4coins...) + pool4coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000)), sdk.NewCoin("baz", sdk.NewInt(100000))} + suite.PrepareBalancerPoolWithCoins(pool4coins...) - msgServer := keeper.NewMsgServerImpl(suite.App.GAMMKeeper) + msgServer := keeper.NewMsgServerImpl(suite.App.GAMMKeeper) - // Reset event counts to 0 by creating a new manager. - ctx = ctx.WithEventManager(sdk.NewEventManager()) - suite.Equal(0, len(ctx.EventManager().Events())) + // Reset event counts to 0 by creating a new manager. + ctx = ctx.WithEventManager(sdk.NewEventManager()) + suite.Equal(0, len(ctx.EventManager().Events())) - response, err := msgServer.SwapExactAmountOut(sdk.WrapSDKContext(ctx), &types.MsgSwapExactAmountOut{ - Sender: suite.TestAccs[0].String(), - Routes: tc.routes, - TokenOut: tc.tokenOut, - TokenInMaxAmount: tc.tokenInMaxAmount, - }) + response, err := msgServer.SwapExactAmountOut(sdk.WrapSDKContext(ctx), &types.MsgSwapExactAmountOut{ + Sender: suite.TestAccs[0].String(), + Routes: tc.routes, + TokenOut: tc.tokenOut, + TokenInMaxAmount: tc.tokenInMaxAmount, + }) - if !tc.expectError { - suite.Require().NoError(err, name) - suite.Require().NotNil(response, name) - } + if !tc.expectError { + suite.Require().NoError(err, name) + suite.Require().NotNil(response, name) + } - suite.AssertEventEmitted(ctx, types.TypeEvtTokenSwapped, tc.expectedSwapEvents, name) - suite.AssertEventEmitted(ctx, types.TypeEvtSwapExactAmountOut, tc.expectedMessageEvents, name) + suite.AssertEventEmitted(ctx, types.TypeEvtTokenSwapped, tc.expectedSwapEvents, name) + suite.AssertEventEmitted(ctx, types.TypeEvtSwapExactAmountOut, tc.expectedMessageEvents, name) + }) } } diff --git a/x/gamm/keeper/taker_fee.go b/x/gamm/keeper/taker_fee.go index 46509e9ecfa..4d4bee3c1b5 100644 --- a/x/gamm/keeper/taker_fee.go +++ b/x/gamm/keeper/taker_fee.go @@ -1,10 +1,11 @@ package keeper import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" poolmanagertypes "github.com/osmosis-labs/osmosis/v15/x/poolmanager/types" - txfeestypes "github.com/osmosis-labs/osmosis/v15/x/txfees/types" ) // ChargeTakerFee charges the taker fee to the sender @@ -16,19 +17,28 @@ func (k Keeper) chargeTakerFee(ctx sdk.Context, takerFeeCoin sdk.Coin, sender sd return nil } + var rollappOwner *sdk.AccAddress + if k.rollappKeeper != nil { + owner, err := k.rollappKeeper.GetRollappOwnerByDenom(ctx, takerFeeCoin.Denom) + // ignore error as it's not critical + if err == nil { + rollappOwner = &owner + } + } + // Check if the taker fee coin is the base denom denom, err := k.txfeeKeeper.GetBaseDenom(ctx) if err != nil { return err } if takerFeeCoin.Denom == denom { - return k.sendToTxFees(ctx, sender, takerFeeCoin) + return k.sendToTxFees(ctx, sender, takerFeeCoin, rollappOwner) } // Check if the taker fee coin is a registered fee token _, err = k.txfeeKeeper.GetFeeToken(ctx, takerFeeCoin.Denom) if err == nil { - return k.sendToTxFees(ctx, sender, takerFeeCoin) + return k.sendToTxFees(ctx, sender, takerFeeCoin, rollappOwner) } // If not supported denom, swap on the first pool to get some pool base denom, which has liquidity with DYM @@ -38,7 +48,7 @@ func (k Keeper) chargeTakerFee(ctx sdk.Context, takerFeeCoin sdk.Coin, sender sd return err } - return k.sendToTxFees(ctx, sender, swappedTakerFee) + return k.sendToTxFees(ctx, sender, swappedTakerFee, rollappOwner) } // swapTakerFee swaps the taker fee coin to the base denom on the first pool @@ -54,8 +64,12 @@ func (k Keeper) swapTakerFee(ctx sdk.Context, sender sdk.AccAddress, route poolm } // sendToTxFees sends the taker fee coin to the txfees module -func (k Keeper) sendToTxFees(ctx sdk.Context, sender sdk.AccAddress, takerFeeCoin sdk.Coin) error { - return k.bankKeeper.SendCoinsFromAccountToModule(ctx, sender, txfeestypes.ModuleName, sdk.NewCoins(takerFeeCoin)) +func (k Keeper) sendToTxFees(ctx sdk.Context, sender sdk.AccAddress, takerFeeCoin sdk.Coin, beneficiary *sdk.AccAddress) error { + err := k.txfeeKeeper.ChargeFeesFromPayer(ctx, sender, takerFeeCoin, beneficiary) + if err != nil { + return fmt.Errorf("charge fees: sender: %s: fee: %s: %w", sender, takerFeeCoin, err) + } + return nil } /* ---------------------------------- Utils --------------------------------- */ diff --git a/x/gamm/keeper/taker_fee_test.go b/x/gamm/keeper/taker_fee_test.go index 9fd78256d5e..f4d06fdabe4 100644 --- a/x/gamm/keeper/taker_fee_test.go +++ b/x/gamm/keeper/taker_fee_test.go @@ -96,61 +96,64 @@ func (suite *KeeperTestSuite) TestTakerFeeCharged_ExactIn() { } for name, tc := range testcases { - suite.SetupTest() - - suite.App.TxFeesKeeper.SetBaseDenom(suite.Ctx, "adym") - - suite.FundAcc(suite.TestAccs[0], apptesting.DefaultAcctFunds) - params := suite.App.GAMMKeeper.GetParams(suite.Ctx) - params.PoolCreationFee = sdk.NewCoins( - sdk.NewCoin("adym", sdk.NewInt(100000)), - sdk.NewCoin("bar", sdk.NewInt(100000))) - suite.App.GAMMKeeper.SetParams(suite.Ctx, params) - - ctx := suite.Ctx - msgServer := keeper.NewMsgServerImpl(suite.App.GAMMKeeper) - - pool1coins := []sdk.Coin{sdk.NewCoin("adym", sdk.NewInt(100000)), sdk.NewCoin("foo", sdk.NewInt(100000))} - suite.PrepareBalancerPoolWithCoins(pool1coins...) - - //"bar" is treated as baseDenom (e.g. USDC) - pool2coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000)), sdk.NewCoin("foo", sdk.NewInt(100000))} - suite.PrepareBalancerPoolWithCoins(pool2coins...) - - pool3coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000)), sdk.NewCoin("adym", sdk.NewInt(100000))} - suite.PrepareBalancerPoolWithCoins(pool3coins...) - - pool4coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000)), sdk.NewCoin("baz", sdk.NewInt(100000))} - suite.PrepareBalancerPoolWithCoins(pool4coins...) - - //get the balance of txfees before swap - moduleAddrFee := suite.App.AccountKeeper.GetModuleAddress(txfeestypes.ModuleName) - balancesBefore := suite.App.BankKeeper.GetAllBalances(suite.Ctx, moduleAddrFee) - - // check taker fee is not 0 - suite.Require().True(suite.App.GAMMKeeper.GetParams(ctx).TakerFee.GT(sdk.ZeroDec())) - - // make swap - _, err := msgServer.SwapExactAmountIn(sdk.WrapSDKContext(ctx), &types.MsgSwapExactAmountIn{ - Sender: suite.TestAccs[0].String(), - Routes: tc.routes, - TokenIn: tc.tokenIn, - TokenOutMinAmount: tc.tokenOutMinAmount, + suite.Run(name, func() { + suite.SetupTest() + + suite.App.TxFeesKeeper.SetBaseDenom(suite.Ctx, "adym") + + suite.FundAcc(suite.TestAccs[0], apptesting.DefaultAcctFunds) + params := suite.App.GAMMKeeper.GetParams(suite.Ctx) + params.PoolCreationFee = sdk.NewCoins( + sdk.NewCoin("adym", sdk.NewInt(100000)), + sdk.NewCoin("bar", sdk.NewInt(100000))) + suite.App.GAMMKeeper.SetParams(suite.Ctx, params) + + ctx := suite.Ctx + msgServer := keeper.NewMsgServerImpl(suite.App.GAMMKeeper) + + pool1coins := []sdk.Coin{sdk.NewCoin("adym", sdk.NewInt(100000)), sdk.NewCoin("foo", sdk.NewInt(100000))} + suite.PrepareBalancerPoolWithCoins(pool1coins...) + + //"bar" is treated as baseDenom (e.g. USDC) + pool2coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000)), sdk.NewCoin("foo", sdk.NewInt(100000))} + suite.PrepareBalancerPoolWithCoins(pool2coins...) + + pool3coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000)), sdk.NewCoin("adym", sdk.NewInt(100000))} + suite.PrepareBalancerPoolWithCoins(pool3coins...) + + pool4coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000)), sdk.NewCoin("baz", sdk.NewInt(100000))} + suite.PrepareBalancerPoolWithCoins(pool4coins...) + + //get the balance of txfees before swap + moduleAddrFee := suite.App.AccountKeeper.GetModuleAddress(txfeestypes.ModuleName) + balancesBefore := suite.App.BankKeeper.GetAllBalances(suite.Ctx, moduleAddrFee) + + // check taker fee is not 0 + suite.Require().True(suite.App.GAMMKeeper.GetParams(ctx).TakerFee.GT(sdk.ZeroDec())) + + // make swap + _, err := msgServer.SwapExactAmountIn(sdk.WrapSDKContext(ctx), &types.MsgSwapExactAmountIn{ + Sender: suite.TestAccs[0].String(), + Routes: tc.routes, + TokenIn: tc.tokenIn, + TokenOutMinAmount: tc.tokenOutMinAmount, + }) + if tc.expectError { + suite.Require().Error(err, name) + return + } + suite.Require().NoError(err, name) + + //get the balance of txfees after swap + balancesAfter := suite.App.BankKeeper.GetAllBalances(suite.Ctx, moduleAddrFee) + + testDenom := tc.tokenIn.Denom + if tc.expectSwap { + testDenom = tc.routes[0].TokenOutDenom + } + // x/txfees balance is the same as initially since the fees are distributed immediately + suite.Require().True(balancesAfter.AmountOf(testDenom).Equal(balancesBefore.AmountOf(testDenom)), name) }) - if tc.expectError { - suite.Require().Error(err, name) - continue - } - suite.Require().NoError(err, name) - - //get the balance of txfees after swap - balancesAfter := suite.App.BankKeeper.GetAllBalances(suite.Ctx, moduleAddrFee) - - testDenom := tc.tokenIn.Denom - if tc.expectSwap { - testDenom = tc.routes[0].TokenOutDenom - } - suite.Require().True(balancesAfter.AmountOf(testDenom).GT(balancesBefore.AmountOf(testDenom)), name) } } @@ -231,61 +234,64 @@ func (suite *KeeperTestSuite) TestTakerFeeCharged_ExactOut() { } for name, tc := range testcases { - suite.SetupTest() - - suite.App.TxFeesKeeper.SetBaseDenom(suite.Ctx, "adym") - - suite.FundAcc(suite.TestAccs[0], apptesting.DefaultAcctFunds) - params := suite.App.GAMMKeeper.GetParams(suite.Ctx) - params.PoolCreationFee = sdk.NewCoins( - sdk.NewCoin("adym", sdk.NewInt(1000)), - sdk.NewCoin("bar", sdk.NewInt(1000))) - suite.App.GAMMKeeper.SetParams(suite.Ctx, params) - - ctx := suite.Ctx - msgServer := keeper.NewMsgServerImpl(suite.App.GAMMKeeper) - - pool1coins := []sdk.Coin{sdk.NewCoin("adym", sdk.NewInt(100000000)), sdk.NewCoin("foo", sdk.NewInt(100000000))} - suite.PrepareBalancerPoolWithCoins(pool1coins...) - - //"bar" is treated as baseDenom (e.g. USDC) - pool2coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000000)), sdk.NewCoin("foo", sdk.NewInt(100000000))} - suite.PrepareBalancerPoolWithCoins(pool2coins...) - - pool3coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000000)), sdk.NewCoin("adym", sdk.NewInt(100000000))} - suite.PrepareBalancerPoolWithCoins(pool3coins...) - - pool4coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000000)), sdk.NewCoin("baz", sdk.NewInt(100000000))} - suite.PrepareBalancerPoolWithCoins(pool4coins...) - - //get the balance of txfees before swap - moduleAddrFee := suite.App.AccountKeeper.GetModuleAddress(txfeestypes.ModuleName) - balancesBefore := suite.App.BankKeeper.GetAllBalances(suite.Ctx, moduleAddrFee) - - // check taker fee is not 0 - suite.Require().True(suite.App.GAMMKeeper.GetParams(ctx).TakerFee.GT(sdk.ZeroDec())) - - // make swap - _, err := msgServer.SwapExactAmountOut(sdk.WrapSDKContext(ctx), &types.MsgSwapExactAmountOut{ - Sender: suite.TestAccs[0].String(), - Routes: tc.routes, - TokenOut: tc.tokenOut, - TokenInMaxAmount: sdk.NewInt(1000000000000000000), + suite.Run(name, func() { + suite.SetupTest() + + suite.App.TxFeesKeeper.SetBaseDenom(suite.Ctx, "adym") + + suite.FundAcc(suite.TestAccs[0], apptesting.DefaultAcctFunds) + params := suite.App.GAMMKeeper.GetParams(suite.Ctx) + params.PoolCreationFee = sdk.NewCoins( + sdk.NewCoin("adym", sdk.NewInt(1000)), + sdk.NewCoin("bar", sdk.NewInt(1000))) + suite.App.GAMMKeeper.SetParams(suite.Ctx, params) + + ctx := suite.Ctx + msgServer := keeper.NewMsgServerImpl(suite.App.GAMMKeeper) + + pool1coins := []sdk.Coin{sdk.NewCoin("adym", sdk.NewInt(100000000)), sdk.NewCoin("foo", sdk.NewInt(100000000))} + suite.PrepareBalancerPoolWithCoins(pool1coins...) + + //"bar" is treated as baseDenom (e.g. USDC) + pool2coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000000)), sdk.NewCoin("foo", sdk.NewInt(100000000))} + suite.PrepareBalancerPoolWithCoins(pool2coins...) + + pool3coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000000)), sdk.NewCoin("adym", sdk.NewInt(100000000))} + suite.PrepareBalancerPoolWithCoins(pool3coins...) + + pool4coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000000)), sdk.NewCoin("baz", sdk.NewInt(100000000))} + suite.PrepareBalancerPoolWithCoins(pool4coins...) + + //get the balance of txfees before swap + moduleAddrFee := suite.App.AccountKeeper.GetModuleAddress(txfeestypes.ModuleName) + balancesBefore := suite.App.BankKeeper.GetAllBalances(suite.Ctx, moduleAddrFee) + + // check taker fee is not 0 + suite.Require().True(suite.App.GAMMKeeper.GetParams(ctx).TakerFee.GT(sdk.ZeroDec())) + + // make swap + _, err := msgServer.SwapExactAmountOut(sdk.WrapSDKContext(ctx), &types.MsgSwapExactAmountOut{ + Sender: suite.TestAccs[0].String(), + Routes: tc.routes, + TokenOut: tc.tokenOut, + TokenInMaxAmount: sdk.NewInt(1000000000000000000), + }) + if tc.expectError { + suite.Require().Error(err, name) + return + } + suite.Require().NoError(err, name) + + //get the balance of txfees after swap + balancesAfter := suite.App.BankKeeper.GetAllBalances(suite.Ctx, moduleAddrFee) + + testDenom := tc.routes[0].TokenInDenom + if tc.expectSwap { + testDenom = tc.tokenOut.Denom + } + // x/txfees balance is the same as initially since the fees are distributed immediately + suite.Require().True(balancesAfter.AmountOf(testDenom).Equal(balancesBefore.AmountOf(testDenom)), testDenom, name) }) - if tc.expectError { - suite.Require().Error(err, name) - continue - } - suite.Require().NoError(err, name) - - //get the balance of txfees after swap - balancesAfter := suite.App.BankKeeper.GetAllBalances(suite.Ctx, moduleAddrFee) - - testDenom := tc.routes[0].TokenInDenom - if tc.expectSwap { - testDenom = tc.tokenOut.Denom - } - suite.Require().True(balancesAfter.AmountOf(testDenom).GT(balancesBefore.AmountOf(testDenom)), testDenom, name) } } diff --git a/x/gamm/types/expected_keepers.go b/x/gamm/types/expected_keepers.go index 205ec882b88..532484aeb9f 100644 --- a/x/gamm/types/expected_keepers.go +++ b/x/gamm/types/expected_keepers.go @@ -78,4 +78,9 @@ type PoolManager interface { type TxFeeKeeper interface { GetFeeToken(ctx sdk.Context, denom string) (txfeestypes.FeeToken, error) GetBaseDenom(ctx sdk.Context) (denom string, err error) + ChargeFeesFromPayer(ctx sdk.Context, payer sdk.AccAddress, takerFeeCoin sdk.Coin, beneficiary *sdk.AccAddress) error +} + +type RollappKeeper interface { + GetRollappOwnerByDenom(ctx sdk.Context, denom string) (sdk.AccAddress, error) } diff --git a/x/poolmanager/events/emit_test.go b/x/poolmanager/events/emit_test.go index 45edb38b570..a26bb3ce2e1 100644 --- a/x/poolmanager/events/emit_test.go +++ b/x/poolmanager/events/emit_test.go @@ -35,6 +35,7 @@ func (suite *PoolManagerEventsTestSuite) TestEmitSwapEvent() { poolId uint64 tokensIn sdk.Coins tokensOut sdk.Coins + closingPrice sdk.Dec }{ "basic valid": { ctx: suite.CreateTestContext(), @@ -42,6 +43,7 @@ func (suite *PoolManagerEventsTestSuite) TestEmitSwapEvent() { poolId: 1, tokensIn: sdk.NewCoins(sdk.NewCoin(testDenomA, sdk.NewInt(1234))), tokensOut: sdk.NewCoins(sdk.NewCoin(testDenomB, sdk.NewInt(5678))), + closingPrice: sdk.NewDec(123), }, "valid with multiple tokens in and out": { ctx: suite.CreateTestContext(), @@ -49,6 +51,7 @@ func (suite *PoolManagerEventsTestSuite) TestEmitSwapEvent() { poolId: 200, tokensIn: sdk.NewCoins(sdk.NewCoin(testDenomA, sdk.NewInt(12)), sdk.NewCoin(testDenomB, sdk.NewInt(99))), tokensOut: sdk.NewCoins(sdk.NewCoin(testDenomC, sdk.NewInt(88)), sdk.NewCoin(testDenomD, sdk.NewInt(34))), + closingPrice: sdk.NewDec(123), }, } @@ -62,13 +65,14 @@ func (suite *PoolManagerEventsTestSuite) TestEmitSwapEvent() { sdk.NewAttribute(types.AttributeKeyPoolId, strconv.FormatUint(tc.poolId, 10)), sdk.NewAttribute(types.AttributeKeyTokensIn, tc.tokensIn.String()), sdk.NewAttribute(types.AttributeKeyTokensOut, tc.tokensOut.String()), + sdk.NewAttribute(types.AttributeKeyClosingPrice, tc.closingPrice.String()), ), } hasNoEventManager := tc.ctx.EventManager() == nil // System under test. - events.EmitSwapEvent(tc.ctx, tc.testAccountAddr, tc.poolId, tc.tokensIn, tc.tokensOut) + events.EmitSwapEvent(tc.ctx, tc.testAccountAddr, tc.poolId, tc.tokensIn, tc.tokensOut, tc.closingPrice) // Assertions if hasNoEventManager { diff --git a/x/txfees/ante/feedecorator.go b/x/txfees/ante/feedecorator.go index c151b3c711f..8bc910700e0 100644 --- a/x/txfees/ante/feedecorator.go +++ b/x/txfees/ante/feedecorator.go @@ -223,6 +223,7 @@ func DeductFees(txFeesKeeper types.TxFeesKeeper, bankKeeper types.BankKeeper, ct return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error()) } } else { + // TODO: investigate handling non-DYM fees https://github.com/dymensionxyz/dymension/issues/1387 // sends to the txfees module to be swapped and burned err := bankKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), types.ModuleName, fees) if err != nil { diff --git a/x/txfees/keeper/feedecorator_test.go b/x/txfees/keeper/feedecorator_test.go index c284f141184..6ddd76bf000 100644 --- a/x/txfees/keeper/feedecorator_test.go +++ b/x/txfees/keeper/feedecorator_test.go @@ -116,7 +116,7 @@ func (suite *KeeperTestSuite) TestFeeDecorator() { for _, tc := range tests { // reset pool and accounts for each test - suite.SetupTest(false) + suite.SetupTest() // setup uion with 1:1 fee suite.PrepareBalancerPoolWithCoins( diff --git a/x/txfees/keeper/fees.go b/x/txfees/keeper/fees.go new file mode 100644 index 00000000000..bfd7468b12d --- /dev/null +++ b/x/txfees/keeper/fees.go @@ -0,0 +1,171 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/dymensionxyz/sdk-utils/utils/uevent" + + "github.com/osmosis-labs/osmosis/v15/osmoutils" + poolmanagertypes "github.com/osmosis-labs/osmosis/v15/x/poolmanager/types" + "github.com/osmosis-labs/osmosis/v15/x/txfees/types" +) + +// ChargeFeesFromPayer charges the specified taker fee from the payer's account and +// processes it according to the fee token's properties. +// Wrapper for ChargeFees that sends the fee to x/txfees in advance. +func (k Keeper) ChargeFeesFromPayer( + ctx sdk.Context, + payer sdk.AccAddress, + takerFeeCoin sdk.Coin, + beneficiary *sdk.AccAddress, +) error { + if takerFeeCoin.IsZero() { + // Nothing to charge + return nil + } + // Charge the fee from the payer to x/txfees + err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, payer, types.ModuleName, sdk.NewCoins(takerFeeCoin)) + if err != nil { + return fmt.Errorf("send coins to txfees account: %w", err) + } + + return k.ChargeFees(ctx, takerFeeCoin, beneficiary, payer.String()) +} + +// ChargeFees processes the specified taker fee according to the fee token's properties. +// The fee must be sent to the module account beforehand. +// Payer field if optional and is only used for the event. +// +// If a beneficiary is provided, half of the fee is sent to the beneficiary. +// The remaining fee is sent to the txfees module account. +// If the fee token is the base denomination, it is burned. +// If the fee token is a registered fee token, it is swapped to the base denomination and then burned. +// If the fee token is unknown, it is sent to the community pool. +func (k Keeper) ChargeFees( + ctx sdk.Context, + takerFeeCoin sdk.Coin, + beneficiary *sdk.AccAddress, + payer string, // optional, only used for the event +) error { + if takerFeeCoin.IsZero() { + // Nothing to charge + return nil + } + + // Swap the taker fee to the base denom + baseDenomFee, communityPoolCoins, err := k.swapFeeToBaseDenom(ctx, takerFeeCoin) + if err != nil { + return fmt.Errorf("swap fee to base denom: %w", err) + } + + // If the fee token is unknown or the swap is unsuccessful, the fee is sent to the community pool. + if !communityPoolCoins.Empty() { + // Send unknown fee tokens to the community pool + err = k.communityPool.FundCommunityPool(ctx, communityPoolCoins, k.accountKeeper.GetModuleAddress(types.ModuleName)) + if err != nil { + return fmt.Errorf("unknown fee token: func community pool: %w", err) + } + + k.Logger(ctx).With("fee", communityPoolCoins.String(), "error", err). + Error("Cannot swap fee to base denom. Send it to the community pool.") + } + + // If the fee token is unknown or the swap is unsuccessful, emit event and return + if baseDenomFee.Empty() { + err = uevent.EmitTypedEvent(ctx, &types.EventChargeFee{ + Payer: payer, + TakerFee: takerFeeCoin.String(), + Beneficiary: ValueFromPtr(beneficiary).String(), + BeneficiaryRevenue: "", + }) + if err != nil { + k.Logger(ctx).Error("Failed to emit event", "event", "EventChargeFee", "error", err) + } + return nil + } + + // Send 50% of the base denom fee to the beneficiary if presented + var beneficiaryCoins sdk.Coins + if beneficiary != nil { + fee := baseDenomFee[0] + // beneficiaryCoin = takerFeeCoin / 2 + // note that beneficiaryCoin * 2 != takerFeeCoin because of the integer division rounding + beneficiaryCoins = sdk.Coins{{Denom: fee.Denom, Amount: fee.Amount.QuoRaw(2)}} + // takerFeeCoin = takerFeeCoin - beneficiaryCoin + baseDenomFee = baseDenomFee.Sub(beneficiaryCoins...) + + err = k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, *beneficiary, beneficiaryCoins) + if err != nil { + return fmt.Errorf("send coins from fee payer to beneficiary: %w", err) + } + } + + // Burn the remaining base denom fee + err = k.bankKeeper.BurnCoins(ctx, types.ModuleName, baseDenomFee) + if err != nil { + return fmt.Errorf("burn coins: %w", err) + } + + err = uevent.EmitTypedEvent(ctx, &types.EventChargeFee{ + Payer: payer, + TakerFee: baseDenomFee.String(), + Beneficiary: ValueFromPtr(beneficiary).String(), + BeneficiaryRevenue: beneficiaryCoins.String(), + }) + if err != nil { + k.Logger(ctx).Error("Failed to emit event", "event", "EventChargeFee", "error", err) + } + + return nil +} + +func ValueFromPtr[T any](ptr *T) (zero T) { + if ptr == nil { + return zero + } + return *ptr +} + +// swapFeeToBaseDenom swaps the taker fee coin to the base denom. +// If the fee token is unknown, it is sent to the community pool. +// The fee must be sent to the txfees module account beforehand. +func (k Keeper) swapFeeToBaseDenom( + ctx sdk.Context, + takerFeeCoin sdk.Coin, +) (baseDenomFee, communityPoolFee sdk.Coins, err error) { + baseDenom, err := k.GetBaseDenom(ctx) + if err != nil { + return nil, nil, fmt.Errorf("get base denom: %w", err) + } + moduleAddr := k.accountKeeper.GetModuleAddress(types.ModuleName) + + // The fee is already in the base denom + if takerFeeCoin.Denom == baseDenom { + return sdk.Coins{takerFeeCoin}, nil, nil + } + + // Get a fee token for the coin + feetoken, err := k.GetFeeToken(ctx, takerFeeCoin.Denom) + if err != nil { + return nil, sdk.Coins{takerFeeCoin}, nil + } + + // Swap the coin to base denom + var ( + tokenOutAmount = sdk.ZeroInt() // Token amount in base denom + route = []poolmanagertypes.SwapAmountInRoute{{ + PoolId: feetoken.PoolID, + TokenOutDenom: baseDenom, + }} + ) + err = osmoutils.ApplyFuncIfNoError(ctx, func(ctx sdk.Context) error { + tokenOutAmount, err = k.poolManager.RouteExactAmountIn(ctx, moduleAddr, route, takerFeeCoin, sdk.ZeroInt()) + return err + }) + if err != nil { + return nil, sdk.Coins{takerFeeCoin}, nil + } + + return sdk.Coins{{Denom: baseDenom, Amount: tokenOutAmount}}, nil, nil +} diff --git a/x/txfees/keeper/fees_test.go b/x/txfees/keeper/fees_test.go new file mode 100644 index 00000000000..55010543832 --- /dev/null +++ b/x/txfees/keeper/fees_test.go @@ -0,0 +1,164 @@ +package keeper_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/gogoproto/proto" + + "github.com/osmosis-labs/osmosis/v15/testutils/apptesting" + "github.com/osmosis-labs/osmosis/v15/x/txfees/types" +) + +func (s *KeeperTestSuite) TestChargeFees() { + accs := apptesting.CreateRandomAccounts(2) + + testCases := map[string]struct { + payer sdk.AccAddress + takerFee sdk.Coin + beneficiary *sdk.AccAddress + expTakerFee sdk.Coins + expBeneficiaryRev sdk.Coins + expCommunityRev sdk.DecCoins + }{ + "beneficiary, base denom": { + payer: accs[0], + takerFee: sdk.NewCoin("adym", sdk.NewInt(100)), + beneficiary: &accs[1], + expTakerFee: sdk.NewCoins(sdk.NewCoin("adym", sdk.NewInt(50))), + expBeneficiaryRev: sdk.NewCoins(sdk.NewCoin("adym", sdk.NewInt(50))), + expCommunityRev: nil, + }, + "beneficiary, fee token": { + payer: accs[0], + takerFee: sdk.NewCoin("foo", sdk.NewInt(100)), + beneficiary: &accs[1], + expTakerFee: sdk.NewCoins(sdk.NewCoin("adym", sdk.NewInt(50))), // 50 = 99 - 49 (99 since 0.01% is the default swap taker fee) + expBeneficiaryRev: sdk.NewCoins(sdk.NewCoin("adym", sdk.NewInt(49))), // 49 = 99 / 2 + expCommunityRev: nil, + }, + "beneficiary, non fee token": { + payer: accs[0], + takerFee: sdk.NewCoin("baz", sdk.NewInt(100)), + beneficiary: &accs[1], + expTakerFee: sdk.NewCoins(sdk.NewCoin("baz", sdk.NewInt(100))), + expBeneficiaryRev: nil, + expCommunityRev: sdk.NewDecCoinsFromCoins(sdk.NewCoins(sdk.NewCoin("baz", sdk.NewInt(100)))...), + }, + "no beneficiary, base denom": { + payer: accs[0], + takerFee: sdk.NewCoin("adym", sdk.NewInt(100)), + beneficiary: nil, + expTakerFee: sdk.NewCoins(sdk.NewCoin("adym", sdk.NewInt(100))), + expBeneficiaryRev: nil, + expCommunityRev: nil, + }, + "no beneficiary, fee token": { + payer: accs[0], + takerFee: sdk.NewCoin("foo", sdk.NewInt(100)), + beneficiary: nil, + expTakerFee: sdk.NewCoins(sdk.NewCoin("adym", sdk.NewInt(99))), // 0.01% is the default fee + expBeneficiaryRev: nil, + expCommunityRev: nil, + }, + "no beneficiary, non fee token": { + payer: accs[0], + takerFee: sdk.NewCoin("baz", sdk.NewInt(100)), + beneficiary: nil, + expTakerFee: sdk.NewCoins(sdk.NewCoin("baz", sdk.NewInt(100))), + expBeneficiaryRev: nil, + expCommunityRev: sdk.NewDecCoinsFromCoins(sdk.NewCoins(sdk.NewCoin("baz", sdk.NewInt(100)))...), + }, + } + + for name, tc := range testCases { + s.Run(name, func() { + s.SetupTest() + + // Create base denom and prepare pools + // + // Base denom: adym + // Fee denoms: foo, bar + // Pools: + // - adym <-> foo + // - bar <-> foo + // - bar <-> adym + // - bar <-> baz + + s.FundAcc(tc.payer, sdk.NewCoins(tc.takerFee)) + + err := s.App.TxFeesKeeper.SetBaseDenom(s.Ctx, "adym") + s.Require().NoError(err) + + pool1coins := []sdk.Coin{sdk.NewCoin("adym", sdk.NewInt(100000)), sdk.NewCoin("foo", sdk.NewInt(100000))} + s.PrepareBalancerPoolWithCoins(pool1coins...) + + pool2coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000)), sdk.NewCoin("foo", sdk.NewInt(100000))} + s.PrepareBalancerPoolWithCoins(pool2coins...) + + pool3coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000)), sdk.NewCoin("adym", sdk.NewInt(100000))} + s.PrepareBalancerPoolWithCoins(pool3coins...) + + pool4coins := []sdk.Coin{sdk.NewCoin("bar", sdk.NewInt(100000)), sdk.NewCoin("baz", sdk.NewInt(100000))} + s.PrepareBalancerPoolWithCoins(pool4coins...) + + initialTxFeesBalance := s.App.BankKeeper.GetAllBalances(s.Ctx, s.App.AccountKeeper.GetModuleAddress(types.ModuleName)) + + // Reset event counts to 0 by creating a new manager. + s.Ctx = s.Ctx.WithEventManager(sdk.NewEventManager()) + + // Charge fees + err = s.App.TxFeesKeeper.ChargeFeesFromPayer(s.Ctx, tc.payer, tc.takerFee, tc.beneficiary) + s.Require().NoError(err) + + // Verify results + + // Verify charge fee event + eventName := proto.MessageName(new(types.EventChargeFee)) + s.AssertEventEmitted(s.Ctx, eventName, 1) + event := s.ExtractChargeFeeEvent(s.Ctx.EventManager().Events(), eventName) + s.Require().Equal(tc.payer.String(), event.Payer) + s.Require().Equal(tc.expTakerFee.String(), event.TakerFee) + if tc.beneficiary != nil { + s.Require().Equal(tc.beneficiary.String(), event.Beneficiary) + s.Require().Equal(tc.expBeneficiaryRev.String(), event.BeneficiaryRevenue) + } else { + s.Require().Equal("", event.Beneficiary) + s.Require().Equal("", event.BeneficiaryRevenue) + } + + // The fee is either burned or not applied if case of error + actualTxFeesBalance := s.App.BankKeeper.GetAllBalances(s.Ctx, s.App.AccountKeeper.GetModuleAddress(types.ModuleName)) + s.Require().Equal(initialTxFeesBalance, actualTxFeesBalance) + + // Check beneficiary balance + var actualBeneficiaryBalance sdk.Coins + if tc.beneficiary != nil { + actualBeneficiaryBalance = s.App.BankKeeper.GetAllBalances(s.Ctx, *tc.beneficiary) + } + s.Require().True(tc.expBeneficiaryRev.IsEqual(actualBeneficiaryBalance)) + + // Check community pool balance + actualCommunityPoolBalance := s.App.DistrKeeper.GetFeePoolCommunityCoins(s.Ctx) + s.Require().Equal(tc.expCommunityRev, actualCommunityPoolBalance) + }) + } +} + +func (s *KeeperTestSuite) ExtractChargeFeeEvent(events []sdk.Event, eventName string) types.EventChargeFee { + event, found := s.FindLastEventOfType(events, eventName) + s.Require().True(found) + chargeFee := types.EventChargeFee{} + attrs := s.ExtractAttributes(event) + for key, value := range attrs { + switch key { + case "payer": + chargeFee.Payer = value + case "taker_fee": + chargeFee.TakerFee = value + case "beneficiary": + chargeFee.Beneficiary = value + case "beneficiary_revenue": + chargeFee.BeneficiaryRevenue = value + } + } + return chargeFee +} diff --git a/x/txfees/keeper/feetokens_test.go b/x/txfees/keeper/feetokens_test.go index b0c4148f5ce..a2f6ce71d2c 100644 --- a/x/txfees/keeper/feetokens_test.go +++ b/x/txfees/keeper/feetokens_test.go @@ -5,7 +5,7 @@ import ( ) func (suite *KeeperTestSuite) TestBaseDenom() { - suite.SetupTest(false) + suite.SetupTest() // Test getting basedenom (should be default from genesis) baseDenom, err := suite.App.TxFeesKeeper.GetBaseDenom(suite.Ctx) @@ -66,7 +66,7 @@ func (suite *KeeperTestSuite) TestFeeTokenConversions() { } for _, tc := range tests { - suite.SetupTest(false) + suite.SetupTest() _ = suite.PrepareBalancerPoolWithCoins( tc.baseDenomPoolInput, diff --git a/x/txfees/keeper/hooks.go b/x/txfees/keeper/hooks.go index b7c12251e6d..cbc279ff92d 100644 --- a/x/txfees/keeper/hooks.go +++ b/x/txfees/keeper/hooks.go @@ -10,7 +10,6 @@ import ( gammtypes "github.com/osmosis-labs/osmosis/v15/x/gamm/types" poolmanagertypes "github.com/osmosis-labs/osmosis/v15/x/poolmanager/types" "github.com/osmosis-labs/osmosis/v15/x/txfees/types" - txfeestypes "github.com/osmosis-labs/osmosis/v15/x/txfees/types" ) // Hooks is the wrapper struct for the txfees keeper. @@ -39,7 +38,7 @@ func (k Keeper) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epochNumb return nil } - moduleAddr := k.accountKeeper.GetModuleAddress(txfeestypes.ModuleName) + moduleAddr := k.accountKeeper.GetModuleAddress(types.ModuleName) baseDenom, _ := k.GetBaseDenom(ctx) //get all balances of this module @@ -144,7 +143,7 @@ func (h Hooks) AfterPoolCreated(ctx sdk.Context, sender sdk.AccAddress, poolId u return } - feeToken := txfeestypes.FeeToken{ + feeToken := types.FeeToken{ PoolID: poolId, Denom: nonNativeDenom, } diff --git a/x/txfees/keeper/hooks_test.go b/x/txfees/keeper/hooks_test.go index dc8297f98a8..947c918f34f 100644 --- a/x/txfees/keeper/hooks_test.go +++ b/x/txfees/keeper/hooks_test.go @@ -43,7 +43,7 @@ func (suite *KeeperTestSuite) TestTxFeesAfterEpochEnd() { } for _, tc := range tests { - suite.SetupTest(false) + suite.SetupTest() // create pools for three separate fee tokens suite.PrepareBalancerPoolWithCoins(sdk.NewCoin(baseDenom, sdk.NewInt(1000000000000)), sdk.NewCoin(uion, sdk.NewInt(5000))) diff --git a/x/txfees/keeper/keeper.go b/x/txfees/keeper/keeper.go index 589e28f85cb..aaaab0f27e1 100644 --- a/x/txfees/keeper/keeper.go +++ b/x/txfees/keeper/keeper.go @@ -22,6 +22,7 @@ type Keeper struct { bankKeeper types.BankKeeper poolManager types.PoolManager spotPriceCalculator types.SpotPriceCalculator + communityPool types.CommunityPoolKeeper } var _ types.TxFeesKeeper = (*Keeper)(nil) @@ -34,6 +35,7 @@ func NewKeeper( bankKeeper types.BankKeeper, poolManager types.PoolManager, spotPriceCalculator types.SpotPriceCalculator, + communityPool types.CommunityPoolKeeper, ) Keeper { if !paramSpace.HasKeyTable() { paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) @@ -47,6 +49,7 @@ func NewKeeper( epochKeeper: epochKeeper, poolManager: poolManager, spotPriceCalculator: spotPriceCalculator, + communityPool: communityPool, } } diff --git a/x/txfees/keeper/keeper_test.go b/x/txfees/keeper/keeper_test.go index d8367db6a1e..8afda896f02 100644 --- a/x/txfees/keeper/keeper_test.go +++ b/x/txfees/keeper/keeper_test.go @@ -18,7 +18,7 @@ func TestKeeperTestSuite(t *testing.T) { suite.Run(t, new(KeeperTestSuite)) } -func (suite *KeeperTestSuite) SetupTest(isCheckTx bool) { +func (suite *KeeperTestSuite) SetupTest() { suite.Setup() // Mint some assets to the accounts. diff --git a/x/txfees/types/events.pb.go b/x/txfees/types/events.pb.go new file mode 100644 index 00000000000..befcbfb14f5 --- /dev/null +++ b/x/txfees/types/events.pb.go @@ -0,0 +1,480 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: dymensionxyz/dymension/txfees/v1beta1/events.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type EventChargeFee struct { + Payer string `protobuf:"bytes,1,opt,name=payer,proto3" json:"payer,omitempty"` + TakerFee string `protobuf:"bytes,2,opt,name=taker_fee,json=takerFee,proto3" json:"taker_fee,omitempty"` + // Beneficiary is the address that will receive the fee. Optional: may be empty. + Beneficiary string `protobuf:"bytes,3,opt,name=beneficiary,proto3" json:"beneficiary,omitempty"` + BeneficiaryRevenue string `protobuf:"bytes,4,opt,name=beneficiary_revenue,json=beneficiaryRevenue,proto3" json:"beneficiary_revenue,omitempty"` +} + +func (m *EventChargeFee) Reset() { *m = EventChargeFee{} } +func (m *EventChargeFee) String() string { return proto.CompactTextString(m) } +func (*EventChargeFee) ProtoMessage() {} +func (*EventChargeFee) Descriptor() ([]byte, []int) { + return fileDescriptor_fdb570c08d9ae603, []int{0} +} +func (m *EventChargeFee) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *EventChargeFee) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_EventChargeFee.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *EventChargeFee) XXX_Merge(src proto.Message) { + xxx_messageInfo_EventChargeFee.Merge(m, src) +} +func (m *EventChargeFee) XXX_Size() int { + return m.Size() +} +func (m *EventChargeFee) XXX_DiscardUnknown() { + xxx_messageInfo_EventChargeFee.DiscardUnknown(m) +} + +var xxx_messageInfo_EventChargeFee proto.InternalMessageInfo + +func (m *EventChargeFee) GetPayer() string { + if m != nil { + return m.Payer + } + return "" +} + +func (m *EventChargeFee) GetTakerFee() string { + if m != nil { + return m.TakerFee + } + return "" +} + +func (m *EventChargeFee) GetBeneficiary() string { + if m != nil { + return m.Beneficiary + } + return "" +} + +func (m *EventChargeFee) GetBeneficiaryRevenue() string { + if m != nil { + return m.BeneficiaryRevenue + } + return "" +} + +func init() { + proto.RegisterType((*EventChargeFee)(nil), "dymensionxyz.dymension.txfees.v1beta1.EventChargeFee") +} + +func init() { + proto.RegisterFile("dymensionxyz/dymension/txfees/v1beta1/events.proto", fileDescriptor_fdb570c08d9ae603) +} + +var fileDescriptor_fdb570c08d9ae603 = []byte{ + // 278 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x4c, 0x90, 0xbd, 0x4e, 0xc3, 0x30, + 0x14, 0x85, 0x63, 0xfe, 0x44, 0x8d, 0xc4, 0x10, 0x3a, 0x44, 0x45, 0xb2, 0x2a, 0x24, 0x24, 0x16, + 0x72, 0x95, 0x22, 0x5e, 0x00, 0x04, 0x13, 0x53, 0x47, 0x96, 0xca, 0x0e, 0x37, 0xa9, 0x05, 0x89, + 0x23, 0xdb, 0x8d, 0x12, 0x9e, 0x82, 0x89, 0x67, 0x62, 0xec, 0xc8, 0x88, 0x92, 0x17, 0x41, 0x71, + 0xda, 0x28, 0x9b, 0xcf, 0xfd, 0xfc, 0xd9, 0x3a, 0x97, 0x2e, 0xde, 0xea, 0x0c, 0x73, 0x23, 0x55, + 0x5e, 0xd5, 0x9f, 0x30, 0x04, 0xb0, 0x55, 0x82, 0x68, 0xa0, 0x8c, 0x04, 0x5a, 0x1e, 0x01, 0x96, + 0x98, 0x5b, 0x13, 0x16, 0x5a, 0x59, 0xe5, 0x5f, 0x8f, 0x9d, 0x70, 0x08, 0x61, 0xef, 0x84, 0x3b, + 0x67, 0x36, 0x4d, 0x55, 0xaa, 0x9c, 0x01, 0xdd, 0xa9, 0x97, 0x67, 0x2c, 0x56, 0x26, 0x53, 0x06, + 0x04, 0x37, 0x38, 0x3c, 0x1f, 0x2b, 0x99, 0xf7, 0xfc, 0xea, 0x9b, 0xd0, 0xf3, 0xa7, 0xee, 0xb7, + 0xc7, 0x35, 0xd7, 0x29, 0x3e, 0x23, 0xfa, 0x53, 0x7a, 0x5c, 0xf0, 0x1a, 0x75, 0x40, 0xe6, 0xe4, + 0x66, 0xb2, 0xec, 0x83, 0x7f, 0x49, 0x27, 0x96, 0xbf, 0xa3, 0x5e, 0x25, 0x88, 0xc1, 0x81, 0x23, + 0xa7, 0x6e, 0xd0, 0x29, 0x73, 0x7a, 0x26, 0x30, 0xc7, 0x44, 0xc6, 0x92, 0xeb, 0x3a, 0x38, 0x74, + 0x78, 0x3c, 0xf2, 0x81, 0x5e, 0x8c, 0xe2, 0x4a, 0x77, 0x0d, 0x37, 0x18, 0x1c, 0xb9, 0x9b, 0xfe, + 0x08, 0x2d, 0x7b, 0xf2, 0xf0, 0xf2, 0xd3, 0x30, 0xb2, 0x6d, 0x18, 0xf9, 0x6b, 0x18, 0xf9, 0x6a, + 0x99, 0xb7, 0x6d, 0x99, 0xf7, 0xdb, 0x32, 0xef, 0x75, 0x91, 0x4a, 0xbb, 0xde, 0x88, 0x30, 0x56, + 0x19, 0xb8, 0x72, 0xd2, 0xdc, 0x7e, 0x70, 0x61, 0xf6, 0x01, 0xca, 0xe8, 0x1e, 0xaa, 0xfd, 0x4a, + 0x6d, 0x5d, 0xa0, 0x11, 0x27, 0xae, 0xed, 0xdd, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa1, 0x80, + 0x0e, 0x05, 0x80, 0x01, 0x00, 0x00, +} + +func (m *EventChargeFee) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *EventChargeFee) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *EventChargeFee) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.BeneficiaryRevenue) > 0 { + i -= len(m.BeneficiaryRevenue) + copy(dAtA[i:], m.BeneficiaryRevenue) + i = encodeVarintEvents(dAtA, i, uint64(len(m.BeneficiaryRevenue))) + i-- + dAtA[i] = 0x22 + } + if len(m.Beneficiary) > 0 { + i -= len(m.Beneficiary) + copy(dAtA[i:], m.Beneficiary) + i = encodeVarintEvents(dAtA, i, uint64(len(m.Beneficiary))) + i-- + dAtA[i] = 0x1a + } + if len(m.TakerFee) > 0 { + i -= len(m.TakerFee) + copy(dAtA[i:], m.TakerFee) + i = encodeVarintEvents(dAtA, i, uint64(len(m.TakerFee))) + i-- + dAtA[i] = 0x12 + } + if len(m.Payer) > 0 { + i -= len(m.Payer) + copy(dAtA[i:], m.Payer) + i = encodeVarintEvents(dAtA, i, uint64(len(m.Payer))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintEvents(dAtA []byte, offset int, v uint64) int { + offset -= sovEvents(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *EventChargeFee) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Payer) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } + l = len(m.TakerFee) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } + l = len(m.Beneficiary) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } + l = len(m.BeneficiaryRevenue) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } + return n +} + +func sovEvents(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozEvents(x uint64) (n int) { + return sovEvents(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *EventChargeFee) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: EventChargeFee: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: EventChargeFee: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Payer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Payer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TakerFee", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TakerFee = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Beneficiary", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Beneficiary = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BeneficiaryRevenue", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BeneficiaryRevenue = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvents(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvents + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipEvents(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEvents + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEvents + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEvents + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthEvents + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupEvents + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthEvents + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthEvents = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowEvents = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupEvents = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/txfees/types/expected_keepers.go b/x/txfees/types/expected_keepers.go index 75fba8175e1..24f94417935 100644 --- a/x/txfees/types/expected_keepers.go +++ b/x/txfees/types/expected_keepers.go @@ -48,6 +48,7 @@ type BankKeeper interface { GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins BurnCoins(ctx sdk.Context, name string, amt sdk.Coins) error + SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error } // TxFeesKeeper defines the expected transaction fee keeper @@ -56,3 +57,8 @@ type TxFeesKeeper interface { GetBaseDenom(ctx sdk.Context) (denom string, err error) GetFeeToken(ctx sdk.Context, denom string) (FeeToken, error) } + +// CommunityPoolKeeper defines the contract needed to be fulfilled for distribution keeper. +type CommunityPoolKeeper interface { + FundCommunityPool(ctx sdk.Context, amount sdk.Coins, sender sdk.AccAddress) error +}