diff --git a/networks/ethereum/README.md b/networks/ethereum/README.md index f4962833..99857dcd 100644 --- a/networks/ethereum/README.md +++ b/networks/ethereum/README.md @@ -12,7 +12,6 @@

- Transaction codec and client to communicate with ethereum blockchain. ## Usage @@ -23,7 +22,7 @@ npm install @interchainjs/ethereum ## Implementations -- **eip712 signer** from `@interchainjs/ethereum/eip712` (Not fully implemented yet) +- **eip712 signer** from `@interchainjs/ethereum/eip712` ## License diff --git a/networks/ethereum/src/defaults.ts b/networks/ethereum/src/defaults.ts deleted file mode 100644 index 99eb3716..00000000 --- a/networks/ethereum/src/defaults.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { computeAddress } from '@ethersproject/transactions'; -import { SignerConfig } from '@interchainjs/types'; -import { Key } from '@interchainjs/utils'; -import { bytes as assertBytes } from '@noble/hashes/_assert'; -import { keccak_256 } from '@noble/hashes/sha3'; - -export const defaultSignerConfig: SignerConfig = { - publicKey: { - isCompressed: false, - hash: (publicKey: Key) => Key.fromHex(computeAddress(publicKey.value)), - }, - message: { - hash: (message: Uint8Array) => { - const hashed = keccak_256(message); - assertBytes(hashed); - return hashed; - }, - }, -}; \ No newline at end of file diff --git a/networks/injective/package.json b/networks/injective/package.json index 899f7678..31c3d87d 100644 --- a/networks/injective/package.json +++ b/networks/injective/package.json @@ -16,7 +16,6 @@ "directory": "dist" }, "scripts": { - "test": "jest --config ./jest.config.js --verbose --bail", "copy": "copyfiles -f ../../LICENSE-MIT ../../LICENSE-Apache README.md package.json dist", "clean": "rimraf dist/**", "build": "npm run clean; tsc; tsc -p tsconfig.esm.json; npm run copy", diff --git a/networks/injective/src/builder/eip712-tx-builder.ts b/networks/injective/src/builder/eip712-tx-builder.ts deleted file mode 100644 index 2bf36ee2..00000000 --- a/networks/injective/src/builder/eip712-tx-builder.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { hexConcat } from '@ethersproject/bytes'; -import { _TypedDataEncoder } from '@ethersproject/hash'; -import { BaseCosmosTxBuilder } from '@interchainjs/cosmos/base'; -import { BaseCosmosTxBuilderContext } from '@interchainjs/cosmos/base/builder-context'; -import { SignMode } from '@interchainjs/cosmos-types/cosmos/tx/signing/v1beta1/signing'; -import { TxRaw } from '@interchainjs/cosmos-types/cosmos/tx/v1beta1/tx'; -import { Eip712Types, SignDocResponse } from '@interchainjs/types'; -import { fromHex } from '@interchainjs/utils'; - -import { - defaultDomainOptions, - defaultEip712Types, - defaultTimeoutHeight, -} from '../defaults'; -import { type Eip712SignerBase } from '../signers/eip712'; -import { InjectiveEip712Doc, InjectiveEip712SignArgs } from '../types'; -import { toEthTypes, updateDomain } from '../utils'; - -export class Eip712TxBuilder extends BaseCosmosTxBuilder { - constructor(protected ctx: BaseCosmosTxBuilderContext) { - super(SignMode.SIGN_MODE_LEGACY_AMINO_JSON, ctx); - } - - async buildDoc( - { messages, fee, memo, options }: InjectiveEip712SignArgs, - txRaw: Partial - ): Promise { - messages.forEach((msg) => { - if (msg.typeUrl !== messages[0].typeUrl) { - throw new Error("Doesn't support multiple message types"); - } - }); - - const timeoutHeight = await this.ctx.signer.toAbsoluteTimeoutHeight( - options?.timeoutHeight ?? defaultTimeoutHeight - ); - - const aminoSignDoc = await this.ctx.signer.aminoSigner.txBuilder.buildDoc( - { - messages, - fee, - memo, - options: { - ...options, - timeoutHeight, - signMode: options?.signMode ?? SignMode.SIGN_MODE_DIRECT, - extensionOptions: [ - ...(options?.extensionOptions ?? []), - { - typeUrl: '/injective.types.v1beta1.ExtensionOptionsWeb3Tx', - value: new Uint8Array([8, 1]), - }, - ], - }, - }, - txRaw - ); - - const signDoc: InjectiveEip712Doc = { - primaryType: defaultEip712Types.primaryType, - domain: updateDomain(defaultDomainOptions, options), - types: { - ...defaultEip712Types.types, - ...toEthTypes(aminoSignDoc.msgs[0].value), - }, - message: { - ...aminoSignDoc, - timeout_height: timeoutHeight.value.toString(), - fee: { - amount: aminoSignDoc.fee.amount, - gas: aminoSignDoc.fee.gas, - feePayer: aminoSignDoc.fee.payer, - }, - }, - }; - return signDoc; - } - - async buildDocBytes(doc: InjectiveEip712Doc): Promise { - const domainTypes: Eip712Types = {}; - const restTypes: Eip712Types = {}; - Object.entries(doc.types).forEach(([key, value]) => { - if (key === 'EIP712Domain') { - domainTypes[key] = value; - } else { - restTypes[key] = value; - } - }); - const encoded = hexConcat([ - '0x1901', - _TypedDataEncoder.from(domainTypes).hash(doc.domain), - _TypedDataEncoder.from(restTypes).hash(doc.message), - ]); - - return fromHex(encoded); - } - - async syncSignedDoc(txRaw: TxRaw, signResp: SignDocResponse): Promise { - throw new Error('Method not implemented.'); - } -} diff --git a/networks/injective/src/defaults.ts b/networks/injective/src/defaults.ts index 7c60b6d7..6d73e287 100644 --- a/networks/injective/src/defaults.ts +++ b/networks/injective/src/defaults.ts @@ -11,15 +11,18 @@ import { toDecoder } from '@interchainjs/cosmos/utils'; import { BaseAccount } from '@interchainjs/cosmos-types/cosmos/auth/v1beta1/auth'; import { PubKey as Secp256k1PubKey } from '@interchainjs/cosmos-types/cosmos/crypto/secp256k1/keys'; import { EthAccount } from '@interchainjs/cosmos-types/injective/types/v1beta1/account'; -import { defaultSignerConfig as EthereumSignerConfig } from '@interchainjs/ethereum/defaults'; import { Eip712Doc } from '@interchainjs/ethereum/types'; import { IKey, SignerConfig } from '@interchainjs/types'; import { DomainOptions, EthereumChainId } from './types'; +import { bytes as assertBytes } from '@noble/hashes/_assert'; +import { keccak_256 } from '@noble/hashes/sha3'; +import { computeAddress } from '@ethersproject/transactions'; +import { Key } from '@interchainjs/utils'; export const defaultPublicKeyConfig: SignerConfig['publicKey'] = { isCompressed: CosmosSignerConfig.publicKey.isCompressed, - hash: EthereumSignerConfig.publicKey.hash, + hash: (publicKey: Key) => Key.fromHex(computeAddress(publicKey.value)) }; export const defaultEncodePublicKey = (key: IKey): EncodedMessage => { @@ -50,7 +53,11 @@ export const defaultSignerOptions: Record> = { ...CosmosSignerConfig, message: { ...CosmosSignerConfig.message, - hash: EthereumSignerConfig.message.hash, + hash: (message: Uint8Array) => { + const hashed = keccak_256(message); + assertBytes(hashed); + return hashed; + }, }, publicKey: defaultPublicKeyConfig, encodePublicKey: defaultEncodePublicKey, @@ -58,7 +65,13 @@ export const defaultSignerOptions: Record> = { prefix: 'inj', }, Ethereum: { - ...EthereumSignerConfig, + message: { + hash: (message: Uint8Array) => { + const hashed = keccak_256(message); + assertBytes(hashed); + return hashed; + }, + }, publicKey: defaultPublicKeyConfig, encodePublicKey: defaultEncodePublicKey, parseAccount: defaultAccountParser, diff --git a/networks/injective/src/eth-utils/helpers.ts b/networks/injective/src/eth-utils/helpers.ts deleted file mode 100644 index 27a28f66..00000000 --- a/networks/injective/src/eth-utils/helpers.ts +++ /dev/null @@ -1,11 +0,0 @@ -export const snakeToPascal = (str: string): string => { - return str - .split('/') - .map((snake) => - snake - .split('_') - .map((substr) => substr.charAt(0).toUpperCase() + substr.slice(1)) - .join('') - ) - .join('/'); -}; diff --git a/networks/injective/src/eth-utils/injective-LICENSE b/networks/injective/src/eth-utils/injective-LICENSE deleted file mode 100644 index 3d714d64..00000000 --- a/networks/injective/src/eth-utils/injective-LICENSE +++ /dev/null @@ -1,203 +0,0 @@ -Copyright © 2021 - 2022 Injective Labs Inc. (https://injectivelabs.org/) - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [2022] [InjectiveLabs] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/networks/injective/src/eth-utils/map.ts b/networks/injective/src/eth-utils/map.ts deleted file mode 100644 index 8f26f2bf..00000000 --- a/networks/injective/src/eth-utils/map.ts +++ /dev/null @@ -1,426 +0,0 @@ -import { GeneralException } from '@injectivelabs/exceptions'; -import snakecaseKeys from 'snakecase-keys'; - -import { snakeToPascal } from './helpers'; -import { isNumber, numberToCosmosSdkDecString } from './numbers'; - -export interface TypedDataField { - name: string; - type: string; -} - -const msgExecuteContractType = 'wasm/MsgExecuteContract'; - -/** - * Function used to generate EIP712 types based on a message object - * and its structure (recursive) - */ -export const objectKeysToEip712Types = ({ - object, - messageType, - primaryType = 'MsgValue', -}: { - object: Record; - messageType?: string; - primaryType?: string; -}) => { - const numberFieldsWithStringValue = [ - 'order_mask', - 'order_type', - 'oracle_type', - 'round', - 'oracle_scale_factor', - 'expiry', - 'option', - 'proposal_id', - 'creation_height', - ]; - const stringFieldsWithNumberValue = [ - 'timeout_timestamp', - 'revision_height', - 'revision_number', - ]; - const stringFieldsToOmitIfEmpty = ['cid']; - const output = new Map(); - const types = new Array(); - - for (const property in snakecaseKeys(object)) { - const propertyValue = snakecaseKeys(object)[property]; - - if (property === '@type') { - continue; - } - - const type = typeof propertyValue; - - if (type === 'boolean') { - types.push({ name: property, type: 'bool' }); - } else if ( - type === 'number' || - type === 'bigint' || - numberFieldsWithStringValue.includes(property) - ) { - types.push({ - name: property, - type: numberTypeToReflectionNumberType(property), - }); - } else if (type === 'string') { - if (stringFieldsToOmitIfEmpty.includes(property) && !propertyValue) { - continue; - } - - if (stringFieldsWithNumberValue.includes(property)) { - types.push({ - name: property, - type: stringTypeToReflectionStringType(property), - }); - - continue; - } - - types.push({ name: property, type: 'string' }); - } else if (type === 'object') { - if (Array.isArray(propertyValue) && propertyValue.length === 0) { - throw new GeneralException(new Error('Array with length 0 found')); - } else if (Array.isArray(propertyValue) && propertyValue.length > 0) { - const arrayFirstType = typeof propertyValue[0]; - const isPrimitive = - arrayFirstType === 'boolean' || - arrayFirstType === 'number' || - arrayFirstType === 'string'; - - if (isPrimitive) { - for (const arrayEntry in propertyValue) { - if (typeof arrayEntry !== arrayFirstType) { - throw new GeneralException( - new Error('Array with different types found') - ); - } - } - - if (arrayFirstType === 'boolean') { - types.push({ name: property, type: 'bool[]' }); - } else if (arrayFirstType === 'number') { - types.push({ name: property, type: 'number[]' }); - } else if (arrayFirstType === 'string') { - types.push({ name: property, type: 'string[]' }); - } - } else if (arrayFirstType === 'object') { - const propertyType = getObjectEip712PropertyType({ - property: snakeToPascal(property), - parentProperty: primaryType, - messageType, - }); - const recursiveOutput = objectKeysToEip712Types({ - object: propertyValue[0], - primaryType: propertyType, - messageType, - }); - const recursiveTypes = recursiveOutput.get(propertyType); - - types.push({ name: property, type: `${propertyType}[]` }); - output.set(propertyType, recursiveTypes!); - - for (const key of recursiveOutput.keys()) { - if (key !== primaryType) { - output.set(key, recursiveOutput.get(key)!); - } - } - } else { - throw new GeneralException( - new Error('Array with elements of unknown type found') - ); - } - } else if (propertyValue instanceof Date) { - types.push({ name: property, type: 'string' }); - } else { - const propertyType = getObjectEip712PropertyType({ - property: snakeToPascal(property), - parentProperty: primaryType, - messageType, - }); - const recursiveOutput = objectKeysToEip712Types({ - object: propertyValue, - primaryType: propertyType, - messageType, - }); - const recursiveTypes = recursiveOutput.get(propertyType); - - types.push({ name: property, type: propertyType }); - output.set(propertyType, recursiveTypes!); - - for (const key of recursiveOutput.keys()) { - if (key !== primaryType) { - output.set(key, recursiveOutput.get(key)!); - } - } - } - } else { - throw new GeneralException(new Error(`Type ${property} not found`)); - } - } - - output.set(primaryType, types); - - return output; -}; -/** - * JavaScript doesn't know the exact number types that - * we represent these fields on chain so we have to map - * them in their chain representation from the number value - * that is available in JavaScript - */ -export const numberTypeToReflectionNumberType = (property?: string) => { - switch (property) { - case 'order_mask': - return 'int32'; - case 'timeout_timestamp': - return 'timeout_timestamp'; - case 'revision_number': - return 'uint64'; - case 'revision_height': - return 'uint64'; - case 'order_type': - return 'int32'; - case 'oracle_type': - return 'int32'; - case 'exponent': - return 'uint32'; - case 'round': - return 'uint64'; - case 'oracle_scale_factor': - return 'uint64'; - case 'expiry': - return 'int64'; - case 'creation_height': - return 'int64'; - case 'option': - return 'int32'; - case 'proposal_id': - return 'uint64'; - default: - return 'uint64'; - } -}; -/** - * JavaScript doesn't know the exact string types that - * we represent these fields on chain so we have to map - * them in their chain representation from the string value - * that is available in JavaScript - */ -export const stringTypeToReflectionStringType = (property?: string) => { - switch (property) { - case 'timeout_timestamp': - return 'uint64'; - case 'revision_number': - return 'uint64'; - case 'revision_height': - return 'uint64'; - default: - return 'uint64'; - } -}; - -/** - * We need to represent some of the values in a proper format acceptable by the chain. - * - * 1. We need to represent some values from a number to string - * This needs to be done for every number value except for maps (ex: vote option) - * - * 2. We need to convert every `sdk.Dec` value from a raw value to shifted by 1e18 value - * ex: 0.01 -> 0.01000000000000000000, 1 -> 1.000000000000000000 - * - * 3. For some fields, like 'amount' in the 'MsgIncreasePositionMargin' we have - * to also specify the Message type to apply the sdk.Dec conversion because there - * are other amount fields in other messages as well and we don't want to affect them - */ -export const mapValuesToProperValueType = >( - object: T, - messageTypeUrl?: string -): T => { - const numberToStringKeys = [ - 'proposal_id', - 'round', - 'oracle_scale_factor', - 'timeout_timestamp', - 'revision_height', - 'revision_number', - 'expiry', - ]; - const sdkDecKeys = [ - 'min_price_tick_size', - 'price', - 'quantity', - 'margin', - 'trigger_price', - 'min_quantity_tick_size', - ]; - const sdkDecKeyWithTypeMaps = { - 'exchange/MsgIncreasePositionMargin': ['amount'], - }; - const nullableStringsTypeMaps = { - 'wasmx/MsgExecuteContractCompat': ['funds'], - }; - - const nullableStrings = ['uri', 'uri_hash']; - - return Object.keys(object).reduce((result, key) => { - const value = object[key]; - - if (!value) { - // Message Type Specific checks - if (messageTypeUrl) { - const typeInMap = Object.keys(nullableStringsTypeMaps).find( - (key) => key === messageTypeUrl - ); - - if (typeInMap) { - const nullableStringKeys = - nullableStringsTypeMaps[ - typeInMap as keyof typeof nullableStringsTypeMaps - ]; - - if (nullableStringKeys.includes(key)) { - return { - ...result, - [key]: value, - }; - } - } - } - - if (nullableStrings.includes(key)) { - return { - ...result, - [key]: value, - }; - } - - return result; - } - - if (typeof value === 'object') { - if (value instanceof Date) { - return { - ...result, - [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) - ), - }; - } - - return { - ...result, - [key]: mapValuesToProperValueType(value as Record), - }; - } - - if (isNumber(value as string | number)) { - if (numberToStringKeys.includes(key)) { - return { - ...result, - [key]: value.toString(), - }; - } - - // Maybe some other check needed - } - - if (typeof value === 'string') { - if (sdkDecKeys.includes(key)) { - return { - ...result, - [key]: numberToCosmosSdkDecString(value), - }; - } - - // Message Type Specific checks - if (messageTypeUrl) { - const typeInMap = Object.keys(sdkDecKeyWithTypeMaps).find( - (key) => key === messageTypeUrl - ); - - if (typeInMap) { - const sdkDecKeys = - sdkDecKeyWithTypeMaps[ - typeInMap as keyof typeof sdkDecKeyWithTypeMaps - ]; - - if (sdkDecKeys.includes(key)) { - return { - ...result, - [key]: numberToCosmosSdkDecString(value), - }; - } - } - } - } - - return { - ...result, - [key]: value, - }; - }, {} as T); -}; - -export const getObjectEip712PropertyType = ({ - property, - parentProperty, - messageType, -}: { - property: string; - parentProperty: string; - messageType?: string; -}) => { - if (messageType === msgExecuteContractType) { - return appendWasmTypePrefixToPropertyType(property, parentProperty); - } - - return appendTypePrefixToPropertyType(property, parentProperty); -}; - -/** - * Append Wasm Type prefix to a Level0 EIP712 type - * including its parent property type - */ -const appendWasmTypePrefixToPropertyType = ( - property: string, - parentProperty: string = '' -) => { - const cosmWasmMsgPrefix = 'CosmwasmInnerMsgMarker'; - const propertyWithoutTypePrefix = property.replace('Type', ''); - - if (propertyWithoutTypePrefix === 'Msg') { - return cosmWasmMsgPrefix; - } - - const parentPropertyWithoutTypePrefix = parentProperty.replace( - cosmWasmMsgPrefix, - '' - ); - - return `${parentPropertyWithoutTypePrefix + propertyWithoutTypePrefix}Value`; -}; - -/** - * Append Type prefix to a Level0 EIP712 type - * including its parent property type - */ -const appendTypePrefixToPropertyType = ( - property: string, - parentProperty: string = '' -) => { - const propertyWithoutTypePrefix = property.replace('Type', ''); - const parentPropertyWithoutTypePrefix = - parentProperty === 'MsgValue' ? '' : parentProperty.replace('Type', ''); - - return `Type${parentPropertyWithoutTypePrefix + propertyWithoutTypePrefix}`; -}; diff --git a/networks/injective/src/eth-utils/numbers.ts b/networks/injective/src/eth-utils/numbers.ts deleted file mode 100644 index 4485dd7d..00000000 --- a/networks/injective/src/eth-utils/numbers.ts +++ /dev/null @@ -1,13 +0,0 @@ -import Decimal from 'decimal.js'; - -export const isNumber = (number: string | number) => { - if (typeof number === 'number') { - return true; - } - - return !isNaN(parseFloat(number)); -}; - -export const numberToCosmosSdkDecString = (value: string | number): string => { - return new Decimal(value).toFixed(18); -}; diff --git a/networks/injective/src/signers/eip712.ts b/networks/injective/src/signers/eip712.ts deleted file mode 100644 index 9ea84124..00000000 --- a/networks/injective/src/signers/eip712.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { AminoSignerBase } from '@interchainjs/cosmos/signers/amino'; -import { BaseCosmosTxBuilder } from '@interchainjs/cosmos/base'; -import { BaseCosmosTxBuilderContext } from '@interchainjs/cosmos/base/builder-context'; -import { - AminoConverter, - Encoder, - SignerOptions, -} from '@interchainjs/cosmos/types'; -import { Auth, HttpEndpoint } from '@interchainjs/types'; - -import { InjAccount } from '../accounts/inj-account'; -import { AminoSigner } from './amino'; -import { Eip712TxBuilder } from '../builder/eip712-tx-builder'; -import { defaultSignerOptions } from '../defaults'; -import {InjectiveEip712Doc } from '../types'; - -export class Eip712SignerBase extends AminoSignerBase { - readonly aminoSigner: AminoSigner; - - constructor( - auth: Auth, - encoders: Encoder[], - converters: AminoConverter[], - endpoint?: string | HttpEndpoint, - options: SignerOptions = defaultSignerOptions.Ethereum - ) { - super(auth, encoders, converters, endpoint, options); - this.aminoSigner = new AminoSigner( - auth, - encoders, - converters, - endpoint, - options - ); - } - - async getAccount() { - return new InjAccount( - await this.getPrefix(), - this.auth, - this.config.publicKey.isCompressed - ); - } - - getTxBuilder(): BaseCosmosTxBuilder { - return new Eip712TxBuilder(new BaseCosmosTxBuilderContext(this)); - } -} - -export class Eip712Signer extends Eip712SignerBase { - static async fromWallet( - _wallet: any, - encoders: Encoder[], - converters: AminoConverter[], - endpoint?: string | HttpEndpoint, - options?: SignerOptions - ) { - throw new Error('Not implemented yet'); - } - - static async fromWalletToSigning( - _wallet: any, - encoders: Encoder[], - converters: AminoConverter[], - endpoint?: string | HttpEndpoint, - options?: SignerOptions - ) { - throw new Error('Not implemented yet'); - } -} diff --git a/networks/injective/src/types/cosmos/tx/signing/v1beta1/signing.ts b/networks/injective/src/types/cosmos/tx/signing/v1beta1/signing.ts deleted file mode 100644 index bdfb866a..00000000 --- a/networks/injective/src/types/cosmos/tx/signing/v1beta1/signing.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * SignMode represents a signing mode with its own security guarantees. - * - * This enum should be considered a registry of all known sign modes - * in the Cosmos ecosystem. Apps are not expected to support all known - * sign modes. Apps that would like to support custom sign modes are - * encouraged to open a small PR against this file to add a new case - * to this SignMode enum describing their sign mode so that different - * apps have a consistent version of this enum. - */ -export enum SignMode { - /** - * SIGN_MODE_EIP712_V2 - Injective EIP712 support for any cosmos messages which uses proto-json encoded string for messages - * Signature verification is implemented in injective core - */ - SIGN_MODE_EIP712_V2 = 128, -} \ No newline at end of file diff --git a/networks/injective/src/utils.spec.ts b/networks/injective/src/utils.spec.ts deleted file mode 100644 index a25e4585..00000000 --- a/networks/injective/src/utils.spec.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { MsgSendAmino } from 'interchainjs/cosmos/bank/v1beta1/tx'; -import { Eip712Types } from '@interchainjs/types'; - -import { toEthTypes } from './utils'; - -it('should match', () => { - const message: MsgSendAmino = { - from_address: 'inj11111', - to_address: 'inj22222', - amount: [ - { - denom: 'inj', - amount: '0.01', - }, - ], - }; - const expectedTypes: Eip712Types = { - MsgValue: [ - { - name: 'from_address', - type: 'string', - }, - { - name: 'to_address', - type: 'string', - }, - { - name: 'amount', - type: 'TypeAmount[]', - }, - ], - TypeAmount: [ - { - name: 'denom', - type: 'string', - }, - { - name: 'amount', - type: 'string', - }, - ], - }; - const types = toEthTypes(message); - expect(types).toEqual(expectedTypes); -}); diff --git a/networks/injective/src/utils.ts b/networks/injective/src/utils.ts index 8f7a1050..c72beb71 100644 --- a/networks/injective/src/utils.ts +++ b/networks/injective/src/utils.ts @@ -1,5 +1,4 @@ import { - Eip712Types, InjectiveDomain, SignerConfig, } from '@interchainjs/types'; @@ -7,7 +6,6 @@ import { Auth } from '@interchainjs/types'; import { fromNumber, toPrefixedHex } from '@interchainjs/utils'; import { defaultPublicKeyConfig } from './defaults'; -import { objectKeysToEip712Types } from './eth-utils/map'; import { DomainOptions, InjectiveAccount } from './types'; export function getAccountFromAuth( @@ -24,11 +22,6 @@ export function getAccountFromAuth( }; } -export function toEthTypes(message: AminoType): Eip712Types { - const map = objectKeysToEip712Types({ object: message }); - return Object.fromEntries(map.entries()); -} - export function updateDomain( defaultOptions: Required, options?: DomainOptions diff --git a/packages/auth/README.md b/packages/auth/README.md index b7c01847..b2312b11 100644 --- a/packages/auth/README.md +++ b/packages/auth/README.md @@ -59,7 +59,7 @@ const [auth] = Secp256k1Auth.fromMnemonic("", [ ## Implementations - **secp256k1 auth** from `@interchainjs/auth/secp256k1` -- **ethSecp256k1 auth** from `@interchainjs/auth/ethSecp256k1` (`Not fully implemented yet`) +- **ethSecp256k1 auth** from `@interchainjs/auth/ethSecp256k1` ## License