From bd99fb431633a6321d3f522999de4052acc3da29 Mon Sep 17 00:00:00 2001 From: Bojan Angjelkoski Date: Sat, 30 Nov 2024 00:25:35 +0100 Subject: [PATCH] fix: eip712v2 for authz authorizations --- .../indexer/grpc/IndexerGrpcWeb3GwApi.ts | 2 +- .../msgs/MsgGrantWithAuthorization.spec.ts | 155 ++++-------------- .../authz/msgs/MsgGrantWithAuthorization.ts | 4 +- .../ContractExecutionAuthorization.ts | 4 +- .../exchange/msgs/MsgCancelSpotOrder.spec.ts | 34 ++-- packages/sdk-ts/src/core/tx/eip712/eip712.ts | 1 - packages/sdk-ts/src/core/tx/eip712/maps.ts | 14 +- packages/sdk-ts/src/core/tx/eip712/utils.ts | 4 +- packages/test-utils/src/mocks/index.ts | 42 +++-- packages/test-utils/src/msgs.ts | 100 +++++++++-- 10 files changed, 181 insertions(+), 179 deletions(-) diff --git a/packages/sdk-ts/src/client/indexer/grpc/IndexerGrpcWeb3GwApi.ts b/packages/sdk-ts/src/client/indexer/grpc/IndexerGrpcWeb3GwApi.ts index 44771ad2d..12fac3889 100644 --- a/packages/sdk-ts/src/client/indexer/grpc/IndexerGrpcWeb3GwApi.ts +++ b/packages/sdk-ts/src/client/indexer/grpc/IndexerGrpcWeb3GwApi.ts @@ -31,7 +31,7 @@ export class IndexerGrpcWeb3GwApi extends IndexerGrpcTransactionApi { memo, sequence, accountNumber, - estimateGas = true, + estimateGas = false, gasLimit = DEFAULT_GAS_LIMIT, feeDenom = DEFAULT_BRIDGE_FEE_DENOM, feePrice = DEFAULT_BRIDGE_FEE_PRICE, diff --git a/packages/sdk-ts/src/core/modules/authz/msgs/MsgGrantWithAuthorization.spec.ts b/packages/sdk-ts/src/core/modules/authz/msgs/MsgGrantWithAuthorization.spec.ts index 755d0cd8f..178234d1b 100644 --- a/packages/sdk-ts/src/core/modules/authz/msgs/MsgGrantWithAuthorization.spec.ts +++ b/packages/sdk-ts/src/core/modules/authz/msgs/MsgGrantWithAuthorization.spec.ts @@ -1,7 +1,9 @@ import MsgGrantWithAuthorization from './MsgGrantWithAuthorization.js' -import { mockFactory } from '@injectivelabs/test-utils' +import { mockFactory, prepareEip712 } from '@injectivelabs/test-utils' import GenericAuthorization from './authorizations/GenericAuthorization.js' import ContractExecutionAuthorization from './authorizations/ContractExecutionAuthorization.js' +import { getEip712TypedData, getEip712TypedDataV2 } from '../../../tx/index.js' +import { IndexerGrpcWeb3GwApi } from './../../../../client/indexer/index.js' const { injectiveAddress, injectiveAddress2 } = mockFactory @@ -39,14 +41,6 @@ describe('MsgGrantWithAuthorization', () => { expiration: new Date(params.expiration! * 1000), }, } - const protoParamsGenericAuthorizationWeb3 = { - grantee: params.grantee, - granter: params.granter, - grant: { - authorization: params.authorization.toWeb3(), - expiration: new Date(params.expiration! * 1000), - }, - } const message = MsgGrantWithAuthorization.fromJSON(params) it('generates proper proto', () => { @@ -74,55 +68,6 @@ describe('MsgGrantWithAuthorization', () => { value: protoParamsGenericAuthorizationAmino, }) }) - - it('generates proper Eip712 types', () => { - const eip712Types = message.toEip712Types() - - expect(Object.fromEntries(eip712Types)).toStrictEqual({ - TypeGrant: [ - { name: 'authorization', type: 'TypeGrantAuthorization' }, - { name: 'expiration', type: 'string' }, - ], - TypeGrantAuthorization: [ - { name: 'type', type: 'string' }, - { name: 'value', type: 'TypeGrantAuthorizationValue' }, - ], - TypeGrantAuthorizationValue: [{ name: 'msg', type: 'string' }], - MsgValue: [ - { name: 'granter', type: 'string' }, - { name: 'grantee', type: 'string' }, - { name: 'grant', type: 'TypeGrant' }, - ], - }) - }) - - it('generates proper Eip712 values', () => { - const eip712 = message.toEip712() - - expect(eip712).toStrictEqual({ - type: 'cosmos-sdk/MsgGrant', - value: { - granter: 'inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku', - grantee: 'inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku', - grant: { - authorization: { - type: 'cosmos-sdk/GenericAuthorization', - value: { msg: '/cosmos.bank.v1beta1.MsgSend' }, - }, - expiration: '2027-01-15T08:00:00Z', - }, - }, - }) - }) - - it('generates proper web3', () => { - const web3 = message.toWeb3() - - expect(web3).toStrictEqual({ - '@type': protoType, - ...protoParamsGenericAuthorizationWeb3, - }) - }) }) describe('ContractExecutionAuthorization', () => { @@ -164,14 +109,6 @@ describe('MsgGrantWithAuthorization', () => { expiration: new Date(params.expiration! * 1000), }, } - const protoParamsContractExecutionAuthorizationWeb3 = { - grantee: params.grantee, - granter: params.granter, - grant: { - authorization: params.authorization.toWeb3(), - expiration: new Date(params.expiration! * 1000), - }, - } const message = MsgGrantWithAuthorization.fromJSON(params) it('generates proper proto', () => { @@ -200,73 +137,37 @@ describe('MsgGrantWithAuthorization', () => { }) }) - it('generates proper Eip712 types', () => { - const eip712Types = message.toEip712Types() - - expect(Object.fromEntries(eip712Types)).toStrictEqual({ - TypeGrant: [ - { name: 'authorization', type: 'TypeGrantAuthorization' }, - { name: 'expiration', type: 'string' }, - ], - TypeGrantAuthorization: [ - { name: 'type', type: 'string' }, - { name: 'grants', type: 'TypeGrantAuthorizationGrants[]' }, - ], - TypeGrantAuthorizationGrants: [ - { name: 'contract', type: 'string' }, - { name: 'limit', type: 'TypeGrantAuthorizationGrantsLimit' }, - { name: 'filter', type: 'TypeGrantAuthorizationGrantsFilter' }, - ], - TypeGrantAuthorizationGrantsLimit: [ - { name: 'type', type: 'string' }, - { name: 'remaining', type: 'uint64' }, - ], - TypeGrantAuthorizationGrantsFilter: [ - { name: 'type', type: 'string' }, - { name: 'keys', type: 'string[]' }, - ], - MsgValue: [ - { name: 'granter', type: 'string' }, - { name: 'grantee', type: 'string' }, - { name: 'grant', type: 'TypeGrant' }, - ], + describe('generates proper EIP712 compared to the Web3Gw (chain)', () => { + const { endpoints, eip712Args, prepareEip712Request } = prepareEip712({ + sequence: 0, + accountNumber: 3, + messages: message, }) - }) - it('generates proper Eip712 values', () => { - const eip712 = message.toEip712() + test('EIP712 v1', async () => { + const eip712TypedData = getEip712TypedData(eip712Args) - expect(eip712).toStrictEqual({ - type: 'cosmos-sdk/MsgGrant', - value: { - granter: 'inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku', - grantee: 'inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku', - grant: { - authorization: { - type: 'wasm/ContractExecutionAuthorization', - grants: [ - { - contract: 'inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku', - limit: { type: 'wasm/MaxCallsLimit', remaining: 100 }, - filter: { - type: 'wasm/AcceptedMessageKeysFilter', - keys: ['set_routes'], - }, - }, - ], - }, - expiration: '2027-01-15T08:00:00Z', - }, - }, + const txResponse = await new IndexerGrpcWeb3GwApi( + endpoints.indexer, + ).prepareEip712Request({ + ...prepareEip712Request, + eip712Version: 'v1', + }) + + expect(eip712TypedData).toStrictEqual(JSON.parse(txResponse.data)) }) - }) - it('generates proper web3', () => { - const web3 = message.toWeb3() + test('EIP712 v2', async () => { + const eip712TypedData = getEip712TypedDataV2(eip712Args) - expect(web3).toStrictEqual({ - '@type': protoType, - ...protoParamsContractExecutionAuthorizationWeb3, + const txResponse = await new IndexerGrpcWeb3GwApi( + endpoints.indexer, + ).prepareEip712Request({ + ...prepareEip712Request, + eip712Version: 'v2', + }) + + expect(eip712TypedData).toStrictEqual(JSON.parse(txResponse.data)) }) }) }) diff --git a/packages/sdk-ts/src/core/modules/authz/msgs/MsgGrantWithAuthorization.ts b/packages/sdk-ts/src/core/modules/authz/msgs/MsgGrantWithAuthorization.ts index b162cfe75..d866f12a0 100644 --- a/packages/sdk-ts/src/core/modules/authz/msgs/MsgGrantWithAuthorization.ts +++ b/packages/sdk-ts/src/core/modules/authz/msgs/MsgGrantWithAuthorization.ts @@ -105,7 +105,9 @@ export default class MsgGrantWithAuthorization extends MsgBase< grantee: amino.value.grantee, grant: { authorization: params.authorization.toWeb3(), - expiration: new Date(Number(timestamp.seconds) * 1000), + expiration: + new Date(Number(timestamp.seconds) * 1000).toJSON().slice(0, -5) + + 'Z', }, } diff --git a/packages/sdk-ts/src/core/modules/authz/msgs/authorizations/ContractExecutionAuthorization.ts b/packages/sdk-ts/src/core/modules/authz/msgs/authorizations/ContractExecutionAuthorization.ts index 11c577803..ae543b835 100644 --- a/packages/sdk-ts/src/core/modules/authz/msgs/authorizations/ContractExecutionAuthorization.ts +++ b/packages/sdk-ts/src/core/modules/authz/msgs/authorizations/ContractExecutionAuthorization.ts @@ -101,7 +101,7 @@ export default class ContractExecutionAuthorization extends BaseAuthorization< if (params.limit) { grant.limit = { type: 'wasm/MaxCallsLimit', - remaining: params.limit.maxCalls, + remaining: params.limit.maxCalls.toString(), } } @@ -128,7 +128,7 @@ export default class ContractExecutionAuthorization extends BaseAuthorization< if (params.limit) { grant.limit = { '@type': '/cosmwasm.wasm.v1.MaxCallsLimit', - remaining: params.limit.maxCalls, + remaining: params.limit.maxCalls.toString(), } } diff --git a/packages/sdk-ts/src/core/modules/exchange/msgs/MsgCancelSpotOrder.spec.ts b/packages/sdk-ts/src/core/modules/exchange/msgs/MsgCancelSpotOrder.spec.ts index cc7791faf..8e27a661e 100644 --- a/packages/sdk-ts/src/core/modules/exchange/msgs/MsgCancelSpotOrder.spec.ts +++ b/packages/sdk-ts/src/core/modules/exchange/msgs/MsgCancelSpotOrder.spec.ts @@ -83,35 +83,33 @@ describe('MsgCancelSpotOrder', () => { }) describe('generates proper EIP712 compared to the Web3Gw (chain)', () => { - const { endpoints, eip712Args, prepareEip712Request } = - prepareEip712(message) + const { endpoints, eip712Args, prepareEip712Request } = prepareEip712({ + sequence: 0, + accountNumber: 3, + messages: message, + }) it('EIP712 v1', async () => { const eip712TypedData = getEip712TypedData(eip712Args) - try { - const txResponse = await new IndexerGrpcWeb3GwApi( - endpoints.indexer, - ).prepareEip712Request({ ...prepareEip712Request, eip712Version: 'v1' }) + const txResponse = await new IndexerGrpcWeb3GwApi( + endpoints.indexer, + ).prepareEip712Request({ + ...prepareEip712Request, + eip712Version: 'v1', + }) - expect(JSON.parse(txResponse.data)).toStrictEqual(eip712TypedData) - } catch (e: any) { - // throw silently now - } + expect(eip712TypedData).toStrictEqual(JSON.parse(txResponse.data)) }) it('EIP712 v2', async () => { const eip712TypedData = getEip712TypedDataV2(eip712Args) - try { - const txResponse = await new IndexerGrpcWeb3GwApi( - endpoints.indexer, - ).prepareEip712Request({ ...prepareEip712Request, eip712Version: 'v2' }) + const txResponse = await new IndexerGrpcWeb3GwApi( + endpoints.indexer, + ).prepareEip712Request({ ...prepareEip712Request, eip712Version: 'v2' }) - expect(JSON.parse(txResponse.data)).toStrictEqual(eip712TypedData) - } catch (e: any) { - // throw silently now - } + expect(eip712TypedData).toStrictEqual(JSON.parse(txResponse.data)) }) }) }) diff --git a/packages/sdk-ts/src/core/tx/eip712/eip712.ts b/packages/sdk-ts/src/core/tx/eip712/eip712.ts index 78bb33e08..22608d9de 100644 --- a/packages/sdk-ts/src/core/tx/eip712/eip712.ts +++ b/packages/sdk-ts/src/core/tx/eip712/eip712.ts @@ -38,7 +38,6 @@ export const getEip712TypedData = ({ fee, types: typesWithMessageTypes, }) - return { ...typesWithFeePayer, primaryType: 'Tx', diff --git a/packages/sdk-ts/src/core/tx/eip712/maps.ts b/packages/sdk-ts/src/core/tx/eip712/maps.ts index c634083e9..097d33659 100644 --- a/packages/sdk-ts/src/core/tx/eip712/maps.ts +++ b/packages/sdk-ts/src/core/tx/eip712/maps.ts @@ -235,6 +235,7 @@ export const mapValuesToProperValueType = >( ): T => { const numberToStringKeys = [ 'proposal_id', + 'remaining', 'round', 'oracle_scale_factor', 'timeout_timestamp', @@ -256,6 +257,9 @@ export const mapValuesToProperValueType = >( const nullableStringsTypeMaps = { 'wasmx/MsgExecuteContractCompat': ['funds'], } + // const dateTypesMap = { + // 'cosmos-sdk/MsgGrant': ['expiration'], + // } const nullableStrings = ['uri', 'uri_hash'] @@ -301,20 +305,25 @@ export const mapValuesToProperValueType = >( [key]: value.toJSON().split('.')[0] + 'Z', } } + if (Array.isArray(value)) { return { ...result, [key]: value.every((i) => typeof i === 'string') ? value : value.map((item) => - mapValuesToProperValueType(item as Record), + mapValuesToProperValueType( + item as Record, + ), ), } } return { ...result, - [key]: mapValuesToProperValueType(value as Record), + [key]: mapValuesToProperValueType( + value as Record, + ), } } @@ -609,6 +618,7 @@ export const protoTypeToAminoType = (type: string): string => { return 'injective/tokenfactory/burn' case 'injective.tokenfactory.v1beta1.MsgSetDenomMetadata': return 'injective/tokenfactory/set-denom-metadata' + // Auth case 'cosmos.auth.v1beta1.MsgUpdateParams': return 'cosmos-sdk/x/auth/MsgUpdateParams' diff --git a/packages/sdk-ts/src/core/tx/eip712/utils.ts b/packages/sdk-ts/src/core/tx/eip712/utils.ts index 2d86e5ade..595a395b0 100644 --- a/packages/sdk-ts/src/core/tx/eip712/utils.ts +++ b/packages/sdk-ts/src/core/tx/eip712/utils.ts @@ -106,7 +106,7 @@ export const getEip712Fee = ( return { fee: { - feePayer: feePayer, + ...(feePayer && { feePayer }), gas, amount, }, @@ -152,7 +152,7 @@ export const getEip712FeeV2 = ( fee: { amount, gas, - payer: payer, + ...(payer && { payer }), }, } } diff --git a/packages/test-utils/src/mocks/index.ts b/packages/test-utils/src/mocks/index.ts index 101fe152a..52f3d3bac 100644 --- a/packages/test-utils/src/mocks/index.ts +++ b/packages/test-utils/src/mocks/index.ts @@ -95,22 +95,36 @@ export const mockFactory = { orderHash2, MAX_TIMEOUT_HEIGHT, - eip712Tx: { + eip712Tx: ({ + chainId = ChainId.Devnet, + ethereumChainId = EthereumChainId.Sepolia, + accountNumber = 1, + sequence = 0, + timeoutHeight = 999999999, + memo = '', + }: { + chainId?: ChainId + ethereumChainId?: EthereumChainId + accountNumber?: number + sequence?: number + timeoutHeight?: number + memo?: string + }) => ({ tx: { - chainId: ChainId.Devnet, - ethereumChainId: EthereumChainId.Sepolia, - accountNumber: '1', - sequence: '1', - timeoutHeight: '9999', - memo: '', + memo, + chainId, + sequence, + ethereumChainId, + accountNumber, + timeoutHeight, }, eip712: { - chainId: ChainId.Devnet, - ethereumChainId: EthereumChainId.Sepolia, - accountNumber: 1, - sequence: 1, - timeoutHeight: 9999, - memo: '', + memo, + chainId, + sequence, + accountNumber, + ethereumChainId, + timeoutHeight, }, - }, + }), } diff --git a/packages/test-utils/src/msgs.ts b/packages/test-utils/src/msgs.ts index a9e24ceb9..555e0e0f7 100644 --- a/packages/test-utils/src/msgs.ts +++ b/packages/test-utils/src/msgs.ts @@ -1,24 +1,102 @@ -import { DEFAULT_STD_FEE } from '@injectivelabs/utils' -import { Network, getNetworkEndpoints } from '@injectivelabs/networks' +import { + BigNumber, + DEFAULT_GAS_LIMIT, + DEFAULT_GAS_PRICE, +} from '@injectivelabs/utils' +import { + Network, + getNetworkInfo, + NetworkEndpoints, + getNetworkEndpoints, +} from '@injectivelabs/networks' import { mockFactory } from './mocks/index.js' +import { ChainId, Coin, EthereumChainId } from '@injectivelabs/ts-types' -export const prepareEip712 = (messages: T) => { - const endpoints = getNetworkEndpoints(Network.Devnet) +export const prepareEip712 = ({ + messages, + gas = DEFAULT_GAS_LIMIT, + network = Network.Devnet, + injectiveAddress = mockFactory.injectiveAddress, + ethereumAddress = mockFactory.ethereumAddress, + accountNumber = 1, + sequence = 0, + timeoutHeight = 999_999_999, + memo = '', +}: { + ethereumAddress?: string + messages: T + network?: Network + gas?: number | string + accountNumber?: number + sequence?: number + timeoutHeight?: number + memo?: string + injectiveAddress?: string +}): { + endpoints: NetworkEndpoints + eip712Args: { + msgs: any + tx: { + memo: string + chainId: ChainId + sequence: string + ethereumChainId: EthereumChainId + accountNumber: string + timeoutHeight: string + } + ethereumChainId: EthereumChainId + fee: { amount: Coin[]; gas: string; payer: string } + } + prepareEip712Request: { + chainId: EthereumChainId + message: any[] + address: string + memo: string + sequence: number + accountNumber: number + ethereumChainId: EthereumChainId + timeoutHeight: number + } +} => { + const chainInfo = getNetworkInfo(network) + const endpoints = getNetworkEndpoints(network) const msgs = Array.isArray(messages) ? messages : [messages] const web3Msgs = msgs.map((msg) => msg.toWeb3()) - const { tx, eip712 } = mockFactory.eip712Tx - const { ethereumChainId } = eip712 + const { tx, eip712 } = mockFactory.eip712Tx({ + ...chainInfo, + accountNumber, + sequence, + timeoutHeight, + memo, + }) const eip712Args = { msgs, - fee: DEFAULT_STD_FEE, - tx: tx, - ethereumChainId: ethereumChainId, + fee: { + amount: [ + { + denom: 'inj', + amount: new BigNumber(gas.toString()) + .times(DEFAULT_GAS_PRICE) + .toFixed(), + }, + ], + gas: gas.toString(), + payer: injectiveAddress, + }, + tx: { + ...tx, + sequence: sequence.toString(), + timeoutHeight: timeoutHeight.toString(), + accountNumber: accountNumber.toString(), + }, + ethereumChainId: eip712.ethereumChainId, } const prepareEip712Request = { ...eip712, - chainId: ethereumChainId, + chainId: eip712.ethereumChainId, message: web3Msgs, - address: mockFactory.ethereumAddress, + gasLimit: gas, + address: ethereumAddress, } return { endpoints, eip712Args, prepareEip712Request }