-
Notifications
You must be signed in to change notification settings - Fork 64
chore: sync exchange proto types for per-market margin modes #370
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
base: dev
Are you sure you want to change the base?
Changes from 3 commits
2355015
5e114a3
92f47c2
2673025
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,151 @@ | ||
| package eip712 | ||
|
|
||
| import ( | ||
| "context" | ||
| "encoding/json" | ||
| "errors" | ||
| "fmt" | ||
|
|
||
| "cosmossdk.io/api/cosmos/tx/signing/v1beta1" | ||
| sdkmath "cosmossdk.io/math" | ||
| "cosmossdk.io/x/tx/signing" | ||
| "github.com/cosmos/cosmos-sdk/codec" | ||
| codectypes "github.com/cosmos/cosmos-sdk/codec/types" | ||
| sdk "github.com/cosmos/cosmos-sdk/types" | ||
| "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" | ||
| ethmath "github.com/ethereum/go-ethereum/common/math" | ||
|
|
||
| "github.com/InjectiveLabs/sdk-go/typeddata" | ||
| ) | ||
|
|
||
| // todo: eventually, refactor the whole ante pkg | ||
|
|
||
| // SignModeHandler is used to provide a way to verify EIP712 signatures from within Cosmos SDK. | ||
| // This gives multisig accounts the ability to send transactions with Ledger signatures | ||
| type SignModeHandler struct { | ||
| cdc codec.Codec | ||
| } | ||
|
|
||
| func NewSignModeHandler(cdc codec.Codec) SignModeHandler { | ||
| return SignModeHandler{cdc: cdc} | ||
| } | ||
|
|
||
| func (SignModeHandler) Mode() signingv1beta1.SignMode { | ||
| return signingv1beta1.SignMode_SIGN_MODE_EIP712_V2 | ||
| } | ||
|
|
||
| func (h SignModeHandler) GetSignBytes( | ||
| _ context.Context, | ||
| signerData signing.SignerData, | ||
| txData signing.TxData, | ||
| ) ([]byte, error) { | ||
| msgsJSON := make([]json.RawMessage, len(txData.Body.Messages)) | ||
| for idx, anyPB := range txData.Body.Messages { | ||
| anyCDC := &codectypes.Any{TypeUrl: anyPB.TypeUrl, Value: anyPB.Value} | ||
|
|
||
| var msg sdk.Msg | ||
| if err := h.cdc.UnpackAny(anyCDC, &msg); err != nil { | ||
| return nil, fmt.Errorf("cannot unpack msg at index %d: %w", idx, err) | ||
| } | ||
|
|
||
| msgJSON, err := h.cdc.MarshalInterfaceJSON(msg) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("cannot marshal json at index %d: %w", idx, err) | ||
| } | ||
|
|
||
| msgsJSON[idx] = msgJSON | ||
| } | ||
|
|
||
| bzMsgs, err := json.Marshal(msgsJSON) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("marshal json err: %w", err) | ||
| } | ||
|
|
||
| feeInfo, err := StdFeeFromTxData(txData) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| bzFee, err := json.Marshal(feeInfo) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("marshal fee info failed: %w", err) | ||
| } | ||
|
|
||
| ctx := map[string]any{ | ||
| "account_number": signerData.AccountNumber, | ||
| "sequence": signerData.Sequence, | ||
| "timeout_height": txData.Body.TimeoutHeight, | ||
| "chain_id": signerData.ChainID, | ||
| "memo": txData.Body.Memo, | ||
| "fee": json.RawMessage(bzFee), | ||
| } | ||
|
|
||
| bzTxContext, err := json.Marshal(ctx) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("marshal json err: %w", err) | ||
| } | ||
|
|
||
| chainID := int64(1) // default: injective-1 == 1 (eth) | ||
| if signerData.ChainID != "injective-1" { | ||
| chainID = 11155111 // injective-777 == 11155111 (sepolia) | ||
| } | ||
|
|
||
| domain := typeddata.TypedDataDomain{ | ||
| Name: "Injective Web3", | ||
| Version: "1.0.0", | ||
| ChainId: ethmath.NewHexOrDecimal256(chainID), | ||
| VerifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC", | ||
| Salt: "0", | ||
| } | ||
|
|
||
| td := typeddata.TypedData{ | ||
| Types: typeddata.SignableTypes(), | ||
| PrimaryType: "Tx", | ||
| Domain: domain, | ||
| Message: typeddata.TypedDataMessage{ | ||
| "context": string(bzTxContext), | ||
| "msgs": string(bzMsgs), | ||
| }, | ||
| } | ||
|
|
||
| _, raw, err := typeddata.ComputeTypedDataAndHash(td) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| return raw, nil | ||
| } | ||
|
|
||
| func StdFeeFromTxData(txData signing.TxData) (legacytx.StdFee, error) { | ||
| if txData.AuthInfo == nil || txData.AuthInfo.Fee == nil { | ||
| return legacytx.StdFee{}, errors.New("missing auth info fee") | ||
| } | ||
|
|
||
| amount := make(sdk.Coins, 0, len(txData.AuthInfo.Fee.Amount)) | ||
| for i, c := range txData.AuthInfo.Fee.Amount { | ||
| amt, ok := sdkmath.NewIntFromString(c.Amount) | ||
| if !ok { | ||
| return legacytx.StdFee{}, fmt.Errorf("invalid fee amount at index %d: %q", i, c.Amount) | ||
| } | ||
|
|
||
| coin := sdk.Coin{Denom: c.Denom, Amount: amt} | ||
| if err := coin.Validate(); err != nil { | ||
| return legacytx.StdFee{}, fmt.Errorf("invalid fee coin at index %d: %w", i, err) | ||
| } | ||
|
|
||
| amount = append(amount, coin) | ||
| } | ||
|
|
||
| if !amount.IsValid() { | ||
| return legacytx.StdFee{}, errors.New("invalid fee coins") | ||
| } | ||
|
|
||
| fee := legacytx.StdFee{ | ||
| Amount: amount.Sort(), | ||
| Gas: txData.AuthInfo.Fee.GasLimit, | ||
| Payer: txData.AuthInfo.Fee.Payer, | ||
| // Granter: txData.AuthInfo.Fee.Granter, // eip712_cosmos.go does not include Granter | ||
| } | ||
|
|
||
| return fee, nil | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -123,4 +123,13 @@ var ( | |
| ErrNotCanonicalLiquidationTarget = errors.Register(ModuleName, 114, "targeted market is not the canonical liquidation target") | ||
| ErrMsgDeprecated = errors.Register(ModuleName, 115, "message type is deprecated") | ||
| ErrTooManyCrossMarginSpotOrders = errors.Register(ModuleName, 116, "cross-margin subaccount has reached the per-denom spot order cap") | ||
| ErrSwapDisabled = errors.Register(ModuleName, 117, "spot swap is disabled") | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: #!/bin/bash
set -eu
file="chain/exchange/types/errors.go"
printf '%s\n' '--- changed file context ---'
sed -n '90,150p' "$file"
printf '%s\n' '--- relevant identifiers and codes ---'
rg -n -C 2 'ErrTooManyIsolatedActiveMarkets|ErrSwapDisabled|Register\(ModuleName, (117|125|134)' "$file"
printf '%s\n' '--- focused diff for the file ---'
git diff --unified=12 -- "$file"Repository: InjectiveLabs/sdk-go Length of output: 6800 🏁 Script executed: #!/bin/bash
set -eu
file="chain/exchange/types/errors.go"
printf '%s\n' '--- repository state ---'
git status --short
git rev-parse --show-toplevel
git rev-parse HEAD
printf '%s\n' '--- parent definitions ---'
git show HEAD^:"$file" | sed -n '118,140p'
printf '%s\n' '--- current definitions and imports ---'
sed -n '1,35p' "$file"
sed -n '118,140p' "$file"
printf '%s\n' '--- direct uses of affected errors ---'
rg -n -C 3 'ErrTooManyIsolatedActiveMarkets|ErrSwapDisabled' --glob '!chain/exchange/types/errors.go' .Repository: InjectiveLabs/sdk-go Length of output: 6503 🌐 Web query:
💡 Result: In the Cosmos SDK, custom errors for modules are registered using the cosmossdk.io/errors package [1][2]. This mechanism ensures that errors are globally unique across the blockchain by combining a codespace (typically the module name) and a numeric error code [1]. Registration and Usage Errors should be defined and registered during the application startup phase [3]. You can register a new error using the Register function [3]: var ErrCustomError = errors.Register(ModuleName, 2, "description of the error") Restrictions on error codes include: 1. Must be greater than one (a value of one is reserved for internal errors) [1]. 2. Must be unique within the module [1]. Attempting to register a duplicate code within the same codespace will trigger a panic unless suppression is enabled via environment variables [3][4]. ABCI Integration The cosmossdk.io/errors package provides built-in functionality to bridge custom errors with ABCI (Application BlockChain Interface) requirements [1][4]. - ABCI Mapping: When an error is returned during transaction execution (CheckTx or DeliverTx), the SDK can extract the corresponding ABCI information, such as the codespace and the error code, using the ABCIInfo function [1][4]. - ABCIError: The ABCIError function is used to map an error code/log back to a registered canonical error, allowing for use cases like.Is checks on errors received from external APIs [3]. - Response Handling: The errors package provides auxiliary functions (often utilized by the SDK framework itself) to automatically convert registered errors into proper ABCI response codes for the network [1]. While registration provides the base error, you can use errors.Wrap to add execution context or stack traces to an error while preserving the underlying registered error type for later identification [1][3][4]. Citations:
Preserve error code 117 for
🤖 Prompt for AI Agents |
||
| ErrInvalidSwapRoute = errors.Register(ModuleName, 118, "invalid swap route") | ||
| ErrSwapDeadlineExceeded = errors.Register(ModuleName, 119, "swap deadline exceeded") | ||
| ErrSwapMinOutputNotMet = errors.Register(ModuleName, 120, "swap output below minimum") | ||
| ErrPoolFundedCloseCannotRest = errors.Register(ModuleName, 121, "pool-funded cross-margin close cannot rest on the orderbook") | ||
| ErrRFQPartialInsuranceNotLastResort = errors.Register(ModuleName, 122, "RFQ partial may draw insurance only when the remaining pool positions hold no positive mark equity") | ||
| ErrRFQInactiveSettlementNotLastResort = errors.Register(ModuleName, 123, "inactive cross-margin legs may be scheduled for settlement only when the active pool positions hold no positive mark equity") | ||
| ErrRFQPartialBelowMarkWhileInsolvent = errors.Register(ModuleName, 124, "a partial RFQ slice may pay below the exact-mark payout only while the pool has no mark shortfall after it") | ||
| ErrTooManyIsolatedActiveMarkets = errors.Register(ModuleName, 125, "cross-exposed subaccount has reached the per-denom isolated active derivative market cap") | ||
| ) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
Repository: InjectiveLabs/sdk-go
Length of output: 31485
🏁 Script executed:
Repository: InjectiveLabs/sdk-go
Length of output: 31447
🌐 Web query:
github InjectiveLabs sdk-go typeddata ComputeTypedDataAndHash typed_data.go💡 Result:
In the Injective Labs sdk-go repository, ComputeTypedDataAndHash is a utility function used to compute the EIP-712 typed data hash [1]. It is frequently utilized in the context of signing transactions and verifying EIP-712 signatures [1]. While you mentioned typed_data.go, the function ComputeTypedDataAndHash is typically imported from the typeddata package within the Injective SDK environment [1]. It is commonly invoked after packing transaction data into an EIP-712 wrapper object [1]. The function returns the signature hash (sigHash) and potentially other values (such as the data hash or errors), which are then used for signature recovery or verification against a public key [1]. In practice, this function is central to the Ante handlers and signing logic in Injective's Cosmos-based chain integration, ensuring that typed data structures are correctly hashed according to EIP-712 standards before being signed or verified by secp256k1 keys [1][2]. Developers working with the SDK usually interact with this by constructing a typeddata.TypedData object and passing it to this function to obtain the hash that requires a digital signature [1].
Citations:
🏁 Script executed:
Repository: InjectiveLabs/sdk-go
Length of output: 50376
Return the EIP-712 digest instead of the raw preimage.
GetSignBytescalls the repository-localtypeddata.ComputeTypedDataAndHashand returns its preimage value. EIP-712 signing requires the 32-byte digest. Return the digest value instead.Proposed fix
📝 Committable suggestion
🤖 Prompt for AI Agents