From 5c96476849d3ab55ed729d9bbfb82f697e4cfa1d Mon Sep 17 00:00:00 2001 From: Aleksandr Kraiz Date: Fri, 22 Apr 2022 07:27:24 +0400 Subject: [PATCH] File structure improvements --- package.json | 2 +- src/crypt.ts | 151 ---------------------- src/crypt/getDomainData.ts | 15 +++ src/{utils => crypt}/hashOrder.ts | 0 src/crypt/index.ts | 4 + src/crypt/signCancelOrder.ts | 49 +++++++ src/crypt/signCancelOrderPersonal.ts | 20 +++ src/crypt/signOrder.ts | 87 +++++++++++++ src/{utils => crypt}/signOrderPersonal.ts | 0 src/utils/index.ts | 2 - 10 files changed, 176 insertions(+), 154 deletions(-) delete mode 100644 src/crypt.ts create mode 100644 src/crypt/getDomainData.ts rename src/{utils => crypt}/hashOrder.ts (100%) create mode 100644 src/crypt/index.ts create mode 100644 src/crypt/signCancelOrder.ts create mode 100644 src/crypt/signCancelOrderPersonal.ts create mode 100644 src/crypt/signOrder.ts rename src/{utils => crypt}/signOrderPersonal.ts (100%) diff --git a/package.json b/package.json index cb90482..7616cf2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@orionprotocol/sdk", - "version": "0.2.1", + "version": "0.2.2", "description": "Orion Protocol SDK", "main": "lib/index.js", "types": "lib/index.d.ts", diff --git a/src/crypt.ts b/src/crypt.ts deleted file mode 100644 index 36dde9f..0000000 --- a/src/crypt.ts +++ /dev/null @@ -1,151 +0,0 @@ -/* eslint-disable no-underscore-dangle */ -import { TypedDataSigner } from '@ethersproject/abstract-signer'; -import BigNumber from 'bignumber.js'; -import { ethers } from 'ethers'; -import { - CancelOrderRequest, Order, SignedCancelOrderRequest, SignedOrder, SupportedChainId, -} from './types'; -import eip712DomainData from './config/eip712DomainData.json'; -import eip712DomainSchema from './config/schemas/eip712DomainSchema'; -import { hashOrder, normalizeNumber } from './utils'; - -import { INTERNAL_ORION_PRECISION } from './constants/precisions'; -import ORDER_TYPES from './constants/orderTypes'; -import CANCEL_ORDER_TYPES from './constants/cancelOrderTypes'; -import signOrderPersonal from './utils/signOrderPersonal'; - -const DEFAULT_EXPIRATION = 29 * 24 * 60 * 60 * 1000; // 29 days - -type SignerWithTypedDataSign = ethers.Signer & TypedDataSigner; - -const EIP712Domain = eip712DomainSchema.parse(eip712DomainData); -const { arrayify, joinSignature, splitSignature } = ethers.utils; - -/** - * See {@link https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator} - */ -const getDomainData = (chainId: SupportedChainId) => ({ - ...EIP712Domain, - chainId, -}); - -export const signOrder = async ( - baseAssetAddr: string, - quoteAssetAddr: string, - side: 'BUY' | 'SELL', - price: BigNumber.Value, - amount: BigNumber.Value, - matcherFee: BigNumber.Value, - senderAddress: string, - matcherAddress: string, - orionFeeAssetAddr: string, - usePersonalSign: boolean, - signer: ethers.Signer, - chainId: SupportedChainId, -) => { - const nonce = Date.now(); - const expiration = nonce + DEFAULT_EXPIRATION; - - const order: Order = { - senderAddress, - matcherAddress, - baseAsset: baseAssetAddr, - quoteAsset: quoteAssetAddr, - matcherFeeAsset: orionFeeAssetAddr, - amount: normalizeNumber( - amount, - INTERNAL_ORION_PRECISION, - BigNumber.ROUND_FLOOR, - ).toNumber(), - price: normalizeNumber( - price, - INTERNAL_ORION_PRECISION, - BigNumber.ROUND_FLOOR, - ).toNumber(), - matcherFee: normalizeNumber( - matcherFee, - INTERNAL_ORION_PRECISION, - BigNumber.ROUND_CEIL, // ROUND_CEIL because we don't want get "not enough fee" error - ).toNumber(), - nonce, - expiration, - buySide: side === 'BUY' ? 1 : 0, - isPersonalSign: usePersonalSign, - }; - - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - const typedDataSigner = signer as SignerWithTypedDataSign; - - const signature = usePersonalSign - ? await signOrderPersonal(order, signer) - : await typedDataSigner._signTypedData( - getDomainData(chainId), - ORDER_TYPES, - order, - ); - - // https://github.com/poap-xyz/poap-fun/pull/62#issue-928290265 - // "Signature's v was always send as 27 or 28, but from Ledger was 0 or 1" - const fixedSignature = joinSignature(splitSignature(signature)); - - if (!fixedSignature) throw new Error("Can't sign order"); - - const signedOrder: SignedOrder = { - ...order, - id: hashOrder(order), - signature: fixedSignature, - }; - return signedOrder; -}; - -export const signCancelOrderPersonal = async ( - cancelOrderRequest: CancelOrderRequest, - signer: ethers.Signer, -) => { - const types = ['string', 'string', 'address']; - const message = ethers.utils.solidityKeccak256( - types, - ['cancelOrder', cancelOrderRequest.id, cancelOrderRequest.senderAddress], - ); - const signature = await signer.signMessage(arrayify(message)); - - // NOTE: metamask broke sig.v value and we fix it in next line - return joinSignature(splitSignature(signature)); -}; - -export const signCancelOrder = async ( - senderAddress: string, - id: string, - usePersonalSign: boolean, - signer: ethers.Signer, - chainId: SupportedChainId, -) => { - const cancelOrderRequest: CancelOrderRequest = { - id, - senderAddress, - isPersonalSign: usePersonalSign, - }; - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - const typedDataSigner = signer as SignerWithTypedDataSign; - - const signature = usePersonalSign - ? await signCancelOrderPersonal(cancelOrderRequest, signer) - // https://docs.ethers.io/v5/api/signer/#Signer-signTypedData - : await typedDataSigner._signTypedData( - getDomainData(chainId), - CANCEL_ORDER_TYPES, - cancelOrderRequest, - ); - - // https://github.com/poap-xyz/poap-fun/pull/62#issue-928290265 - // "Signature's v was always send as 27 or 28, but from Ledger was 0 or 1" - const fixedSignature = joinSignature(splitSignature(signature)); - - if (!fixedSignature) throw new Error("Can't sign order cancel"); - - const signedCancelOrderReqeust: SignedCancelOrderRequest = { - ...cancelOrderRequest, - signature: fixedSignature, - }; - return signedCancelOrderReqeust; -}; diff --git a/src/crypt/getDomainData.ts b/src/crypt/getDomainData.ts new file mode 100644 index 0000000..ed459e7 --- /dev/null +++ b/src/crypt/getDomainData.ts @@ -0,0 +1,15 @@ +import { SupportedChainId } from '../types'; +import eip712DomainData from '../config/eip712DomainData.json'; +import eip712DomainSchema from '../config/schemas/eip712DomainSchema'; + +const EIP712Domain = eip712DomainSchema.parse(eip712DomainData); + +/** + * See {@link https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator} + */ +const getDomainData = (chainId: SupportedChainId) => ({ + ...EIP712Domain, + chainId, +}); + +export default getDomainData; diff --git a/src/utils/hashOrder.ts b/src/crypt/hashOrder.ts similarity index 100% rename from src/utils/hashOrder.ts rename to src/crypt/hashOrder.ts diff --git a/src/crypt/index.ts b/src/crypt/index.ts new file mode 100644 index 0000000..4b1f786 --- /dev/null +++ b/src/crypt/index.ts @@ -0,0 +1,4 @@ +export { default as signCancelOrder } from './signCancelOrder'; +export { default as signCancelOrderPersonal } from './signCancelOrderPersonal'; +export { default as signOrder } from './signOrder'; +export { default as signOrderPersonal } from './signOrderPersonal'; diff --git a/src/crypt/signCancelOrder.ts b/src/crypt/signCancelOrder.ts new file mode 100644 index 0000000..098b7e9 --- /dev/null +++ b/src/crypt/signCancelOrder.ts @@ -0,0 +1,49 @@ +/* eslint-disable no-underscore-dangle */ +import { TypedDataSigner } from '@ethersproject/abstract-signer'; +import { ethers } from 'ethers'; +import { joinSignature, splitSignature } from 'ethers/lib/utils'; +import CANCEL_ORDER_TYPES from '../constants/cancelOrderTypes'; +import { CancelOrderRequest, SignedCancelOrderRequest, SupportedChainId } from '../types'; +import getDomainData from './getDomainData'; +import signCancelOrderPersonal from './signCancelOrderPersonal'; + +type SignerWithTypedDataSign = ethers.Signer & TypedDataSigner; + +const signCancelOrder = async ( + senderAddress: string, + id: string, + usePersonalSign: boolean, + signer: ethers.Signer, + chainId: SupportedChainId, +) => { + const cancelOrderRequest: CancelOrderRequest = { + id, + senderAddress, + isPersonalSign: usePersonalSign, + }; + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + const typedDataSigner = signer as SignerWithTypedDataSign; + + const signature = usePersonalSign + ? await signCancelOrderPersonal(cancelOrderRequest, signer) + // https://docs.ethers.io/v5/api/signer/#Signer-signTypedData + : await typedDataSigner._signTypedData( + getDomainData(chainId), + CANCEL_ORDER_TYPES, + cancelOrderRequest, + ); + + // https://github.com/poap-xyz/poap-fun/pull/62#issue-928290265 + // "Signature's v was always send as 27 or 28, but from Ledger was 0 or 1" + const fixedSignature = joinSignature(splitSignature(signature)); + + if (!fixedSignature) throw new Error("Can't sign order cancel"); + + const signedCancelOrderReqeust: SignedCancelOrderRequest = { + ...cancelOrderRequest, + signature: fixedSignature, + }; + return signedCancelOrderReqeust; +}; + +export default signCancelOrder; diff --git a/src/crypt/signCancelOrderPersonal.ts b/src/crypt/signCancelOrderPersonal.ts new file mode 100644 index 0000000..2f795e2 --- /dev/null +++ b/src/crypt/signCancelOrderPersonal.ts @@ -0,0 +1,20 @@ +import { ethers } from 'ethers'; +import { arrayify, joinSignature, splitSignature } from 'ethers/lib/utils'; +import { CancelOrderRequest } from '../types'; + +export const signCancelOrderPersonal = async ( + cancelOrderRequest: CancelOrderRequest, + signer: ethers.Signer, +) => { + const types = ['string', 'string', 'address']; + const message = ethers.utils.solidityKeccak256( + types, + ['cancelOrder', cancelOrderRequest.id, cancelOrderRequest.senderAddress], + ); + const signature = await signer.signMessage(arrayify(message)); + + // NOTE: metamask broke sig.v value and we fix it in next line + return joinSignature(splitSignature(signature)); +}; + +export default signCancelOrderPersonal; diff --git a/src/crypt/signOrder.ts b/src/crypt/signOrder.ts new file mode 100644 index 0000000..9bd9c88 --- /dev/null +++ b/src/crypt/signOrder.ts @@ -0,0 +1,87 @@ +/* eslint-disable no-underscore-dangle */ +import { TypedDataSigner } from '@ethersproject/abstract-signer'; +import BigNumber from 'bignumber.js'; +import { ethers } from 'ethers'; +import { joinSignature, splitSignature } from 'ethers/lib/utils'; +import { INTERNAL_ORION_PRECISION } from '../constants'; +import ORDER_TYPES from '../constants/orderTypes'; +import { Order, SignedOrder, SupportedChainId } from '../types'; +import normalizeNumber from '../utils/normalizeNumber'; +import getDomainData from './getDomainData'; +import hashOrder from './hashOrder'; +import signOrderPersonal from './signOrderPersonal'; + +const DEFAULT_EXPIRATION = 29 * 24 * 60 * 60 * 1000; // 29 days + +type SignerWithTypedDataSign = ethers.Signer & TypedDataSigner; + +export const signOrder = async ( + baseAssetAddr: string, + quoteAssetAddr: string, + side: 'BUY' | 'SELL', + price: BigNumber.Value, + amount: BigNumber.Value, + matcherFee: BigNumber.Value, + senderAddress: string, + matcherAddress: string, + orionFeeAssetAddr: string, + usePersonalSign: boolean, + signer: ethers.Signer, + chainId: SupportedChainId, +) => { + const nonce = Date.now(); + const expiration = nonce + DEFAULT_EXPIRATION; + + const order: Order = { + senderAddress, + matcherAddress, + baseAsset: baseAssetAddr, + quoteAsset: quoteAssetAddr, + matcherFeeAsset: orionFeeAssetAddr, + amount: normalizeNumber( + amount, + INTERNAL_ORION_PRECISION, + BigNumber.ROUND_FLOOR, + ).toNumber(), + price: normalizeNumber( + price, + INTERNAL_ORION_PRECISION, + BigNumber.ROUND_FLOOR, + ).toNumber(), + matcherFee: normalizeNumber( + matcherFee, + INTERNAL_ORION_PRECISION, + BigNumber.ROUND_CEIL, // ROUND_CEIL because we don't want get "not enough fee" error + ).toNumber(), + nonce, + expiration, + buySide: side === 'BUY' ? 1 : 0, + isPersonalSign: usePersonalSign, + }; + + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + const typedDataSigner = signer as SignerWithTypedDataSign; + + const signature = usePersonalSign + ? await signOrderPersonal(order, signer) + : await typedDataSigner._signTypedData( + getDomainData(chainId), + ORDER_TYPES, + order, + ); + + // https://github.com/poap-xyz/poap-fun/pull/62#issue-928290265 + // "Signature's v was always send as 27 or 28, but from Ledger was 0 or 1" + const fixedSignature = joinSignature(splitSignature(signature)); + + if (!fixedSignature) throw new Error("Can't sign order"); + + const signedOrder: SignedOrder = { + ...order, + id: hashOrder(order), + signature: fixedSignature, + }; + return signedOrder; +}; + +export default signOrder; diff --git a/src/utils/signOrderPersonal.ts b/src/crypt/signOrderPersonal.ts similarity index 100% rename from src/utils/signOrderPersonal.ts rename to src/crypt/signOrderPersonal.ts diff --git a/src/utils/index.ts b/src/utils/index.ts index cfd59ab..763927f 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -2,9 +2,7 @@ export { default as calculateFeeInFeeAsset } from './calculateFeeInFeeAsset'; export { default as calculateNetworkFee } from './calculateNetworkFee'; export { default as calculateNetworkFeeInFeeAsset } from './calculateNetworkFeeInFeeAsset'; export { default as calculateOrionFeeInFeeAsset } from './calculateOrionFeeInFeeAsset'; -export { default as hashOrder } from './hashOrder'; export { default as checkIsToken } from './checkIsToken'; -export { default as signOrderPersonal } from './signOrderPersonal'; export { default as generateSecret } from './generateSecret'; export { default as isValidChainId } from './isValidChainId'; export { default as denormalizeNumber } from './denormalizeNumber';