diff --git a/README.md b/README.md index a180a64..06dcc87 100644 --- a/README.md +++ b/README.md @@ -27,26 +27,87 @@ Program setup, - types.WalletType.ERC1271 - types.WalletType.EOA - SIGNING_URL, If you wanna sign orders in your own service instead of the mmsk, - please set the SIGNING_URL to your service endpoint. the mmsk would post every unsigned PMM/RFQV1/RFQV2 orders to your service. Remember to set the WALLET_ADDRESS as well. An example RFQV1 request is shown below: + please set the SIGNING_URL to your service endpoint. the mmsk would post every unsigned PMM/RFQV1/RFQV2 orders to your service. Remember to set the WALLET_ADDRESS as well. Example PMMV5/RFQV1/RFQV2 requests are shown below: + + PMMV5: + ``` + { + quoteId: '0x123', + protocol: 'PMMV5', + pmmOrder: { + makerAddress: '0x86b9f429c3ef44c599eb560eb531a0e3f2e36f64', + makerAssetAmount: '100000000', + makerAssetData: '0xf47261b0000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7', + makerFee: '0', + takerAddress: '0x7bd7d025d4231aad1233967b527ffd7416410257', + takerAssetAmount: '1000000000000000000', + takerAssetData: '0xf47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + takerFee: '0', + senderAddress: '0x7bd7d025d4231aad1233967b527ffd7416410257', + feeRecipientAddress: '0x8fba2dd6968ddc51aea563091008d8451fec4db6', + expirationTimeSeconds: '1620444917', + exchangeAddress: '0x86b9f429c3ef44c599eb560eb531a0e3f2e36f64', + salt: '22685491128062564230891640495451214097' + }, + feeFactor: 30, + orderHash: '0x9f9bb186d77c19a763266f54978eef923f3e6ebd5ac6d2c687b1323abe91d8b5', + orderSignDigest: '0x6e95144f3539f8679b94e858a0bcd755e8b17a4011e2fdf025387e4523a9b0fe', + userAddr: '0x8fba2dd6968ddc51aea563091008d8451fec4db6', + chainId: 1, + pmmAddr: '0x7bd7d025D4231aAD1233967b527FFd7416410257' + } + ``` + + RFQV1: ``` { + quoteId: '0x123', protocol: 'RFQV1', rfqOrder: { - takerAddr: '0x87fca7135c1c54876a62dc4922da3ce45f38debf', - makerAddr: '0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64', + takerAddr: '0xcabfea3a7f41452a9c8e475a53b30c43fbff6683', + makerAddr: '0x86b9f429c3ef44c599eb560eb531a0e3f2e36f64', takerAssetAddr: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', makerAssetAddr: '0xdac17f958d2ee523a2206206994597c13d831ec7', takerAssetAmount: '1000000000000000000', makerAssetAmount: '100000000', deadline: 1620444917, feeFactor: 30, - salt: '54987026777386128963216107663301166813737035846370728350988439404382800511006' + salt: '7719472615821079694904732333912527190235994441565629342017219118620679208990' }, - userAddr: '0x87fca7135c1c54876a62dc4922da3ce45f38debf', + feeFactor: 30, + orderHash: '0x77eda617afe88090a34cf031470b0968c1754a474f573dfb5c5b5c67cf8167ce', + orderSignDigest: '0xdd785ffa1a694db8af972523ee115fc95580929e23ac5c46a62692b0f6600fc5', + userAddr: '0xcabfea3a7f41452a9c8e475a53b30c43fbff6683', chainId: 1, - rfqAddr: '0xfD6C2d2499b1331101726A8AC68CCc9Da3fAB54F' + rfqAddr: '0x117CAf73eB142eDC431E707DC33D4dfeF7c5BAd0' } ``` + + RFQV2: + ``` + { + quoteId: '0x123', + protocol: 'RFQV2', + rfqOrder: { + taker: '0x8fda8bc038af1c426838248718eb2fd5425882cc', + maker: '0x86b9f429c3ef44c599eb560eb531a0e3f2e36f64', + takerToken: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + takerTokenAmount: '1000000000000000000', + makerToken: '0xdac17f958d2ee523a2206206994597c13d831ec7', + makerTokenAmount: '100000000', + feeFactor: '30', + expiry: '1620444917', + salt: '0x11111111111111111111111111111111' + }, + feeFactor: 30, + orderHash: '0xd431d9a453b67d76244e6ea1244895fa4c2e874eee03bc2af1f6e171afa938ae', + orderSignDigest: '0x9573a91c47d9bdad67354a5a677d778eff3ccb94866bfe3c2907827db7866c91', + userAddr: '0x8fda8bc038af1c426838248718eb2fd5425882cc', + chainId: 1, + rfqAddr: '0xaE5FDd548E5B107C54E5c0D36952fB8a089f10C7' + } + ``` + An example response the signing service should return ``` { diff --git a/app/mmConfig.js b/app/mmConfig.js index 454e27d..ead5701 100644 --- a/app/mmConfig.js +++ b/app/mmConfig.js @@ -1,4 +1,6 @@ const types = require('../lib/signer/types') +const dotenv = require('dotenv') +dotenv.config() module.exports = { // Tokenlon server address diff --git a/package-lock.json b/package-lock.json index 3c7b35e..b2eb344 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@consenlabs/tokenlon-mmsk", - "version": "5.2.8", + "version": "5.3.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@consenlabs/tokenlon-mmsk", - "version": "5.2.8", + "version": "5.3.2", "license": "MIT", "dependencies": { "@0x/contract-addresses": "^4.11.0", @@ -51,6 +51,7 @@ "ethereum-types": "^3.2.0", "hardhat": "^2.9.3", "hardhat-gas-reporter": "1.0.4", + "nock": "^13.3.3", "npm-run-all": "4.1.5", "prettier": "^2.0.5", "ts-node": "8.10.2", @@ -18702,6 +18703,21 @@ "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" }, + "node_modules/nock": { + "version": "13.3.3", + "resolved": "https://registry.npmjs.org/nock/-/nock-13.3.3.tgz", + "integrity": "sha512-z+KUlILy9SK/RjpeXDiDUEAq4T94ADPHE3qaRkf66mpEhzc/ytOMm3Bwdrbq6k1tMWkbdujiKim3G2tfQARuJw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.21", + "propagate": "^2.0.0" + }, + "engines": { + "node": ">= 10.13" + } + }, "node_modules/node-abi": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz", @@ -19608,6 +19624,15 @@ "node": ">=0.10.0" } }, + "node_modules/propagate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", + "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -36972,6 +36997,18 @@ "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" }, + "nock": { + "version": "13.3.3", + "resolved": "https://registry.npmjs.org/nock/-/nock-13.3.3.tgz", + "integrity": "sha512-z+KUlILy9SK/RjpeXDiDUEAq4T94ADPHE3qaRkf66mpEhzc/ytOMm3Bwdrbq6k1tMWkbdujiKim3G2tfQARuJw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.21", + "propagate": "^2.0.0" + } + }, "node-abi": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz", @@ -37640,6 +37677,12 @@ "set-immediate-shim": "^1.0.1" } }, + "propagate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", + "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", + "dev": true + }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", diff --git a/package.json b/package.json index 2bde119..84ddf47 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@consenlabs/tokenlon-mmsk", - "version": "5.3.1", + "version": "5.3.2", "description": "Tokenlon market maker server kit", "author": "imToken PTE. LTD.", "license": "MIT", @@ -26,7 +26,7 @@ "check": "node ./app/check.js", "clean": "rm -rf ./lib", "start": "node ./app/start.js", - "test": "chainId=5 npx hardhat --network hardhat test", + "test": "chainId=1 npx hardhat --network hardhat test", "watch": "tsc -w" }, "devDependencies": { @@ -46,6 +46,7 @@ "ethereum-types": "^3.2.0", "hardhat": "^2.9.3", "hardhat-gas-reporter": "1.0.4", + "nock": "^13.3.3", "npm-run-all": "4.1.5", "prettier": "^2.0.5", "ts-node": "8.10.2", diff --git a/src/handler/index.ts b/src/handler/index.ts index 2909ec5..951da70 100644 --- a/src/handler/index.ts +++ b/src/handler/index.ts @@ -8,3 +8,4 @@ export { getOrderState } from './getOrderState' export { dealOrder } from './dealOrder' export { exceptionOrder } from './exceptionOrder' export { version } from './version' +export { signOrder } from './signOrder' diff --git a/src/handler/newOrder.ts b/src/handler/newOrder.ts index 5f1ba3e..0702470 100644 --- a/src/handler/newOrder.ts +++ b/src/handler/newOrder.ts @@ -5,7 +5,6 @@ import { Protocol, QueryInterface } from '../types' import { validateNewOrderRequest, validateRequest } from '../validations' import { ValidationError } from './errors' import { addQuoteIdPrefix, constructQuoteResponse, preprocessQuote } from '../quoting' - import { assetDataUtils } from '0x-v2-order-utils' import { buildSignedOrder as buildRFQV1SignedOrder } from '../signer/rfqv1' import { buildSignedOrder as buildRFQV2SignedOrder } from '../signer/rfqv2' @@ -22,27 +21,28 @@ import { getWethAddrIfIsEth, getTimestamp, } from '../utils' +import { ExtendedZXOrder } from '../signer/types' type NumberOrString = number | string -interface Order { +export interface Order { // quoteId is from market maker backend quoter. - quoteId: string + quoteId: string | number // protocol represents the order type as enum, [PMMV4, PMMV5, AMMV1, RFQV1, AMMV2]. protocol: Protocol // Common fields makerAddress: string - makerAssetAmount: string + makerAssetAmount: string | BigNumber makerAssetAddress: string takerAddress: string - takerAssetAmount: string + takerAssetAmount: string | BigNumber takerAssetAddress: string - expirationTimeSeconds: string + expirationTimeSeconds: BigNumber | string // feeFactor is tokenlon protocol field, works like BPS, should <= 10000. feeFactor: number // salt represents the uniqueness of order, is to prevent replay attack. - salt: string + salt?: BigNumber | string // 0x protocol specific fields makerAssetData: string @@ -53,14 +53,14 @@ interface Order { exchangeAddress: string // makerFee and takerFee are not used, but keep to make 0x order signature. - makerFee: string - takerFee: string + makerFee: BigNumber | string + takerFee: BigNumber | string // PMM/RFQ market maker signature - makerWalletSignature: string + makerWalletSignature?: string // Extra data - payload: string + payload?: string } interface Response { @@ -97,7 +97,10 @@ function extractAssetAmounts( side, rate: number | string, amountBN: BigNumber -) { +): { + makerAssetAmount: BigNumber + takerAssetAmount: BigNumber +} { let makerAssetAmount, takerAssetAmount if (side === 'BUY') { makerAssetAmount = fromUnitToDecimalBN( @@ -121,7 +124,13 @@ function extractAssetAmounts( return { makerAssetAmount, takerAssetAmount } } -function getOrderAndFeeFactor(query: QueryInterface, rate, tokenList, tokenConfigs, config) { +function getOrderAndFeeFactor( + query: QueryInterface, + rate, + tokenList, + tokenConfigs, + config +): ExtendedZXOrder { const { side, amount, feefactor } = query const baseToken = getTokenByAddress(tokenList, query.baseAddress) const quoteToken = getTokenByAddress(tokenList, query.quoteAddress) @@ -129,7 +138,7 @@ function getOrderAndFeeFactor(query: QueryInterface, rate, tokenList, tokenConfi const takerToken = side === 'BUY' ? quoteToken : baseToken const foundTokenConfig = tokenConfigs.find((t) => t.symbol === makerToken.symbol) - let fFactor = config.feeFactor || 10 + let fFactor: number = Number(config.feeFactor) || 10 if (foundTokenConfig?.feeFactor) { // console.log('set fee factor from token config', { factor: foundTokenConfig.feeFactor }) fFactor = foundTokenConfig.feeFactor @@ -154,32 +163,37 @@ function getOrderAndFeeFactor(query: QueryInterface, rate, tokenList, tokenConfi ) // ETH -> WETH - const makerAssetAddress = getWethAddrIfIsEth( + const makerAssetAddress: string = getWethAddrIfIsEth( makerToken.contractAddress, config.wethContractAddress ) // ETH -> WETH - let takerAssetAddress = getWethAddrIfIsEth(takerToken.contractAddress, config.wethContractAddress) + let takerAssetAddress: string = getWethAddrIfIsEth( + takerToken.contractAddress, + config.wethContractAddress + ) if (Protocol.RFQV2 === query.protocol) { takerAssetAddress = takerToken.contractAddress } return { + protocol: query.protocol, + quoteId: query.uniqId, makerAddress: config.mmProxyContractAddress.toLowerCase(), makerAssetAmount, makerAssetAddress: makerAssetAddress, makerAssetData: assetDataUtils.encodeERC20AssetData(makerAssetAddress), makerFee: toBN(0), - takerAddress: config.userProxyContractAddress, + takerAddress: config.userProxyContractAddress as string, takerAssetAmount, takerAssetAddress: takerAssetAddress, takerAssetData: assetDataUtils.encodeERC20AssetData(takerAssetAddress), takerFee: toBN(0), senderAddress: config.tokenlonExchangeContractAddress.toLowerCase(), - feeRecipientAddress: FEE_RECIPIENT_ADDRESS, + feeRecipientAddress: FEE_RECIPIENT_ADDRESS.toLowerCase(), expirationTimeSeconds: toBN(getTimestamp() + +config.orderExpirationSeconds), - exchangeAddress: config.exchangeContractAddress, + exchangeAddress: config.exchangeContractAddress.toLowerCase() as string, feeFactor: fFactor, } diff --git a/src/handler/signOrder.ts b/src/handler/signOrder.ts new file mode 100644 index 0000000..1442225 --- /dev/null +++ b/src/handler/signOrder.ts @@ -0,0 +1,139 @@ +import { Protocol } from '../types' + +import { signByMMPSigner as signRFQV1ByMMPSigner, signRFQOrder } from '../signer/rfqv1' +import { signByMMPSigner as signRFQV2ByMMPSigner, signOffer } from '../signer/rfqv2' +import { signByEOA as signPMMV5ByEOA, signByMMPSigner } from '../signer/pmmv5' +import { BigNumber } from '../utils' +import { getWallet } from '../config' +import { SignatureType, WalletType } from '../signer/types' +import { updaterStack } from '../worker' + +export interface Order { + // quoteId is from market maker backend quoter. + quoteId: string | number + // protocol represents the order type as enum, [PMMV4, PMMV5, AMMV1, RFQV1, AMMV2]. + protocol: Protocol + + // Common fields + makerAddress: string + makerAssetAmount: string | BigNumber + makerAssetAddress: string + takerAddress: string + takerAssetAmount: string | BigNumber + takerAssetAddress: string + expirationTimeSeconds: BigNumber | string + // feeFactor is tokenlon protocol field, works like BPS, should <= 10000. + feeFactor: number + // salt represents the uniqueness of order, is to prevent replay attack. + salt?: BigNumber | string + + // 0x protocol specific fields + makerAssetData: string + takerAssetData: string + senderAddress: string + // For PMMV5, we use this field as receiver address (user address). + feeRecipientAddress: string + exchangeAddress: string + + // makerFee and takerFee are not used, but keep to make 0x order signature. + makerFee: BigNumber | string + takerFee: BigNumber | string + + // PMM/RFQ market maker signature + makerWalletSignature?: string + + // Extra data + payload?: string +} + +export const signOrder = async (ctx) => { + const { chainID, walletType } = ctx + const order = ctx.request.body + const protocol = ctx.request.body.protocol + const signer = getWallet() + console.log('signer') + console.log(signer) + const config = updaterStack.markerMakerConfigUpdater.cacheResult + let signature + try { + switch (protocol) { + case Protocol.PMMV5: + signature = + signer.address.toLowerCase() == order.pmmOrder.makerAddress.toLowerCase() + ? await signPMMV5ByEOA(order.orderSignDigest, signer) + : await signByMMPSigner(order.orderSignDigest, order.userAddr, order.feeFactor, signer) + break + case Protocol.RFQV1: + if (signer.address.toLowerCase() == order.rfqOrder.makerAddr.toLowerCase()) { + signature = await signRFQOrder( + chainID, + config.addressBookV5.RFQ, + order.rfqOrder, + signer, + order.feeFactor, + SignatureType.EIP712 + ) + } else if (walletType === WalletType.MMP_VERSION_4) { + signature = await signRFQV1ByMMPSigner( + order.orderSignDigest, + order.userAddr, + order.feeFactor, + signer, + WalletType.MMP_VERSION_4 + ) + } else if (walletType === WalletType.ERC1271_EIP712) { + signature = await signRFQOrder( + chainID, + config.addressBookV5.RFQ, + order.rfqOrder, + signer, + order.feeFactor, + SignatureType.WalletBytes32 + ) + } + break + case Protocol.RFQV2: + if (signer.address.toLowerCase() == order.rfqOrder.maker.toLowerCase()) { + signature = await signOffer( + chainID, + config.addressBookV5.RFQV2, + order.rfqOrder, + signer, + SignatureType.EIP712 + ) + } else if (walletType === WalletType.MMP_VERSION_4) { + signature = await signRFQV2ByMMPSigner( + order.orderSignDigest, + order.userAddr, + order.feeFactor, + signer, + WalletType.MMP_VERSION_4 + ) + } else if (walletType === WalletType.ERC1271_EIP712) { + signature = await signOffer( + chainID, + config.addressBookV5.RFQV2, + order.rfqOrder, + signer, + SignatureType.WalletBytes32 + ) + } + break + default: + console.log(`unknown protocol ${protocol}`) + throw new Error('Unrecognized protocol: ' + protocol) + } + ctx.body = { + result: true, + signature: signature, + } + return + } catch (e) { + console.error(e.stack) + ctx.body = { + result: false, + message: e.message, + } + return e.message + } +} diff --git a/src/handler/version.ts b/src/handler/version.ts index 24bc157..1aaeef1 100644 --- a/src/handler/version.ts +++ b/src/handler/version.ts @@ -1,4 +1,4 @@ -export const VERSION = '5.3.1' +export const VERSION = '5.3.2' export const version = (ctx) => { ctx.body = { diff --git a/src/remote_sign.ts b/src/remote_sign.ts new file mode 100644 index 0000000..b820bb2 --- /dev/null +++ b/src/remote_sign.ts @@ -0,0 +1,154 @@ +import * as Koa from 'koa' +import * as Router from 'koa-router' +import * as Bodyparser from 'koa-bodyparser' +import { Protocol } from './types' +import { signByEOA as signPMMV5EOA, signByMMPSigner as signPMMV5ByMMPSigner } from './signer/pmmv5' +import { signRFQOrder, signByMMPSigner as signRFQV1ByMMPSigner } from './signer/rfqv1' +import { signOffer, signByMMPSigner as signRFQV2ByMMPSigner } from './signer/rfqv2' +import * as ethers from 'ethers' +import { + RemoteSigningPMMV5Request, + RemoteSigningRFQV1Request, + RemoteSigningRFQV2Request, + SignatureType, + WalletType, +} from './signer/types' +import * as config from '../app/mmConfig.js' + +const privateKey = config.WALLET_PRIVATE_KEY as string +const signer = new ethers.Wallet(privateKey) + +const walletType = WalletType.MMP_VERSION_4 + +const port = 3000 + +const signPMMV5 = async (signRequest: RemoteSigningPMMV5Request) => { + console.log(signRequest) + const pmmOrder = signRequest.pmmOrder + let signature + if (signer.address.toLowerCase() === pmmOrder.makerAddress.toLowerCase()) { + signature = signPMMV5EOA(signRequest.orderSignDigest, signer) + } else { + signature = await signPMMV5ByMMPSigner( + signRequest.orderSignDigest, + signRequest.userAddr, + signRequest.feeFactor, + signer + ) + } + console.log(signature) + return signature +} + +const signRFQV1 = async (signRequest: RemoteSigningRFQV1Request) => { + console.log(signRequest) + const rfqOrder = signRequest.rfqOrder + let signature + if (signer.address.toLowerCase() === rfqOrder.makerAddr.toLowerCase()) { + signature = await signRFQOrder( + signRequest.chainId, + `0xfD6C2d2499b1331101726A8AC68CCc9Da3fAB54F`, + signRequest.rfqOrder, + signer, + signRequest.feeFactor, + SignatureType.EIP712 + ) + } else if (walletType === WalletType.MMP_VERSION_4) { + signature = await signRFQV1ByMMPSigner( + signRequest.orderSignDigest, + signRequest.userAddr, + signRequest.feeFactor, + signer, + WalletType.MMP_VERSION_4 + ) + } else if (walletType === WalletType.ERC1271_EIP712) { + signature = await signRFQOrder( + signRequest.chainId, + `0xfD6C2d2499b1331101726A8AC68CCc9Da3fAB54F`, + signRequest.rfqOrder, + signer, + signRequest.feeFactor, + SignatureType.WalletBytes32 + ) + } + console.log(`signature: ${signature}`) + return signature +} + +const signRFQV2 = async (signRequest: RemoteSigningRFQV2Request) => { + console.log(signRequest) + const rfqOrder = signRequest.rfqOrder + let signature + if (signer.address.toLowerCase() === rfqOrder.maker.toLowerCase()) { + signature = await signOffer( + signRequest.chainId, + '0x91C986709Bb4fE0763edF8E2690EE9d5019Bea4a', + signRequest.rfqOrder, + signer, + SignatureType.EIP712 + ) + } else if (walletType === WalletType.MMP_VERSION_4) { + signature = await signRFQV2ByMMPSigner( + signRequest.orderSignDigest, + signRequest.userAddr, + signRequest.feeFactor, + signer, + WalletType.MMP_VERSION_4 + ) + } else if (walletType === WalletType.ERC1271_EIP712) { + signature = await signOffer( + signRequest.chainId, + '0x91C986709Bb4fE0763edF8E2690EE9d5019Bea4a', + signRequest.rfqOrder, + signer, + SignatureType.WalletBytes32 + ) + } + console.log(`signature: ${signature}`) + return signature +} + +const sign = async (ctx) => { + const signRequest = ctx.request.body + let signature + if (signRequest.protocol === Protocol.PMMV5) { + signature = await signPMMV5(signRequest) + } else if (signRequest.protocol === Protocol.RFQV1) { + signature = await signRFQV1(signRequest) + } else if (signRequest.protocol === Protocol.RFQV2) { + signature = await signRFQV2(signRequest) + } else { + throw new Error('Invalid protocol') + } + + const response = { + signature: signature, + } + ctx.body = response +} + +const main = async () => { + const app = new Koa() + const router = new Router() + + router.get(`/`, (ctx) => { + console.log(ctx) + ctx.body = { + result: true, + version: '5.3.2', + } + }) + router.post('/sign', sign) + + app.use(Bodyparser()) + app.use(router.routes()) + app.use(router.allowedMethods()) + app.on('error', (err) => { + console.error(err) + }) + app.listen(port) + console.log(router.routes()) + console.log(`Server started ${port} port`) +} + +main().catch(console.error) diff --git a/src/signer/pmmv5.ts b/src/signer/pmmv5.ts index 2adaa82..6aef7e1 100644 --- a/src/signer/pmmv5.ts +++ b/src/signer/pmmv5.ts @@ -11,6 +11,8 @@ import { utils, Wallet } from 'ethers' import axios from 'axios' import { BigNumber, orderBNToString } from '../utils' import { Protocol } from '../types' +import { ExtendedZXOrder, RemoteSigningPMMV5Request } from './types' +import { Order as ZXOrder } from '0x-v2-order-utils' const EIP712_ORDER_SCHEMA = { name: 'Order', @@ -90,7 +92,7 @@ export async function signWithUserAndFee( // +------|---------|---------|---------+ // | v | R | S | type(3) | // +------|---------|---------|---------+ -async function signByEOA(orderSignDigest: string, wallet: Wallet): Promise { +export async function signByEOA(orderSignDigest: string, wallet: Wallet): Promise { const hashArray = utils.arrayify(orderSignDigest) let signature = await wallet.signMessage(hashArray) signature = signature.slice(2) @@ -105,7 +107,7 @@ async function signByEOA(orderSignDigest: string, wallet: Wallet): Promise => { +export const forwardUnsignedOrder = async ( + signingUrl: string, + orderInfo: RemoteSigningPMMV5Request +): Promise => { + console.log(`Signing url: ${signingUrl}`) + console.log(`PMMV5 order:`) + console.log(orderInfo) const resp = await axios.post(signingUrl, orderInfo) const body = resp.data + console.log(`response:`) + console.log(body) if (body.signature) { return body.signature } else { @@ -127,27 +137,41 @@ export const forwardUnsignedOrder = async (signingUrl: string, orderInfo: any): // Move fee factor to salt field export const buildSignedOrder = async ( - signer: Wallet, - order, - userAddr, - chainId, - pmm, + signer: Wallet | undefined, + order: ExtendedZXOrder, + userAddr: string, + chainId: number, + pmm: string, options?: { signingUrl?: string salt?: string } -): Promise => { +): Promise => { const signingUrl = options ? options.signingUrl : undefined const feeFactor = order.feeFactor order.takerAddress = pmm.toLowerCase() order.senderAddress = pmm.toLowerCase() order.feeRecipientAddress = userAddr - + const salt = options ? options.salt : undefined + order.salt = salt ? new BigNumber(salt) : generateSaltWithFeeFactor(feeFactor) // inject fee factor to salt - const o = { - ...order, - salt: generateSaltWithFeeFactor(feeFactor), + const o: ZXOrder = { + makerAddress: order.makerAddress, + makerAssetAmount: order.makerAssetAmount as BigNumber, + makerAssetData: order.makerAssetData, + makerFee: order.makerFee as BigNumber, + takerAddress: order.takerAddress, + takerAssetAmount: order.takerAssetAmount as BigNumber, + takerAssetData: order.takerAssetData, + takerFee: order.takerFee as BigNumber, + senderAddress: order.senderAddress, + feeRecipientAddress: order.feeRecipientAddress, + expirationTimeSeconds: order.expirationTimeSeconds as BigNumber, + exchangeAddress: order.exchangeAddress, + salt: order.salt, } + console.log(`ZXOrder:`) + console.log(orderBNToString(o)) const orderHashBuffer = eip712Utils.structHash(EIP712_ORDER_SCHEMA, o) const orderHash = '0x' + orderHashBuffer.toString('hex') console.log(`orderHash: ${orderHash}`) @@ -161,8 +185,9 @@ export const buildSignedOrder = async ( : await signByMMPSigner(orderSignDigest, userAddr, feeFactor, signer) } else { makerWalletSignature = await forwardUnsignedOrder(signingUrl, { + quoteId: order.quoteId, protocol: Protocol.PMMV5, - pmmOrder: o, + pmmOrder: orderBNToString(o), feeFactor: feeFactor, orderHash: orderHash, orderSignDigest: orderSignDigest, @@ -173,7 +198,7 @@ export const buildSignedOrder = async ( } const signedOrder = { - ...o, + ...order, makerWalletSignature, } diff --git a/src/signer/rfqv1.ts b/src/signer/rfqv1.ts index bfa6b10..8019b9a 100644 --- a/src/signer/rfqv1.ts +++ b/src/signer/rfqv1.ts @@ -2,7 +2,7 @@ import { Wallet, utils } from 'ethers' import { orderBNToString, BigNumber } from '../utils' import { generateSaltWithFeeFactor, signWithUserAndFee } from './pmmv5' import { getOrderHash, getOrderSignDigest } from './orderHash' -import { RFQOrder, WalletType } from './types' +import { ExtendedZXOrder, RFQOrder, RemoteSigningRFQV1Request, WalletType } from './types' import * as ethUtils from 'ethereumjs-util' import { SignatureType } from './types' import axios from 'axios' @@ -68,9 +68,17 @@ export async function signByMMPSigner( } } -export const forwardUnsignedOrder = async (signingUrl: string, orderInfo: any): Promise => { +export const forwardUnsignedOrder = async ( + signingUrl: string, + orderInfo: RemoteSigningRFQV1Request +): Promise => { + console.log(`Signing url: ${signingUrl}`) + console.log(`RFQV1 order:`) + console.log(orderInfo) const resp = await axios.post(signingUrl, orderInfo) const body = resp.data + console.log(`response:`) + console.log(body) if (body.signature) { return body.signature } else { @@ -81,11 +89,11 @@ export const forwardUnsignedOrder = async (signingUrl: string, orderInfo: any): export const signRFQOrder = async ( chainId: number, rfqAddr: string, - order: any, + order: RFQOrder, maker: Wallet, feeFactor = 30, signatureType = SignatureType.EIP712 -) => { +): Promise => { const domain = { name: 'Tokenlon', version: 'v5', @@ -132,8 +140,8 @@ export const signRFQOrder = async ( } export const buildSignedOrder = async ( - signer: Wallet, - order: any, + signer: Wallet | undefined, + order: ExtendedZXOrder, userAddr: string, chainId: number, rfqAddr: string, @@ -142,7 +150,7 @@ export const buildSignedOrder = async ( signingUrl?: string salt?: string } -): Promise => { +): Promise => { // inject fee factor to salt const feeFactor = order.feeFactor order.takerAddress = userAddr.toLowerCase() @@ -150,7 +158,11 @@ export const buildSignedOrder = async ( const signingUrl = options ? options.signingUrl : undefined order.salt = generateSaltWithFeeFactor(feeFactor, salt) + console.log(`rfqV1Order:`) + console.log(orderBNToString(order)) const rfqOrder = toRFQOrder(order) + console.log(`rfqOrder:`) + console.log(orderBNToString(rfqOrder)) const orderHash = getOrderHash(rfqOrder) console.log(`orderHash: ${orderHash}`) @@ -189,8 +201,12 @@ export const buildSignedOrder = async ( } } else { makerWalletSignature = await forwardUnsignedOrder(signingUrl, { + quoteId: order.quoteId, protocol: Protocol.RFQV1, - rfqOrder: rfqOrder, + rfqOrder: orderBNToString(rfqOrder), + feeFactor: feeFactor, + orderHash: orderHash, + orderSignDigest: orderSignDigest, userAddr: userAddr, chainId: chainId, rfqAddr: rfqAddr, @@ -207,7 +223,7 @@ export const buildSignedOrder = async ( const toNumber = (obj: BigNumber | string): number => new BigNumber(obj).toNumber() -export function toRFQOrder(order): RFQOrder { +export function toRFQOrder(order: ExtendedZXOrder): RFQOrder { return { takerAddr: order.takerAddress, makerAddr: order.makerAddress, diff --git a/src/signer/rfqv2.ts b/src/signer/rfqv2.ts index b13db77..ee3576e 100644 --- a/src/signer/rfqv2.ts +++ b/src/signer/rfqv2.ts @@ -1,12 +1,20 @@ import { utils, Wallet } from 'ethers' import { orderBNToString } from '../utils' import { getOfferHash, getOfferSignDigest } from './orderHash' -import { Offer, PermitType, WalletType, SignatureType } from './types' +import { + Offer, + PermitType, + WalletType, + SignatureType, + ExtendedZXOrder, + RemoteSigningRFQV2Request, +} from './types' import * as ethUtils from 'ethereumjs-util' import axios from 'axios' import { generatePseudoRandomSalt } from '0x-v2-order-utils' import { signWithUserAndFee } from './pmmv5' import { Protocol } from '../types' +import { BigNumber } from '0x-v2-utils' // spec of RFQV2 // - taker address point to userAddr @@ -68,9 +76,17 @@ export async function signByMMPSigner( } } -export const forwardUnsignedOrder = async (signingUrl: string, orderInfo: any): Promise => { +export const forwardUnsignedOrder = async ( + signingUrl: string, + orderInfo: RemoteSigningRFQV2Request +): Promise => { + console.log(`Signing url: ${signingUrl}`) + console.log(`RFQV2 order:`) + console.log(orderInfo) const resp = await axios.post(signingUrl, orderInfo) const body = resp.data + console.log(`response:`) + console.log(body) if (body.signature) { return body.signature } else { @@ -117,8 +133,8 @@ export const signOffer = async ( } export const buildSignedOrder = async ( - signer: Wallet, - order: any, + signer: Wallet | undefined, + order: ExtendedZXOrder, userAddr: string, chainId: number, rfqAddr: string, @@ -128,17 +144,22 @@ export const buildSignedOrder = async ( signingUrl?: string salt?: string } -): Promise => { +): Promise => { // inject fee factor to salt const feeFactor = order.feeFactor order.takerAddress = userAddr.toLowerCase() const salt = options ? options.salt : undefined - order.salt = salt ? salt : generatePseudoRandomSalt() + const rfqV2Order = { + ...order, + salt: salt ? salt : generatePseudoRandomSalt(), + } + console.log(`rfqV2Order:`) + console.log(orderBNToString(rfqV2Order)) const signingUrl = options ? options.signingUrl : undefined - const rfqOrder = toOffer(order) - console.log(`rfqOrder`) - console.log(rfqOrder) + const rfqOrder = toOffer(rfqV2Order) + console.log(`offer:`) + console.log(orderBNToString(rfqOrder)) const orderHash = getOfferHash(rfqOrder) console.log(`orderHash: ${orderHash}`) const orderSignDigest = getOfferSignDigest(rfqOrder, chainId, rfqAddr) @@ -176,8 +197,12 @@ export const buildSignedOrder = async ( } } else { makerWalletSignature = await forwardUnsignedOrder(signingUrl, { + quoteId: order.quoteId, protocol: Protocol.RFQV2, - rfqOrder: rfqOrder, + rfqOrder: orderBNToString(rfqOrder), + feeFactor: feeFactor, + orderHash: orderHash, + orderSignDigest: orderSignDigest, userAddr: userAddr, chainId: chainId, rfqAddr: rfqAddr, @@ -185,7 +210,7 @@ export const buildSignedOrder = async ( } const signedOrder = { - ...order, + ...rfqV2Order, payload: Buffer.from(JSON.stringify({ makerTokenPermit: permitType })).toString('base64'), makerWalletSignature, } @@ -193,7 +218,9 @@ export const buildSignedOrder = async ( return orderBNToString(signedOrder) } -export function toOffer(order): Offer { +const toNumber = (obj: BigNumber | string): number => new BigNumber(obj).toNumber() + +export function toOffer(order: ExtendedZXOrder): Offer { return { taker: order.takerAddress, maker: order.makerAddress, @@ -201,8 +228,8 @@ export function toOffer(order): Offer { takerTokenAmount: order.takerAssetAmount.toString(), makerToken: order.makerAssetAddress, makerTokenAmount: order.makerAssetAmount.toString(), - feeFactor: order.feeFactor.toString(), - expiry: order.expirationTimeSeconds.toString(), + feeFactor: order.feeFactor, + expiry: toNumber(order.expirationTimeSeconds), salt: order.salt.toString(), } } diff --git a/src/signer/types.ts b/src/signer/types.ts index 85f12ca..d98fc6c 100644 --- a/src/signer/types.ts +++ b/src/signer/types.ts @@ -1,5 +1,6 @@ import { BigNumber } from '../utils' -import { MarketMakerConfig, Token, TokenConfig } from '../types' +import { MarketMakerConfig, Protocol, Token, TokenConfig } from '../types' +import { Order as ZXOrder } from '0x-v2-order-utils' export interface SimpleOrder { side: string @@ -26,9 +27,9 @@ export interface RFQOrder { makerAddr: string takerAssetAddr: string makerAssetAddr: string - takerAssetAmount: BigNumber - makerAssetAmount: BigNumber - salt: BigNumber + takerAssetAmount: BigNumber | string + makerAssetAmount: BigNumber | string + salt: BigNumber | string deadline: number feeFactor: number } @@ -37,17 +38,71 @@ export interface Offer { taker: string maker: string takerToken: string - takerTokenAmount: BigNumber + takerTokenAmount: BigNumber | string makerToken: string - makerTokenAmount: BigNumber + makerTokenAmount: BigNumber | string feeFactor: number expiry: number salt: BigNumber | string } -export interface RFQV2Order { - offer: Offer - recipient: string +export interface ExtendedZXOrder { + senderAddress: string + makerAddress: string + makerAssetAddress: string + takerAddress: string + takerAssetAddress: string + makerFee: BigNumber | string + takerFee: BigNumber | string + makerAssetAmount: BigNumber | string + takerAssetAmount: BigNumber | string + makerAssetData: string + takerAssetData: string + salt?: string | BigNumber | string + exchangeAddress: string + feeRecipientAddress: string + expirationTimeSeconds: BigNumber | string + feeFactor: number + quoteId: number | string + protocol: Protocol + makerWalletSignature?: string + payload?: string +} + +export interface RemoteSigningPMMV5Request { + quoteId: number | string + protocol: Protocol + pmmOrder: ZXOrder + feeFactor: number + orderHash: string + orderSignDigest: string + userAddr: string + chainId: number + pmmAddr: string +} + +export interface RemoteSigningRFQV1Request { + quoteId: number | string + protocol: Protocol + rfqOrder: RFQOrder + feeFactor: number + orderHash: string + orderSignDigest: string + userAddr: string + chainId: number + rfqAddr: string +} + +export interface RemoteSigningRFQV2Request { + quoteId: number | string + protocol: Protocol + rfqOrder: Offer + feeFactor: number + orderHash: string + orderSignDigest: string + userAddr: string + chainId: number + rfqAddr: string } export enum SignatureType { diff --git a/src/start.ts b/src/start.ts index caedb2e..e3fb925 100644 --- a/src/start.ts +++ b/src/start.ts @@ -15,6 +15,7 @@ import { dealOrder, exceptionOrder, version, + signOrder, } from './handler' import { setConfig, getWallet } from './config' import { ConfigForStart } from './types' @@ -88,8 +89,10 @@ export const startMMSK = async (config: ConfigForStart) => { version: VERSION, signerAddress: config.WALLET_ADDRESS, mmpType: config.WALLET_TYPE || WalletType.MMP_VERSION_4, + permitType: config.PERMIT_TYPE || PermitType.ALLOWANCE_TARGET, chainId: config.CHAIN_ID, exchangeUrl: config.EXCHANGE_URL, + signingUrl: config.SIGNING_URL, }) // init sentry @@ -99,6 +102,7 @@ export const startMMSK = async (config: ConfigForStart) => { // Respond to Tokenlon quoting server router.get('/getRate', getRate) + router.post('/signOrder', signOrder) router.get('/newOrder', newOrder) router.get('/version', version) router.get('/getSupportedTokenList', getSupportedTokenList) diff --git a/src/utils/format.ts b/src/utils/format.ts index fb095f3..dd5174f 100644 --- a/src/utils/format.ts +++ b/src/utils/format.ts @@ -1,5 +1,7 @@ import { reduce } from 'lodash' import { BigNumber } from '@0xproject/utils' +import { ExtendedZXOrder, Offer, RFQOrder } from '../signer/types' +import { Order as ZXOrder } from '0x-v2-order-utils' BigNumber.config({ ROUNDING_MODE: BigNumber.ROUND_FLOOR, @@ -27,14 +29,16 @@ export const isBigNumber = (v: any): boolean => { ) } -export const orderBNToString = (order) => { +export function orderBNToString( + order: T +): T { return reduce( order, (acc, v, key) => { acc[key] = isBigNumber(v) ? v.toString() : v return acc }, - {} + {} as T ) } diff --git a/test/new_order.spec.ts b/test/new_order.spec.ts index 973f2d7..f3bce6b 100644 --- a/test/new_order.spec.ts +++ b/test/new_order.spec.ts @@ -4,16 +4,22 @@ import { newOrder } from '../src/handler' import { updaterStack, Updater } from '../src/worker' import { NULL_ADDRESS } from '../src/constants' import { Protocol } from '../src/types' -import { buildSignedOrder, toRFQOrder } from '../src/signer/rfqv1' -import { SignatureType, WalletType } from '../src/signer/types' +import { toRFQOrder } from '../src/signer/rfqv1' +import { buildSignedOrder as buildPMMV5SignedOrder } from '../src/signer/pmmv5' +import { buildSignedOrder as buildRFQV1SignedOrder } from '../src/signer/rfqv1' +import { buildSignedOrder as buildRFQV2SignedOrder } from '../src/signer/rfqv2' +import { ExtendedZXOrder, PermitType, SignatureType, WalletType } from '../src/signer/types' import { getOrderSignDigest, getOfferSignDigest } from '../src/signer/orderHash' -import { BigNumber } from '../src/utils' +import { BigNumber, toBN } from '../src/utils' import * as ethUtils from 'ethereumjs-util' import { AllowanceTarget, USDT, ABI, WETH, ZERO } from '@tokenlon/sdk' import * as crypto from 'crypto' import { expect } from 'chai' import { generateSaltWithFeeFactor } from '../src/signer/pmmv5' import { toOffer } from '../src/signer/rfqv2' +import { assetDataUtils } from '0x-v2-order-utils' +import * as nock from 'nock' + const usdtHolders = { 1: '0x15abb66bA754F05cBC0165A64A11cDed1543dE48', 5: '0x031BBFB9379c4e6E3F42fb93a9f09C060c7fA037', @@ -128,6 +134,8 @@ describe('NewOrder', function () { expect(signedOrderResp).is.not.null // verify data object const order = signedOrderResp.order + console.log(`order`) + console.log(order) expect(order).is.not.null expect(order.protocol).eq(Protocol.AMMV1) expect(order.quoteId).eq('1--echo-testing-8888') @@ -1174,40 +1182,177 @@ describe('NewOrder', function () { const orderHash = getOrderSignDigest(order, 1, rfqAddr) expect(orderHash).eq('0x8d70993864d87daa0b2bae0c2be1c56067f45363680d0dca8657e1e51d1d6a40') }) - it('Should forward unsigned orders to signing service', async () => { - // const url = `http://localhost:3000` + it('Should forward unsigned PMMV5 orders to signing service', async () => { + const url = `http://localhost:3000` + const pmm = '0x7bd7d025D4231aAD1233967b527FFd7416410257' + const order: ExtendedZXOrder = { + protocol: Protocol.PMMV5, + quoteId: `0x123`, + exchangeAddress: `0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64`.toLowerCase(), + feeRecipientAddress: `0x45352`, + senderAddress: `0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64`, + takerAddress: '0x6813Eb9362372EEF6200f3b1dbC3f819671cBA69', + makerAddress: '0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64'.toLowerCase(), + takerAssetData: assetDataUtils.encodeERC20AssetData( + '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' + ), + makerAssetData: assetDataUtils.encodeERC20AssetData( + '0xdac17f958d2ee523a2206206994597c13d831ec7' + ), + takerFee: toBN(0), + makerFee: toBN(0), + takerAssetAddress: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + makerAssetAddress: '0xdac17f958d2ee523a2206206994597c13d831ec7', + takerAssetAmount: new BigNumber('0x0de0b6b3a7640000'), + makerAssetAmount: new BigNumber('0x05f5e100'), + salt: new BigNumber('0x44df74b1c54e9792989c61fedcef6f94b534b58933cde70bc456ec74cf4d3610'), + expirationTimeSeconds: toBN(1620444917), + feeFactor: 30, + } + const defaultSignature = `0x12345677777777777777777` + const scope = nock(url) + .post('/') + .reply(200, (_, requestBody) => { + console.log(`requestBody: `) + console.log(requestBody) + return { + signature: defaultSignature, + } + }) + const signedOrder = await buildPMMV5SignedOrder( + undefined, + order, + Wallet.createRandom().address.toLowerCase(), + chainId, + pmm, + { + signingUrl: url, + salt: '0x11111111111111111111111111111111', + } + ) + scope.done() + console.log(signedOrder) + expect(signedOrder).not.null + expect(signedOrder.makerWalletSignature).not.null + expect(signedOrder.makerWalletSignature).eq(defaultSignature) + }) + it('Should forward unsigned RFQV1 orders to signing service', async () => { + const url = `http://localhost:3000` const rfqAddr = '0x117CAf73eB142eDC431E707DC33D4dfeF7c5BAd0' - const order = { + const order: ExtendedZXOrder = { + protocol: Protocol.RFQV1, + quoteId: `0x123`, + exchangeAddress: `0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64`.toLowerCase(), + feeRecipientAddress: `0x45352`, + senderAddress: `0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64`, takerAddress: '0x6813Eb9362372EEF6200f3b1dbC3f819671cBA69', - makerAddress: '0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64', + makerAddress: '0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64'.toLowerCase(), + takerAssetData: assetDataUtils.encodeERC20AssetData( + '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' + ), + makerAssetData: assetDataUtils.encodeERC20AssetData( + '0xdac17f958d2ee523a2206206994597c13d831ec7' + ), + takerFee: toBN(0), + makerFee: toBN(0), takerAssetAddress: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', makerAssetAddress: '0xdac17f958d2ee523a2206206994597c13d831ec7', takerAssetAmount: new BigNumber('0x0de0b6b3a7640000'), makerAssetAmount: new BigNumber('0x05f5e100'), salt: new BigNumber('0x44df74b1c54e9792989c61fedcef6f94b534b58933cde70bc456ec74cf4d3610'), - expirationTimeSeconds: 1620444917, + expirationTimeSeconds: toBN(1620444917), feeFactor: 30, } - const signedOrder = await buildSignedOrder( - signer, + const defaultSignature = `0x12345677777777777777777` + const scope = nock(url) + .post('/') + .reply(200, (_, requestBody) => { + console.log(`requestBody: `) + console.log(requestBody) + return { + signature: defaultSignature, + } + }) + const signedOrder = await buildRFQV1SignedOrder( + undefined, order, Wallet.createRandom().address.toLowerCase(), chainId, rfqAddr, WalletType.MMP_VERSION_4, { + signingUrl: url, salt: '0x11111111111111111111111111111111', } ) + scope.done() console.log(signedOrder) expect(signedOrder).not.null + expect(signedOrder.makerWalletSignature).not.null + expect(signedOrder.makerWalletSignature).eq(defaultSignature) + }) + it('Should forward unsigned RFQV2 orders to signing service', async () => { + const url = `http://localhost:3000` + const rfqV2Addr = '0xaE5FDd548E5B107C54E5c0D36952fB8a089f10C7' + const order: ExtendedZXOrder = { + protocol: Protocol.RFQV2, + quoteId: `0x123`, + exchangeAddress: `0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64`.toLowerCase(), + feeRecipientAddress: `0x45352`, + senderAddress: `0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64`, + takerAddress: '0x6813Eb9362372EEF6200f3b1dbC3f819671cBA69', + makerAddress: '0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64'.toLowerCase(), + takerAssetData: assetDataUtils.encodeERC20AssetData( + '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' + ), + makerAssetData: assetDataUtils.encodeERC20AssetData( + '0xdac17f958d2ee523a2206206994597c13d831ec7' + ), + takerFee: toBN(0), + makerFee: toBN(0), + takerAssetAddress: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + makerAssetAddress: '0xdac17f958d2ee523a2206206994597c13d831ec7', + takerAssetAmount: new BigNumber('0x0de0b6b3a7640000'), + makerAssetAmount: new BigNumber('0x05f5e100'), + salt: new BigNumber('0x44df74b1c54e9792989c61fedcef6f94b534b58933cde70bc456ec74cf4d3610'), + expirationTimeSeconds: toBN(1620444917), + feeFactor: 30, + } + const defaultSignature = `0x12345677777777777777777` + const scope = nock(url) + .post('/') + .reply(200, (_, requestBody) => { + console.log(`requestBody: `) + console.log(requestBody) + return { + signature: defaultSignature, + } + }) + const signedOrder = await buildRFQV2SignedOrder( + undefined, + order, + Wallet.createRandom().address.toLowerCase(), + chainId, + rfqV2Addr, + WalletType.MMP_VERSION_4, + PermitType.ALLOWANCE_TARGET, + { + signingUrl: url, + salt: '0x11111111111111111111111111111111', + } + ) + scope.done() + expect(signedOrder).not.null + expect(signedOrder.makerWalletSignature).not.null + expect(signedOrder.makerWalletSignature).eq(defaultSignature) }) it('Should generate correct salt', async () => { const givenPrefixSalt = generateSaltWithFeeFactor(30, '0x11111111111111111111111111111111') const salt = generateSaltWithFeeFactor(30) console.log(givenPrefixSalt.toString(16)) + console.log(ethUtils.toBuffer('0x' + salt.toString(16)).length) console.log(salt.toString(16)) - expect(givenPrefixSalt.toString(16).length).is.eq(64) - expect(salt.toString(16).length).is.eq(64) + expect(ethUtils.toBuffer('0x' + givenPrefixSalt.toString(16)).length).is.eq(32) + expect(ethUtils.toBuffer('0x' + salt.toString(16)).length).is.eq(32) }) }) diff --git a/test/numbers.spec.ts b/test/numbers.spec.ts index 122e7ac..cac24e1 100644 --- a/test/numbers.spec.ts +++ b/test/numbers.spec.ts @@ -1,17 +1,17 @@ import { assert } from 'chai' -import { fromUnitToDecimalBN, orderBNToString, toBN, truncateAmount } from '../src/utils' +import { fromUnitToDecimalBN, toBN, truncateAmount } from '../src/utils' describe('Numbers', function () { it('.fromUnitToDecimalBN works', function () { assert.equal(fromUnitToDecimalBN(1.23456789, 6).toString(), toBN(1234567).toString()) }) - describe('.orderBNToString', function () { - it('works', function () { - assert.notStrictEqual(orderBNToString({ foo: 'bar' }), { foo: 'bar' }) - assert.notStrictEqual(orderBNToString({ foo: toBN(1) }), { foo: '1' }) - }) - }) + // describe('.orderBNToString', function () { + // it('works', function () { + // assert.notStrictEqual(orderBNToString({ foo: 'bar' }), { foo: 'bar' }) + // assert.notStrictEqual(orderBNToString({ foo: toBN(1) }), { foo: toBN('1') }) + // }) + // }) describe('.truncateAmount', function () { it('works', function () { diff --git a/tsconfig.json b/tsconfig.json index ba9e108..195d2e5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -22,7 +22,7 @@ ] }, "include": [ - "./src/**/*" + "./src/**/*", ], "exclude": [ "./node_modules",