Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
ccd24ed
encoding: register cosmos/evm crypto types so EIP-712 pubkeys decode
trevormil May 6, 2026
9bac8b6
app: initialize cosmos/evm EIP-712 verifier codec singletons on app boot
trevormil May 6, 2026
ccddc31
modules: register tokenization + managersplitter amino types on app c…
trevormil May 6, 2026
c1dea3c
tokenization: split RegisterAminoConcretes from chain-wide RegisterCodec
trevormil May 6, 2026
9db7db6
proto: nullable=true on all nested struct fields — fixes EIP-712 veri…
trevormil May 6, 2026
0f47c65
encoding: register cosmos/evm ethsecp256k1 PubKey on legacy amino codec
trevormil May 6, 2026
79d6ccc
keeper: normalize nil pointer fields on storage load to preserve pre-…
trevormil May 6, 2026
af58ec8
proto: nullable=true on gamm/poolmanager unannotated nested struct fi…
trevormil May 6, 2026
46577c6
types: IsBasicallyEmpty for "is set" semantic checks after normalize-…
trevormil May 6, 2026
a72a6f4
keeper: normalize collection on freshly-built/loaded entry into Unive…
trevormil May 6, 2026
28a7763
types: IsBasicallyEmpty deep-zero check (size-based was over-firing p…
trevormil May 6, 2026
76f0f39
keeper: NormalizeNilPointers also recovers uninitialized sdkmath.Uint…
trevormil May 6, 2026
30a6e9f
keeper: scope NormalizeNilPointers to Uint init only — keep nil-vs-em…
trevormil May 6, 2026
dd446be
keeper: nil-guard OrderCalculationMethod access in HandleMerkleChalle…
trevormil May 6, 2026
f210595
keeper: nil-guard OrderCalculationMethod / MaxNumTransfers chain access
trevormil May 6, 2026
f738c53
test: fix TestGenesis_ValidTokenIdsPreserved + TestGetKnownGoodCollec…
trevormil May 6, 2026
0b8a607
keeper: use nil-safe GetCollectionPermissions().GetX() accessors
trevormil May 6, 2026
9581a98
keeper+types: ProtoEqualNullableAware for change-detection comparators
trevormil May 6, 2026
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
10 changes: 10 additions & 0 deletions app/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/ethereum/go-ethereum/common"

eip712 "github.com/cosmos/evm/ethereum/eip712"
precompiletypes "github.com/cosmos/evm/precompiles/types"
erc20 "github.com/cosmos/evm/x/erc20"
erc20keeper "github.com/cosmos/evm/x/erc20/keeper"
Expand Down Expand Up @@ -82,6 +83,15 @@ func (app *App) registerEVMModules(appOpts servertypes.AppOptions) error {
return err
}

// Initialize the cosmos/evm EIP-712 verifier's package-level codec/chain-id
// singletons. Without this call, every `verifySignatureAsEIP712` call inside
// `ethsecp256k1.PubKey.VerifySignature` errors out at `validateCodecInit`
// and silently returns false, falling back to standard ECDSA verification of
// raw cosmos sign bytes — which never matches an EIP-712 signature.
// Symptom: "signature verification failed; ... unauthorized" on every
// EIP-712-signed broadcast.
eip712.SetEncodingConfig(app.legacyAmino, app.interfaceRegistry, evmChainIDUint64)

// Get all non-transient KV store keys for the EVM keeper
// The EVM keeper needs access to all stores so precompiles can access any store they need
// (e.g., account store, bank store, tokenization store, etc.)
Expand Down
27 changes: 26 additions & 1 deletion encoding/codec/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
solana "github.com/bitbadges/bitbadgeschain/chain-handlers/solana/utils"

// EVM module types - required for JSON-RPC tx decoding
evmcryptocodec "github.com/cosmos/evm/crypto/codec"
evmethsecp256k1 "github.com/cosmos/evm/crypto/ethsecp256k1"
evmtypes "github.com/cosmos/evm/x/vm/types"
erc20types "github.com/cosmos/evm/x/erc20/types"
feemarkettypes "github.com/cosmos/evm/x/feemarket/types"
Expand All @@ -25,7 +27,25 @@ import (
// RegisterLegacyAminoCodec registers Interfaces from types, crypto, and SDK std.
func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
ethereumcodec.RegisterCrypto(cdc)
// Note: evmtypes amino registration is handled by the EVM module itself

// Register cosmos/evm's `ethsecp256k1.PubKey` / `PrivKey` on the legacy
// amino codec under their canonical amino names. Required because
// `ConsumeTxSizeGasDecorator` (and any other ante decorator that
// invokes `LegacyAmino.MustMarshal` on a tx for size estimation)
// fails with "Cannot encode unregistered concrete type
// ethsecp256k1.PubKey" if the SignerInfo's pubkey type isn't
// registered as an amino concrete. The proto interface registration
// in `RegisterInterfaces` covers tx decode, but the gas-size path
// goes through legacy amino specifically.
//
// We register inline rather than calling `evmcryptocodec.RegisterCrypto`
// because that helper also re-runs `cryptocodec.RegisterCrypto(cdc)` —
// already invoked by `ethereumcodec.RegisterCrypto` above — which
// double-registers the cosmos-sdk standard crypto types and panics
// with "TypeInfo already exists for types.PubKey".
cdc.RegisterConcrete(&evmethsecp256k1.PubKey{}, "cosmos-evm/PubKeyEthSecp256k1", nil)
cdc.RegisterConcrete(&evmethsecp256k1.PrivKey{}, "cosmos-evm/PrivKeyEthSecp256k1", nil)
_ = evmcryptocodec.RegisterCrypto // imported above for grep-ability; kept registered manually to avoid duplicate cryptocodec call
}

// RegisterInterfaces registers Interfaces from types, crypto, and SDK std.
Expand All @@ -35,6 +55,11 @@ func RegisterInterfaces(interfaceRegistry codectypes.InterfaceRegistry) {
solana.RegisterInterfaces(interfaceRegistry)
bitcoin.RegisterInterfaces(interfaceRegistry)

// cosmos/evm crypto types — registers `cosmos.evm.crypto.v1.ethsecp256k1.PubKey`
// on the InterfaceRegistry so the chain can decode EIP-712-signed txs whose
// SignerInfo wraps the pubkey under that canonical type URL.
evmcryptocodec.RegisterInterfaces(interfaceRegistry)

// EVM module types - required for JSON-RPC tx decoding (MsgEthereumTx, etc.)
evmtypes.RegisterInterfaces(interfaceRegistry)
erc20types.RegisterInterfaces(interfaceRegistry)
Expand Down
2 changes: 1 addition & 1 deletion proto/gamm/poolmodels/balancer/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,5 @@ message MsgCreateBalancerPoolResponse {

// Used for WASM bindings and JSON parsing
message BalancerCustomMsgType {
MsgCreateBalancerPool createBalancerPoolMsg = 1;
MsgCreateBalancerPool createBalancerPoolMsg = 1 [(gogoproto.nullable) = true];
}
20 changes: 10 additions & 10 deletions proto/gamm/v1beta1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -346,14 +346,14 @@ message QueryTotalLiquidityResponse {

// Used for WASM bindings and JSON parsing
message GammCustomQueryType {
QueryPoolRequest queryPool = 1;
QueryPoolsRequest queryPools = 2;
QueryPoolTypeRequest queryPoolType = 3;
QueryPoolsWithFilterRequest queryPoolsWithFilter = 4;
QueryNumPoolsRequest queryNumPools = 5;
QueryTotalLiquidityRequest queryTotalLiquidity = 6;
QueryTotalPoolLiquidityRequest queryTotalPoolLiquidity = 7;
QuerySpotPriceRequest querySpotPrice = 8;
QueryPoolParamsRequest queryPoolParams = 9;
QueryTotalSharesRequest queryTotalShares = 10;
QueryPoolRequest queryPool = 1 [(gogoproto.nullable) = true];
QueryPoolsRequest queryPools = 2 [(gogoproto.nullable) = true];
QueryPoolTypeRequest queryPoolType = 3 [(gogoproto.nullable) = true];
QueryPoolsWithFilterRequest queryPoolsWithFilter = 4 [(gogoproto.nullable) = true];
QueryNumPoolsRequest queryNumPools = 5 [(gogoproto.nullable) = true];
QueryTotalLiquidityRequest queryTotalLiquidity = 6 [(gogoproto.nullable) = true];
QueryTotalPoolLiquidityRequest queryTotalPoolLiquidity = 7 [(gogoproto.nullable) = true];
QuerySpotPriceRequest querySpotPrice = 8 [(gogoproto.nullable) = true];
QueryPoolParamsRequest queryPoolParams = 9 [(gogoproto.nullable) = true];
QueryTotalSharesRequest queryTotalShares = 10 [(gogoproto.nullable) = true];
}
18 changes: 9 additions & 9 deletions proto/gamm/v1beta1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -325,13 +325,13 @@ message MsgExitSwapExternAmountOutResponse {

// Used for WASM bindings and JSON parsing
message GammCustomMsgType {
MsgJoinPool joinPoolMsg = 1;
MsgExitPool exitPoolMsg = 2;
MsgSwapExactAmountIn swapExactAmountInMsg = 3;
MsgSwapExactAmountOut swapExactAmountOutMsg = 4;
MsgJoinSwapExternAmountIn joinSwapExternAmountInMsg = 5;
MsgJoinSwapShareAmountOut joinSwapShareAmountOutMsg = 6;
MsgExitSwapShareAmountIn exitSwapShareAmountInMsg = 7;
MsgExitSwapExternAmountOut exitSwapExternAmountOutMsg = 8;
MsgSwapExactAmountInWithIBCTransfer swapExactAmountInWithIBCTransferMsg = 9;
MsgJoinPool joinPoolMsg = 1 [(gogoproto.nullable) = true];
MsgExitPool exitPoolMsg = 2 [(gogoproto.nullable) = true];
MsgSwapExactAmountIn swapExactAmountInMsg = 3 [(gogoproto.nullable) = true];
MsgSwapExactAmountOut swapExactAmountOutMsg = 4 [(gogoproto.nullable) = true];
MsgJoinSwapExternAmountIn joinSwapExternAmountInMsg = 5 [(gogoproto.nullable) = true];
MsgJoinSwapShareAmountOut joinSwapShareAmountOutMsg = 6 [(gogoproto.nullable) = true];
MsgExitSwapShareAmountIn exitSwapShareAmountInMsg = 7 [(gogoproto.nullable) = true];
MsgExitSwapExternAmountOut exitSwapExternAmountOutMsg = 8 [(gogoproto.nullable) = true];
MsgSwapExactAmountInWithIBCTransfer swapExactAmountInWithIBCTransferMsg = 9 [(gogoproto.nullable) = true];
}
22 changes: 11 additions & 11 deletions proto/managersplitter/permissions.proto
Original file line number Diff line number Diff line change
Expand Up @@ -16,36 +16,36 @@ message PermissionCriteria {
// but maps each permission to criteria for execution.
message ManagerSplitterPermissions {
// Permissions related to deleting the collection.
PermissionCriteria canDeleteCollection = 1;
PermissionCriteria canDeleteCollection = 1 [(gogoproto.nullable) = true];

// Permissions related to archiving the collection.
PermissionCriteria canArchiveCollection = 2;
PermissionCriteria canArchiveCollection = 2 [(gogoproto.nullable) = true];

// Permissions related to updating standards for the collection.
PermissionCriteria canUpdateStandards = 3;
PermissionCriteria canUpdateStandards = 3 [(gogoproto.nullable) = true];

// Permissions related to updating custom data for the collection.
PermissionCriteria canUpdateCustomData = 4;
PermissionCriteria canUpdateCustomData = 4 [(gogoproto.nullable) = true];

// Permissions related to updating the collection's manager.
PermissionCriteria canUpdateManager = 5;
PermissionCriteria canUpdateManager = 5 [(gogoproto.nullable) = true];

// Permissions related to updating the metadata of the collection.
PermissionCriteria canUpdateCollectionMetadata = 6;
PermissionCriteria canUpdateCollectionMetadata = 6 [(gogoproto.nullable) = true];

// Permissions related to creating more tokens for the collection.
PermissionCriteria canUpdateValidTokenIds = 7;
PermissionCriteria canUpdateValidTokenIds = 7 [(gogoproto.nullable) = true];

// Permissions related to updating token metadata for specific tokens.
PermissionCriteria canUpdateTokenMetadata = 8;
PermissionCriteria canUpdateTokenMetadata = 8 [(gogoproto.nullable) = true];

// Permissions related to updating collection approvals.
PermissionCriteria canUpdateCollectionApprovals = 9;
PermissionCriteria canUpdateCollectionApprovals = 9 [(gogoproto.nullable) = true];

// Permissions related to adding more alias paths to the collection.
PermissionCriteria canAddMoreAliasPaths = 10;
PermissionCriteria canAddMoreAliasPaths = 10 [(gogoproto.nullable) = true];

// Permissions related to adding more cosmos coin wrapper paths to the collection.
PermissionCriteria canAddMoreCosmosCoinWrapperPaths = 11;
PermissionCriteria canAddMoreCosmosCoinWrapperPaths = 11 [(gogoproto.nullable) = true];
}

2 changes: 1 addition & 1 deletion proto/managersplitter/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ message QueryGetManagerSplitterRequest {

// QueryGetManagerSplitterResponse is response type for the Query/ManagerSplitter RPC method.
message QueryGetManagerSplitterResponse {
ManagerSplitter managerSplitter = 1;
ManagerSplitter managerSplitter = 1 [(gogoproto.nullable) = true];
}

// QueryAllManagerSplittersRequest is request type for the Query/AllManagerSplitters RPC method.
Expand Down
14 changes: 7 additions & 7 deletions proto/managersplitter/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ message ManagerSplitter {
string admin = 2;

// Permissions mapping each CollectionPermission field to execution criteria.
ManagerSplitterPermissions permissions = 3;
ManagerSplitterPermissions permissions = 3 [(gogoproto.nullable) = true];
}

// MsgCreateManagerSplitter creates a new manager splitter entity.
Expand All @@ -66,7 +66,7 @@ message MsgCreateManagerSplitter {
string admin = 1;

// Permissions mapping each CollectionPermission field to execution criteria.
ManagerSplitterPermissions permissions = 2;
ManagerSplitterPermissions permissions = 2 [(gogoproto.nullable) = true];
}

// MsgCreateManagerSplitterResponse is the response to MsgCreateManagerSplitter.
Expand All @@ -87,7 +87,7 @@ message MsgUpdateManagerSplitter {
string address = 2;

// New permissions to set.
ManagerSplitterPermissions permissions = 3;
ManagerSplitterPermissions permissions = 3 [(gogoproto.nullable) = true];
}

// MsgUpdateManagerSplitterResponse is the response to MsgUpdateManagerSplitter.
Expand Down Expand Up @@ -132,9 +132,9 @@ message MsgExecuteUniversalUpdateCollectionResponse {

// Used for WASM bindings and JSON parsing
message ManagersplitterCustomMsgType {
MsgCreateManagerSplitter createManagerSplitterMsg = 1;
MsgUpdateManagerSplitter updateManagerSplitterMsg = 2;
MsgDeleteManagerSplitter deleteManagerSplitterMsg = 3;
MsgExecuteUniversalUpdateCollection executeUniversalUpdateCollectionMsg = 4;
MsgCreateManagerSplitter createManagerSplitterMsg = 1 [(gogoproto.nullable) = true];
MsgUpdateManagerSplitter updateManagerSplitterMsg = 2 [(gogoproto.nullable) = true];
MsgDeleteManagerSplitter deleteManagerSplitterMsg = 3 [(gogoproto.nullable) = true];
MsgExecuteUniversalUpdateCollection executeUniversalUpdateCollectionMsg = 4 [(gogoproto.nullable) = true];
}

4 changes: 2 additions & 2 deletions proto/tokenization/approval_conditions.proto
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ message MustOwnTokens {
string collectionId = 1 [(gogoproto.customtype) = "Uint", (gogoproto.nullable) = false];

// The range of amounts the user must own (min to max).
UintRange amountRange = 2;
UintRange amountRange = 2 [(gogoproto.nullable) = true];

// The time ranges during which the user must own the tokens.
repeated UintRange ownershipTimes = 3;
Expand Down Expand Up @@ -116,7 +116,7 @@ message UserApprovalSettings {
// If true, user-level approvals cannot trigger coinTransfers at all for transfers matched by this collection approval.
bool disableUserCoinTransfers = 2;
// User-level royalties to enforce for transfers matched by this collection approval.
UserRoyalties userRoyalties = 3;
UserRoyalties userRoyalties = 3 [(gogoproto.nullable) = true];
}

// UserRoyalties defines the royalties for a user.
Expand Down
Loading