generated from dymensionxyz/rollapp
-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(wasm): authz handler for signless contract execution
- Loading branch information
Showing
7 changed files
with
600 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
syntax = "proto3"; | ||
package rollapp.wasm; | ||
|
||
import "gogoproto/gogo.proto"; | ||
import "cosmos_proto/cosmos.proto"; | ||
import "cosmos/base/v1beta1/coin.proto"; | ||
|
||
option go_package = "github.com/dymensionxyz/rollapp-wasm/x/wasm"; | ||
|
||
// ContractExecutionAuthorization defines authorization for wasm execute. | ||
message ContractExecutionAuthorization { | ||
option (cosmos_proto.implements_interface) = "cosmos.authz.v1beta1.Authorization"; | ||
|
||
// Contracts is a list of allowed contracts. Optional. | ||
repeated string contracts = 1; | ||
|
||
// SpendLimits defines spending limits for contracts interactions. | ||
repeated cosmos.base.v1beta1.Coin spend_limit = 2 [ | ||
(gogoproto.nullable) = false, | ||
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" | ||
]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package wasm | ||
|
||
import ( | ||
errors "errors" | ||
"fmt" | ||
"slices" | ||
|
||
wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
authztypes "github.com/cosmos/cosmos-sdk/x/authz" | ||
) | ||
|
||
var _ authztypes.Authorization = &ContractExecutionAuthorization{} | ||
|
||
func NewContractExecutionAuthorization(contracts []string, spendLimit sdk.Coins) *ContractExecutionAuthorization { | ||
return &ContractExecutionAuthorization{ | ||
Contracts: contracts, | ||
SpendLimit: spendLimit, | ||
} | ||
} | ||
|
||
// MsgTypeURL implements Authorization.MsgTypeURL. | ||
func (a *ContractExecutionAuthorization) MsgTypeURL() string { | ||
return sdk.MsgTypeURL(&wasmtypes.MsgExecuteContract{}) | ||
} | ||
|
||
func (a *ContractExecutionAuthorization) Accept(_ sdk.Context, msg sdk.Msg) (authztypes.AcceptResponse, error) { | ||
m, ok := msg.(*wasmtypes.MsgExecuteContract) | ||
if !ok { | ||
return authztypes.AcceptResponse{}, errors.New("invalid message type") | ||
} | ||
|
||
// Check whitelisted contracts if specified | ||
if len(a.Contracts) > 0 && !slices.Contains(a.Contracts, m.Contract) { | ||
return authztypes.AcceptResponse{}, errors.New("contract not authorized") | ||
} | ||
|
||
// Check spend limits if specified | ||
if !a.SpendLimit.Empty() { | ||
if m.Funds.IsAnyGT(a.SpendLimit) { | ||
return authztypes.AcceptResponse{}, errors.New("exceeds spend limit") | ||
} | ||
|
||
// Update spend limits | ||
a.SpendLimit = a.SpendLimit.Sub(m.Funds...) | ||
if a.SpendLimit.Empty() { | ||
return authztypes.AcceptResponse{Accept: true, Delete: true}, nil | ||
} | ||
} | ||
|
||
return authztypes.AcceptResponse{Accept: true, Updated: a}, nil | ||
} | ||
|
||
func (a *ContractExecutionAuthorization) ValidateBasic() error { | ||
// Check for duplicate contracts | ||
contractSet := make(map[string]struct{}) | ||
for _, contract := range a.Contracts { | ||
if _, err := sdk.AccAddressFromBech32(contract); err != nil { | ||
return fmt.Errorf("invalid contract address: %s: %w", contract, err) | ||
} | ||
if _, exists := contractSet[contract]; exists { | ||
return fmt.Errorf("duplicate contract address: %s", contract) | ||
} | ||
contractSet[contract] = struct{}{} | ||
} | ||
|
||
if !a.SpendLimit.IsZero() { | ||
err := a.SpendLimit.Validate() | ||
if err != nil { | ||
return fmt.Errorf("validate spend limit: %s", err) | ||
} | ||
} | ||
|
||
return nil | ||
} |
Oops, something went wrong.