Skip to content

Commit 5d1a0a3

Browse files
feat!: ibc transfer quota (#1568)
* WIP: add ibc rate limit middleware to ibc transfer * WIP: add cll tx,query cmds 1. add cli queries for rate_limits and params 2. add updateProposal for rate_limits and ibcPause status * WIP: add check rate limits for ibc denom * remove ibc-rate-limits and move rate limits into ibctransfer module * move the umme ibctransfer into ics20 folder * fix: fix the lint * refactor: change the module structure to 'authz' type of cosmos-sdk * remove inflow_limit in rate limits * chore: check the rate limits by exchange rate * add denom exponent to calculate amount in USD * calculating the sent amount with exponent of registerd token * fix: fix the amount calculation * fix: fix the rate-limit reset issue * refactor: update the params 1. add token_quota, total_quota, quota_duration params 2. ibc-transfer token quota checking with token_quota and total_quota params * fix: fix the build * chore: update the limits and quota interval * chore: fix the lint issues * chore: fix the lint issues * chore: addree the pr comments 1. rename ibcratelimit to uibc module 2. update the uibc cli tx and queries 3. fix the quota expires of ibc-transfer * chore: remove the param subspace from uibc * refactor: refactor the proto and logic 1. ibc-transfer status now enum (enabled,disabled,paused) 2. get the exchange from base denom (ibc/xxx) * chore: address the pr comments 1. remove expire time for quota records 2. removed params subspace keys * fix: fix the buf lint * chore: get the exchange price from TokenValue of leverage * chore: convert uToken to baseToken in ibc-transfer quota checking * chore: add typed events for emit events * address the review comments 1. Rename ibc_denom to denom query * refactor the code 1. rename the GovUpdateTransferStatus to GovSetIBCPause 2. address the pr comments * address the pr comments * chore: fix the build issue * chore: add tests for params * fix: fix the update quota params * chore: address the pr comments * chore: fix the lint * address the pr comments++ * address the pr comments * update reset quota * move to Marshal to MustMarshal in uibc * add TODO for ibc middleware acknowledgement * add comment to outflow_sum --------- Co-authored-by: Robert Zaremba <robert@zaremba.ch>
1 parent 6253a22 commit 5d1a0a3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+5713
-68
lines changed

app/app.go

Lines changed: 77 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -118,14 +118,20 @@ import (
118118
appparams "github.com/umee-network/umee/v4/app/params"
119119
"github.com/umee-network/umee/v4/swagger"
120120
"github.com/umee-network/umee/v4/util/genmap"
121-
uibctransfer "github.com/umee-network/umee/v4/x/ibctransfer"
122-
uibctransferkeeper "github.com/umee-network/umee/v4/x/ibctransfer/keeper"
123121
"github.com/umee-network/umee/v4/x/leverage"
124122
leveragekeeper "github.com/umee-network/umee/v4/x/leverage/keeper"
125123
leveragetypes "github.com/umee-network/umee/v4/x/leverage/types"
126124
"github.com/umee-network/umee/v4/x/oracle"
127125
oraclekeeper "github.com/umee-network/umee/v4/x/oracle/keeper"
128126
oracletypes "github.com/umee-network/umee/v4/x/oracle/types"
127+
128+
// umee ibc-transfer and quota for ibc-transfer
129+
"github.com/umee-network/umee/v4/x/uibc"
130+
uics20transfer "github.com/umee-network/umee/v4/x/uibc/ics20"
131+
uibctransferkeeper "github.com/umee-network/umee/v4/x/uibc/ics20/keeper"
132+
uibcmodule "github.com/umee-network/umee/v4/x/uibc/module"
133+
uibcquota "github.com/umee-network/umee/v4/x/uibc/quota"
134+
uibcquotakeeper "github.com/umee-network/umee/v4/x/uibc/quota/keeper"
129135
)
130136

131137
var (
@@ -174,7 +180,7 @@ func init() {
174180
}
175181

176182
if Experimental {
177-
moduleBasics = append(moduleBasics, wasm.AppModuleBasic{})
183+
moduleBasics = append(moduleBasics, wasm.AppModuleBasic{}, uibcmodule.AppModuleBasic{})
178184
}
179185

180186
ModuleBasics = module.NewBasicManager(moduleBasics...)
@@ -196,6 +202,7 @@ func init() {
196202

197203
if Experimental {
198204
maccPerms[wasm.ModuleName] = []string{authtypes.Burner}
205+
maccPerms[uibc.ModuleName] = nil
199206
}
200207
}
201208

@@ -241,6 +248,7 @@ type UmeeApp struct {
241248
LeverageKeeper leveragekeeper.Keeper
242249
OracleKeeper oraclekeeper.Keeper
243250
bech32IbcKeeper bech32ibckeeper.Keeper
251+
uibcQuotaKeeper uibcquotakeeper.Keeper
244252

245253
// make scoped keepers public for testing purposes
246254
ScopedIBCKeeper capabilitykeeper.ScopedKeeper
@@ -300,12 +308,11 @@ func New(
300308
govtypes.StoreKey, paramstypes.StoreKey, upgradetypes.StoreKey, feegrant.StoreKey,
301309
evidencetypes.StoreKey, capabilitytypes.StoreKey,
302310
authzkeeper.StoreKey, nftkeeper.StoreKey, group.StoreKey,
303-
ibchost.StoreKey, ibctransfertypes.StoreKey,
304-
gravitytypes.StoreKey,
311+
ibchost.StoreKey, ibctransfertypes.StoreKey, gravitytypes.StoreKey,
305312
leveragetypes.StoreKey, oracletypes.StoreKey, bech32ibctypes.StoreKey,
306313
}
307314
if Experimental {
308-
storeKeys = append(storeKeys, wasm.StoreKey)
315+
storeKeys = append(storeKeys, wasm.StoreKey, uibc.StoreKey)
309316
}
310317

311318
keys := sdk.NewKVStoreKeys(storeKeys...)
@@ -442,18 +449,14 @@ func New(
442449
app.StakingKeeper,
443450
distrtypes.ModuleName,
444451
)
445-
var err error
446-
app.LeverageKeeper, err = leveragekeeper.NewKeeper(
452+
app.LeverageKeeper = leveragekeeper.NewKeeper(
447453
appCodec,
448454
keys[leveragetypes.ModuleName],
449455
app.GetSubspace(leveragetypes.ModuleName),
450456
app.BankKeeper,
451457
app.OracleKeeper,
452458
cast.ToBool(appOpts.Get(leveragetypes.FlagEnableLiquidatorQuery)),
453459
)
454-
if err != nil {
455-
panic(err)
456-
}
457460
app.LeverageKeeper = *app.LeverageKeeper.SetHooks(
458461
leveragetypes.NewMultiHooks(
459462
app.OracleKeeper.Hooks(),
@@ -494,13 +497,35 @@ func New(
494497
// If evidence needs to be handled for the app, set routes in router here and seal
495498
app.EvidenceKeeper = *evidenceKeeper
496499

500+
app.IBCKeeper = ibckeeper.NewKeeper(
501+
appCodec,
502+
keys[ibchost.StoreKey],
503+
app.GetSubspace(ibchost.ModuleName),
504+
*app.StakingKeeper,
505+
app.UpgradeKeeper,
506+
app.ScopedIBCKeeper,
507+
)
508+
509+
var ics4Wrapper ibcporttypes.ICS4Wrapper
510+
if Experimental {
511+
app.uibcQuotaKeeper = uibcquotakeeper.NewKeeper(
512+
appCodec,
513+
keys[uibc.StoreKey],
514+
app.IBCKeeper.ChannelKeeper, app.LeverageKeeper,
515+
)
516+
ics4Wrapper = app.uibcQuotaKeeper
517+
} else {
518+
ics4Wrapper = app.IBCKeeper.ChannelKeeper
519+
}
520+
521+
// Middleware Stacks
497522
// Create an original ICS-20 transfer keeper and AppModule and then use it to
498523
// created an Umee wrapped ICS-20 transfer keeper and AppModule.
499524
ibcTransferKeeper := ibctransferkeeper.NewKeeper(
500525
appCodec,
501526
keys[ibctransfertypes.StoreKey],
502527
app.GetSubspace(ibctransfertypes.ModuleName),
503-
app.IBCKeeper.ChannelKeeper,
528+
ics4Wrapper, // ISC4 Wrapper: IBC Rate Limit middleware
504529
app.IBCKeeper.ChannelKeeper,
505530
&app.IBCKeeper.PortKeeper,
506531
app.AccountKeeper,
@@ -509,15 +534,34 @@ func New(
509534
)
510535

511536
app.UIBCTransferKeeper = uibctransferkeeper.New(ibcTransferKeeper, app.BankKeeper)
512-
ibcTransferModule := ibctransfer.NewAppModule(ibcTransferKeeper)
513-
uibcTransferIBCModule := uibctransfer.NewIBCModule(
514-
ibctransfer.NewIBCModule(ibcTransferKeeper), app.UIBCTransferKeeper,
537+
538+
// Create Transfer Stack
539+
// SendPacket, since it is originating from the application to core IBC:
540+
// transferKeeper.SendPacket -> uibcquota.SendPacket -> channel.SendPacket
541+
542+
// RecvPacket, message that originates from core IBC and goes down to app, the flow is the other way
543+
// channel.RecvPacket -> uibcquota.OnRecvPacket -> transfer.OnRecvPacket
544+
545+
// transfer stack contains (from top to bottom):
546+
// - Umee IBC Transfer
547+
// - IBC Rate Limit Middleware
548+
549+
// create IBC module from bottom to top of stack
550+
var transferStack ibcporttypes.IBCModule
551+
transferStack = uics20transfer.NewIBCModule(
552+
ibctransfer.NewIBCModule(ibcTransferKeeper),
553+
app.UIBCTransferKeeper,
515554
)
516555

556+
if Experimental {
557+
transferStack = uibcquota.NewIBCMiddleware(transferStack, app.uibcQuotaKeeper)
558+
}
559+
560+
// Create IBC Router
517561
// create static IBC router, add transfer route, then set and seal it
518562
ibcRouter := ibcporttypes.NewRouter()
519-
ibcRouter.AddRoute(ibctransfertypes.ModuleName, uibcTransferIBCModule)
520-
563+
// Add transfer stack to IBC Router
564+
ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferStack)
521565
ibcRouter.AddRoute(wasm.ModuleName, wasm.NewIBCHandler(app.WasmKeeper, app.IBCKeeper.ChannelKeeper))
522566
app.IBCKeeper.SetRouter(ibcRouter)
523567

@@ -593,15 +637,18 @@ func New(
593637
groupmodule.NewAppModule(appCodec, app.GroupKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry),
594638
nftmodule.NewAppModule(appCodec, app.NFTKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry),
595639

596-
ibcTransferModule,
640+
ibctransfer.NewAppModule(ibcTransferKeeper),
597641
gravity.NewAppModule(app.GravityKeeper, app.BankKeeper),
598642
leverage.NewAppModule(appCodec, app.LeverageKeeper, app.AccountKeeper, app.BankKeeper),
599643
oracle.NewAppModule(appCodec, app.OracleKeeper, app.AccountKeeper, app.BankKeeper),
600644
bech32ibc.NewAppModule(appCodec, app.bech32IbcKeeper),
601645
}
602646
if Experimental {
603-
appModules = append(appModules,
604-
wasm.NewAppModule(app.appCodec, &app.WasmKeeper, app.StakingKeeper, app.AccountKeeper, app.BankKeeper))
647+
appModules = append(
648+
appModules,
649+
wasm.NewAppModule(app.appCodec, &app.WasmKeeper, app.StakingKeeper, app.AccountKeeper, app.BankKeeper),
650+
uibcmodule.NewAppModule(appCodec, app.uibcQuotaKeeper),
651+
)
605652
}
606653

607654
app.mm = module.NewManager(appModules...)
@@ -626,6 +673,7 @@ func New(
626673
gravitytypes.ModuleName,
627674
bech32ibctypes.ModuleName,
628675
}
676+
629677
endBlockers := []string{
630678
crisistypes.ModuleName,
631679
oracletypes.ModuleName, // must be before gov and staking
@@ -661,6 +709,7 @@ func New(
661709
gravitytypes.ModuleName,
662710
bech32ibctypes.ModuleName,
663711
}
712+
664713
orderMigrations := []string{
665714
capabilitytypes.ModuleName, authtypes.ModuleName, banktypes.ModuleName, distrtypes.ModuleName,
666715
stakingtypes.ModuleName, slashingtypes.ModuleName, govtypes.ModuleName, minttypes.ModuleName,
@@ -676,10 +725,10 @@ func New(
676725
}
677726

678727
if Experimental {
679-
beginBlockers = append(beginBlockers, wasm.ModuleName)
680-
endBlockers = append(endBlockers, wasm.ModuleName)
681-
initGenesis = append(initGenesis, wasm.ModuleName)
682-
orderMigrations = append(orderMigrations, wasm.ModuleName)
728+
beginBlockers = append(beginBlockers, wasm.ModuleName, uibc.ModuleName)
729+
endBlockers = append(endBlockers, wasm.ModuleName, uibc.ModuleName)
730+
initGenesis = append(initGenesis, wasm.ModuleName, uibc.ModuleName)
731+
orderMigrations = append(orderMigrations, wasm.ModuleName, uibc.ModuleName)
683732
}
684733

685734
app.mm.SetOrderBeginBlockers(beginBlockers...)
@@ -704,8 +753,10 @@ func New(
704753
authtypes.ModuleName: auth.NewAppModule(app.appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts),
705754
}
706755

707-
simStateModules := genmap.Pick(app.mm.Modules,
708-
[]string{stakingtypes.ModuleName, authtypes.ModuleName, oracletypes.ModuleName})
756+
simStateModules := genmap.Pick(
757+
app.mm.Modules,
758+
[]string{stakingtypes.ModuleName, authtypes.ModuleName, oracletypes.ModuleName},
759+
)
709760
// TODO: Ensure x/leverage implements simulator and add it here:
710761
simTestModules := genmap.Pick(simStateModules, []string{oracletypes.ModuleName})
711762

proto/umee/uibc/v1/events.proto

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
syntax = "proto3";
2+
package umee.uibc.v1;
3+
4+
import "gogoproto/gogo.proto";
5+
6+
option go_package = "github.com/umee-network/umee/v4/x/uibc";
7+
option (gogoproto.goproto_getters_all) = false;
8+
9+
// EventBadRevert is emitted on failure of ibc-transfer quota.
10+
message EventBadRevert {
11+
// module name
12+
string module = 1;
13+
// failure event type
14+
string failure_type = 2;
15+
// ibc packet data
16+
string packet = 3;
17+
}

proto/umee/uibc/v1/genesis.proto

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
syntax = "proto3";
2+
package umee.uibc.v1;
3+
4+
import "gogoproto/gogo.proto";
5+
import "cosmos_proto/cosmos.proto";
6+
import "google/protobuf/timestamp.proto";
7+
import "umee/uibc/v1/quota.proto";
8+
9+
option go_package = "github.com/umee-network/umee/v4/x/uibc";
10+
option (gogoproto.goproto_getters_all) = false;
11+
12+
// GenesisState defines the uibc module's genesis state.
13+
message GenesisState {
14+
Params params = 1 [(gogoproto.nullable) = false];
15+
repeated Quota quotas = 2 [(gogoproto.nullable) = false];
16+
// total_outflow_sum defines the total outflow sum of ibc-transfer in USD
17+
string total_outflow_sum = 3 [
18+
(cosmos_proto.scalar) = "cosmos.Dec",
19+
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
20+
(gogoproto.nullable) = false
21+
];
22+
// quota_expires defines quota expires for ibc-transfer denom in seconds
23+
google.protobuf.Timestamp quota_expires = 4 [
24+
(gogoproto.nullable) = false,
25+
(gogoproto.stdtime) = true,
26+
(gogoproto.jsontag) = "quota_duration,omitempty",
27+
(gogoproto.moretags) = "yaml:\"quota_expires\""
28+
];
29+
}

proto/umee/uibc/v1/query.proto

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
syntax = "proto3";
2+
package umee.uibc.v1;
3+
4+
import "google/api/annotations.proto";
5+
import "gogoproto/gogo.proto";
6+
import "umee/uibc/v1/quota.proto";
7+
8+
option go_package = "github.com/umee-network/umee/v4/x/uibc";
9+
10+
option (gogoproto.goproto_getters_all) = false;
11+
12+
// Query defines the gRPC querier service.
13+
service Query {
14+
// Params queries the parameters of the x/uibc module.
15+
rpc Params(QueryParams) returns (QueryParamsResponse) {
16+
option (google.api.http).get = "/umee/uibc/v1/params";
17+
}
18+
19+
// Quota queries the rate limits of ibc denoms.
20+
// If denom is empty, returns quota for all tokens.
21+
rpc Quota(QueryQuota) returns (QueryQuotaResponse) {
22+
option (google.api.http).get = "/umee/uibc/v1/quota/{denom}";
23+
}
24+
}
25+
26+
// QueryParams defines the request structure for the Params gRPC service
27+
// handler.
28+
message QueryParams {}
29+
30+
// QueryParamsResponse defines the response structure for the Params gRPC
31+
// service handler.
32+
message QueryParamsResponse {
33+
Params params = 1 [(gogoproto.nullable) = false];
34+
}
35+
36+
// QueryQuota defines request type for query the quota of denoms
37+
message QueryQuota {
38+
string denom = 1;
39+
}
40+
41+
// QueryQuotaResponse defines response type of Query/Quota
42+
message QueryQuotaResponse {
43+
repeated Quota quota = 1 [(gogoproto.nullable) = false];
44+
}

proto/umee/uibc/v1/quota.proto

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
syntax = "proto3";
2+
package umee.uibc.v1;
3+
4+
import "gogoproto/gogo.proto";
5+
import "google/protobuf/duration.proto";
6+
import "cosmos_proto/cosmos.proto";
7+
8+
option go_package = "github.com/umee-network/umee/v4/x/uibc";
9+
10+
// Quota stores current sum of IBC outflow transfers of IBC Denom.
11+
message Quota {
12+
// ibc_denom defines the ibc denom
13+
string ibc_denom = 1;
14+
// outflow_sum defines the sum of price (USD) value of outflow tokens through ibc-transfer
15+
string outflow_sum = 3 [
16+
(cosmos_proto.scalar) = "cosmos.Dec",
17+
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
18+
(gogoproto.nullable) = false
19+
];
20+
}
21+
22+
// Params of x/uibc module
23+
message Params {
24+
// ibc_status defines the wethever ibc-transfer enabled, disbaled or paused
25+
IBCTransferStatus ibc_pause = 1;
26+
// total_quota defines the total outflow limit of ibc-transfer in USD
27+
string total_quota = 2 [
28+
(cosmos_proto.scalar) = "cosmos.Dec",
29+
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
30+
(gogoproto.nullable) = false
31+
];
32+
// token_quota defines the outflow limit per token in USD
33+
string token_quota = 3 [
34+
(cosmos_proto.scalar) = "cosmos.Dec",
35+
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
36+
(gogoproto.nullable) = false
37+
];
38+
// quota_duration defines quota expires for each ibc-transfer denom in seconds
39+
google.protobuf.Duration quota_duration = 4 [
40+
(gogoproto.nullable) = false,
41+
(gogoproto.stdduration) = true,
42+
(gogoproto.jsontag) = "quota_duration,omitempty",
43+
(gogoproto.moretags) = "yaml:\"quota_duration\""
44+
];
45+
}
46+
47+
// IBCTransferStatus status of ibc-transfer
48+
enum IBCTransferStatus {
49+
// UNSPECIFIED defines a no-op status.
50+
IBC_TRANSFER_STATUS_UNSPECIFIED = 0;
51+
// DISABLED defines the quota checking diabled for ibc-transfer.
52+
IBC_TRANSFER_STATUS_DISABLED = 1;
53+
// ENABLED defines the enable quota checking for ibc-transfer.
54+
IBC_TRANSFER_STATUS_ENABLED = 2;
55+
// PAUSED defines pause the ibc-transfer from app.
56+
IBC_TRANSFER_STATUS_PAUSED = 3;
57+
}

0 commit comments

Comments
 (0)