Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat(cwgrants): Implement x/cwgrants module #527

Merged
merged 31 commits into from
Jan 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
45a6d85
add protos
fdymylja Jan 2, 2024
b7022de
impl module API
fdymylja Jan 2, 2024
40e6a4f
add codec
fdymylja Jan 2, 2024
8910607
add errors
fdymylja Jan 2, 2024
e267e48
add msg implementation
fdymylja Jan 2, 2024
60199f4
add genesis validation + test
fdymylja Jan 2, 2024
0ec2f1f
add keys
fdymylja Jan 2, 2024
cfb6aae
add keeper and keeper testing
fdymylja Jan 2, 2024
0816749
add msg and query server
fdymylja Jan 2, 2024
69765eb
add cw type wrapper
fdymylja Jan 2, 2024
6b0bd1a
add ante handler logic for grants
fdymylja Jan 2, 2024
9d4c712
do wiring
fdymylja Jan 2, 2024
fabbc72
add cwgrant contract
fdymylja Jan 2, 2024
023f34e
finalise testing
fdymylja Jan 2, 2024
2972709
add more safety test case
fdymylja Jan 2, 2024
b4d6e98
add cwgrant wasm
fdymylja Jan 2, 2024
5c0f264
lint
fdymylja Jan 2, 2024
60fcee5
PR feedback: check if genesis granter is CW contract
fdymylja Jan 9, 2024
d080e6c
adjust genesis test
fdymylja Jan 9, 2024
d37eb2f
add UnregisterAsGranterMsg
fdymylja Jan 9, 2024
adcafa0
implement UnregisterAsGranter
fdymylja Jan 9, 2024
66301fb
rename to CWFees
fdymylja Jan 9, 2024
d009356
move test contract to appropriate package
fdymylja Jan 9, 2024
70b9d88
add to upgrade handler!
fdymylja Jan 9, 2024
98bb046
add cw fees adr
fdymylja Jan 9, 2024
529cd80
lint
fdymylja Jan 9, 2024
1708c80
Merge branch 'main' into fd/cw_grants
fdymylja Jan 9, 2024
e6f2ef2
apply gas limits for request for grants
fdymylja Jan 9, 2024
d7396b9
update ADR
fdymylja Jan 16, 2024
3f4c618
Merge branch 'main' into fd/cw_grants
fdymylja Jan 16, 2024
6c3505b
merge main
fdymylja Jan 16, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Contains all the PRs that improved the code without changing the behaviors.
- [#462](https://github.com/archway-network/archway/pull/462) - adding docs ADR-008 – Improvements on rewards withdrawal experience
- [#501](https://github.com/archway-network/archway/pull/501) - Adding x/callback module
- [#532](https://github.com/archway-network/archway/pull/532) - Adding ADR-009 for x/callback module
- [#527](https://github.com/archway-network/archway/pull/527) - Add x/cwfees module for

### Improvements

Expand Down
7 changes: 5 additions & 2 deletions app/ante.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
ibcante "github.com/cosmos/ibc-go/v7/modules/core/ante"
ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper"

"github.com/archway-network/archway/x/cwfees"

rewardsAnte "github.com/archway-network/archway/x/rewards/ante"
rewardsKeeper "github.com/archway-network/archway/x/rewards/keeper"
trackingAnte "github.com/archway-network/archway/x/tracking/ante"
Expand All @@ -33,7 +35,8 @@ type HandlerOptions struct {
TrackingKeeper trackingKeeper.Keeper
RewardsKeeper rewardsKeeper.Keeper

Codec codec.BinaryCodec
Codec codec.BinaryCodec
CWFeesKeeper cwfees.Keeper
}

func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
Expand Down Expand Up @@ -78,7 +81,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
// Custom Archway interceptor to track new transactions
trackingAnte.NewTxGasTrackingDecorator(options.TrackingKeeper),
// Custom Archway fee deduction, which splits fees between x/rewards and x/auth fee collector
rewardsAnte.NewDeductFeeDecorator(options.Codec, options.AccountKeeper, options.RewardsAnteBankKeeper, options.FeegrantKeeper, options.RewardsKeeper),
rewardsAnte.NewDeductFeeDecorator(options.Codec, options.AccountKeeper, options.RewardsAnteBankKeeper, options.FeegrantKeeper, options.RewardsKeeper, options.CWFeesKeeper),
// SetPubKeyDecorator must be called before all signature verification decorators
ante.NewSetPubKeyDecorator(options.AccountKeeper),
ante.NewValidateSigCountDecorator(options.AccountKeeper),
Expand Down
11 changes: 10 additions & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"path/filepath"

"github.com/archway-network/archway/app/keepers"
"github.com/archway-network/archway/x/cwfees"
"github.com/archway-network/archway/x/genmsg"

autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
Expand Down Expand Up @@ -207,6 +208,7 @@ var (
rewards.AppModuleBasic{},
genmsg.AppModule{},
callback.AppModuleBasic{},
cwfees.AppModule{},
)

// module account permissions
Expand Down Expand Up @@ -304,7 +306,7 @@ func NewArchwayApp(
feegrant.StoreKey, authzkeeper.StoreKey, wasmdTypes.StoreKey, consensusparamtypes.StoreKey,
icahosttypes.StoreKey, ibcfeetypes.StoreKey, crisistypes.StoreKey, group.StoreKey, nftkeeper.StoreKey,

trackingTypes.StoreKey, rewardsTypes.StoreKey, callbackTypes.StoreKey,
trackingTypes.StoreKey, rewardsTypes.StoreKey, callbackTypes.StoreKey, cwfees.ModuleName,
)
tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey)
memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey)
Expand Down Expand Up @@ -572,6 +574,8 @@ func NewArchwayApp(
govModuleAddr,
)

app.Keepers.CWFeesKeeper = cwfees.NewKeeper(appCodec, keys[cwfees.ModuleName], app.Keepers.WASMKeeper)

var transferStack porttypes.IBCModule
transferStack = transfer.NewIBCModule(app.Keepers.TransferKeeper)
transferStack = ibcfee.NewIBCMiddleware(transferStack, app.Keepers.IBCFeeKeeper)
Expand Down Expand Up @@ -644,6 +648,7 @@ func NewArchwayApp(
consensus.NewAppModule(appCodec, app.Keepers.ConsensusParamsKeeper),
tracking.NewAppModule(app.appCodec, app.Keepers.TrackingKeeper),
rewards.NewAppModule(app.appCodec, app.Keepers.RewardsKeeper),
cwfees.NewAppModule(app.Keepers.CWFeesKeeper),
genmsg.NewAppModule(app.MsgServiceRouter()),
callback.NewAppModule(app.appCodec, app.Keepers.CallbackKeeper, app.Keepers.WASMKeeper),
crisis.NewAppModule(&app.Keepers.CrisisKeeper, skipGenesisInvariants, app.getSubspace(crisistypes.ModuleName)), // always be last to make sure that it checks for all invariants and not only part of them
Expand Down Expand Up @@ -685,6 +690,7 @@ func NewArchwayApp(
trackingTypes.ModuleName,
rewardsTypes.ModuleName,
callbackTypes.ModuleName,
cwfees.ModuleName, // does not have being blocker.
)

app.mm.SetOrderEndBlockers(
Expand Down Expand Up @@ -720,6 +726,7 @@ func NewArchwayApp(
callbackTypes.ModuleName,
// invariants checks are always the last to run
crisistypes.ModuleName,
cwfees.ModuleName, // does not have end blocker
)

// NOTE: The genutils module must occur after staking so that pools are
Expand Down Expand Up @@ -757,6 +764,7 @@ func NewArchwayApp(
// wasm after ibc transfer
wasmdTypes.ModuleName,
// wasm gas tracking
cwfees.ModuleName, // depends on wasmd.
trackingTypes.ModuleName,
genmsg.ModuleName,
callbackTypes.ModuleName,
Expand Down Expand Up @@ -817,6 +825,7 @@ func NewArchwayApp(
TXCounterStoreKey: keys[wasmdTypes.StoreKey],
TrackingKeeper: app.Keepers.TrackingKeeper,
RewardsKeeper: app.Keepers.RewardsKeeper,
CWFeesKeeper: app.Keepers.CWFeesKeeper,
},
)
if err != nil {
Expand Down
3 changes: 3 additions & 0 deletions app/keepers/keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import (
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper"

"github.com/archway-network/archway/x/cwfees"

icahostkeeper "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/host/keeper"
ibcfeekeeper "github.com/cosmos/ibc-go/v7/modules/apps/29-fee/keeper"
ibctransferkeeper "github.com/cosmos/ibc-go/v7/modules/apps/transfer/keeper"
Expand Down Expand Up @@ -57,5 +59,6 @@ type ArchwayKeepers struct {
// Archway Keepers
TrackingKeeper trackingKeeper.Keeper
RewardsKeeper rewardsKeeper.Keeper
CWFeesKeeper cwfees.Keeper
CallbackKeeper callbackKeeper.Keeper
}
2 changes: 2 additions & 0 deletions app/upgrades/latest/upgrades.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/archway-network/archway/app/keepers"
"github.com/archway-network/archway/app/upgrades"
callbackTypes "github.com/archway-network/archway/x/callback/types"
"github.com/archway-network/archway/x/cwfees"
)

// This upgrade handler is used for all the current changes to the protocol
Expand All @@ -32,6 +33,7 @@ var Upgrade = upgrades.Upgrade{
StoreUpgrades: storetypes.StoreUpgrades{
Added: []string{
callbackTypes.ModuleName,
cwfees.ModuleName,
},
},
}
50 changes: 50 additions & 0 deletions contracts/cwfees/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
[package]
name = "cwgrant"
version = "0.1.0"
authors = ["Frojdi"]
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
crate-type = ["cdylib", "rlib"]

[profile.release]
opt-level = 3
debug = false
rpath = false
lto = true
debug-assertions = false
codegen-units = 1
panic = 'abort'
incremental = false
overflow-checks = true

[features]
# for more explicit tests, cargo test --features=backtraces
backtraces = ["cosmwasm-std/backtraces"]
# use library feature to disable all instantiate/execute/query exports
library = []

[package.metadata.scripts]
optimize = """docker run --rm -v "$(pwd)":/code \
--mount type=volume,source="$(basename "$(pwd)")_cache",target=/target \
--mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \
cosmwasm/optimizer:0.15.0
"""

[dependencies]
cosmwasm-schema = "1.5.0"
cosmwasm-std = { version = "1.5.0", features = [
"cosmwasm_1_3",
# Enable this if you only deploy to chains that have CosmWasm 1.4 or higher
# "cosmwasm_1_4",
] }
cw-storage-plus = "1.1.0"
cw2 = "1.1.1"
schemars = "0.8.15"
serde = { version = "1.0.189", default-features = false, features = ["derive"] }
thiserror = { version = "1.0.49" }

[dev-dependencies]
cw-multi-test = "0.17.0"
2 changes: 2 additions & 0 deletions contracts/cwfees/artifacts/checksums.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
87a239f88d13f5d6f4a170d95f281563a91e01dcaae4a699ef1981dfef24115b cwgrant-aarch64.wasm
72cdb4ffa538ff9365328a65427469c603a87007c3155b52515bf728a9b02c95 cwgrant.wasm
1 change: 1 addition & 0 deletions contracts/cwfees/artifacts/checksums_intermediate.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
92df70ecf8e205915633d93114aefd0340e65a72de4390ea2e14c27161271408 /target/wasm32-unknown-unknown/release/cwgrant.wasm
Binary file added contracts/cwfees/artifacts/cwfees.wasm
Binary file not shown.
57 changes: 57 additions & 0 deletions contracts/cwfees/src/contract.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use cosmwasm_std::{DepsMut, Empty, Env, MessageInfo, Response, entry_point};
use crate::errors::ContractError;
use crate::msgs::{CwGrant, InstantiateMsg, SudoMsg};
use crate::state::GRANTS;

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn instantiate(
deps: DepsMut,
_env: Env,
_: MessageInfo,
msg: InstantiateMsg,
) -> Result<Response, ContractError> {
for addr in &msg.grants {
let addr = deps.api.addr_validate(addr)?;
GRANTS.save(deps.storage, &addr, &Empty{})?
}
Ok(Response::default())
}
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn sudo(
deps: DepsMut,
_env: Env,
msg: SudoMsg,
) -> Result<Response, ContractError> {
return match msg {
SudoMsg::CwGrant(grant) => {
sudo_grant(deps, grant)
}
}
}

fn sudo_grant(deps: DepsMut, msg: CwGrant) -> Result<Response, ContractError> {
// in order to pay the fees all message senders need to be
// in the grants list.
for m in &msg.msgs {
let sender = deps.api.addr_validate(&m.sender)?;
if !GRANTS.has(deps.storage, &sender) {
return Err(ContractError::Unauthorized {})
}
}

Ok(Response::default())
}

#[cfg(test)]
mod test {
use cosmwasm_std::to_json_binary;
use crate::msgs::{CwGrant, SudoMsg};

#[test]
fn encoding() {
println!("{}", to_json_binary(&SudoMsg::CwGrant(CwGrant{
fee_requested: vec![],
msgs: vec![],
})).unwrap());
}
}
11 changes: 11 additions & 0 deletions contracts/cwfees/src/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use cosmwasm_std::StdError;
use thiserror::Error;

#[derive(Error, Debug)]
pub enum ContractError {
#[error("{0}")]
Std(#[from] StdError),

#[error("Unauthorized")]
Unauthorized {},
}
4 changes: 4 additions & 0 deletions contracts/cwfees/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
mod msgs;
mod contract;
mod errors;
mod state;
29 changes: 29 additions & 0 deletions contracts/cwfees/src/msgs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use cosmwasm_schema::{cw_serde};
use cosmwasm_std::{Binary, Coin};

#[cw_serde]
pub struct InstantiateMsg {
pub grants: Vec<String>
}

#[cw_serde]
pub enum SudoMsg {
CwGrant(CwGrant)
}
#[cw_serde]
pub struct CwGrant {
pub fee_requested: Vec<Coin>,
pub msgs: Vec<CwGrantMessage>,
}
#[cw_serde]
pub struct CwGrantMessage {
pub sender: String,
pub type_url: String,
pub msg: Binary,
}

#[cfg(test)]
mod test {
#[test]
fn build() {}
}
4 changes: 4 additions & 0 deletions contracts/cwfees/src/state.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
use cosmwasm_std::{Addr, Empty};
use cw_storage_plus::Map;

pub const GRANTS: Map<&Addr, Empty> = Map::new("grants");
64 changes: 64 additions & 0 deletions docs/adr/ADR-010-cw-fees.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---

# ADR-010: Introduction of CWFees Module

Date: 2023-01-16

## Status

Accepted | Implemented.

## Context

The introduction of the CWFees module marks a significant advancement in how transaction fees are handled within the
ecosystem. Previously confined to entities registered under the standard x/feegrant module, the `FeeGranter` role within
a transaction's `AuthInfo.Fee` can now be assumed by a CosmWasm contract. This transition from a static,
binary-implemented fee grant logic to a dynamic, contract-based approach enhances flexibility, eliminating the need for
chain upgrades for modifications in fee grant logic.

## Decision

We have expanded the capabilities of the CWFees module by introducing two key message entry points: `RegisterAsGranter`
and `UnregisterAsGranter`, exclusively accessible to CosmWasm contracts. This enables a contract, for example during its
instantiation phase, to declare itself as a fee granter by issuing a `StargateMsg` containing a `RegisterAsGranter`
message. Once registered, the system acknowledges the contract as an eligible fee granter.

In the event of a transaction, the user can designate a registered CosmWasm contract as the `Tx.AuthInfo.Fee.Granter`.
The system, in turn, invokes this contract via sudo, providing it with critical information encapsulated in a structured
JSON format:

```golang
type SudoMsg struct {
CWGrant *CWGrant `json:"cw_grant"`
}

type CWGrant struct {
FeeRequested wasmVmTypes.Coins `json:"fee_requested"`
Msgs []CWGrantMessage `json:"msgs"`
}

type CWGrantMessage struct {
Sender string `json:"sender"`
TypeUrl string `json:"type_url"`
Msg []byte `json:"msg"`
}
```

This detailed information empowers the contract to make an informed decision regarding the grant request. If the contract
consents (i.e., no errors are returned), the runtime itself handles the transfer of fees from the contract to the
auth collector. Conversely, if the contract opts to decline the grant, it must issue an error response. Overall, the contract
is not required to do anything besides signaling it accepts or refuses the grant (no coin moving is required!).

## Consequences

### Positive
1. Grants developers enhanced control over the application of fee grants.
2. Enables transactions where contracts absorb the gas costs for users, creating a gas-less experience.
3. Supports the development of diverse incentive models.
4. Accommodates the use of multiple coin types for fee payments.

### Negative
1. Introduces a layer of complexity to the system's architecture.

### Security Considerations
- To mitigate potential risks, the gas usage within a CWGrant will be capped, preventing a CWFees contract from incurring excessive gas consumption.
Loading
Loading